diff --git a/include/Parsodus/backends/cppLR.h b/include/Parsodus/backends/cppLR.h index b7c1eff..697fccd 100644 --- a/include/Parsodus/backends/cppLR.h +++ b/include/Parsodus/backends/cppLR.h @@ -3,6 +3,14 @@ #define PARSODUS_BACKENDS_CPP_H #include "Parsodus/backend.h" +#include "Parsodus/lrtables/table.h" +#include "Parsodus/template.h" +#include "Parsodus/util/symbols.h" + +#include +#include +#include +#include namespace pds { namespace backends { @@ -10,7 +18,7 @@ namespace backends { /** * A backend that emits c++ code */ - template + template class CppLRBackend : public Backend { public: CppLRBackend(util::ParserType parserType): Backend(), m_parserType(parserType) {} @@ -31,7 +39,84 @@ namespace backends { } void generateParser(std::function(std::string)> getOstreamForFileName, std::string parserName, const Config& config) { - //TODO + assert(parserName.length()); + + Generator gen(config.grammar); + lr::LRTable table(gen.generate()); + + std::map topLevel; + topLevel["name"] = parserName; + topLevel["num_states"] = templ::make_string(std::to_string(table.act.size())); + topLevel["num_rules"] = templ::make_string(std::to_string(config.grammar.rules.size())); + topLevel["num_symbols"] = templ::make_string(std::to_string(config.grammar.terminals.size() + 1 + config.grammar.variables.size())); // + 1 for EOF + + std::vector symbols; + symbols.push_back(templ::make_map({{"symbol", "TEOF"}})); + for (auto& s : config.grammar.terminals) + symbols.push_back(templ::make_map({{"symbol", s}})); + for (auto& s : config.grammar.variables) + symbols.push_back(templ::make_map({{"symbol", s}})); + topLevel["symbols"] = std::move(symbols); + + std::vector rules; + for (std::size_t i = 0; i < config.grammar.rules.size(); i++) { + std::map r; + r["index"] = templ::make_string(std::to_string(i)); + r["rhs_length"] = templ::make_string(std::to_string(config.grammar.rules[i]->tail.size())); + if (false /* the rule has a name */) + r["name"] = templ::make_string(""); //The name + rules.push_back(templ::make_map(std::move(r))); + } + topLevel["rules"] = templ::make_array(std::move(rules)); + + std::set terminals = config.grammar.terminals; + terminals.insert(util::EOF_PLACEHOLDER); + std::vector states(table.act.size()); + for (std::size_t i = 0; i < table.act.size(); i++) { + std::map st; + + std::vector actions; + for (const auto& term : terminals) { + std::string a = ""; + std::string data = "0"; + if (table.act[i].find(term) != table.act[i].end()) { + const auto& tmp = table.act[i][term]; + switch (tmp.first) { + case lr::Action::SHIFT: + a = "SHIFT"; + data = std::to_string(tmp.second); + break; + case lr::Action::REDUCE: + a = "REDUCE"; + data = term + " << 31 | " + std::to_string(tmp.second); + break; + case lr::Action::ACCEPT: + a = "ACCEPT"; + break; + case lr::Action::ERROR: + a = "ERROR"; + break; + } + } + actions.push_back(templ::make_map({{"action", templ::make_string(a)}, + {"data", templ::make_string(data)}})); + + std::vector gotos; + for (const auto& nonterm : config.grammar.variables) { + gotos.push_back(templ::make_string(std::to_string(table.goto_[i][nonterm]))); + } + + st["actions"] = templ::make_array(std::move(actions)); + st["gotos"] = templ::make_array(std::move(gotos)); + states[i] = templ::make_map(std::move(st)); + } + } + topLevel["states"] = templ::make_array(std::move(states)); + + std::unique_ptr headerOut = getOstreamForFileName(parserName + ".h"); + std::unique_ptr implOut = getOstreamForFileName(parserName + ".cpp"); + this->doTemplate(*headerOut, "c++/lr.h", topLevel); + this->doTemplate(*implOut, "c++/lr.h", topLevel); } private: util::ParserType m_parserType;