From 54ba62bfb7e77db43df7f50dbdfc9640bc10ebb2 Mon Sep 17 00:00:00 2001 From: "Sven M. Hallberg" <pesco@khjk.org> Date: Wed, 19 Jun 2013 17:01:13 +0200 Subject: [PATCH] record conflicts in a special HLRAction type --- src/backends/lalr.c | 13 ++++++++++--- src/backends/lr.c | 21 +++++++++++++++++++++ src/backends/lr.h | 13 ++++++++++--- src/backends/lr0.c | 24 +++++++++++++++--------- 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/backends/lalr.c b/src/backends/lalr.c index fa67e5a7..698b106d 100644 --- a/src/backends/lalr.c +++ b/src/backends/lalr.c @@ -138,7 +138,8 @@ int h_lrtable_put(HLRTable *tbl, size_t state, HCFChoice *x, HLRAction *action) HLRAction *prev = h_hashtable_get(tbl->rows[state], x); if(prev && prev != action) { // conflict - h_slist_push(tbl->inadeq, (void *)(uintptr_t)state); + action = h_lr_conflict(tbl->arena, prev, action); + h_hashtable_put(tbl->rows[state], x, action); return -1; } else { h_hashtable_put(tbl->rows[state], x, action); @@ -221,6 +222,7 @@ int h_lalr_compile(HAllocator* mm__, HParser* parser, const void* params) for(HSlistNode *x=inadeq->head; x; x=x->next) { size_t state = (uintptr_t)x->elem; + bool inadeq = false; // clear old forall entry, it's being replaced by more fine-grained ones table->forall[state] = NULL; @@ -255,7 +257,8 @@ int h_lalr_compile(HAllocator* mm__, HParser* parser, const void* params) if(fs->end_branch) { HCFChoice *terminal = h_arena_malloc(arena, sizeof(HCFChoice)); terminal->type = HCF_END; - h_lrtable_put(table, state, terminal, action); + if(h_lrtable_put(table, state, terminal, action) < 0) + inadeq = true; } H_FOREACH(fs->char_branches, void *key, HStringMap *m) if(!m->epsilon_branch) @@ -265,10 +268,14 @@ int h_lalr_compile(HAllocator* mm__, HParser* parser, const void* params) terminal->type = HCF_CHAR; terminal->chr = key_char((HCharKey)key); - h_lrtable_put(table, state, terminal, action); + if(h_lrtable_put(table, state, terminal, action) < 0) + inadeq = true; H_END_FOREACH // lookahead character } H_END_FOREACH // enhanced production H_END_FOREACH // reducible item + + if(inadeq) + h_slist_push(table->inadeq, (void *)(uintptr_t)state); } } diff --git a/src/backends/lr.c b/src/backends/lr.c index 2d329b13..bf066455 100644 --- a/src/backends/lr.c +++ b/src/backends/lr.c @@ -159,6 +159,25 @@ HLRAction *h_reduce_action(HArena *arena, const HLRItem *item) return action; } +// adds 'new' to the branches of 'action' +// returns a 'action' if it is already of type HLR_CONFLICT +// allocates a new HLRAction otherwise +HLRAction *h_lr_conflict(HArena *arena, HLRAction *action, HLRAction *new) +{ + if(action->type != HLR_CONFLICT) { + HLRAction *old = action; + action = h_arena_malloc(arena, sizeof(HLRAction)); + action->type = HLR_CONFLICT; + action->branches = h_slist_new(arena); + h_slist_push(action->branches, old); + } + + assert(action->type == HLR_CONFLICT); + h_slist_push(action->branches, new); + + return action; +} + /* LR driver */ @@ -239,6 +258,8 @@ bool h_lrengine_step(HLREngine *engine, const HLRAction *action) if(action == NULL) return false; // no handle recognizable in input, terminate + assert(action->type == HLR_SHIFT || action->type == HLR_REDUCE); + if(action->type == HLR_SHIFT) { h_slist_push(left, (void *)(uintptr_t)engine->state); h_slist_pop(right); // symbol (discard) diff --git a/src/backends/lr.h b/src/backends/lr.h index b95c1332..13e10d41 100644 --- a/src/backends/lr.h +++ b/src/backends/lr.h @@ -28,16 +28,22 @@ typedef struct HLRItem_ { } HLRItem; typedef struct HLRAction_ { - enum {HLR_SHIFT, HLR_REDUCE} type; + enum {HLR_SHIFT, HLR_REDUCE, HLR_CONFLICT} type; union { - size_t nextstate; // used with SHIFT + // used with HLR_SHIFT + size_t nextstate; + + // used with HLR_REDUCE struct { HCFChoice *lhs; // symbol carrying semantic actions etc. size_t length; // # of symbols in rhs #ifndef NDEBUG HCFChoice **rhs; // NB: the rhs symbols are not needed for the parse #endif - } production; // used with REDUCE + } production; + + // used with HLR_CONFLICT + HSlist *branches; // list of possible HLRActions }; } HLRAction; @@ -104,6 +110,7 @@ void h_lrtable_free(HLRTable *table); HLREngine *h_lrengine_new(HArena *arena, HArena *tarena, const HLRTable *table); HLRAction *h_reduce_action(HArena *arena, const HLRItem *item); HLRAction *h_shift_action(HArena *arena, size_t nextstate); +HLRAction *h_lr_conflict(HArena *arena, HLRAction *action, HLRAction *new); bool h_eq_symbol(const void *p, const void *q); bool h_eq_lr_itemset(const void *p, const void *q); diff --git a/src/backends/lr0.c b/src/backends/lr0.c index aab2ad19..67cf2aa0 100644 --- a/src/backends/lr0.c +++ b/src/backends/lr0.c @@ -182,23 +182,29 @@ HLRTable *h_lr0_table(HCFGrammar *g, const HLRDFA *dfa) // add reduce entries, record inadequate states for(size_t i=0; i<dfa->nstates; i++) { + bool inadeq = false; + // find reducible items in state H_FOREACH_KEY(dfa->states[i], HLRItem *item) if(item->mark == item->len) { // mark at the end - // check for conflicts - // XXX store more informative stuff in the inadeq records? + HLRAction *reduce = h_reduce_action(arena, item); + + // check for reduce/reduce conflict on forall if(table->forall[i]) { - // reduce/reduce conflict with a previous item - h_slist_push(table->inadeq, (void *)(uintptr_t)i); - } else if(!h_hashtable_empty(table->rows[i])) { - // shift/reduce conflict with one of the row's entries - h_slist_push(table->inadeq, (void *)(uintptr_t)i); + reduce = h_lr_conflict(arena, table->forall[i], reduce); + inadeq = true; } + table->forall[i] = reduce; - // set reduce action for the entire row - table->forall[i] = h_reduce_action(arena, item); + // check for shift/reduce conflict with other entries + // NOTE: these are not recorded as HLR_CONFLICTs at this point + if(!h_hashtable_empty(table->rows[i])) + inadeq = true; } H_END_FOREACH + + if(inadeq) + h_slist_push(table->inadeq, (void *)(uintptr_t)i); } return table; -- GitLab