diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2015-04-16 22:07:29 +0200 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2015-04-17 17:20:25 +0200 |
commit | 6c8cd11dad10587e5dde9ab7706384927b961bb6 (patch) | |
tree | 83df2371191ee2dea8ba2154ef538b91d38089ed /src/output_source.cpp | |
parent | bb018683c93673679bb54b63c8aff43f507948de (diff) | |
download | solar-6c8cd11dad10587e5dde9ab7706384927b961bb6.tar solar-6c8cd11dad10587e5dde9ab7706384927b961bb6.zip |
Completely refactor code generation
Diffstat (limited to 'src/output_source.cpp')
-rw-r--r-- | src/output_source.cpp | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/src/output_source.cpp b/src/output_source.cpp new file mode 100644 index 0000000..7000ef9 --- /dev/null +++ b/src/output_source.cpp @@ -0,0 +1,234 @@ +/* + Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net> + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "output_source.hpp" + +#include <cstring> + + +namespace solar { + +void output_source_t::emit_header_include() { +#ifdef _WIN32 + const char sep = '\\'; +#else + const char sep = '/'; +#endif + + const char *slash = std::strrchr(header_filename, sep); + const char *basename = slash ? slash+1 : header_filename; + + write_line("#include \"", basename, "\""); +} + +void output_source_t::emit_type_symbol_value() { + block_t symbol_value(this, "typedef union ", prefixed("symbol_value")); + + write_line_(variable_t({prefixed("token_value_t"), "token"})); + + for (const auto &nonterm : get_generator()->get_nonterminals()) { + const std::string &type = get_generator()->get_grammar().get_nonterm_type(nonterm); + + if (!type.empty()) + write_line_(variable_t({type, "symbol_" + nonterm})); + } + + symbol_value.close_(" ", prefixed("symbol_value_t")); +} + +void output_source_t::emit_type_context_state() { + block_t context_state(this, "typedef struct ", prefixed("context_state")); + + write_line_(variable_t({"unsigned", "state"})); + write_line_(variable_t({prefixed("symbol_value_t"), "value"})); + + context_state.close_(" ", prefixed("context_state_t")); +} + +void output_source_t::emit_type_context() { + block_t context(this, "struct ", prefixed("context")); + + write_line_(variable_t({"unsigned", "top"})); + write_line_(variable_t({prefixed("context_state_t"), combine("stack[", stack_size, "]")})); + + context.close_(); +} + +void output_source_t::emit_types() { + emit_type_symbol_value(); + write_line(); + + emit_type_context_state(); + write_line(); + + emit_type_context(); + write_line(); +} + +void output_source_t::emit_alloc() { + block_t alloc(this, sig_alloc()); + write_line_(prefixed("context_t *"), "parser = (", prefixed("context_t *"), ")alloc_func(sizeof(", prefixed("context_t"), "))"); + write_line_("parser->top = 0"); + write_line_("parser->stack[0].state = 0"); + write_line_("return parser"); +} + +void output_source_t::emit_free() { + block_t free_(this, sig_free()); + write_line_("free_func(parser)"); +} + +codegen_t::function_t output_source_t::sig_reduction(unsigned rule_id) { + const rule_t &rule = get_generator()->get_grammar().rules[rule_id]; + const item_t &item = rule.item; + const std::string &type = get_generator()->get_grammar().get_nonterm_type(item.get_lhs()); + + function_t sig("static inline " + (type.empty() ? "void" : type), prefixed(combine("reduce_", rule_id))); + + for (unsigned i = 0; i < rule.variables.size(); i++) { + const auto &var = rule.variables[i]; + + if (var.first.empty()) + continue; + + sig.add_arg(get_generator()->get_grammar().get_type(item.get_rhs()[i]), var.first); + } + + for (const auto &arg : get_generator()->get_grammar().extra_args) + sig.add_arg(arg); + + return sig; +} + +void output_source_t::emit_reduction(unsigned rule_id) { + function_t sig = sig_reduction(rule_id); + write_line(sig, " {", get_generator()->get_grammar().rules[rule_id].action, "}"); + write_line(); +} + +void output_source_t::emit_reductions() { + const auto &rules = get_generator()->get_grammar().rules; + + for (size_t i = 0; i < rules.size(); i++) { + if (!rules[i].action.empty()) + emit_reduction(i); + } +} + +void output_source_t::emit_gotos(const std::string &lhs) { + std::map<unsigned, std::set<unsigned>> gotos; + + for (size_t state = 0; state < get_generator()->get_state_count(); state++) { + auto it = get_generator()->get_gotos().find(std::make_pair(state, lhs)); + if (it == get_generator()->get_gotos().end()) + continue; + + std::set<unsigned> &states = gotos.insert(std::make_pair(it->second, std::set<unsigned>())).first->second; + states.insert(state); + } + + if (gotos.size() == 1) { + write_line_("parser->stack[++parser->top].state = ", gotos.begin()->first); + } + else { + block_t switch_state(this, "switch (parser->stack[parser->top].state)"); + + for (const auto &entry : gotos) { + for (unsigned state : entry.second) + write_case(state); + write_line_("parser->stack[++parser->top].state = ", entry.first); + write_line_("break"); + write_line(); + } + } +} + +void output_source_t::emit_states() { + for (size_t state = 0; state < get_generator()->get_state_count(); state++) { + write_case(state); + emit_state(state); + write_line_("break"); + write_line(); + } +} + +void output_source_t::emit_do_push() { + function_t do_push_sig("static int", prefixed("do_push")); + do_push_sig.add_arg(prefixed("context_t *"), "parser"); + do_push_sig.add_arg("int", "token"); + for (const auto &arg : get_generator()->get_grammar().extra_args) + do_push_sig.add_arg(arg); + + block_t do_push(this, do_push_sig); + + write_line_(prefixed("symbol_value_t"), " result"); + write_line(); + + block_t while_1(this, "while (1)"); + block_t switch_state(this, "switch (parser->stack[parser->top].state)"); + + emit_states(); +} + +void output_source_t::emit_push() { + block_t push(this, sig_push()); + write_line_("int ret = parse_do_push(parser, token, grammar)"); + write_line(); + write_line("if (ret > 0)"); + _write_line_("parser->stack[parser->top-1].value.token = *value"); + write_line(); + write_line_("return ret"); + +} + +void output_source_t::write() { + emit_header_include(); + write_line(); + + if (!get_generator()->get_grammar().source_block.empty()) { + write_line(get_generator()->get_grammar().source_block); + write_line(); + } + + emit_types(); + write_line(); + + emit_alloc(); + write_line(); + emit_free(); + write_line(); + write_line(); + + emit_reductions(); + write_line(); + + emit_do_push(); + write_line(); + + emit_push(); +} + +} |