File indexing completed on 2024-04-21 04:36:15

0001 /* This file is part of kdev-pg-qt
0002    Copyright (C) 2005 Roberto Raggi <roberto@kdevelop.org>
0003    Copyright (C) 2006 Jakob Petsovits <jpetso@gmx.at>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "kdev-pg-generate.h"
0022 
0023 #include "kdev-pg.h"
0024 #include "kdev-pg-code-gen.h"
0025 #include "kdev-pg-ast-gen.h"
0026 #include "kdev-pg-visitor-gen.h"
0027 #include "kdev-pg-visitor-bits-gen.h"
0028 #include "kdev-pg-default-visitor-gen.h"
0029 #include "kdev-pg-default-visitor-bits-gen.h"
0030 #include "kdev-pg-serialize-visitor-gen.h"
0031 #include "kdev-pg-debug-visitor-gen.h"
0032 #include "kdev-pg-new-visitor-gen.h"
0033 #include "kdev-pg-new-visitor-bits-gen.h"
0034 #include "kdev-pg-beautifier.h"
0035 #include "kdev-pg-regexp.h"
0036 
0037 #include <QTextStream>
0038 #include <QFile>
0039 #include "kdev-pg-token-type-gen.h"
0040 
0041 namespace KDevPG
0042 {
0043 void generateOutput()
0044 {
0045   QByteArray language = globalSystem.language.toUpper().toLatin1();
0046   for(int i = 0; i != language.size(); ++i)
0047   {
0048     if(language[i] < '0' || (language[i] > '9' && language[i] < 'A') || language[i] > 'Z')
0049       language[i] = '_';
0050   }
0051 
0052   if (globalSystem.generateAst)
0053   {
0054     { // generate the ast
0055       QString str;
0056       QTextStream s(&str, QIODevice::WriteOnly);
0057 
0058       GenerateAst _Ast(s);
0059 
0060       s << "// THIS FILE IS GENERATED" << Qt::endl
0061         << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0062         << Qt::endl
0063 
0064         << "#ifndef " << language << "_AST_H_INCLUDED" << Qt::endl
0065         << "#define " << language << "_AST_H_INCLUDED" << Qt::endl
0066         << Qt::endl
0067         
0068         << "#include \"" << globalSystem.language << "ast-fwd.h\"" << Qt::endl
0069         << Qt::endl;
0070       if (!globalSystem.exportMacroHeader.isEmpty())
0071         s << "#include \"" << globalSystem.exportMacroHeader << "\""
0072           << Qt::endl;
0073 
0074       foreach (const QString& header, globalSystem.astHeaders)
0075         s << "#include \"" << header << "\"\n";
0076       
0077       s <<  "#include <QList>" << Qt::endl
0078         << "#include <kdev-pg-list.h>" << Qt::endl
0079         << Qt::endl;
0080       
0081       if (!globalSystem.decl.isEmpty())
0082         s << globalSystem.decl << Qt::endl;
0083 
0084       s << "namespace " << globalSystem.ns << "{" << Qt::endl
0085         << Qt::endl;
0086 
0087       _Ast();
0088 
0089       s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0090         << Qt::endl
0091 
0092         << "#endif" << Qt::endl
0093         << Qt::endl;
0094 
0095       QString oname = globalSystem.language;
0096       oname += "ast.h";
0097 
0098       format(s, oname);
0099     }
0100     { // generate ast forward declarations
0101     
0102       QString str;
0103       QTextStream s(&str, QIODevice::WriteOnly);
0104       
0105       GenerateAstFwd _AstFwd(s);
0106       
0107       s << ""// THIS FILE IS GENERATED" << Qt::endl
0108         << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0109         << Qt::endl
0110 
0111         << "#ifndef " << language << "_AST_FWD_INCLUDED" << Qt::endl
0112         << "#define " << language << "_AST_FWD_INCLUDED" << Qt::endl
0113         << Qt::endl;
0114       if (!globalSystem.exportMacroHeader.isEmpty())
0115         s << "#include \"" << globalSystem.exportMacroHeader << "\""
0116           << Qt::endl;
0117       
0118       s << "namespace " << globalSystem.ns << "{" << Qt::endl
0119         << Qt::endl;
0120       
0121       _AstFwd();
0122       
0123       s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0124         << Qt::endl
0125       
0126         << "#endif" << Qt::endl
0127         << Qt::endl;
0128       
0129       QString oname = globalSystem.language;
0130       oname += "ast-fwd.h";
0131       
0132       format(s, oname);
0133     }
0134   }
0135   { // generate token type
0136     QString str;
0137     QTextStream s(&str, QIODevice::WriteOnly);
0138 
0139     GenerateTokenType gen(s);
0140 
0141     s << "// THIS FILE IS GENERATED" << Qt::endl
0142       << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0143       << Qt::endl
0144 
0145       << "#ifndef " << language << "_TOKEN_TYPE_H_INCLUDED" << Qt::endl
0146       << "#define " << language << "_TOKEN_TYPE_H_INCLUDED" << Qt::endl
0147       << Qt::endl;
0148     if (!globalSystem.exportMacroHeader.isEmpty())
0149       s << "#include \"" << globalSystem.exportMacroHeader << "\""
0150         << Qt::endl;
0151 
0152     foreach (const QString& header, globalSystem.astHeaders)
0153       s << "#include \"" << header << "\"\n";
0154 
0155     if (!globalSystem.decl.isEmpty())
0156       s << globalSystem.decl << Qt::endl;
0157 
0158     s << "namespace " << globalSystem.ns << "{" << Qt::endl
0159       << Qt::endl;
0160 
0161     gen();
0162 
0163     s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0164       << Qt::endl
0165 
0166       << "#endif" << Qt::endl
0167       << Qt::endl;
0168 
0169     QString oname = globalSystem.language;
0170     oname += "tokentype.h";
0171 
0172     format(s, oname);
0173   }
0174   { // generate the parser decls
0175     QString str;
0176     QTextStream s(&str, QIODevice::WriteOnly);
0177 
0178     GenerateParserDeclarations __decls(s);
0179 
0180     s << "// THIS FILE IS GENERATED" << Qt::endl
0181       << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0182       << Qt::endl
0183 
0184       << "#ifndef " << language << "_H_INCLUDED" << Qt::endl
0185       << "#define " << language << "_H_INCLUDED" << Qt::endl
0186       << Qt::endl;
0187     
0188     
0189     s << "#include \"" << globalSystem.language << "tokentype.h\"" << Qt::endl;
0190     
0191     if(globalSystem.hasLexer)
0192       s << "#include \"" << globalSystem.language << "lexer.h\"" << Qt::endl;
0193 
0194     if (globalSystem.generateAst)
0195       {
0196         s << "#include \"" << globalSystem.language << "ast-fwd.h\"" << Qt::endl
0197           << "#include <kdev-pg-memory-pool.h>" << Qt::endl
0198           << "#include <kdev-pg-allocator.h>" << Qt::endl;
0199       }
0200 
0201     if (globalSystem.tokenStream == "KDevPG::TokenStream")
0202       s << "#include <kdev-pg-token-stream.h>" << Qt::endl;
0203     
0204     foreach (const QString& header, globalSystem.parserDeclarationHeaders)
0205       s << "#include \"" << header << "\"\n";
0206 
0207     s << Qt::endl;
0208     if (!globalSystem.exportMacroHeader.isEmpty())
0209       s << "#include \"" << globalSystem.exportMacroHeader << "\""
0210         << Qt::endl;
0211     
0212     if (globalSystem.needOperatorStack)
0213       s << "#include <QVector>" << Qt::endl;
0214     
0215     if (!globalSystem.decl.isEmpty() && !globalSystem.generateAst)
0216       s << globalSystem.decl << Qt::endl;
0217 
0218     s << "namespace " << globalSystem.ns << "{" << Qt::endl
0219       << Qt::endl;
0220 
0221     __decls();
0222 
0223     s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0224       << Qt::endl
0225 
0226       << "#endif" << Qt::endl
0227       << Qt::endl;
0228 
0229     QString oname = globalSystem.language;
0230     oname += "parser.h";
0231 
0232     format(s, oname);
0233   }
0234 
0235   if (globalSystem.generateAst)
0236   { // generate the visitor decls
0237     QString str;
0238     QTextStream s(&str, QIODevice::WriteOnly);
0239 
0240     GenerateVisitor __visitor(s);
0241 
0242     s << "// THIS FILE IS GENERATED" << Qt::endl
0243       << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0244       << Qt::endl
0245 
0246       << "#ifndef " << language << "_VISITOR_H_INCLUDED" << Qt::endl
0247       << "#define " << language << "_VISITOR_H_INCLUDED" << Qt::endl
0248       << Qt::endl
0249 
0250       << "#include \"" << globalSystem.language << "ast.h\"" << Qt::endl
0251       << Qt::endl;
0252     if (!globalSystem.exportMacroHeader.isEmpty())
0253       s << "#include \"" << globalSystem.exportMacroHeader << "\""
0254         << Qt::endl;
0255 
0256     s << "namespace " << globalSystem.ns << "{" << Qt::endl
0257       << Qt::endl;
0258 
0259     __visitor();
0260 
0261     s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0262       << Qt::endl
0263 
0264       << "#endif" << Qt::endl
0265       << Qt::endl;
0266 
0267     QString oname = globalSystem.language;
0268     oname += "visitor.h";
0269 
0270     format(s, oname);
0271   }
0272 
0273   if (globalSystem.generateAst)
0274   { // generate the default visitor
0275     QString str;
0276     QTextStream s(&str, QIODevice::WriteOnly);
0277 
0278     GenerateDefaultVisitor __DefaultVisitor(s);
0279 
0280     s << "// THIS FILE IS GENERATED" << Qt::endl
0281       << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0282       << Qt::endl
0283 
0284       << "#ifndef " << language << "_DEFAULT_VISITOR_H_INCLUDED" << Qt::endl
0285       << "#define " << language << "_DEFAULT_VISITOR_H_INCLUDED" << Qt::endl
0286       << Qt::endl
0287 
0288       << "#include \"" << globalSystem.language << "visitor.h\"" << Qt::endl
0289       << Qt::endl;
0290     if (!globalSystem.exportMacroHeader.isEmpty())
0291       s << "#include \"" << globalSystem.exportMacroHeader << "\""
0292         << Qt::endl;
0293 
0294     s << "namespace " << globalSystem.ns << "{" << Qt::endl
0295       << Qt::endl;
0296 
0297     __DefaultVisitor();
0298 
0299     s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0300       << Qt::endl
0301 
0302       << "#endif" << Qt::endl
0303       << Qt::endl;
0304 
0305     QString oname = globalSystem.language;
0306     oname += "defaultvisitor.h";
0307 
0308     format(s, oname);
0309   }
0310 
0311   if (globalSystem.generateSerializeVisitor)
0312   { // generate the serialization visitor
0313     QString str;
0314     QTextStream s(&str, QIODevice::WriteOnly);
0315 
0316     GenerateSerializeVisitor __serialize_visitor(s);
0317 
0318     s << "// THIS FILE IS GENERATED" << Qt::endl
0319       << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0320       << Qt::endl
0321 
0322       << "#ifndef " << language << "_SERIALIZATION_H_INCLUDED" << Qt::endl
0323       << "#define " << language << "_SERIALIZATION_H_INCLUDED" << Qt::endl
0324       << Qt::endl
0325 
0326       << "#include \"" << globalSystem.language << "defaultvisitor.h\"" << Qt::endl
0327       << Qt::endl;
0328     if (!globalSystem.exportMacroHeader.isEmpty())
0329       s << "#include \"" << globalSystem.exportMacroHeader << "\""
0330         << Qt::endl;
0331 
0332     s << "#include <QTextStream>" << Qt::endl
0333       << "#include <QFile>" << Qt::endl
0334       << Qt::endl
0335 
0336       << "namespace " << globalSystem.ns << "{" << Qt::endl
0337       << Qt::endl;
0338 
0339     __serialize_visitor();
0340 
0341     s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0342       << Qt::endl;
0343 
0344     s << "#endif" << Qt::endl
0345       << Qt::endl;
0346 
0347     QString oname = globalSystem.language;
0348     oname += "serializevisitor.h";
0349 
0350     format(s, oname);
0351   }
0352 
0353   if (globalSystem.generateDebugVisitor)
0354   { // generate the debug visitor
0355     QString str;
0356     QTextStream s(&str, QIODevice::WriteOnly);
0357 
0358     GenerateDebugVisitor __debug_visitor(s);
0359 
0360     s << "// THIS FILE IS GENERATED" << Qt::endl
0361       << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0362       << Qt::endl
0363 
0364       << "#ifndef " << language << "_DEBUG_VISITOR_H_INCLUDED" << Qt::endl
0365       << "#define " << language << "_DEBUG_VISITOR_H_INCLUDED" << Qt::endl
0366       << Qt::endl
0367 
0368       << "#include \"" << globalSystem.language << "defaultvisitor.h\"" << Qt::endl
0369       << Qt::endl;
0370     if (!globalSystem.exportMacroHeader.isEmpty())
0371       s << "#include \"" << globalSystem.exportMacroHeader << "\""
0372         << Qt::endl;
0373 
0374     s << "#include <kdev-pg-token-stream.h>" << Qt::endl;
0375     
0376     s << "#include <QTextStream>" << Qt::endl
0377       << "#include <QDebug>" << Qt::endl
0378       << Qt::endl
0379 
0380       << "namespace " << globalSystem.ns << "{" << Qt::endl
0381       << Qt::endl;
0382 
0383     __debug_visitor();
0384 
0385     s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0386       << Qt::endl;
0387 
0388     s << "#endif" << Qt::endl
0389       << Qt::endl;
0390 
0391     QString oname = globalSystem.language;
0392     oname += "debugvisitor.h";
0393 
0394     format(s, oname);
0395   }
0396   if (globalSystem.generateTokenText || globalSystem.generateDebugVisitor)
0397   { // generate the token text function
0398     QString str;
0399     QTextStream s(&str, QIODevice::WriteOnly);
0400 
0401     s << "// THIS FILE IS GENERATED" << Qt::endl
0402       << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0403       << Qt::endl
0404 
0405       << "#ifndef " << language << "_TOKEN_TEXT_H_INCLUDED" << Qt::endl
0406       << "#define " << language << "_TOKEN_TEXT_H_INCLUDED" << Qt::endl
0407       << Qt::endl;
0408     
0409     if (!globalSystem.exportMacroHeader.isEmpty())
0410       s << "#include \"" << globalSystem.exportMacroHeader << "\"" << Qt::endl;
0411     
0412     s << "#include \"" << globalSystem.language << "tokentype.h\"" << Qt::endl
0413 
0414       << "namespace " << globalSystem.ns << "{" << Qt::endl
0415       << Qt::endl
0416 
0417       << "QString tokenText(int token)" << Qt::endl << "{" << Qt::endl;
0418 
0419     GenerateTokenTexts gen(s);
0420     gen();
0421 
0422     s << "}"
0423       << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0424       << Qt::endl;
0425 
0426     s << "#endif" << Qt::endl
0427       << Qt::endl;
0428 
0429     QString oname = globalSystem.language;
0430     oname += "tokentext.h";
0431 
0432     format(s, oname);
0433   }
0434   { // generate the parser bits
0435     QString str;
0436     QTextStream s(&str, QIODevice::WriteOnly);
0437 
0438     GenerateParserBits __bits(s);
0439 
0440     s << "// THIS FILE IS GENERATED" << Qt::endl
0441       << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0442       << Qt::endl;
0443 
0444     s << "#include \"" << globalSystem.language << "parser.h\""
0445       << Qt::endl;
0446     
0447     if (globalSystem.generateAst)
0448     {
0449       s << "#include \"" << globalSystem.language << "ast.h\"" << Qt::endl;
0450     }
0451 
0452     foreach (const QString& header, globalSystem.parserBitsHeaders)
0453       s << "#include \"" << header << "\"\n";
0454 
0455     s << Qt::endl;
0456 
0457     if (!globalSystem.bits.isEmpty())
0458       s << globalSystem.bits << Qt::endl;
0459 
0460     s << "namespace " << globalSystem.ns << "{" << Qt::endl
0461       << Qt::endl;
0462 
0463     __bits();
0464 
0465     s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0466       << Qt::endl;
0467 
0468     QString oname = globalSystem.language;
0469     oname += "parser.cpp";
0470 
0471     format(s, oname);
0472   }
0473 
0474   if (globalSystem.generateAst)
0475   { // generate the visitor bits
0476     QString str;
0477     QTextStream s(&str, QIODevice::WriteOnly);
0478 
0479     GenerateVisitorBits __visitor_bits(s);
0480 
0481     s << "// THIS FILE IS GENERATED" << Qt::endl
0482       << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0483       << Qt::endl
0484 
0485       << "#include \"" << globalSystem.language << "visitor.h\"" << Qt::endl
0486 
0487       << Qt::endl
0488 
0489       << "namespace " << globalSystem.ns << "{" << Qt::endl
0490       << Qt::endl;
0491 
0492     __visitor_bits();
0493 
0494     s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0495       << Qt::endl;
0496 
0497     QString oname = globalSystem.language;
0498     oname += "visitor.cpp";
0499 
0500     format(s, oname);
0501   }
0502 
0503   if (globalSystem.generateAst)
0504   { // generate the default visitor bits
0505     QString str;
0506     QTextStream s(&str, QIODevice::WriteOnly);
0507 
0508     s << "// THIS FILE IS GENERATED" << Qt::endl
0509       << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0510       << Qt::endl
0511 
0512       << "#include \"" << globalSystem.language << "defaultvisitor.h\"" << Qt::endl
0513       << Qt::endl
0514 
0515       << "namespace " << globalSystem.ns << "{" << Qt::endl
0516 
0517       << Qt::endl;
0518 
0519     GenerateDefaultVisitorBitsRule gen(s);
0520     for( World::SymbolSet::iterator it = globalSystem.symbols.begin();
0521         it != globalSystem.symbols.end(); ++it )
0522     {
0523       gen(qMakePair(it.key(), *it));
0524     }
0525 
0526     s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0527       << Qt::endl;
0528 
0529     QString oname = globalSystem.language;
0530     oname += "defaultvisitor.cpp";
0531 
0532     format(s, oname);
0533   }
0534 }
0535 
0536 void generateLexer()
0537 {
0538   QByteArray language = globalSystem.language.toUpper().toLatin1();
0539   bool hasStates = globalSystem.lexerEnvs.size() > 1;
0540   
0541   { // generate the lexer header
0542     QString str;
0543     QTextStream s(&str, QIODevice::WriteOnly);
0544     
0545     s << "// THIS FILE IS GENERATED" << Qt::endl
0546       << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0547       << Qt::endl
0548     
0549       << "#ifndef " << language << "_LEXER_H_INCLUDED" << Qt::endl
0550       << "#define " << language << "_LEXER_H_INCLUDED" << Qt::endl
0551       << Qt::endl
0552       
0553       << "#include \"" << globalSystem.language << "tokentype.h\"" << Qt::endl
0554       << Qt::endl
0555       
0556       << "#include <kdev-pg-char-sets.h>" << Qt::endl
0557       << "#include <kdev-pg-token-stream.h>" << Qt::endl
0558       << Qt::endl;
0559       
0560     foreach (const QString& header, globalSystem.lexerDeclarationHeaders)
0561       s << "#include \"" << header << "\"\n";
0562     
0563     s << Qt::endl << "namespace " << globalSystem.ns << "{" << Qt::endl
0564       << Qt::endl
0565       
0566       << "class " << globalSystem.exportMacro << " " << globalSystem.tokenStream << " : " 
0567       << (globalSystem.lexerBaseClass.isEmpty() ? QString() : " public " + globalSystem.lexerBaseClass + ",")
0568       << "public " << globalSystem.inputStream << ","
0569       << "public TokenTypeWrapper" << Qt::endl
0570       << "{" << Qt::endl
0571       << "public:" << Qt::endl
0572       << "typedef " << (globalSystem.lexerBaseClass.isEmpty() ? globalSystem.tokenStream : globalSystem.lexerBaseClass) << " Base;" << Qt::endl
0573       << "typedef " << globalSystem.inputStream << " Iterator;" << Qt::endl << Qt::endl << "private:" << Qt::endl;
0574       
0575     
0576     if(hasStates)
0577     {
0578       foreach(QString state, globalSystem.lexerEnvs.keys())
0579         s << "Base::Token& lex" << KDevPG::capitalized(state) << "();" << Qt::endl;
0580       s << "public:\nenum RuleSet {\n";
0581       foreach(QString state, globalSystem.lexerEnvs.keys())
0582         s << "State_" << state << ", /*" << globalSystem.lexerEnvs[state].size() << "*/" << Qt::endl;
0583       s << "State_COUNT\n};\n"
0584            "private:\n"
0585            "RuleSet m_ruleSet;\n"
0586            "public:\n"
0587            "inline RuleSet ruleSet()\n{\nreturn m_ruleSet;\n}\n"
0588            "void setRuleSet(RuleSet rs);\n";
0589       foreach(QString state, globalSystem.lexerEnvs.keys())
0590       {
0591         s << "inline void enteringRuleSet" << state << "();" << Qt::endl;
0592         s << "inline void leavingRuleSet" << state << "();" << Qt::endl;
0593       }
0594     }
0595       
0596     s << "Iterator::PlainIterator spos;" << Qt::endl
0597       << "bool continueLexeme;" << Qt::endl << Qt::endl
0598       
0599       << "public:" << Qt::endl << globalSystem.tokenStream << "(const Iterator& iter);" << Qt::endl
0600       // non-virtual, virtuality will be inherited
0601       << "~" << globalSystem.tokenStream << "();"
0602       <<  Qt::endl << "Base::Token& read();" << Qt::endl;
0603     
0604       /// TODO: not good that it happens in a separate file for the parser but in this file for the lexer
0605 #define LEXER_EXTRA_CODE_GEN(name) \
0606     if (globalSystem.lexerclassMembers.name.empty() == false) \
0607     { \
0608       s << "\n// user defined code:" << Qt::endl; \
0609       GenerateMemberCode gen(s, Settings::MemberItem::PublicDeclaration \
0610                                 | Settings::MemberItem::ProtectedDeclaration \
0611                                 | Settings::MemberItem::PrivateDeclaration \
0612                                 | Settings::MemberItem::ConstructorCode \
0613                                 | Settings::MemberItem::DestructorCode); \
0614       for( auto it = globalSystem.lexerclassMembers.name.begin(); \
0615       it != globalSystem.lexerclassMembers.name.end(); ++it ) \
0616       { \
0617         gen(*it); \
0618       } \
0619     }
0620     
0621     LEXER_EXTRA_CODE_GEN(declarations)
0622     
0623     s << "};" << Qt::endl << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0624       << Qt::endl
0625       
0626       << "#endif" << Qt::endl
0627       << Qt::endl;
0628       
0629     QString oname = globalSystem.language;
0630     oname += "lexer.h";
0631         
0632     format(s, oname);
0633     
0634   }
0635   { // generate the lexer bits
0636     QString str;
0637     QTextStream s(&str, QIODevice::WriteOnly);
0638     
0639     s << "// THIS FILE IS GENERATED" << Qt::endl
0640       << "// WARNING! All changes made in this file will be lost!" << Qt::endl
0641       << Qt::endl
0642     
0643       << "#include \"" << globalSystem.language << "lexer.h\"" << Qt::endl
0644       << Qt::endl;
0645     
0646     foreach (const QString& header, globalSystem.lexerBitsHeaders)
0647       s << "#include \"" << header << "\"\n";
0648     
0649     s << "\n#include <cassert>\n";
0650     
0651     s << Qt::endl << "namespace " << globalSystem.ns << "{" << Qt::endl
0652       << Qt::endl << globalSystem.tokenStream << "::" << globalSystem.tokenStream
0653       << "(const " << globalSystem.tokenStream << "::Iterator& iter) : Base(), Iterator(iter), " << (hasStates ? "m_ruleSet(State_start), " : "") << "continueLexeme(false)" << Qt::endl
0654       << "{";
0655     LEXER_EXTRA_CODE_GEN(constructorCode)
0656     s << "}" << Qt::endl << Qt::endl
0657       << globalSystem.tokenStream << "::~" << globalSystem.tokenStream
0658       << "()\n{";
0659     LEXER_EXTRA_CODE_GEN(destructorCode)
0660     s << "}" << Qt::endl << Qt::endl
0661             
0662       << "#define PP_CONCAT_IMPL(x, y) x ## y\n" // necessary, otherwise CURRENT_RULE_SET would not get resolved
0663          "#define PP_CONCAT(x, y) PP_CONCAT_IMPL(x, y)\n\n"
0664          
0665          "#define lxCURR_POS (Iterator::plain())\n"
0666          "#define lxCURR_IDX (Iterator::plain() - Iterator::begin())\n"
0667          "#define lxCONTINUE {continueLexeme = true; return read();}\n"
0668          "#define lxLENGTH (Iterator::plain() - Iterator::begin())\n"
0669          "#define lxBEGIN_POS (spos)\n"
0670          "#define lxBEGIN_IDX (spos - Iterator::begin())\n"
0671          "#define lxNAMED_TOKEN(token, X) KDevPG::Token& token(Base::push()); token.kind = Token_##X; token.begin = lxBEGIN_IDX; token.end = lxCURR_IDX - 1;\n"
0672          "#define lxTOKEN(X) {lxNAMED_TOKEN(token, X);}\n"
0673          "#define lxDONE {return Base::read();}\n"
0674          "#define lxRETURN(X) {lxTOKEN(X); lxDONE}\n"
0675          "#define lxEOF {Base::Token& _t(Base::push()); _t.kind = Token_EOF;_t.begin = _t.end = Iterator::plain() - Iterator::begin();}\n"
0676          "#define lxFINISH {lxEOF lxDONE}\n"
0677          "#define yytoken (Base::back())\n"
0678          "#define lxFAIL {goto _fail;}\n"
0679          "#define lxSKIP {return read();}\n"
0680          "#define lxNEXT_CHR(chr) { if(!Iterator::hasNext()) goto _end; chr = Iterator::next(); }\n" << Qt::endl;
0681     
0682     if(hasStates)
0683     {
0684       s << "#define lxSET_RULE_SET(r) {PP_CONCAT(leavingRuleSet, CURRENT_RULE_SET) (); m_ruleSet = State_##r; enteringRuleSet##r ();}\n" << Qt::endl << Qt::endl;
0685       
0686       foreach(QString state, globalSystem.lexerEnvs.keys())
0687       {
0688         s << "inline void " << globalSystem.tokenStream << "::enteringRuleSet" << state << "() { " << globalSystem.enteringCode[state] << "}" << Qt::endl;
0689         s << "inline void " << globalSystem.tokenStream << "::leavingRuleSet" << state << "() { " << globalSystem.leavingCode[state] << "}" << Qt::endl;
0690       }
0691       s << "\n"
0692            "void " << globalSystem.tokenStream << "::setRuleSet(RuleSet rs)\n"
0693            "{\n"
0694            "switch(m_ruleSet)\n"
0695            "{\n";
0696       foreach(QString state, globalSystem.lexerEnvs.keys())
0697       {
0698         s << "case State_" << state << ":\n"
0699              "leavingRuleSet" << state << "();\n"
0700              "break;\n";
0701       }
0702       s << "\ndefault:\n"
0703            "assert(0 == \"Invalid rule set\");\n"
0704            "}\n\n"
0705            "m_ruleSet = rs;\n\n"
0706            "switch(m_ruleSet)\n"
0707            "{\n";
0708       foreach(QString state, globalSystem.lexerEnvs.keys())
0709       {
0710         s << "case State_" << state << ":\n"
0711              "enteringRuleSet" << state << "();\n"
0712              "break;\n";
0713       }
0714       s << "\ndefault:\n"
0715            "assert(0 == \"Invalid rule set\");\n"
0716            "}\n"
0717            "}\n\n";
0718     }
0719     
0720 #define LEXER_CORE_IMPL(name, state, extra) \
0721       s << globalSystem.tokenStream << "::Base::Token& " << globalSystem.tokenStream << "::" \
0722         << name << "()" << Qt::endl << "{" \
0723         << extra << "if(!Iterator::hasNext())\n{\nlxFINISH\n}" << Qt::endl \
0724         << "if(continueLexeme) continueLexeme = false;\nelse spos = plain();\nIterator::PlainIterator lpos = Iterator::plain();\nIterator::Int chr = 0;\nint lstate = 0;\n"; \
0725       globalSystem.dfaForNfa[globalSystem.lexerEnvResults[state]]->codegen(s); \
0726       s << "/* assert(false);*/\nreturn Base::read();}" << Qt::endl << Qt::endl;
0727     
0728     if(hasStates)
0729     {
0730       foreach(QString state, globalSystem.lexerEnvs.keys())
0731       {
0732         s << "#define CURRENT_RULE_SET " << state << Qt::endl;
0733         LEXER_CORE_IMPL("lex" + KDevPG::capitalized(state), state, "")
0734         s << "#undef CURRENT_RULE_SET" << Qt::endl;
0735       }
0736       s << globalSystem.tokenStream << "::Base::Token& " << globalSystem.tokenStream
0737         << "::read()" << Qt::endl << "{" << Qt::endl << "if(Base::index() < Base::size())\nreturn Base::read();\nswitch(m_ruleSet)\n{" << Qt::endl;
0738       foreach(QString state, globalSystem.lexerEnvs.keys())
0739         s << "case State_" << state << ": return lex" << capitalized(state) << "();" << Qt::endl;
0740       s << "default:\nexit(-1);\n}\n}" << Qt::endl;
0741     }
0742     else
0743     {
0744       LEXER_CORE_IMPL("read", "start", "if(Base::index() < Base::size())\nreturn Base::read();\n")
0745     }
0746     
0747     s << globalSystem.lexerBits << Qt::endl;
0748     
0749     if(hasStates)
0750     {
0751       s << "#undef lxSET_RULE_SET\n" << Qt::endl;
0752     }
0753     
0754     s << "#undef lxNEXT_CHR\n"
0755          "#undef lxFAIl\n"
0756          "#undef lxRETURN\n"
0757          "#undef lxTOKEN\n"
0758          "#undef lxBEGIN_IDX\n"
0759          "#undef lxBEGIN_POS\n"
0760          "#undef lxLENGTH\n"
0761          "#undef lxCONTINUE\n"
0762          "#undef lxCURR_IDX\n"
0763          "#undef lxCURR_POS\n\n"
0764          
0765          "#undef PP_CONCAT\n"
0766          "#undef PP_CONCAT_IMPL\n" << Qt::endl;
0767     
0768     s << "} // end of namespace " << globalSystem.ns << Qt::endl << Qt::endl;
0769     
0770     QString oname = globalSystem.language;
0771     oname += "lexer.cpp";
0772         
0773     format(s, oname);
0774   }
0775 }
0776 
0777 void generateVisitor(const QString& name, bool inherit_default)
0778 {
0779   QByteArray language = globalSystem.language.toUpper().toLatin1();
0780   for(int i = 0; i != language.size(); ++i)
0781   {
0782     if(language[i] < '0' || (language[i] > '9' && language[i] < 'A') || language[i] > 'Z')
0783       language[i] = '_';
0784   }
0785   QByteArray upper_name = name.toUpper().toLatin1();
0786   
0787   {
0788     QString str;
0789     QTextStream s(&str, QIODevice::WriteOnly);
0790     
0791     s << "#ifndef " << language << "_" << upper_name << "_H" << Qt::endl
0792       << "#define " << language << "_" << upper_name << "_H" << Qt::endl
0793       << Qt::endl
0794     
0795       << "#include \"" << globalSystem.language << (inherit_default ? "default" : "") << "visitor.h\"" << Qt::endl
0796       << Qt::endl;
0797     
0798     if (!globalSystem.exportMacroHeader.isEmpty())
0799       s << "#include \"" << globalSystem.exportMacroHeader << "\""
0800         << Qt::endl;
0801     
0802     s << "namespace " << globalSystem.ns << "{" << Qt::endl << Qt::endl;
0803                                                             
0804     if (inherit_default)
0805     { // generate an empty visitor using the default-visitor
0806       
0807       GenerateNewVisitor visitor(s, name);
0808       
0809       visitor();
0810     }
0811     else
0812     { // generate a visitor like the default visitor
0813       
0814       GenerateDefaultVisitor visitor(s, name);
0815           
0816       visitor();
0817     }
0818         
0819     s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0820       << Qt::endl
0821         
0822       << "#endif" << Qt::endl
0823       << Qt::endl;
0824         
0825     QString oname = globalSystem.language;
0826     oname += name.toLower() + ".h";
0827     
0828     format(s, oname);
0829   }
0830   
0831   {
0832     QString str;
0833     QTextStream s(&str, QIODevice::WriteOnly);
0834     
0835     s << "#include \"" << globalSystem.language << "defaultvisitor.h\"" << Qt::endl
0836       << Qt::endl
0837     
0838       << "namespace " << globalSystem.ns << "{" << Qt::endl
0839     
0840       << Qt::endl;
0841     
0842     if(inherit_default)
0843     {
0844       GenerateNewVisitorBitsRule gen(s, name);
0845       for( World::SymbolSet::iterator it = globalSystem.symbols.begin();
0846               it != globalSystem.symbols.end(); ++it )
0847       {
0848         gen(qMakePair(it.key(), *it));
0849       }
0850     }
0851     else
0852     {
0853       GenerateDefaultVisitorBitsRule gen(s, name);
0854       for( World::SymbolSet::iterator it = globalSystem.symbols.begin();
0855               it != globalSystem.symbols.end(); ++it )
0856       {
0857         gen(qMakePair(it.key(), *it));
0858       }
0859     }
0860     
0861     s << Qt::endl << "} // end of namespace " << globalSystem.ns << Qt::endl
0862       << Qt::endl;
0863     
0864     QString oname = globalSystem.language;
0865     oname += name.toLower() + ".cpp";
0866 
0867     format(s, oname);
0868   }
0869   
0870 }
0871 
0872 }
0873 
0874