#include "Lexesis/backends/cpp.h" #include 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::string)> getOstreamForFileName, std::string lexerName, const DFA& dfa) { assert(lexerName.length()); std::unique_ptr headerStream = getOstreamForFileName(lexerName + ".h"); std::unique_ptr implementationStream = getOstreamForFileName(lexerName + ".cpp"); std::map 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& transition_idx, int num_transitions_per_state) const { std::map reverse_trans; for (int i = 0; i < 256; i++) { reverse_trans[transition_idx[i]] = i; } std::vector table; for (State s = 0; s < dfa.numStates; s++) { std::vector 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 tokens; for (const auto& pr : dfa.acceptingToken) { tokens.insert(pr.second); } tokens.insert("ignore"); std::vector 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, int> CppBackend::buildTransitionIndices(const DFA& /* dfa */) const { //FIXME: this is not really optimal ;-) std::vector 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 transition_indices) const { std::vector 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