summaryrefslogtreecommitdiffstats
path: root/src/output_slr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/output_slr.cpp')
-rw-r--r--src/output_slr.cpp81
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");