#include #include /* * For grammar: (https://en.wikipedia.org/wiki/Recursive_ascent_parser) * expr : expr '+' term { $$ = $1 + $3; } * | expr '-' term { $$ = $1 - $3; } * | term { $$ = $1; } * ; * * term : '(' expr ')' { $$ = $2; } * | num { $$ = $1; } * ; * * num : '0' { $$ = 0; } * | '1' { $$ = 1; } * ; */ #pragma GCC diagnostic ignored "-Wunused-value" #define DIE(...) (printf("ERROR %s:%d\n", __FILE__, __LINE__), __VA_OPT__(exit(__VA_ARGS__),) exit(1), 1) enum nonterminal { EXPR, TERM, NUM }; struct result { enum nonterminal nonterm; int value; int depth; char *s; }; struct args { int args[2]; }; #define new_arg(...) (struct args){{__VA_ARGS__}} #define get_arg(a, n) ((a).args[n]) struct result state0(char *s, struct args a); struct result state1(char *s, struct args a); struct result state2(char *s, struct args a); struct result state3(char *s, struct args a); struct result state4(char *s, struct args a); struct result state5(char *s, struct args a); struct result state6(char *s, struct args a); struct result state7(char *s, struct args a); struct result state8(char *s, struct args a); struct result state9(char *s, struct args a); struct result state10(char *s, struct args a); struct result state11(char *s, struct args a); struct result state12(char *s, struct args a); struct result state13(char *s, struct args a); int main(void) { char *s = "1-((0-1)+1+1+1+1+1)-0+1-(((1)))+1+1+1-1+0+(1-0+1)-1-0"; struct result r = state0(s, new_arg(0)); printf("%s = %d\n", s, r.value); return 0; } /* * 0 $accept: . expr $end * * '(' shift, and go to state 1 * '0' shift, and go to state 2 * '1' shift, and go to state 3 * * expr go to state 4 * term go to state 5 * num go to state 6 */ struct result state0(char *s, struct args a) { struct result r = {0}; switch(*s) { case '(': r = state1(s+1, a); break; case '0': r = state2(s+1, a); break; case '1': r = state3(s+1, a); break; default: DIE(); } while(r.depth == 0) { switch(r.nonterm) { case EXPR: r = state4(r.s, new_arg(r.value)); break; case TERM: r = state5(r.s, new_arg(r.value)); break; case NUM: r = state6(r.s, new_arg(r.value)); break; default: DIE(); } } r.depth--; return r; } /* * 4 term: '(' . expr ')' * * '(' shift, and go to state 1 * '0' shift, and go to state 2 * '1' shift, and go to state 3 * * expr go to state 7 * term go to state 5 * num go to state 6 */ struct result state1(char *s, struct args a) { struct result r = {0}; switch(*s) { case '(': r = state1(s+1, a); break; case '0': r = state2(s+1, a); break; case '1': r = state3(s+1, a); break; default: DIE(); } while(r.depth == 0) { switch(r.nonterm) { case EXPR: r = state7(r.s, new_arg(r.value)); break; case TERM: r = state5(r.s, new_arg(r.value)); break; case NUM: r = state6(r.s, new_arg(r.value)); break; default: DIE(); } } r.depth--; return r; } /* * 6 num: '0' . * * $default reduce using rule 6 (num) */ struct result state2(char *s, struct args a) { (void)a; return (struct result){NUM, 0, 0, s}; } /* * 7 num: '1' . * * $default reduce using rule 7 (num) */ struct result state3(char *s, struct args a) { (void)a; return (struct result){NUM, 1, 0, s}; } /* * 0 $accept: expr . $end * 1 expr: expr . '+' term * 2 | expr . '-' term * * $end shift, and go to state 8 * '+' shift, and go to state 9 * '-' shift, and go to state 10 */ struct result state4(char *s, struct args a) { struct result r = {0}; switch(*s) { case '\0': r = state8(s+1, a); break; case '+': r = state9(s+1, a); break; case '-': r = state10(s+1, a); break; default: DIE(); } (r.depth == 0) && DIE(); r.depth--; return r; } /* * 3 expr: term . * * $default reduce using rule 3 (expr) */ struct result state5(char *s, struct args a) { return (struct result){EXPR, get_arg(a, 0), 0, s}; } /* * 5 term: num . * * $default reduce using rule 5 (term) */ struct result state6(char *s, struct args a) { return (struct result){TERM, get_arg(a, 0), 0, s}; } /* * 1 expr: expr . '+' term * 2 | expr . '-' term * 4 term: '(' expr . ')' * * '+' shift, and go to state 9 * '-' shift, and go to state 10 * ')' shift, and go to state 11 */ struct result state7(char *s, struct args a) { struct result r = {0}; switch(*s) { case '+': r = state9(s+1, a); break; case '-': r = state10(s+1, a); break; case ')': r = state11(s+1, a); break; default: DIE(); } (r.depth == 0) && DIE(); r.depth--; return r; } /* * 0 $accept: expr $end . * * $default accept */ struct result state8(char *s, struct args a) { return (struct result){EXPR, a.args[0], 2, s}; } /* * 1 expr: expr '+' . term * * '(' shift, and go to state 1 * '0' shift, and go to state 2 * '1' shift, and go to state 3 * * term go to state 12 * num go to state 6 */ struct result state9(char *s, struct args a) { struct result r = {0}; switch(*s) { case '(': r = state1(s+1, a); break; case '0': r = state2(s+1, a); break; case '1': r = state3(s+1, a); break; default: DIE(); } while(r.depth == 0) { switch(r.nonterm) { case TERM: r = state12(r.s, new_arg(r.value, get_arg(a, 0))); break; case NUM: r = state6(r.s, new_arg(r.value)); break; default: DIE(); } } r.depth--; return r; } /* * 2 expr: expr '-' . term * * '(' shift, and go to state 1 * '0' shift, and go to state 2 * '1' shift, and go to state 3 * * term go to state 13 * num go to state 6 */ struct result state10(char *s, struct args a) { struct result r = {0}; switch(*s) { case '(': r = state1(s+1, a); break; case '0': r = state2(s+1, a); break; case '1': r = state3(s+1, a); break; default: DIE(); } while(r.depth == 0) { switch(r.nonterm) { case TERM: r = state13(r.s, new_arg(get_arg(a, 0), r.value)); break; case NUM: r = state6(r.s, new_arg(r.value)); break; default: DIE(); } } r.depth--; return r; } /* * 4 term: '(' expr ')' . * * $default reduce using rule 4 (term) */ struct result state11(char *s, struct args a) { return (struct result){TERM, get_arg(a, 0), 2, s}; } /* * 1 expr: expr '+' term . * * $default reduce using rule 1 (expr) */ struct result state12(char *s, struct args a) { return (struct result){EXPR, get_arg(a, 0) + get_arg(a, 1), 2, s}; } /* * 2 expr: expr '-' term . * * $default reduce using rule 2 (expr) */ struct result state13(char *s, struct args a) { return (struct result){EXPR, get_arg(a, 0) - get_arg(a, 1), 2, s}; }