Simplify handling of precedence & associativity in productions

This commit is contained in:
Max Brunsfeld 2015-10-05 16:56:11 -07:00
parent 6d748a6714
commit 5e4bdcbaf8
5 changed files with 37 additions and 74 deletions

View file

@ -156,7 +156,7 @@ 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, 3, AssociativityLeft, 0);
ParseAction right = ParseAction::Reduce(sym2, 1, 2, AssociativityLeft, 0);
it("favors that action", [&]() {
result = conflict_manager->resolve(left, right, sym1);

View file

@ -138,14 +138,14 @@ describe("flatten_grammar", []() {
AssertThat(
get_precedence_sequences(grammar.variables[1].productions),
Equals(vector<vector<int>>({
{ 0, 0, 101, 102, 101, 0 },
{ 0, 0, 101, 101, 0 }
{ 0, 101, 102, 101, 0, 0 },
{ 0, 101, 101, 0, 0 }
})));
AssertThat(
get_precedence_sequences(grammar.variables[2].productions),
Equals(vector<vector<int>>({
{ 0, 102, 0, 103 },
{ 102, 0, 103, 103 },
})));
});
@ -155,8 +155,8 @@ describe("flatten_grammar", []() {
AssertThat(
get_associativity_sequences(grammar.variables[1].productions),
Equals(vector<vector<Associativity>>({
{ none, none, AssociativityLeft, AssociativityRight, AssociativityLeft, none },
{ none, none, AssociativityLeft, AssociativityLeft, none }
{ none, AssociativityLeft, AssociativityRight, AssociativityLeft, none, none },
{ none, AssociativityLeft, AssociativityLeft, none, none }
})));
});

View file

@ -20,7 +20,6 @@
namespace tree_sitter {
namespace build_tables {
using std::dynamic_pointer_cast;
using std::make_shared;
using std::map;
using std::set;

View file

@ -34,7 +34,7 @@ class ParseTableBuilder {
const SyntaxGrammar grammar;
const LexicalGrammar lexical_grammar;
ParseConflictManager conflict_manager;
unordered_map<const ParseItemSet, ParseStateId, ParseItemSet::Hash> parse_state_ids;
unordered_map<ParseItemSet, ParseStateId, ParseItemSet::Hash> parse_state_ids;
vector<pair<ParseItemSet, ParseStateId>> item_sets_to_process;
ParseTable parse_table;
std::set<string> conflicts;
@ -112,18 +112,13 @@ class ParseTableBuilder {
};
CompletionStatus get_completion_status(const ParseItem &item) {
CompletionStatus result{ false, 0, AssociativityNone };
const Production &production =
grammar.productions(item.lhs())[item.production_index];
if (item.step_index == production.size()) {
result.is_done = true;
if (item.step_index > 0) {
const ProductionStep &step = production[item.step_index - 1];
result.precedence = step.precedence;
result.associativity = step.associativity;
}
const ProductionStep &last_step = production[item.step_index - 1];
return { true, last_step.precedence, last_step.associativity };
}
return result;
return { false, 0, AssociativityNone };
}
void add_reduce_actions(const ParseItemSet &item_set, ParseStateId state_id) {
@ -239,12 +234,8 @@ class ParseTableBuilder {
const ParseItem &item = pair.first;
const Production &production =
grammar.productions(item.lhs())[item.production_index];
if (item.step_index > 0) {
if (item.step_index < production.size())
result.add(production[item.step_index].precedence);
else
result.add(production[item.step_index - 1].precedence);
}
if (item.step_index > 0)
result.add(production[item.step_index - 1].precedence);
}
return result;
}

View file

@ -17,56 +17,36 @@ using std::string;
using std::vector;
class FlattenRule : public rules::RuleFn<void> {
public:
bool has_pending_precedence;
int pending_precedence;
private:
vector<int> precedence_stack;
bool has_pending_associativity;
Associativity pending_associativity;
vector<Associativity> associativity_stack;
Production production;
FlattenRule()
: has_pending_precedence(false),
pending_precedence(0),
has_pending_associativity(false),
pending_associativity(AssociativityNone) {}
void apply_to(const rules::Symbol *sym) {
production.push_back(
ProductionStep(*sym, current_precedence(), current_associativity()));
if (has_pending_precedence) {
precedence_stack.push_back(pending_precedence);
has_pending_precedence = false;
}
if (has_pending_associativity) {
associativity_stack.push_back(pending_associativity);
has_pending_associativity = false;
}
production.push_back(ProductionStep(*sym, precedence_stack.back(),
associativity_stack.back()));
}
void apply_to(const rules::Metadata *metadata) {
int precedence = metadata->value_for(rules::PRECEDENCE);
int associativity = metadata->value_for(rules::ASSOCIATIVITY);
if (precedence != 0) {
pending_precedence = precedence;
has_pending_precedence = true;
}
if (associativity != 0) {
pending_associativity = static_cast<Associativity>(associativity);
has_pending_associativity = true;
}
if (precedence != 0)
precedence_stack.push_back(precedence);
if (associativity != 0)
associativity_stack.push_back(static_cast<Associativity>(associativity));
apply(metadata->rule);
if (precedence != 0)
if (precedence != 0) {
precedence_stack.pop_back();
production.back().precedence = precedence_stack.back();
}
if (associativity != 0)
if (associativity != 0) {
associativity_stack.pop_back();
production.back().associativity = associativity_stack.back();
}
}
void apply_to(const rules::Seq *seq) {
@ -74,28 +54,21 @@ class FlattenRule : public rules::RuleFn<void> {
apply(seq->right);
}
private:
int current_precedence() {
if (precedence_stack.empty())
return 0;
else
return precedence_stack.back();
}
public:
FlattenRule()
: precedence_stack({ 0 }), associativity_stack({ AssociativityNone }) {}
Associativity current_associativity() {
if (associativity_stack.empty())
return AssociativityNone;
else
return associativity_stack.back();
Production flatten(const rule_ptr &rule) {
apply(rule);
size_t size = production.size();
if (size > 1) {
production[size - 1].precedence = production[size - 2].precedence;
production[size - 1].associativity = production[size - 2].associativity;
}
return production;
}
};
Production flatten_rule(const rule_ptr &rule) {
FlattenRule flattener;
flattener.apply(rule);
return flattener.production;
}
struct ProductionSlice {
vector<ProductionStep>::const_iterator start;
vector<ProductionStep>::const_iterator end;
@ -137,7 +110,7 @@ SyntaxGrammar flatten_grammar(const InitialSyntaxGrammar &grammar) {
for (const Variable &variable : grammar.variables) {
vector<Production> productions;
for (const rule_ptr &rule_component : extract_choices(variable.rule))
productions.push_back(flatten_rule(rule_component));
productions.push_back(FlattenRule().flatten(rule_component));
result.variables.push_back(
SyntaxVariable(variable.name, variable.type, productions));
}