summaryrefslogtreecommitdiffstats
path: root/src/output_source.cpp
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2015-04-16 22:07:29 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2015-04-17 17:20:25 +0200
commit6c8cd11dad10587e5dde9ab7706384927b961bb6 (patch)
tree83df2371191ee2dea8ba2154ef538b91d38089ed /src/output_source.cpp
parentbb018683c93673679bb54b63c8aff43f507948de (diff)
downloadsolar-6c8cd11dad10587e5dde9ab7706384927b961bb6.tar
solar-6c8cd11dad10587e5dde9ab7706384927b961bb6.zip
Completely refactor code generation
Diffstat (limited to 'src/output_source.cpp')
-rw-r--r--src/output_source.cpp234
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();
+}
+
+}