+Being able to visualize the parser in action can be invaluable when
+debugging the parser code, or trying to understand how the parse of a
+particular grammar progresses. The stack contains all the important
+state, so just printing out the stack every time around the parse loop
+can make it possible to see exactly what is happening.
+
+This doesn't explicitly show each SHIFT and REDUCE action. However they
+are easily deduced from the change between consecutive lines, and the
+details of each state can be found by cross referencing the states list
+in the stack with the "report" that parsergen can generate.
+
+For terminal symbols, we just dump the token. For non-terminals we
+print the name of the symbol. The look ahead token is reported at the
+end inside square brackets.
+
+###### parser functions
+
+ static char *reserved_words[] = {
+ [TK_error] = "ERROR",
+ [TK_in] = "IN",
+ [TK_out] = "OUT",
+ [TK_newline] = "NEWLINE",
+ [TK_eof] = "$eof",
+ };
+ void parser_trace(FILE *trace, struct parser *p,
+ struct token *tk, const struct state states[],
+ const char *non_term[], int knowns)
+ {
+ int i;
+ for (i = 0; i < p->tos; i++) {
+ int sym = p->stack[i].sym;
+ fprintf(trace, "(%d) ", p->stack[i].state);
+ if (sym < TK_reserved &&
+ reserved_words[sym] != NULL)
+ fputs(reserved_words[sym], trace);
+ else if (sym < TK_reserved + knowns) {
+ struct token *t = p->asn_stack[i];
+ text_dump(trace, t->txt, 20);
+ } else
+ fputs(non_term[sym - TK_reserved - knowns],
+ trace);
+ fputs(" ", trace);
+ }
+ fprintf(trace, "(%d) [", p->next.state);
+ if (tk->num < TK_reserved &&
+ reserved_words[tk->num] != NULL)
+ fputs(reserved_words[tk->num], trace);
+ else
+ text_dump(trace, tk->txt, 20);
+ fputs("]\n", trace);
+ }