diff options
Diffstat (limited to 'recursive/recursive-ascent.c')
-rw-r--r-- | recursive/recursive-ascent.c | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/recursive/recursive-ascent.c b/recursive/recursive-ascent.c new file mode 100644 index 0000000..7f69e57 --- /dev/null +++ b/recursive/recursive-ascent.c @@ -0,0 +1,316 @@ +#include <stdio.h> +#include <stdlib.h> + +/* + * 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}; +} |