diff --git a/src/backends/lalr.c b/src/backends/lalr.c index db9b88ae28caf5d39bf134df454add37577d86c8..ba10e0ca8587c866b72e96d03c1351a9a037d8a2 100644 --- a/src/backends/lalr.c +++ b/src/backends/lalr.c @@ -31,18 +31,24 @@ static size_t follow_transition(const HLRTable *table, size_t x, HCFChoice *A) { HLRAction *action = lrtable_lookup(table, x, A); assert(action != NULL); + + // we are interested in a transition out of state x, i.e. a shift action. + // while there could also be reduce actions associated with A in state x, + // those are not what we are here for. so if action is a conflict, search it + // for the shift. there will only be one and it will be the bottom element. + if(action->type == HLR_CONFLICT) { + HSlistNode *x; + for(x=action->branches->head; x; x=x->next) { + action = x->elem; + assert(action->type != HLR_CONFLICT); // no nesting of conflicts + if(action->type == HLR_SHIFT) + break; + } + assert(x != NULL && x->next == NULL); // shift found at the bottom + } assert(action->type == HLR_SHIFT); - return action->nextstate; -} -static inline HLRTransition *transition(HArena *arena, - size_t x, const HCFChoice *A, size_t y) -{ - HLRTransition *t = h_arena_malloc(arena, sizeof(HLRTransition)); - t->from = x; - t->symbol = A; - t->to = y; - return t; + return action->nextstate; } // no-op on terminal symbols @@ -69,8 +75,8 @@ static void transform_productions(const HLRTable *table, HLREnhGrammar *eg, HCFChoice **iBj = items; for(; *B; B++, iBj++) { size_t j = follow_transition(table, i, *B); - HLRTransition *i_B_j = transition(arena, i, *B, j); - *iBj = h_hashtable_get(eg->tmap, i_B_j); + HLRTransition i_B_j = {i, *B, j}; + *iBj = h_hashtable_get(eg->tmap, &i_B_j); assert(*iBj != NULL); i = j; } diff --git a/src/t_regression.c b/src/t_regression.c index 771582cfd835b348e0ed2b4da567ad40fc27800f..7a04bc6e7b89646edc172c50b4078cbd162431d1 100644 --- a/src/t_regression.c +++ b/src/t_regression.c @@ -366,6 +366,24 @@ static void test_ast_length_index() { } #endif // 0 +static void test_issue91() { + // this ambiguous grammar caused intermittent (?) assertion failures when + // trying to compile with the LALR backend: + // + // assertion "action->type == HLR_SHIFT" failed: file "src/backends/lalr.c", + // line 34, function "follow_transition" + // + // cf. https://gitlab.special-circumstanc.es/hammer/hammer/issues/91 + + H_RULE(schar, h_ch_range(' ', '~')); /* overlaps digit */ + H_RULE(digit, h_ch_range('0', '9')); + H_RULE(digits, h_choice(h_repeat_n(digit, 2), digit, NULL)); + H_RULE(p, h_many(h_choice(schar, digits, NULL))); + + int r = h_compile(p, PB_LALR, NULL); + g_check_cmp_int(r, ==, -2); +} + void register_regression_tests(void) { g_test_add_func("/core/regression/bug118", test_bug118); g_test_add_func("/core/regression/seq_index_path", test_seq_index_path); @@ -378,4 +396,5 @@ void register_regression_tests(void) { g_test_add_func("/core/regression/bug19", test_bug_19); g_test_add_func("/core/regression/flatten_null", test_flatten_null); //XXX g_test_add_func("/core/regression/ast_length_index", test_ast_length_index); + g_test_add_func("/core/regression/issue91", test_issue91); }