]> ocean-lang.org Git - ocean/blobdiff - csrc/parsergen.mdc
parsergen: split out the "shift or ignore" section of parsing.
[ocean] / csrc / parsergen.mdc
index 0986fc28c2b2d0d411eac8ed71d822fb0e323c01..4708e0c01c6ce80f7665ae2f02e1a9f9260acdab 100644 (file)
@@ -2768,6 +2768,82 @@ in the thing that preceed:
 Here the NEWLINE will be shifted because nothing can be reduced until
 the `if` is seen.
 
+For other tokens, we shift the next token if that is possible, otherwise
+we try to reduce a production.
+
+###### try shift or ignore
+
+       if (tk->num == TK_in) {
+               free(tk);
+               tk = NULL;
+               parser_trace_action(trace, "Record");
+               continue;
+       }
+       if (tk->num == TK_out) {
+               if (1) {
+                       // OK to cancel
+                               free(tk);
+                       tk = NULL;
+                       parser_trace_action(trace, "Cancel");
+                       continue;
+               }
+               // fall through to error handling as both SHIFT and REDUCE
+               // will fail.
+       }
+       if (tk->num == TK_newline) {
+               if (1) {
+                       free(tk);
+                       tk = NULL;
+                       parser_trace_action(trace, "Discard");
+                       continue;
+               }
+       }
+       if (shift(&p, tk->num, tk, states)) {
+               tk = NULL;
+               parser_trace_action(trace, "Shift");
+               ## did shift
+               continue;
+       }
+
+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 +2902,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);
@@ -2837,64 +2912,8 @@ dropping tokens until either we manage to shift one, or reach end-of-file.
                        parser_trace(trace, &p,
                                     tk, states, non_term, config->known_count);
 
-                       if (tk->num == TK_in) {
-                               free(tk);
-                               tk = NULL;
-                               parser_trace_action(trace, "Record");
-                               continue;
-                       }
-                       if (tk->num == TK_out) {
-                               if (1) {
-                                       // OK to cancel
-
-                                       free(tk);
-                                       tk = NULL;
-                                       parser_trace_action(trace, "Cancel");
-                                       continue;
-                               }
-                               // fall through to error handling as both SHIFT and REDUCE
-                               // will fail.
-                       }
-                       if (tk->num == TK_newline) {
-                               if (1) {
-                                       free(tk);
-                                       tk = NULL;
-                                       parser_trace_action(trace, "Discard");
-                                       continue;
-                               }
-                       }
-                       if (shift(&p, tk->num, tk, states)) {
-                               tk = NULL;
-                               parser_trace_action(trace, "Shift");
-                               ## did shift
-                               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 shift or ignore
+                       ## try reduce
                        ## handle error
                }
                free(tk);