]> ocean-lang.org Git - ocean/blobdiff - csrc/parsergen.mdc
parsergen: split out heart-of-the-parser code
[ocean] / csrc / parsergen.mdc
index 0986fc28c2b2d0d411eac8ed71d822fb0e323c01..554e63c37c921faea604399f7a9dd1f968b7cc84 100644 (file)
@@ -2724,6 +2724,28 @@ Now we have the parser.  For each token we might shift it, trigger a
 reduction, or start error handling.  2D tokens (IN, OUT, EOL) also need
 to be handled.
 
+###### parser vars
+
+       struct parser p = { 0 };
+       struct token *tk = NULL;
+       int accepted = 0;
+
+###### heart of parser
+
+       shift(&p, TK_eof, NULL, states);
+       while (!accepted && p.tos > 0) {
+               struct frame *tos = &p.stack[p.tos-1];
+               if (!tk)
+                       tk = tok_copy(token_next(tokens));
+               parser_trace(trace, &p,
+                            tk, states, non_term, config->known_count);
+
+               ## try shift or ignore
+               ## try reduce
+               ## handle error
+       }
+
+
 We return whatever `asn` was returned by reducing production zero.
 
 When we find `TK_in` and `TK_out` tokens which report indents we need
@@ -2768,6 +2790,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
@@ -2823,80 +2921,10 @@ dropping tokens until either we manage to shift one, or reach end-of-file.
                         FILE *trace, const char *non_term[],
                         struct token_config *config)
        {
-               struct parser p = { 0 };
-               struct token *tk = NULL;
-               int accepted = 0;
-               void *ret = NULL;
                ## parser vars
 
-               shift(&p, TK_eof, NULL, states);
-               while (!accepted && p.tos > 0) {
-                       struct frame *tos = &p.stack[p.tos-1];
-                       if (!tk)
-                               tk = tok_copy(token_next(tokens));
-                       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;
-                       }
+               ## heart of parser
 
-                       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;
-                       }
-                       ## handle error
-               }
                free(tk);
                pop(&p, p.tos, do_free);
                free(p.asn_stack);