From 61c3aa15c347624cb3c4a3106235d061e718ccad Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 2 Apr 2015 11:52:05 +0200 Subject: Add simple output generator --- src/CMakeLists.txt | 1 + src/generator.cpp | 6 +- src/generator.hpp | 18 +++++- src/output.cpp | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/output.hpp | 74 +++++++++++++++++++++ src/solar.cpp | 4 ++ 6 files changed, 284 insertions(+), 5 deletions(-) create mode 100644 src/output.cpp create mode 100644 src/output.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ca658c2..711506c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ add_executable(solar generator.cpp lex.cpp + output.cpp parser.cpp parser_state.cpp solar.cpp diff --git a/src/generator.cpp b/src/generator.cpp index a9a20aa..f336772 100644 --- a/src/generator.cpp +++ b/src/generator.cpp @@ -96,12 +96,10 @@ void generator_t::generate_itemsets() { auto added = add_set(entry.second); - auto action = std::make_pair(std::make_pair(cur.second, entry.first), added.first->second); - if (entry.first.get_type() == SYMBOL_TYPE_NONTERM) - gotos.insert(std::move(action)); + gotos.emplace(std::make_pair(cur.second, entry.first.get_value()), added.first->second); else - shifts.insert(std::move(action)); + shifts.emplace(std::make_pair(cur.second, entry.first), added.first->second); if (added.second) queue.push(*added.first); diff --git a/src/generator.hpp b/src/generator.hpp index 5396d3e..4c5f9af 100644 --- a/src/generator.hpp +++ b/src/generator.hpp @@ -47,7 +47,7 @@ private: std::map, size_t> shifts; std::map reductions; - std::map, size_t> gotos; + std::map, size_t> gotos; void close_set(std::set *set); std::set get_set(const std::string &nonterm); @@ -67,6 +67,22 @@ public: return itemsets.size(); } + const std::vector & get_rules() const { + return rules; + } + + const std::map & get_reductions() const { + return reductions; + } + + const std::map, size_t> & get_shifts() const { + return shifts; + } + + const std::map, size_t> & get_gotos() const { + return gotos; + } + generator_t(const std::vector &rules0); }; 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 + 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 +#include + + +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> 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(); +} + +} diff --git a/src/output.hpp b/src/output.hpp new file mode 100644 index 0000000..f129716 --- /dev/null +++ b/src/output.hpp @@ -0,0 +1,74 @@ +/* + Copyright (c) 2015, Matthias Schiffer + 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. +*/ + + +#pragma once + +#include "generator.hpp" + +#include + + +namespace solar { + +class output_t { +private: + std::string prefix_str; + std::string token_prefix_str; + unsigned stack_size; + + const generator_t *generator; + + std::FILE *header_file; + std::FILE *source_file; + + std::map tokens; + std::map nonterms; + + const char * prefix() const { + return prefix_str.c_str(); + } + + const char * token_prefix() const { + return token_prefix_str.c_str(); + } + + void emit_tokens(); + void emit_token_value(); + void emit_header(); + + void emit_state_shift(unsigned i); + void emit_state_reduce(const item_t &item); + void emit_state(unsigned i); + void emit_states(); + void emit_source(); + +public: + output_t(const generator_t *generator0, const char *header, const char *source); + + void write(); +}; + +} diff --git a/src/solar.cpp b/src/solar.cpp index c022a6d..c2e1545 100644 --- a/src/solar.cpp +++ b/src/solar.cpp @@ -27,6 +27,7 @@ #include "lex.hpp" #include "parser.hpp" #include "generator.hpp" +#include "output.hpp" #include @@ -88,5 +89,8 @@ int main(int argc, char *argv[]) { generator_t generator(state.get_rules()); + output_t output(&generator, "/dev/stdout", "/dev/stdout"); + output.write(); + return 0; } -- cgit v1.2.3