#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 int (*semantic_action_fn)(int *stack_head); extern semantic_action_fn *semantic_actions; typedef int stack_item; #define STACK_CAP 128 static stack_item stack_bottom[STACK_CAP]; static stack_item *stack_head = stack_bottom; int lr_parser() { #define push(item) ({ if(++stack_head - stack_bottom < STACK_CAP ) (*stack_head = item); else { fprintf(stderr, "ERROR: STACK_CAP exceeded\n"); return 1; }}) #define pop() (--stack_head) #define eat() toklist_eat() #define peek() ({ \ symbol s = toklist_peek(); \ if(!symbol_is_valid(s)) { fprintf(stderr, "ERROR: Unknown token '%d'\n", s); return 1;} \ s; }) while(1) { struct action a = table[(size_t)*stack_head][peek()]; switch(a.type) { case ACTION_SHIFT: push(eat()); push(-10000000); // the semantic action push(a.arg); break; case ACTION_REDUCE: int semantic_value = semantic_actions[a.arg](stack_head); for(size_t i = 0; i < 3*grammar[a.arg].nRHS; i++) pop(); symbol lhs = grammar[a.arg].LHS; struct action a_goto = table[(size_t)*stack_head][lhs]; if(a_goto.type != ACTION_GOTO) { fprintf(stderr, "ERROR: Expected goto action for token '%d' at state %zu\n", lhs, (size_t)*stack_head); return 1; } push(lhs); push(semantic_value); push(a_goto.arg); break; case ACTION_ACCEPT: return *(stack_head-1); case ACTION_NOT_SET: default: fprintf(stderr, "ERROR: Unexpected token '%d' at state %zu\n", peek(), (size_t)*stack_head); return 1; } } return 1; } #ifdef _LR_PARSER_STANDALONE // implement symbol.h enum symbol { PLUS = 0, MINUS, LPAREN, RPAREN, N0, N1, END_INPUT, EP, E, T, N, SYMBOLS_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), }; 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 static symbol toklist[] = {N0, PLUS, N1, END_INPUT}; static symbol *tok = toklist; symbol toklist_eat() { return *(tok++); } // unsafe symbol toklist_peek() { return *tok; } // unsafe int none(int *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) { return lr_parser(); } #endif