Store shift states for non-terminals directly in the main parse table
This commit is contained in:
parent
8d9c261e3a
commit
fad7294ba4
20 changed files with 204 additions and 195 deletions
|
|
@ -116,17 +116,16 @@ class ParseTableBuilder {
|
|||
}
|
||||
|
||||
for (const Symbol &symbol : grammar.extra_tokens) {
|
||||
if (!error_state.entries.count(symbol)) {
|
||||
error_state.entries[symbol].actions.push_back(ParseAction::ShiftExtra());
|
||||
if (!error_state.terminal_entries.count(symbol.index)) {
|
||||
error_state.terminal_entries[symbol.index].actions.push_back(ParseAction::ShiftExtra());
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < grammar.variables.size(); i++) {
|
||||
Symbol symbol(i, false);
|
||||
add_out_of_context_parse_state(&error_state, symbol);
|
||||
add_out_of_context_parse_state(&error_state, Symbol(i, false));
|
||||
}
|
||||
|
||||
error_state.entries[END_OF_INPUT()].actions.push_back(ParseAction::Recover(0));
|
||||
error_state.terminal_entries[END_OF_INPUT().index].actions.push_back(ParseAction::Recover(0));
|
||||
parse_table.states[0] = error_state;
|
||||
}
|
||||
|
||||
|
|
@ -135,7 +134,11 @@ class ParseTableBuilder {
|
|||
const ParseItemSet &item_set = recovery_states[symbol];
|
||||
if (!item_set.entries.empty()) {
|
||||
ParseStateId state = add_parse_state(item_set);
|
||||
error_state->entries[symbol].actions.push_back(ParseAction::Recover(state));
|
||||
if (symbol.is_token) {
|
||||
error_state->terminal_entries[symbol.index].actions.assign({ ParseAction::Recover(state) });
|
||||
} else {
|
||||
error_state->nonterminal_entries[symbol.index] = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -158,14 +161,19 @@ class ParseTableBuilder {
|
|||
const ParseItemSet &next_item_set = transition.second.first;
|
||||
const PrecedenceRange &precedence = transition.second.second;
|
||||
|
||||
ParseAction *new_action = add_action(
|
||||
state_id, symbol, ParseAction::Shift(0, precedence), item_set);
|
||||
|
||||
if (!allow_any_conflict)
|
||||
if (!allow_any_conflict) {
|
||||
recovery_states[symbol].add(next_item_set);
|
||||
}
|
||||
|
||||
if (new_action)
|
||||
new_action->state_index = add_parse_state(next_item_set);
|
||||
if (symbol.is_token) {
|
||||
ParseAction *new_action = add_terminal_action(
|
||||
state_id, symbol, ParseAction::Shift(0, precedence), item_set);
|
||||
if (new_action) {
|
||||
new_action->state_index = add_parse_state(next_item_set);
|
||||
}
|
||||
} else {
|
||||
parse_table.set_nonterminal_action(state_id, symbol.index, add_parse_state(next_item_set));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -185,8 +193,9 @@ class ParseTableBuilder {
|
|||
status.associativity, *item.production);
|
||||
}
|
||||
|
||||
for (const auto &lookahead_sym : *lookahead_symbols.entries)
|
||||
add_action(state_id, lookahead_sym, action, item_set);
|
||||
for (const Symbol &lookahead : *lookahead_symbols.entries) {
|
||||
add_terminal_action(state_id, lookahead, action, item_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -195,24 +204,25 @@ class ParseTableBuilder {
|
|||
ParseAction action = ParseAction::ShiftExtra();
|
||||
ParseState &state = parse_table.states[state_id];
|
||||
for (const Symbol &extra_symbol : grammar.extra_tokens)
|
||||
if (!state.entries.count(extra_symbol) || state.has_shift_action() ||
|
||||
allow_any_conflict)
|
||||
parse_table.add_action(state_id, extra_symbol, action);
|
||||
if (!state.terminal_entries.count(extra_symbol.index) ||
|
||||
state.has_shift_action() || allow_any_conflict)
|
||||
parse_table.add_terminal_action(state_id, extra_symbol.index, action);
|
||||
}
|
||||
|
||||
void mark_fragile_actions() {
|
||||
for (ParseState &state : parse_table.states) {
|
||||
set<Symbol> symbols_with_multiple_actions;
|
||||
|
||||
for (auto &entry : state.entries) {
|
||||
const Symbol &symbol = entry.first;
|
||||
for (auto &entry : state.terminal_entries) {
|
||||
const Symbol symbol(entry.first, true);
|
||||
auto &actions = entry.second.actions;
|
||||
|
||||
if (actions.size() > 1)
|
||||
if (actions.size() > 1) {
|
||||
symbols_with_multiple_actions.insert(symbol);
|
||||
}
|
||||
|
||||
for (ParseAction &action : actions) {
|
||||
if (action.type == ParseActionTypeReduce && !action.extra) {
|
||||
if (action.type == ParseActionTypeReduce) {
|
||||
if (has_fragile_production(action.production))
|
||||
action.fragile = true;
|
||||
|
||||
|
|
@ -231,21 +241,8 @@ class ParseTableBuilder {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!erased)
|
||||
if (!erased) {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!symbols_with_multiple_actions.empty()) {
|
||||
for (auto &entry : state.entries) {
|
||||
if (!entry.first.is_token) {
|
||||
set<Symbol> first_set = get_first_set(entry.first);
|
||||
for (const Symbol &symbol : symbols_with_multiple_actions) {
|
||||
if (first_set.count(symbol)) {
|
||||
entry.second.reusable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -253,33 +250,34 @@ class ParseTableBuilder {
|
|||
}
|
||||
|
||||
void remove_duplicate_parse_states() {
|
||||
remove_duplicate_states<ParseTable, ParseAction>(&parse_table);
|
||||
remove_duplicate_states<ParseTable>(&parse_table);
|
||||
}
|
||||
|
||||
ParseAction *add_action(ParseStateId state_id, Symbol lookahead,
|
||||
const ParseAction &new_action,
|
||||
const ParseItemSet &item_set) {
|
||||
ParseAction *add_terminal_action(ParseStateId state_id, Symbol lookahead,
|
||||
const ParseAction &new_action,
|
||||
const ParseItemSet &item_set) {
|
||||
const ParseState &state = parse_table.states[state_id];
|
||||
const auto ¤t_entry = state.entries.find(lookahead);
|
||||
if (current_entry == state.entries.end())
|
||||
return &parse_table.set_action(state_id, lookahead, new_action);
|
||||
const auto ¤t_entry = state.terminal_entries.find(lookahead.index);
|
||||
if (current_entry == state.terminal_entries.end())
|
||||
return &parse_table.set_terminal_action(state_id, lookahead.index, new_action);
|
||||
if (allow_any_conflict)
|
||||
return &parse_table.add_action(state_id, lookahead, new_action);
|
||||
return &parse_table.add_terminal_action(state_id, lookahead.index, new_action);
|
||||
|
||||
const ParseAction old_action = current_entry->second.actions[0];
|
||||
auto resolution = conflict_manager.resolve(new_action, old_action);
|
||||
|
||||
switch (resolution.second) {
|
||||
case ConflictTypeNone:
|
||||
if (resolution.first)
|
||||
return &parse_table.set_action(state_id, lookahead, new_action);
|
||||
if (resolution.first) {
|
||||
return &parse_table.set_terminal_action(state_id, lookahead.index, new_action);
|
||||
}
|
||||
break;
|
||||
|
||||
case ConflictTypeResolved: {
|
||||
if (resolution.first) {
|
||||
if (old_action.type == ParseActionTypeReduce)
|
||||
fragile_productions.insert(old_action.production);
|
||||
return &parse_table.set_action(state_id, lookahead, new_action);
|
||||
return &parse_table.set_terminal_action(state_id, lookahead.index, new_action);
|
||||
} else {
|
||||
if (new_action.type == ParseActionTypeReduce)
|
||||
fragile_productions.insert(new_action.production);
|
||||
|
|
@ -293,7 +291,7 @@ class ParseTableBuilder {
|
|||
fragile_productions.insert(old_action.production);
|
||||
if (new_action.type == ParseActionTypeReduce)
|
||||
fragile_productions.insert(new_action.production);
|
||||
return &parse_table.add_action(state_id, lookahead, new_action);
|
||||
return &parse_table.add_terminal_action(state_id, lookahead.index, new_action);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue