diff options
Diffstat (limited to 'src/output.cpp')
-rw-r--r-- | src/output.cpp | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/src/output.cpp b/src/output.cpp new file mode 100644 index 0000000..0901b29 --- /dev/null +++ b/src/output.cpp @@ -0,0 +1,186 @@ +/* + 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.hpp" + +#include <cerrno> +#include <system_error> + + +namespace solar { + +output_t::output_t(const generator_t *generator0, const char *header, const char *source) + : prefix_str("parse_"), + token_prefix_str("TOKEN_"), + stack_size(100), + generator(generator0) { + header_file = std::fopen(header, "w"); + if (!header_file) + throw std::system_error(errno, std::generic_category(), "unable to open header output file for writing"); + + source_file = std::fopen(source, "w"); + 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()); + } +} + +void output_t::emit_tokens() { + if (tokens.empty()) + return; + + std::fprintf(header_file, "enum %stoken_t {\n", prefix()); + + for (const auto &token : tokens) + std::fprintf(header_file, "\t%s%s = %u,\n", token_prefix(), token.first.c_str(), token.second + 256); + + std::fprintf(header_file, "};\n\n"); +} + +void output_t::emit_token_value() { + std::fprintf(source_file, "typedef struct %stoken_value {\n", prefix()); + std::fprintf(source_file, "} %stoken_value_t;\n\n", prefix()); +} + +void output_t::emit_header() { + emit_tokens(); + emit_token_value(); + + std::fprintf(header_file, "typedef struct %scontext %scontext_t;\n", prefix(), prefix()); +} + +void output_t::emit_state_shift(unsigned i) { + std::fprintf(source_file, "\t\t\tswitch (token) {\n"); + + if (generator->get_shifts().find(std::make_pair(i, symbol_t::make_nonterm(""))) != generator->get_shifts().end()) { + std::fprintf(source_file, "\t\t\tcase 0:\n"); + std::fprintf(source_file, "\t\t\t\treturn 0;\n\n"); + } + + for (const auto &token : generator->get_terminals()) { + auto it = generator->get_shifts().find(std::make_pair(i, token)); + if (it == generator->get_shifts().end()) + continue; + + if (token.get_type() == SYMBOL_TYPE_CHAR) + std::fprintf(source_file, "\t\t\tcase '%c':\n", token.get_value()[0]); + else + std::fprintf(source_file, "\t\t\tcase %u:\n", tokens[token.get_value()]); + + 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"); + } + + 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"); +} + +void output_t::emit_state_reduce(const item_t &item) { + if (item.get_rhs().size()) + std::fprintf(source_file, "\t\t\tparser->top -= %u;\n", unsigned(item.get_rhs().size())); + + std::vector<std::pair<unsigned, unsigned>> gotos; + + for (size_t i = 0; i < generator->get_state_count(); i++) { + auto it = generator->get_gotos().find(std::make_pair(i, item.get_lhs())); + if (it == generator->get_gotos().end()) + continue; + + gotos.emplace_back(i, it->second); + } + + if (gotos.size() == 1) { + std::fprintf(source_file, "\t\t\tparser->stack[++parser->top].state = %u;\n", gotos[0].second); + } + else { + std::fprintf(source_file, "\t\t\tswitch (parser->stack[parser->top].state) {\n"); + + for (size_t i = 0; i < generator->get_state_count(); i++) { + auto it = generator->get_gotos().find(std::make_pair(i, item.get_lhs())); + if (it == generator->get_gotos().end()) + continue; + + std::fprintf(source_file, "\t\t\tcase %u:\n", unsigned(i)); + std::fprintf(source_file, "\t\t\t\tparser->stack[++parser->top].state = %u;\n", unsigned(it->second)); + std::fprintf(source_file, "\t\t\t\tbreak;\n"); + } + + + std::fprintf(source_file, "\t\t\t}\n"); + } +} + +void output_t::emit_state(unsigned i) { + std::fprintf(source_file, "\t\tcase %u:\n", i); + + auto it = generator->get_reductions().find(i); + if (it == generator->get_reductions().end()) + emit_state_shift(i); + else + emit_state_reduce(generator->get_rules()[it->second]); + + std::fprintf(source_file, "\t\t\tbreak;\n\n"); +} + +void output_t::emit_states() { + for (size_t i = 0; i < generator->get_state_count(); i++) + emit_state(i); +} + +void output_t::emit_source() { + std::fprintf(source_file, "typedef struct %scontext_state {\n", prefix()); + std::fprintf(source_file, "\tunsigned state;\n"); + std::fprintf(source_file, "} %scontext_state_t;\n\n", prefix()); + + std::fprintf(source_file, "typedef struct %scontext {\n", prefix()); + std::fprintf(source_file, "\tunsigned top;\n"); + std::fprintf(source_file, "\t%scontext_state_t stack[%u];\n", prefix(), stack_size); + std::fprintf(source_file, "} %scontext_t;\n\n", prefix()); + + std::fprintf(source_file, "int %spush(%scontext_t *parser, int token, const %stoken_value_t *value) {\n", prefix(), prefix(), prefix()); + std::fprintf(source_file, "\twhile (1) {\n"); + std::fprintf(source_file, "\t\tswitch (parser->stack[parser->top].state) {\n"); + + emit_states(); + + std::fprintf(source_file, "\t\t}\n"); + std::fprintf(source_file, "\t}\n"); + std::fprintf(source_file, "}\n"); +} + +void output_t::write() { + emit_header(); + std::fflush(header_file); + + emit_source(); +} + +} |