From 1e9e9bf3bcaae175eac4ceb07cff74ac165d13c8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 10 Mar 2021 10:56:15 +1100 Subject: [PATCH] parsergen: split out reduce step of parser Split out the "reduce" code so it can be more easily documented. Signed-off-by: NeilBrown --- csrc/parsergen.mdc | 66 ++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/csrc/parsergen.mdc b/csrc/parsergen.mdc index 0986fc2..6eb4318 100644 --- a/csrc/parsergen.mdc +++ b/csrc/parsergen.mdc @@ -2768,6 +2768,45 @@ in the thing that preceed: Here the NEWLINE will be shifted because nothing can be reduced until the `if` is seen. +We have already discussed the bulk of the handling of a "reduce" action, +with the `pop()` and `shift()` functions doing much of the work. There +is a little more complexity needed to manage storage for the asn (Abstract +Syntax Node), and also a test of whether the reduction is permitted. + +When we try to shift the result of reducing production-zero, it will +fail because there is no next state. In this case the asn will not have +been stored on the stack, so it get stored in the `ret` variable, and we +report that that input has been accepted. + +###### parser vars + + void *ret = NULL; + +###### try reduce + + if (states[tos->state].reduce_prod >= 0) { + void **body; + void *res; + const struct state *nextstate = &states[tos->state]; + int prod = nextstate->reduce_prod; + int size = nextstate->reduce_size; + int res_size = nextstate->result_size; + + body = p.asn_stack + (p.tos - size); + res = res_size ? calloc(1, res_size) : NULL; + res_size = do_reduce(prod, body, config, res); + if (res_size != nextstate->result_size) + abort(); + pop(&p, size, do_free); + if (!shift(&p, nextstate->reduce_sym, res, states)) { + accepted = 1; + ret = res; + parser_trace_action(trace, "Accept"); + } else + parser_trace_action(trace, "Reduce"); + continue; + } + If we can neither shift nor reduce we have an error to handle. There are two possible responses to an error: we can pop single frames off the stack until we find a frame that can shift `TK_error`, or we can discard @@ -2826,7 +2865,6 @@ dropping tokens until either we manage to shift one, or reach end-of-file. struct parser p = { 0 }; struct token *tk = NULL; int accepted = 0; - void *ret = NULL; ## parser vars shift(&p, TK_eof, NULL, states); @@ -2870,31 +2908,7 @@ dropping tokens until either we manage to shift one, or reach end-of-file. continue; } - if (states[tos->state].reduce_prod >= 0) { - void **body; - void *res; - const struct state *nextstate = &states[tos->state]; - int prod = nextstate->reduce_prod; - int size = nextstate->reduce_size; - int res_size = nextstate->result_size; - - body = p.asn_stack + (p.tos - size); - res = res_size ? calloc(1, res_size) : NULL; - res_size = do_reduce(prod, body, config, res); - if (res_size != nextstate->result_size) - abort(); - - pop(&p, size, do_free); - - if (!shift(&p, nextstate->reduce_sym, - res, states)) { - if (prod != 0) abort(); - accepted = 1; - ret = res; - } - parser_trace_action(trace, "Reduce"); - continue; - } + ## try reduce ## handle error } free(tk); -- 2.43.0