Parsodus/include/Parsodus/backends/cppLR.h

129 lines
5.7 KiB
C++

#pragma once
#ifndef PARSODUS_BACKENDS_CPP_H
#define PARSODUS_BACKENDS_CPP_H
#include "Parsodus/backend.h"
#include "Parsodus/lrtables/table.h"
#include "Parsodus/template.h"
#include "Parsodus/util/symbols.h"
#include <cassert>
#include <map>
#include <string>
#include <vector>
namespace pds {
namespace backends {
/**
* A backend that emits c++ code
*/
template<typename Generator>
class CppLRBackend : public Backend {
public:
CppLRBackend(util::ParserType parserType): Backend(), m_parserType(parserType) {}
~CppLRBackend() {}
std::string getName() {
return "c++";
}
bool canProcessLang(std::string lang) {
for (char& c : lang)
c = std::tolower(c);
return lang == "c++" || lang == "cpp" || lang == "cxx";
}
bool canGenerateParser(util::ParserType parserType) {
return parserType == m_parserType;
}
void generateParser(std::function<std::unique_ptr<std::ostream>(std::string)> getOstreamForFileName, std::string parserName, const Config& config) {
assert(parserName.length());
Generator gen(config.grammar);
lr::LRTable table(gen.generate());
std::map<const std::string, templ::TemplateContext> 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<templ::TemplateContext> symbols;
symbols.push_back(templ::make_map({{"symbol", templ::make_string("T_EOF")}}));
for (auto& s : config.grammar.terminals)
symbols.push_back(templ::make_map({{"symbol", templ::make_string("T_" + s)}}));
for (auto& s : config.grammar.variables)
symbols.push_back(templ::make_map({{"symbol", templ::make_string("V_" + s)}}));
topLevel["symbols"] = std::move(symbols);
std::vector<templ::TemplateContext> rules;
for (std::size_t i = 0; i < config.grammar.rules.size(); i++) {
std::map<const std::string, templ::TemplateContext> 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["rname"] = templ::make_string(""); //The name
rules.push_back(templ::make_map(std::move(r)));
}
topLevel["rules"] = templ::make_array(std::move(rules));
std::set<std::string> terminals = config.grammar.terminals;
terminals.insert(util::EOF_PLACEHOLDER);
std::vector<templ::TemplateContext> states(table.act.size());
for (std::size_t i = 0; i < table.act.size(); i++) {
std::map<const std::string, templ::TemplateContext> st;
std::vector<templ::TemplateContext> actions;
for (std::string term : terminals) {
std::string a = "ERROR";
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 = "static_cast<std::uint64_t>(" + parserName + "_Symbol::V_" + config.grammar.rules[tmp.second]->head + ") << 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<templ::TemplateContext> 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<std::ostream> headerOut = getOstreamForFileName(parserName + ".h");
std::unique_ptr<std::ostream> implOut = getOstreamForFileName(parserName + ".cpp");
this->doTemplate(*headerOut, "c++/lr.h", topLevel);
this->doTemplate(*implOut, "c++/lr.cpp", topLevel);
}
private:
util::ParserType m_parserType;
};
}
}
#endif //PARSODUS_BACKENDS_CPP_H