📄 cppcodegenerator.cpp
字号:
/* $Id: CppCodeGenerator.cpp,v 1.15 1997/02/22 09:00:23 matt Exp $ C++ code generator class. (c) Matt Phillips 1996. */#include "CppCodeGenerator.h"CppCodeGenerator::CppCodeGenerator (const FooObject &s, istream &cf, ostream &h, ostream &b) : scandef (s), codefrags (cf, "cpp"), header (h), body (b), errors (0), errorProduction ("ElexState::DefaultErrorProduction"){ doHeader (); doBody ();}// output chr as 'c' is ASCII or as a number if not.void CppCodeGenerator::doOutputChar (unsigned char chr){ if (chr < 32 || chr > 127) body << (unsigned)chr; else if (chr == '\\') body << "'\\\\'"; else body << '\'' << (char)chr << '\'';}void CppCodeGenerator::doHeader (){ // includes header << "#include <cppscan/ElexScanner.h>\n\n"; // do header includes codefrags.nextFrag (); if (codefrags.hasFrag ()) { codefrags.outputFrag (header); header << endl; } // class header << "class " << scandef.getAttrString ("name") << " : public "; // base class if (scandef.hasAttr ("base")) header << scandef.getAttrString ("base") << endl; else header << "ElexScanner\n"; header << "{\npublic:\n\n"; doTokenSymbols (); doProdSymbols (); // constructor header << " " << scandef.getAttrString ("name") << " (XInputStream &i);\n\n"; header << " virtual int invokeProduction (int prod);\n\n"; doProdDecls (); header << "};\n";}// do the enum declarations for productionsvoid CppCodeGenerator::doProdSymbols (){ const FooObject::Objects &productions = scandef.getAttrs ("productions"); if (productions.nItems () > 0) { header << " enum {"; for (FooObject::Objects::Iterator p (productions); p; ) { header << "Prod" << p.ref ().getAttr (); p++; if (p) header << ", "; } header << "};\n\n"; }}// do the enum declarations for token symbolsvoid CppCodeGenerator::doTokenSymbols (){ const FooObject::Objects &tokens = scandef.getAttrs ("tokens"); if (tokens.nItems () > 0) { header << " enum {"; for (FooObject::Objects::Iterator i (tokens); i; ) { header << i.ref ().getAttr (); i++; if (i) header << ", "; } header << "};\n\n"; }}// do the production member function declarationsvoid CppCodeGenerator::doProdDecls (){ const FooObject::Objects &productions = scandef.getAttrs ("productions"); for (FooObject::Objects::Iterator p (productions); p; p++) { header << " int prod" << p.ref ().getAttr () << " ();\n"; }}void CppCodeGenerator::doBody (){ const string &scannerName = scandef.getAttrString ("name"); body << "static ElexState states [];\n\n"; body << "//////////////////// Edges ////////////////////\n\n"; doEdgeLists (); body << "//////////////////// States ////////////////////\n\n"; doStates (); body << "\n////////////////// Productions /////////////////\n\n"; body << "typedef int (" << scannerName << "::*ProdFunc) ();\n\n"; doProdFuncsTable (scannerName); body << "int " << scannerName << "::invokeProduction (int prod)\n"; body << "{\n return (this->*(funcs [prod])) ();\n}\n\n"; doProdBodies (scannerName); body << "////////////////// Constructor /////////////////\n\n"; body << "static ElexScannerData scannerData = {states, " << errorProduction << "};\n\n"; body << scannerName << "::" << scannerName << " (XInputStream &i) :\n"; body << " ElexScanner (scannerData, i) {}\n\n";}// do the edge list definitions for all statesvoid CppCodeGenerator::doEdgeLists (){ const FooObject::Objects &states = scandef.getAttrs ("states"); for (FooObject::Objects::Iterator s (states); s; s++) { const string &stateNo = s.ref ().getAttrString ("state"); const FooObject::Objects &edges = s.ref ().getAttrs ("edges"); // output any edges for this state if (edges.nItems () > 0) { body << "static ElexEdge state" << stateNo << "_edgelist [] =\n{\n"; doEdgeList (edges, stateNo); body << "};\n"; body << "static ElexEdges state" << stateNo << "_edges = {state" << stateNo << "_edgelist, " << edges.nItems () << "};\n\n"; } }}// do <edges> for state <stateNo>void CppCodeGenerator::doEdgeList (const FooObject::Objects &edges, const string &stateNo){ for (FooObject::Objects::Iterator e (edges); e; ) { const FooObject &edge = e.ref (); const string &range = edge.getAttrString ("range"); body << " {"; doOutputChar (range [0]); body << ", "; // if range is of form 'l-u', then output upper, otherwise // output the lower again doOutputChar (range.length () > 1 ? range [2] : range [0]); body << ", states + " << edge.getAttrString ("target") << "}"; e++; if (e) body << ",\n"; else body << endl; }}// do the states tablevoid CppCodeGenerator::doStates (){ body << "static ElexState states [] =\n{\n"; const string &scannerName = scandef.getAttrString ("name"); const FooObject::Objects &states = scandef.getAttrs ("states"); for (FooObject::Objects::Iterator s (states); s; ) { const FooObject &state = s.ref (); const string &stateNo = state.getAttrString ("state"); const string &prodName = state.getAttrString ("production"); const FooObject::Objects &edges = state.getAttrs ("edges"); if (state.hasAttr ("edges")) body << " {&state" << stateNo << "_edges, "; else body << " {0, "; if (prodName.length () > 0) body << scannerName << "::Prod" << prodName; else body << "ElexState::NoProduction"; body << "}"; s++; if (s) body << ",\n"; else body << endl; } body << "};\n";}// do the production member functions table: maps production number to// member function. also looks for the error production, and sets// errorProduction if found.void CppCodeGenerator::doProdFuncsTable (const string &scannerName){ const FooObject::Objects &productions = scandef.getAttrs ("productions"); body << "static ProdFunc funcs [] =\n{\n"; int first = 1; for (FooObject::Objects::Iterator p (productions); p; ) { const string &prodName = p.ref ().getAttr (); body << " " << scannerName << "::prod" << prodName; if (prodName == "error") errorProduction = scannerName + "::Prod" + prodName; p++; if (p) body << ",\n"; else body << endl; } body << "};\n\n";}// inserts the production bodies from the code fragsvoid CppCodeGenerator::doProdBodies (const string &scannerName){ const FooObject::Objects &productions = scandef.getAttrs ("productions"); for (FooObject::Objects::Iterator p (productions); p; p++) { body << "int " << scannerName << "::prod" << p.ref ().getAttr () << " ()\n{\n"; codefrags.nextFrag (); if (codefrags.hasFrag ()) codefrags.outputFrag (body); else { cerr << "warning: no code for production " << p.ref ().getAttr () << endl; body << "// *** Missing code fragment\n"; } body << "}\n\n"; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -