From e9be0ff24e2c94e8fa91ad07e1a16d6592dfa604 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 30 Oct 2015 14:07:33 -0700 Subject: [PATCH] Make completion_status() a method on ParseItem --- spec/compiler/build_tables/parse_item_spec.cc | 101 +++++++++++++----- .../build_tables/build_parse_table.cc | 29 +---- src/compiler/build_tables/parse_item.cc | 20 +++- src/compiler/build_tables/parse_item.h | 8 +- 4 files changed, 99 insertions(+), 59 deletions(-) diff --git a/spec/compiler/build_tables/parse_item_spec.cc b/spec/compiler/build_tables/parse_item_spec.cc index f189d98f..64a055b3 100644 --- a/spec/compiler/build_tables/parse_item_spec.cc +++ b/spec/compiler/build_tables/parse_item_spec.cc @@ -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 diff --git a/src/compiler/build_tables/build_parse_table.cc b/src/compiler/build_tables/build_parse_table.cc index 7ae65e95..2277d025 100644 --- a/src/compiler/build_tables/build_parse_table.cc +++ b/src/compiler/build_tables/build_parse_table.cc @@ -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) diff --git a/src/compiler/build_tables/parse_item.cc b/src/compiler/build_tables/parse_item.cc index 1a285a10..d9b9153b 100644 --- a/src/compiler/build_tables/parse_item.cc +++ b/src/compiler/build_tables/parse_item.cc @@ -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 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 }; diff --git a/src/compiler/build_tables/parse_item.h b/src/compiler/build_tables/parse_item.h index b7f1cea8..78eaa1bf 100644 --- a/src/compiler/build_tables/parse_item.h +++ b/src/compiler/build_tables/parse_item.h @@ -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 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;