234 lines
6.6 KiB
C++
234 lines
6.6 KiB
C++
/*
|
|
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();
|
|
}
|
|
|
|
}
|