Make completion_status() a method on ParseItem

This commit is contained in:
Max Brunsfeld 2015-10-30 14:07:33 -07:00
parent 4850384b78
commit e9be0ff24e
4 changed files with 99 additions and 59 deletions

View file

@ -8,39 +8,84 @@ using namespace build_tables;
START_TEST
describe("ParseItem::completion_status()", [&]() {
SyntaxGrammar grammar{{
SyntaxVariable("rule_0", VariableTypeNamed, {
Production({
{Symbol(11, true), 0, AssociativityNone, 101},
{Symbol(12, true), 0, AssociativityNone, 102},
{Symbol(13), 0, AssociativityNone, 103},
{Symbol(14, true), 4, AssociativityLeft, 104},
}),
Production({
{Symbol(15, true), 0, AssociativityNone, 101},
{Symbol(16, true), 0, AssociativityNone, 102},
{Symbol(17, true), 5, AssociativityRight, 104},
}),
Production({}),
}),
}, {}, {}};
auto production = [&](int variable_index, int production_index) -> const Production & {
return grammar.variables[variable_index].productions[production_index];
};
it("indicates whether the parse item is done, and its associativity and precedence", [&]() {
ParseItem item(Symbol(0), production(0, 0), 3);
AssertThat(item.completion_status().is_done, IsFalse());
AssertThat(item.completion_status().precedence, Equals(0));
AssertThat(item.completion_status().associativity, Equals(AssociativityNone));
item = ParseItem(Symbol(0), production(0, 0), 4);
AssertThat(item.completion_status().is_done, IsTrue());
AssertThat(item.completion_status().precedence, Equals(4));
AssertThat(item.completion_status().associativity, Equals(AssociativityLeft));
item = ParseItem(Symbol(0), production(0, 1), 3);
AssertThat(item.completion_status().is_done, IsTrue());
AssertThat(item.completion_status().precedence, Equals(5));
AssertThat(item.completion_status().associativity, Equals(AssociativityRight));
item = ParseItem(Symbol(0), production(0, 2), 0);
AssertThat(item.completion_status().is_done, IsTrue());
AssertThat(item.completion_status().precedence, Equals(0));
AssertThat(item.completion_status().associativity, Equals(AssociativityNone));
});
});
describe("ParseItemSet::transitions())", [&]() {
it("computes the ParseItemSet that would occur after consuming each lookahead symbol, along with its precedence", [&]() {
SyntaxGrammar grammar{{
SyntaxVariable("rule_0", VariableTypeNamed, {
Production({
{Symbol(11, true), 0, AssociativityNone, 101},
{Symbol(12, true), 0, AssociativityNone, 102},
{Symbol(13), 5, AssociativityNone, 103},
{Symbol(14, true), 0, AssociativityNone, 104},
}),
Production({
{Symbol(11, true), 0, AssociativityNone, 105},
{Symbol(12, true), 0, AssociativityNone, 106},
{Symbol(15), 6, AssociativityNone, 107},
})
SyntaxGrammar grammar{{
SyntaxVariable("rule_0", VariableTypeNamed, {
Production({
{Symbol(11, true), 0, AssociativityNone, 101},
{Symbol(12, true), 0, AssociativityNone, 102},
{Symbol(13), 5, AssociativityNone, 103},
{Symbol(14, true), 0, AssociativityNone, 104},
}),
SyntaxVariable("rule_1", VariableTypeNamed, {
Production({
{Symbol(15), 7, AssociativityNone, 109},
{Symbol(16, true), 0, AssociativityNone, 110},
})
}),
SyntaxVariable("rule_2", VariableTypeNamed, {
Production({
{Symbol(18, true), 0, AssociativityNone, 111},
})
Production({
{Symbol(11, true), 0, AssociativityNone, 105},
{Symbol(12, true), 0, AssociativityNone, 106},
{Symbol(15), 6, AssociativityNone, 107},
})
}, {}, {}};
}),
SyntaxVariable("rule_1", VariableTypeNamed, {
Production({
{Symbol(15), 7, AssociativityNone, 109},
{Symbol(16, true), 0, AssociativityNone, 110},
})
}),
SyntaxVariable("rule_2", VariableTypeNamed, {
Production({
{Symbol(18, true), 0, AssociativityNone, 111},
})
})
}, {}, {}};
auto production = [&](int variable_index, int production_index) -> const Production & {
return grammar.variables[variable_index].productions[production_index];
};
auto production = [&](int variable_index, int production_index) -> const Production & {
return grammar.variables[variable_index].productions[production_index];
};
it("computes the ParseItemSet that would occur after consuming each lookahead symbol, along with its precedence", [&]() {
ParseItemSet item_set({
// Two symbols into the first production for rule_0

View file

@ -8,7 +8,6 @@
#include "compiler/parse_table.h"
#include "compiler/build_tables/parse_conflict_manager.h"
#include "compiler/build_tables/parse_item.h"
#include "compiler/build_tables/get_completion_status.h"
#include "compiler/build_tables/get_metadata.h"
#include "compiler/build_tables/item_set_closure.h"
#include "compiler/lexical_grammar.h"
@ -111,39 +110,19 @@ class ParseTableBuilder {
}
}
struct CompletionStatus {
bool is_done;
int precedence;
rules::Associativity associativity;
};
CompletionStatus get_completion_status(const ParseItem &item) {
CompletionStatus result = { false, 0, rules::AssociativityNone };
if (item.step_index == item.production->size()) {
result.is_done = true;
if (item.step_index > 0) {
const ProductionStep &last_step =
item.production->at(item.step_index - 1);
result.precedence = last_step.precedence;
result.associativity = last_step.associativity;
}
}
return result;
}
void add_reduce_actions(const ParseItemSet &item_set, ParseStateId state_id) {
for (const auto &pair : item_set.entries) {
const ParseItem &item = pair.first;
const auto &lookahead_symbols = pair.second;
CompletionStatus completion_status = get_completion_status(item);
if (completion_status.is_done) {
ParseItem::CompletionStatus status = item.completion_status();
if (status.is_done) {
ParseAction action =
(item.lhs() == rules::START())
? ParseAction::Accept()
: ParseAction::Reduce(Symbol(item.variable_index), item.step_index,
completion_status.precedence,
completion_status.associativity,
status.precedence,
status.associativity,
*item.production);
for (const auto &lookahead_sym : *lookahead_symbols.entries)

View file

@ -41,14 +41,24 @@ Symbol ParseItem::lhs() const {
return Symbol(variable_index);
}
bool ParseItem::is_done() const {
return step_index == production->size();
ParseItem::CompletionStatus ParseItem::completion_status() const {
CompletionStatus result = { false, 0, rules::AssociativityNone };
if (step_index == production->size()) {
result.is_done = true;
if (step_index > 0) {
const ProductionStep &last_step =
production->at(step_index - 1);
result.precedence = last_step.precedence;
result.associativity = last_step.associativity;
}
}
return result;
}
int ParseItem::precedence() const {
if (production->empty())
return 0;
else if (is_done())
else if (completion_status().is_done)
return production->back().precedence;
else
return production->at(step_index).precedence;
@ -57,7 +67,7 @@ int ParseItem::precedence() const {
rules::Associativity ParseItem::associativity() const {
if (production->empty())
return rules::AssociativityNone;
else if (is_done())
else if (completion_status().is_done)
return production->back().associativity;
else
return production->at(step_index).associativity;
@ -66,7 +76,7 @@ rules::Associativity ParseItem::associativity() const {
pair<int, int> ParseItem::remaining_rule_id() const {
if (production->empty())
return { -2, -1 };
else if (is_done())
else if (completion_status().is_done)
return { production->back().associativity, production->back().precedence };
else
return { -1, production->at(step_index).rule_id };

View file

@ -16,13 +16,19 @@ class ParseItem {
public:
ParseItem(const rules::Symbol &, const Production &, unsigned int);
struct CompletionStatus {
bool is_done;
int precedence;
rules::Associativity associativity;
};
bool operator==(const ParseItem &other) const;
bool operator<(const ParseItem &other) const;
rules::Symbol lhs() const;
std::pair<int, int> remaining_rule_id() const;
bool is_done() const;
int precedence() const;
rules::Associativity associativity() const;
CompletionStatus completion_status() const;
int variable_index;
const Production *production;