- struct parser p = { 0 };
- struct frame next = { 0 };
- struct token *tk = NULL;
- int accepted = 0;
- void *ret = NULL;
-
- shift(&p, &next, NULL, states);
- while (!accepted) {
- struct token *err_tk;
- struct frame *tos = &p.stack[p.tos-1];
- if (!tk)
- tk = tok_copy(token_next(tokens));
- next.sym = tk->num;
- parser_trace(trace, &p, &next, tk, states, non_term, config->known_count);
-
- if (next.sym == TK_in) {
- next.starts_indented = 1;
- next.indents = 1;
- next.since_newline = 0;
- free(tk);
- tk = NULL;
- parser_trace_action(trace, "Record");
- continue;
- }
- if (next.sym == TK_out) {
- if (tos->indents > tos->starts_indented ||
- (tos->indents == 1 &&
- states[tos->state].reduce_size != 1)) {
- tos->indents -= 1;
- if (tos->indents <= tos->starts_indented) {
- // no internal indent any more, reassess 'newline_permitted'
- if (states[tos->state].starts_line)
- tos->newline_permitted = 1;
- else if (p.tos > 1)
- tos->newline_permitted = p.stack[p.tos-2].newline_permitted;
- else
- tos->newline_permitted = 0;
- }
- free(tk);
- tk = NULL;
- parser_trace_action(trace, "Cancel");
- continue;
- }
- // fall through and force a REDUCE (as 'shift'
- // will fail).
- }
- if (next.sym == TK_newline) {
- if (!tos->newline_permitted) {
- free(tk);
- tk = NULL;
- parser_trace_action(trace, "Discard");
- continue;
- }
- if (states[tos->state].reduce_size > 0 &&
- states[tos->state].reduce_size < tos->since_newline)
- goto force_reduce;
- }
- if (shift(&p, &next, tk, states)) {
- next.since_newline = !(tk->num == TK_newline);
- next.starts_indented = 0;
- next.indents = 0;
- tk = NULL;
- parser_trace_action(trace, "Shift");
- continue;
- }
- force_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 bufsize;
- static char buf[16*1024];
- struct frame frame;
- frame.sym = nextstate->reduce_sym;
-
- body = p.asn_stack + (p.tos - size);
-
- bufsize = do_reduce(prod, body, config, buf);
-
- if (size)
- pop(&p, size, &frame, do_free);
- else {
- frame.indents = next.indents;
- frame.starts_indented = frame.indents;
- frame.since_newline = 1;
- next.indents = 0;
- next.starts_indented = 0;
- }
- res = memdup(buf, bufsize);
- memset(buf, 0, bufsize);
- if (!shift(&p, &frame, res, states)) {
- if (prod != 0) abort();
- accepted = 1;
- ret = res;
- }
- parser_trace_action(trace, "Reduce");
- continue;
- }
- if (tk->num == TK_out) {
- // Indent problem - synthesise tokens to get us
- // out of here.
- struct frame frame = { 0 };
- fprintf(stderr, "Synthesize %d to handle indent problem\n", states[tos->state].shift_sym);
- frame.sym = states[tos->state].shift_sym;
- frame.since_newline = 1;
- shift(&p, &frame, tok_copy(*tk), states);
- // FIXME need to report this error somehow
- parser_trace_action(trace, "Synthesize");
- continue;
- }
- /* Error. We walk up the stack until we
- * find a state which will accept TK_error.
- * We then shift in TK_error and see what state
- * that takes us too.
- * Then we discard input tokens until
- * we find one that is acceptable.
- */
- parser_trace_action(trace, "ERROR");
-
- err_tk = tok_copy(*tk);
- next.sym = TK_error;
- while (shift(&p, &next, err_tk, states) == 0
- && p.tos > 0)
- // discard this state
- pop(&p, 1, &next, do_free);
- if (p.tos == 0) {
- free(err_tk);
- // no state accepted TK_error
- break;
- }
- tos = &p.stack[p.tos-1];
- while (search(&states[tos->state], tk->num) < 0 &&
- tk->num != TK_eof) {
- free(tk);
- tk = tok_copy(token_next(tokens));
- if (tk->num == TK_in)
- next.indents += 1;
- if (tk->num == TK_out) {
- if (next.indents == 0)
- break;
- next.indents -= 1;
- }
- }
- if (p.tos == 0 && tk->num == TK_eof)
- break;
- }