diff options
Diffstat (limited to 'src/output.cpp')
-rw-r--r-- | src/output.cpp | 111 |
1 files changed, 98 insertions, 13 deletions
diff --git a/src/output.cpp b/src/output.cpp index d4f86a9..7e9029b 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -45,9 +45,14 @@ output_t::output_t(const generator_t *generator0, const char *header, const char if (!source_file) throw std::system_error(errno, std::generic_category(), "unable to open source output file for writing"); - for (const auto &token : generator->get_terminals()) { - if (token.get_type() == SYMBOL_TYPE_TERM) - tokens.emplace(token.get_value(), tokens.size()); + for (const std::string &nonterm : generator->get_nonterminals()) + symbol_values.emplace(symbol_t::make_nonterm(nonterm.c_str()), "symbol_" + nonterm); + + for (const symbol_t &term : generator->get_terminals()) { + if (term.get_type() == SYMBOL_TYPE_TERM) + tokens.emplace(term.get_value(), tokens.size()); + + symbol_values.emplace(term, "token." + generator->get_term_type(term).second); } } @@ -65,6 +70,18 @@ void output_t::emit_tokens() { void output_t::emit_token_value() { std::fprintf(header_file, "typedef struct %stoken_value {\n", prefix()); + + std::map<std::string, std::string> token_values; + + for (const auto &term : generator->get_terminals()) { + const auto &type = generator->get_term_type(term); + if (!type.first.empty()) + token_values.emplace(type.second, type.first); + } + + for (const auto &value : token_values) + std::fprintf(header_file, "\t%s %s;\n", value.second.c_str(), value.first.c_str()); + std::fprintf(header_file, "} %stoken_value_t;\n\n", prefix()); } @@ -75,9 +92,40 @@ void output_t::emit_header() { std::fprintf(header_file, "typedef struct %scontext %scontext_t;\n", prefix(), prefix()); } -void output_t::emit_reduction(unsigned rule_id, const std::string &action) { - std::fprintf(source_file, "static inline void %sreduce_%u(void) {", prefix(), rule_id); - std::fprintf(source_file, "%s", action.c_str()); +void output_t::emit_reduction(unsigned rule_id) { + const auto &rule = generator->get_rules()[rule_id]; + + std::fprintf(source_file, "static inline "); + + const item_t &item = std::get<0>(rule); + const std::string &type = generator->get_nonterm_type(item.get_lhs()); + if (type.empty()) + std::fprintf(source_file, "void"); + else + std::fprintf(source_file, "%s", type.c_str()); + + std::fprintf(source_file, " %sreduce_%u(", prefix(), rule_id); + + bool empty = true; + for (unsigned i = 0; i < std::get<1>(rule).size(); i++) { + const std::string &var = std::get<1>(rule)[i]; + + if (var.empty()) + continue; + + if (!empty) + std::fprintf(source_file, ", "); + + std::fprintf(source_file, "%s %s", generator->get_type(item.get_rhs()[i]).c_str(), var.c_str()); + + empty = false; + } + + if (empty) + std::fprintf(source_file, "void"); + + std::fprintf(source_file, ") {"); + std::fprintf(source_file, "%s", std::get<2>(rule).c_str()); std::fprintf(source_file, "}\n\n"); } @@ -86,8 +134,8 @@ void output_t::emit_reductions() { const auto &rules = generator->get_rules(); for (size_t i = 0; i < rules.size(); i++) { - if (!rules[i].second.empty()) - emit_reduction(i, rules[i].second); + if (!std::get<2>(rules[i]).empty()) + emit_reduction(i); } } @@ -110,6 +158,7 @@ void output_t::emit_state_shift(unsigned i) { std::fprintf(source_file, "\t\t\tcase %s%s:\n", token_prefix(), token.get_value().c_str()); std::fprintf(source_file, "\t\t\t\tparser->stack[++parser->top].state = %u;\n", unsigned(it->second)); + std::fprintf(source_file, "\t\t\t\tparser->stack[parser->top].value.token = *value;\n"); std::fprintf(source_file, "\t\t\t\treturn 1;\n\n"); } @@ -120,11 +169,34 @@ void output_t::emit_state_shift(unsigned i) { } void output_t::emit_state_reduce(const item_t &item, int rule_id) { - if (item.get_rhs().size()) - std::fprintf(source_file, "\t\t\tparser->top -= %u;\n", unsigned(item.get_rhs().size())); + const auto &rhs = item.get_rhs(); + if (rhs.size()) + std::fprintf(source_file, "\t\t\tparser->top -= %u;\n", unsigned(rhs.size())); + + if (rule_id >= 0) { + const std::string &type = generator->get_nonterm_type(item.get_lhs()); + + std::fprintf(source_file, "\t\t\t"); + if (!type.empty()) + std::fprintf(source_file, "parser->stack[parser->top].value.symbol_%s = ", item.get_lhs().c_str()); + std::fprintf(source_file, "%sreduce_%i(", prefix(), rule_id); + + bool empty = true; + const auto &vars = std::get<1>(generator->get_rules()[rule_id]); + for (unsigned i = 0; i < vars.size(); i++) { + const std::string &var = vars[i]; + if (var.empty()) + continue; - if (rule_id >= 0) - std::fprintf(source_file, "\t\t\t%sreduce_%i();\n", prefix(), rule_id); + if (!empty) + std::fprintf(source_file, ", "); + + std::fprintf(source_file, "parser->stack[parser->top + %u].value.%s", i, symbol_values[rhs[i]].c_str()); + empty = false; + } + + std::fprintf(source_file, ");\n"); + } std::vector<std::pair<unsigned, unsigned>> gotos; @@ -166,7 +238,7 @@ void output_t::emit_state(unsigned i) { } else { const auto &rule = generator->get_rules()[it->second]; - emit_state_reduce(rule.first, rule.second.empty() ? -1 : it->second); + emit_state_reduce(std::get<0>(rule), std::get<2>(rule).empty() ? -1 : it->second); } std::fprintf(source_file, "\t\t\tbreak;\n\n"); @@ -178,8 +250,21 @@ void output_t::emit_states() { } void output_t::emit_source() { + std::fprintf(source_file, "typedef union %ssymbol_value {\n", prefix()); + std::fprintf(source_file, "\t%stoken_value_t token;\n", prefix()); + + for (const auto &nonterm : generator->get_nonterminals()) { + const std::string &type = generator->get_nonterm_type(nonterm); + + if (!type.empty()) + std::fprintf(source_file, "\t%s symbol_%s;\n", type.c_str(), nonterm.c_str()); + } + + std::fprintf(source_file, "} %ssymbol_value_t;\n\n", prefix()); + std::fprintf(source_file, "typedef struct %scontext_state {\n", prefix()); std::fprintf(source_file, "\tunsigned state;\n"); + std::fprintf(source_file, "\t%ssymbol_value_t value;\n", prefix()); std::fprintf(source_file, "} %scontext_state_t;\n\n", prefix()); std::fprintf(source_file, "struct %scontext {\n", prefix()); |