102 lines
3.8 KiB
C++
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
|