diff options
Diffstat (limited to 'libparser.c')
| -rw-r--r-- | libparser.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/libparser.c b/libparser.c index eec9337..7ef7267 100644 --- a/libparser.c +++ b/libparser.c @@ -119,7 +119,7 @@ struct choice { /** * The follow-ups */ - struct followup *followups; + struct followup *followups; /* TODO add memory pool, maybe even use a memory stack */ /** * The number of follow-ups; this is @@ -266,6 +266,7 @@ sentence_type_string(enum libparser_sentence_type type) case LIBPARSER_SENTENCE_TYPE_EXCEPTION: return "EXCEPTION"; case LIBPARSER_SENTENCE_TYPE_EOF: return "EOF"; case LIBPARSER_SENTENCE_TYPE_EPSILON: return "EPSILON"; + case LIBPARSER_SENTENCE_TYPE_COMMITTED: return "COMMITTED"; default: return "<invalid>"; } } @@ -390,6 +391,13 @@ print_sentence(const union libparser_sentence *sentence, int indent) indent += 1; break; + case LIBPARSER_SENTENCE_TYPE_COMMITTED: + fprintf(stderr, "+("); + indent = print_sentence(sentence->unary.sentence, indent + 2); + fprintf(stderr, ")"); + indent += 1; + break; + case LIBPARSER_SENTENCE_TYPE_OPTIONAL: fprintf(stderr, "["); indent = print_sentence(sentence->unary.sentence, indent + 1); @@ -882,6 +890,12 @@ add_unit(const char *rule, const union libparser_sentence *sentence, struct cont ctx->previous_rejection = ctx->units.count - 1u; return 1; + case LIBPARSER_SENTENCE_TYPE_COMMITTED: + if (incomplete(NULL, sentence, start, ctx) || + push(NULL, sentence->unary.sentence, ctx)) + return -1; + return 1; + case LIBPARSER_SENTENCE_TYPE_RULE: for (i = 0; ctx->rules[i]; i++) if (!strcmp(ctx->rules[i]->name, sentence->rule.rule)) @@ -993,6 +1007,7 @@ make_tree(struct context *ctx, size_t *unit_i, struct libparser_unit **last) case LIBPARSER_SENTENCE_TYPE_RULE: case LIBPARSER_SENTENCE_TYPE_OPTIONAL: case LIBPARSER_SENTENCE_TYPE_ALTERNATION: + case LIBPARSER_SENTENCE_TYPE_COMMITTED: #if PRINT_ACTIONS fprintf(stderr, "Unary unit: %s: %s [%zu, %zu)\n", sentence_type_string(unit->sentence->type), @@ -1164,7 +1179,7 @@ libparser_parse_file(const struct libparser_rule *const rules[], const char *dat #endif /* TODO guard against left-side recursion */ - /* TODO make branching opt-in ("?"), and add commit statements ("+") */ + /* TODO make branching opt-in ("?") */ /* TODO break REPEATED on empty match */ followup: #if PRINT_ACTIONS @@ -1234,6 +1249,17 @@ followup: } if (!match) goto mismatch; + if (sentence->type == LIBPARSER_SENTENCE_TYPE_COMMITTED) { +#if PRINT_ACTIONS + fprintf(stderr, "Removing interior choices for matched COMMITTED\n"); +#endif + j = ctx.followups.followups[i].unit_index; + while (ctx.choices.count && + ctx.choices.choices[ctx.choices.count - 1u].unit_index > j) { + ctx.choices.next = --ctx.choices.count; + free(ctx.choices.choices[ctx.choices.count].followups.followups); + } + } #if PRINT_ACTIONS fprintf(stderr, "Setting end of popped unit to %zu\n", ctx.position); #endif |
