diff options
Diffstat (limited to 'src/output_slr.cpp')
-rw-r--r-- | src/output_slr.cpp | 81 |
1 files changed, 55 insertions, 26 deletions
diff --git a/src/output_slr.cpp b/src/output_slr.cpp index 01b0560..563fd60 100644 --- a/src/output_slr.cpp +++ b/src/output_slr.cpp @@ -33,20 +33,29 @@ namespace solar { -void output_slr_t::emit_state_shift(unsigned state, const symbol_t &token) { - auto it = generator->get_shifts().find(std::make_pair(state, token)); - if (it == generator->get_shifts().end()) - return; - - std::fprintf(source_file, "\t\t\tcase %s:\n", symbol_case(token).c_str()); - std::fprintf(source_file, "\t\t\t\tparser->stack[parser->top].value.token = *value;\n"); - std::fprintf(source_file, "\t\t\t\tparser->stack[++parser->top].state = %u;\n", unsigned(it->second)); - std::fprintf(source_file, "\t\t\t\treturn 1;\n\n"); -} +void output_slr_t::emit_state_shift(unsigned state) { + std::map<unsigned, std::set<symbol_t>> shifts; + + for (const symbol_t &token : generator->get_terminals()) { + auto it = generator->get_shifts().find(std::make_pair(state, token)); + if (it == generator->get_shifts().end()) + continue; -void output_slr_t::emit_state_reduce(const item_t &item, const symbol_t &token, int rule_id) { - std::fprintf(source_file, "\t\t\tcase %s:\n", symbol_case(token).c_str()); + std::set<symbol_t> &symbols = shifts.insert(std::make_pair(it->second, std::set<symbol_t>())).first->second; + symbols.insert(token); + } + + for (const auto &entry : shifts) { + for (const symbol_t &sym : entry.second) + std::fprintf(source_file, "\t\t\tcase %s:\n", symbol_case(sym).c_str()); + std::fprintf(source_file, "\t\t\t\tparser->stack[parser->top].value.token = *value;\n"); + std::fprintf(source_file, "\t\t\t\tparser->stack[++parser->top].state = %u;\n", entry.first); + std::fprintf(source_file, "\t\t\t\treturn 1;\n\n"); + } +} + +void output_slr_t::emit_state_reduce_code(const item_t &item, int rule_id) { const auto &rhs = item.get_rhs(); if (rhs.size()) std::fprintf(source_file, "\t\t\t\tparser->top -= %u;\n", unsigned(rhs.size())); @@ -114,19 +123,38 @@ void output_slr_t::emit_state_reduce(const item_t &item, const symbol_t &token, std::fprintf(source_file, "\t\t\t\t}\n"); } - - std::fprintf(source_file, "\t\t\t\tbreak;\n\n"); } -void output_slr_t::do_emit_state(unsigned state, const symbol_t &token) { - auto it = generator->get_reductions().find(std::make_pair(state, token)); - if (it == generator->get_reductions().end()) { - emit_state_shift(state, token); +bool output_slr_t::emit_state_reduce(unsigned state) { + std::map<unsigned, std::set<symbol_t>> reductions; + + for (const symbol_t &token : generator->get_terminals()) { + auto it = generator->get_reductions().find(std::make_pair(state, token)); + if (it == generator->get_reductions().end()) + continue; + + std::set<symbol_t> &symbols = reductions.insert(std::make_pair(it->second, std::set<symbol_t>())).first->second; + symbols.insert(token); } - else { - const rule_t &rule = generator->get_grammar().rules[it->second]; - emit_state_reduce(rule.item, token, rule.action.empty() ? -1 : it->second); + + for (const auto &entry : reductions) { + if (reductions.size() == 1) { + std::fprintf(source_file, "\t\t\tdefault:\n"); + } + else { + for (const symbol_t &sym : entry.second) + std::fprintf(source_file, "\t\t\tcase %s:\n", symbol_case(sym).c_str()); + } + + const rule_t &rule = generator->get_grammar().rules[entry.first]; + emit_state_reduce_code(rule.item, rule.action.empty() ? -1 : entry.first); + + if (reductions.size() != 1) + std::fprintf(source_file, "\t\t\t\tbreak;\n\n"); + } + + return (reductions.size() == 1); } void output_slr_t::emit_state(unsigned state) { @@ -138,13 +166,14 @@ void output_slr_t::emit_state(unsigned state) { std::fprintf(source_file, "\t\t\t\treturn 0;\n\n"); } - do_emit_state(state, symbol_t::empty()); + emit_state_shift(state); - for (const symbol_t &token : generator->get_terminals()) - do_emit_state(state, token); + bool def = emit_state_reduce(state); - std::fprintf(source_file, "\t\t\tdefault:\n"); - std::fprintf(source_file, "\t\t\t\treturn -1;\n"); + if (!def) { + std::fprintf(source_file, "\t\t\tdefault:\n"); + std::fprintf(source_file, "\t\t\t\treturn -1;\n"); + } std::fprintf(source_file, "\t\t\t}\n"); std::fprintf(source_file, "\t\t\tbreak;\n\n"); |