Fix conflation of finished items w/ different precedence

This commit is contained in:
Max Brunsfeld 2015-10-17 22:54:56 -07:00
parent 84fe01e145
commit 1983bcfb60
16 changed files with 19073 additions and 18250 deletions

View file

@ -35,28 +35,32 @@ describe("item_set_closure", []() {
}),
}, {}, {}};
auto production = [&](int variable_index, int production_index) -> const Production & {
return grammar.variables[variable_index].productions[production_index];
};
ParseItemSet item_set = item_set_closure(ParseItemSet({
{
ParseItem(Symbol(0), 0, 0, 100),
ParseItem(Symbol(0), production(0, 0), 0),
LookaheadSet({ Symbol(10, true) }),
}
}), grammar);
AssertThat(item_set, Equals(ParseItemSet({
{
ParseItem(Symbol(0), 0, 0, 100),
ParseItem(Symbol(0), production(0, 0), 0),
LookaheadSet({ Symbol(10, true) })
},
{
ParseItem(Symbol(1), 0, 0, 102),
ParseItem(Symbol(1), production(1, 0), 0),
LookaheadSet({ Symbol(11, true) })
},
{
ParseItem(Symbol(1), 1, 0, 104),
ParseItem(Symbol(1), production(1, 1), 0),
LookaheadSet({ Symbol(11, true) })
},
{
ParseItem(Symbol(2), 0, 0, 105),
ParseItem(Symbol(2), production(2, 0), 0),
LookaheadSet({ Symbol(11, true) })
},
})));
@ -79,24 +83,28 @@ describe("item_set_closure", []() {
}),
}, {}, {}};
auto production = [&](int variable_index, int production_index) -> const Production & {
return grammar.variables[variable_index].productions[production_index];
};
ParseItemSet item_set = item_set_closure(ParseItemSet({
{
ParseItem(Symbol(0), 0, 0, 100),
ParseItem(Symbol(0), production(0, 0), 0),
LookaheadSet({ Symbol(10, true) }),
}
}), grammar);
AssertThat(item_set, Equals(ParseItemSet({
{
ParseItem(Symbol(0), 0, 0, 100),
ParseItem(Symbol(0), production(0, 0), 0),
LookaheadSet({ Symbol(10, true) })
},
{
ParseItem(Symbol(1), 0, 0, 102),
ParseItem(Symbol(1), production(1, 0), 0),
LookaheadSet({ Symbol(11, true) })
},
{
ParseItem(Symbol(1), 1, 0, 0),
ParseItem(Symbol(1), production(1, 1), 0),
LookaheadSet({ Symbol(11, true) })
},
})));

View file

@ -31,6 +31,8 @@ describe("ParseConflictManager", []() {
delete conflict_manager;
});
const Production &production = syntax_grammar.variables[0].productions[0];
describe(".resolve", [&]() {
describe("errors", [&]() {
ParseAction error = ParseAction::Error();
@ -65,7 +67,7 @@ describe("ParseConflictManager", []() {
describe("shift/reduce conflicts", [&]() {
describe("when the shift has higher precedence", [&]() {
ParseAction shift = ParseAction::Shift(2, {3, 4});
ParseAction reduce = ParseAction::Reduce(sym2, 1, 2, AssociativityLeft, 0);
ParseAction reduce = ParseAction::Reduce(sym2, 1, 2, AssociativityLeft, production);
it("favors the shift and reports the conflict as resolved", [&]() {
result = conflict_manager->resolve(shift, reduce, sym1);
@ -80,7 +82,7 @@ describe("ParseConflictManager", []() {
describe("when the reduce has higher precedence", [&]() {
ParseAction shift = ParseAction::Shift(2, {1, 2});
ParseAction reduce = ParseAction::Reduce(sym2, 1, 3, AssociativityLeft, 0);
ParseAction reduce = ParseAction::Reduce(sym2, 1, 3, AssociativityLeft, production);
it("favors the reduce and reports the conflict as resolved", [&]() {
result = conflict_manager->resolve(shift, reduce, sym1);
@ -95,7 +97,7 @@ describe("ParseConflictManager", []() {
describe("when the precedences are equal and the reduce's rule is left associative", [&]() {
ParseAction shift = ParseAction::Shift(2, { 0, 0 });
ParseAction reduce = ParseAction::Reduce(sym2, 1, 0, AssociativityLeft, 0);
ParseAction reduce = ParseAction::Reduce(sym2, 1, 0, AssociativityLeft, production);
it("favors the reduce and reports the conflict as resolved", [&]() {
result = conflict_manager->resolve(reduce, shift, sym1);
@ -110,7 +112,7 @@ describe("ParseConflictManager", []() {
describe("when the precedences are equal and the reduce's rule is right-associative", [&]() {
ParseAction shift = ParseAction::Shift(2, { 0, 0 });
ParseAction reduce = ParseAction::Reduce(sym2, 1, 0, AssociativityRight, 0);
ParseAction reduce = ParseAction::Reduce(sym2, 1, 0, AssociativityRight, production);
it("favors the shift, and reports the conflict as resolved", [&]() {
result = conflict_manager->resolve(reduce, shift, sym1);
@ -126,7 +128,7 @@ describe("ParseConflictManager", []() {
describe("when the precedences are equal and the reduce's rule has no associativity", [&]() {
it("reports an unresolved conflict", [&]() {
ParseAction shift = ParseAction::Shift(2, { 0, 0 });
ParseAction reduce = ParseAction::Reduce(Symbol(2), 1, 0, AssociativityNone, 0);
ParseAction reduce = ParseAction::Reduce(Symbol(2), 1, 0, AssociativityNone, production);
result = conflict_manager->resolve(reduce, shift, lookahead_sym);
AssertThat(result.first, IsFalse());
@ -139,7 +141,7 @@ describe("ParseConflictManager", []() {
describe("when the shift has conflicting precedences compared to the reduce", [&]() {
ParseAction shift = ParseAction::Shift(2, { 1, 3 });
ParseAction reduce = ParseAction::Reduce(Symbol(2), 1, 2, AssociativityLeft, 0);
ParseAction reduce = ParseAction::Reduce(Symbol(2), 1, 2, AssociativityLeft, production);
it("returns false and reports an unresolved conflict", [&]() {
result = conflict_manager->resolve(reduce, shift, lookahead_sym);
@ -155,8 +157,8 @@ describe("ParseConflictManager", []() {
describe("reduce/reduce conflicts", [&]() {
describe("when one action has higher precedence", [&]() {
ParseAction left = ParseAction::Reduce(sym2, 1, 0, AssociativityLeft, 0);
ParseAction right = ParseAction::Reduce(sym2, 1, 2, AssociativityLeft, 0);
ParseAction left = ParseAction::Reduce(sym2, 1, 0, AssociativityLeft, production);
ParseAction right = ParseAction::Reduce(sym2, 1, 2, AssociativityLeft, production);
it("favors that action", [&]() {
result = conflict_manager->resolve(left, right, sym1);
@ -171,8 +173,8 @@ describe("ParseConflictManager", []() {
describe("when the actions have the same precedence", [&]() {
it("returns false and reports a conflict", [&]() {
ParseAction left = ParseAction::Reduce(Symbol(2), 1, 0, AssociativityLeft, 0);
ParseAction right = ParseAction::Reduce(Symbol(3), 1, 0, AssociativityLeft, 0);
ParseAction left = ParseAction::Reduce(Symbol(2), 1, 0, AssociativityLeft, production);
ParseAction right = ParseAction::Reduce(Symbol(3), 1, 0, AssociativityLeft, production);
result = conflict_manager->resolve(right, left, lookahead_sym);
AssertThat(result.first, IsFalse());

View file

@ -32,27 +32,31 @@ describe("parse_item_set_transitions(ParseItemSet, SyntaxGrammar)", [&]() {
})
}, {}, {}};
auto production = [&](int variable_index, int production_index) -> const Production & {
return grammar.variables[variable_index].productions[production_index];
};
ParseItemSet set1({
{
ParseItem(Symbol(0), 0, 2, 103),
ParseItem(Symbol(0), production(0, 0), 2),
LookaheadSet({ Symbol(16, true) })
},
{
ParseItem(Symbol(1), 0, 0, 106),
ParseItem(Symbol(1), production(1, 0), 0),
LookaheadSet({ Symbol(17, true) })
},
{
ParseItem(Symbol(2), 0, 1, 106),
ParseItem(Symbol(2), production(2, 0), 1),
LookaheadSet({ Symbol(17, true) })
}
});
AssertThat(set1.transitions(grammar), Equals(map<Symbol, ParseItemSet>({
AssertThat(set1.transitions(), Equals(map<Symbol, ParseItemSet>({
{
Symbol(1),
ParseItemSet({
{
ParseItem(Symbol(0), 0, 3, 104),
ParseItem(Symbol(0), production(0, 0), 3),
LookaheadSet({ Symbol(16, true) })
}
})
@ -62,7 +66,7 @@ describe("parse_item_set_transitions(ParseItemSet, SyntaxGrammar)", [&]() {
Symbol(2),
ParseItemSet({
{
ParseItem(Symbol(1), 0, 1, 106),
ParseItem(Symbol(1), production(1, 0), 1),
LookaheadSet({ Symbol(17, true) })
},
})

View file

@ -126,9 +126,8 @@ ostream &operator<<(ostream &stream, const LexItemSet &item_set) {
ostream &operator<<(ostream &stream, const ParseItem &item) {
return stream << string("(item variable:") << to_string(item.variable_index)
<< string(" production:") << to_string(item.production_index)
<< string(" production:") << to_string((size_t)&item.production % 1000)
<< string(" step:") << to_string(item.step_index)
<< string(" remaining_rule:") << to_string(item.rule_id)
<< string(")");
}