Lexesis/src/backends/cpp.cpp

102 lines
3.8 KiB
C++

#include "Lexesis/backends/cpp.h"
#include <cassert>
namespace lxs { namespace backends {
CppBackend::CppBackend() : Backend()
{}
CppBackend::~CppBackend()
{}
bool CppBackend::canProcessLang(std::string lang) {
for (char& c : lang)
c = std::tolower(c);
return lang == "c++" || lang == "cpp" || lang == "cxx";
}
void CppBackend::generateLexer(
std::function<std::unique_ptr<std::ostream>(std::string)> getOstreamForFileName,
std::string lexerName,
const DFA& dfa)
{
assert(lexerName.length());
std::unique_ptr<std::ostream> headerStream = getOstreamForFileName(lexerName + ".h");
std::unique_ptr<std::ostream> implementationStream = getOstreamForFileName(lexerName + ".cpp");
std::map<const std::string, templ::TemplateContext> topLevel;
lexerName[0] = std::toupper(lexerName[0]);
topLevel["name"] = templ::make_string(lexerName);
//The DEADSTATE gets a brand new state: dfa.numStates
topLevel["reject_state"] = templ::make_string(std::to_string(dfa.numStates));
topLevel["num_states"] = templ::make_string(std::to_string(dfa.numStates + 1));
auto transition_indices = buildTransitionIndices(dfa);
topLevel["trans_idx"] = transformTransitionIndices(transition_indices.first);
topLevel["num_transitions_per_state"] = templ::make_string(std::to_string(transition_indices.second));
topLevel["table"] = buildTable(dfa, transition_indices.first, transition_indices.second);
topLevel["token_types"] = buildTokenList(dfa);
templ::TemplateContext topLevelMap = templ::make_map(topLevel);
doTemplate(*headerStream, "c++/lexer.h", topLevelMap);
doTemplate(*implementationStream, "c++/lexer.cpp", topLevelMap);
}
templ::TemplateContext CppBackend::buildTable(const DFA& dfa, const std::vector<char>& transition_idx, int num_transitions_per_state) const {
std::map<char, char> reverse_trans;
for (int i = 0; i < 256; i++) {
reverse_trans[transition_idx[i]] = i;
}
std::vector<templ::TemplateContext> table;
for (State s = 0; s < dfa.numStates; s++) {
std::vector<templ::TemplateContext> row;
for (int i = 0; i < num_transitions_per_state; i++) {
State to = dfa.delta.find(s)->second.find(reverse_trans[i])->second;
row.push_back(templ::make_map({{"state", templ::make_string(std::to_string(to))}}));
}
}
return templ::make_array(table);
}
templ::TemplateContext CppBackend::buildTokenList(const DFA& dfa) const {
std::set<std::string> tokens;
for (const auto& pr : dfa.acceptingToken) {
tokens.insert(pr.second);
}
tokens.insert("ignore");
std::vector<templ::TemplateContext> tokenList;
for (const std::string& s : tokens) {
tokenList.push_back(templ::make_map({{"type", templ::make_string(s)}}));
}
return templ::make_array(tokenList);
}
std::pair<std::vector<char>, int> CppBackend::buildTransitionIndices(const DFA& /* dfa */) const {
//FIXME: this is not really optimal ;-)
std::vector<char> transition_idx;
for (int i = 0; i < 256; i++)
transition_idx.push_back(i);
return std::make_pair(transition_idx, 256);
}
templ::TemplateContext CppBackend::transformTransitionIndices(std::vector<char> transition_indices) const {
std::vector<templ::TemplateContext> new_trans;
for (auto& i : transition_indices) {
new_trans.push_back(templ::make_map({{"trans", templ::make_string("(char)" + std::to_string(i))}}));
}
return templ::make_array(new_trans);
}
} } //namespace lxs::backends