#include #include #include // TODO: - check erros and fail safely and // see connection with the lexer // - standardize this // Requirements #include "parts/symbol.h" #include "parts/grammar.h" #include "parts/table.h" #include "parts/toklist.h" // and typedef stack_item (*semantic_action_fn)(stack_item *item_head); extern semantic_action_fn *semantic_actions; #define STACK_CAP 128 static stack_item item_bottom[STACK_CAP]; static stack_item *item_head = item_bottom; static int state_bottom[STACK_CAP]; static int *state_head = state_bottom; static void print_stack() { fprintf(stderr, "STACK: { "); for(int *s = state_bottom+1; s <= state_head; s += 2) fprintf(stderr, "%s ", symbol_to_str[*(symbol *)s]); fprintf(stderr, "}\n\n"); } struct lr_errinfo { enum lr_errtype { LR_ERR_STACKCAP_EXCEEDED, LR_ERR_UNEXPECTED_SYMBOL, LR_ERR_NO_GOTO_ENTRY } type; union { size_t stack_cap; struct { symbol sym; size_t state; } idx; }; }; struct lr_errinfo *lr_parser(void *value) { static struct lr_errinfo errinfo; #define push(stack_head, stack_bottom, item) do { \ if(++stack_head - stack_bottom < STACK_CAP ) *stack_head = item; \ else { errinfo = (struct lr_errinfo){.type = LR_ERR_STACKCAP_EXCEEDED, .stack_cap = STACK_CAP }; return &errinfo; } \ } while(0) #define pop(stack_head) (--stack_head) #define spush(item) push(state_head, state_bottom, item) #define spop() pop(state_head) #define ipush(item) push(item_head, item_bottom, item) #define ipop() pop(item_head) #define eat() toklist_eat() #define peek() toklist_peek() while(1) { struct action a = table[(size_t)*state_head][token_sym(peek())]; switch(a.type) { case ACTION_SHIFT:; struct token *t = eat(); ipush(*(stack_item*)token_val(t)); spush(token_sym(t)); spush(a.arg); #ifdef _LR_PARSER_DEBUG fprintf(stderr, "SHIFT %s\n", symbol_to_str[token_sym(t)]); print_stack(); #endif break; case ACTION_REDUCE: stack_item semantic_value = semantic_actions[a.arg](item_head); for(size_t i = 0; i < grammar[a.arg].nRHS; i++) { ipop(); spop(); spop(); } symbol lhs = grammar[a.arg].LHS; struct action a_goto = table[(size_t)*state_head][lhs]; if(a_goto.type != ACTION_GOTO) { errinfo = (struct lr_errinfo){.type = LR_ERR_NO_GOTO_ENTRY, .idx = {lhs, (size_t)*state_head}}; return &errinfo; } ipush(semantic_value); spush(lhs); spush(a_goto.arg); #ifdef _LR_PARSER_DEBUG fprintf(stderr, "READUCE %s\n", symbol_to_str[lhs]); print_stack(); #endif break; case ACTION_ACCEPT: ipush((stack_item){0}); spush(0); spush(0); // todo: better fix for reducing the final production expecting an END_INPUT on the stack *(stack_item *)value = semantic_actions[0](item_head); return NULL; case ACTION_NOT_SET: default: errinfo = (struct lr_errinfo){.type = LR_ERR_UNEXPECTED_SYMBOL, .idx = {token_sym(peek()), (size_t)*state_head}}; return &errinfo; } } } char *lr_err_str(struct lr_errinfo *errinfo) { // TODO: check if strbuf cap is exceeded static char strbuf[128]; switch(errinfo->type) { case LR_ERR_STACKCAP_EXCEEDED: snprintf(strbuf, sizeof(strbuf), "LR parser stack capacity of %zu has been exceeded", errinfo->stack_cap); break; case LR_ERR_UNEXPECTED_SYMBOL: snprintf(strbuf, sizeof(strbuf), "Unexpected symbol '%s' at state '%zu'", symbol_to_str[errinfo->idx.sym], errinfo->idx.state); break; case LR_ERR_NO_GOTO_ENTRY: snprintf(strbuf, sizeof(strbuf), "No GOTO state for symbol '%s' at state '%zu'", symbol_to_str[errinfo->idx.sym], errinfo->idx.state); break; } return strbuf; } #ifdef _LR_PARSER_STANDALONE // implement symbol.h enum symbol { PLUS = 0, MINUS, LPAREN, RPAREN, N0, N1, END_INPUT, EP, E, T, N, SYMBOLS_END, }; char **symbol_to_str = (char*[]){"+", "-", "(", ")", "0", "1", "IN_END", "EP", "E", "T", "N", "S_END"}; size_t total_symbols = SYMBOLS_END; IMPLEMENT_FUNCPTR(int, symbol_is_valid, (symbol s)) { return s < SYMBOLS_END; } // implement grammar.h #define PROD(LHS, _, ...) {LHS, (symbol[]){__VA_ARGS__}, sizeof((symbol[]){__VA_ARGS__})/sizeof(symbol)} static struct production _grammar[] = { PROD(EP, ->, E, END_INPUT), PROD(E, -->, E, PLUS, T), PROD(E, -->, E, MINUS, T), PROD(E, -->, T), PROD(T, -->, LPAREN, E, RPAREN), PROD(T, -->, N), PROD(N, -->, N0), PROD(N, -->, N1), }; int *precedence_symbol = (int[]){0}; int *precedence_production = (int[]){0}; struct production *grammar = _grammar; size_t total_productions = sizeof(_grammar)/sizeof(*_grammar); // implement table.h struct action **table = (struct action *([])){ (struct action[]){{0, 0},{0, 0},{1, 1},{0, 0},{1, 2},{1, 3},{0, 0},{0, 0},{2, 12},{2, 11},{2, 7},}, (struct action[]){{0, 0},{0, 0},{1, 1},{0, 0},{1, 2},{1, 3},{0, 0},{0, 0},{2, 4},{2, 11},{2, 7},}, (struct action[]){{3, 6},{3, 6},{0, 0},{3, 6},{0, 0},{0, 0},{3, 6},{0, 0},{0, 0},{0, 0},{0, 0},}, (struct action[]){{3, 7},{3, 7},{0, 0},{3, 7},{0, 0},{0, 0},{3, 7},{0, 0},{0, 0},{0, 0},{0, 0},}, (struct action[]){{1, 5},{1, 8},{0, 0},{1, 10},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},{0, 0},}, (struct action[]){{0, 0},{0, 0},{1, 1},{0, 0},{1, 2},{1, 3},{0, 0},{0, 0},{0, 0},{2, 6},{2, 7},}, (struct action[]){{3, 1},{3, 1},{0, 0},{3, 1},{0, 0},{0, 0},{3, 1},{0, 0},{0, 0},{0, 0},{0, 0},}, (struct action[]){{3, 5},{3, 5},{0, 0},{3, 5},{0, 0},{0, 0},{3, 5},{0, 0},{0, 0},{0, 0},{0, 0},}, (struct action[]){{0, 0},{0, 0},{1, 1},{0, 0},{1, 2},{1, 3},{0, 0},{0, 0},{0, 0},{2, 9},{2, 7},}, (struct action[]){{3, 2},{3, 2},{0, 0},{3, 2},{0, 0},{0, 0},{3, 2},{0, 0},{0, 0},{0, 0},{0, 0},}, (struct action[]){{3, 4},{3, 4},{0, 0},{3, 4},{0, 0},{0, 0},{3, 4},{0, 0},{0, 0},{0, 0},{0, 0},}, (struct action[]){{3, 3},{3, 3},{0, 0},{3, 3},{0, 0},{0, 0},{3, 3},{0, 0},{0, 0},{0, 0},{0, 0},}, (struct action[]){{1, 5},{1, 8},{0, 0},{0, 0},{0, 0},{0, 0},{4, 0},{0, 0},{0, 0},{0, 0},{0, 0},}, }; size_t table_states = 13; // implement toklist.h struct token { symbol s; intmax_t v; }; static struct token toklist[] = {{N0, 0}, {PLUS, 0}, {N1, 0}, {END_INPUT, 0}}; static const size_t ntoklist = sizeof(toklist)/sizeof(*toklist); static size_t tok; struct token *toklist_eat() { if(tok == ntoklist) return toklist + ntoklist-1; return toklist + tok++; } struct token *toklist_peek() { return toklist + tok; } symbol token_sym(struct token *t) { return t->s; } intptr_t token_val(struct token *t) { return (intptr_t)&t->v; } intmax_t none(intmax_t *stack_head) {(void)stack_head; return 0;} semantic_action_fn *semantic_actions = (semantic_action_fn[]){none, none, none, none, none, none, none, none}; int main(void) { intmax_t value; if(lr_parser(&value)) return 1; printf("%ld\n", value); return 0; } #endif