Generated lexer depended on parser, fixed
[kdevelop:the-user-kdevelop-pg-qt.git] / kdev-pg / kdev-pg-generate.cpp
1 /* This file is part of kdev-pg-qt
2    Copyright (C) 2005 Roberto Raggi <roberto@kdevelop.org>
3    Copyright (C) 2006 Jakob Petsovits <jpetso@gmx.at>
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19 */
20
21 #include "kdev-pg-generate.h"
22
23 #include "kdev-pg.h"
24 #include "kdev-pg-code-gen.h"
25 #include "kdev-pg-ast-gen.h"
26 #include "kdev-pg-visitor-gen.h"
27 #include "kdev-pg-visitor-bits-gen.h"
28 #include "kdev-pg-default-visitor-gen.h"
29 #include "kdev-pg-default-visitor-bits-gen.h"
30 #include "kdev-pg-serialize-visitor-gen.h"
31 #include "kdev-pg-debug-visitor-gen.h"
32 #include "kdev-pg-new-visitor-gen.h"
33 #include "kdev-pg-new-visitor-bits-gen.h"
34 #include "kdev-pg-beautifier.h"
35 #include "kdev-pg-regexp.h"
36
37 #include <QtCore/QTextStream>
38 #include <QtCore/QFile>
39 #include "kdev-pg-token-type-gen.h"
40
41 namespace KDevPG
42 {
43 void generateOutput()
44 {
45   QByteArray language = globalSystem.language.toUpper().toLatin1();
46   for(int i = 0; i != language.size(); ++i)
47   {
48     if(language[i] < '0' || (language[i] > '9' && language[i] < 'A') || language[i] > 'Z')
49       language[i] = '_';
50   }
51
52   if (globalSystem.generateAst)
53   {
54     { // generate the ast
55       QString str;
56       QTextStream s(&str, QIODevice::WriteOnly);
57
58       GenerateAst _Ast(s);
59
60       s << "// THIS FILE IS GENERATED" << endl
61         << "// WARNING! All changes made in this file will be lost!" << endl
62         << endl
63
64         << "#ifndef " << language << "_AST_H_INCLUDED" << endl
65         << "#define " << language << "_AST_H_INCLUDED" << endl
66         << endl
67         
68         << "#include \"" << globalSystem.language << "ast-fwd.h\"" << endl
69         << endl
70
71         << "#include <QtCore/QList>" << endl
72         << "#include <kdev-pg-list.h>" << endl
73         << endl;
74       if (!globalSystem.exportMacroHeader.isEmpty())
75         s << "#include \"" << globalSystem.exportMacroHeader << "\""
76           << endl;
77
78       foreach (const QString& header, globalSystem.astHeaders)
79         s << "#include \"" << header << "\"\n";
80
81       if (!globalSystem.decl.isEmpty())
82         s << globalSystem.decl << endl;
83
84       s << "namespace " << globalSystem.ns << "{" << endl
85         << endl;
86
87       _Ast();
88
89       s << endl << "} // end of namespace " << globalSystem.ns << endl
90         << endl
91
92         << "#endif" << endl
93         << endl;
94
95       QString oname = globalSystem.language;
96       oname += "ast.h";
97
98       format(s, oname);
99     }
100     { // generate ast forward declarations
101     
102       QString str;
103       QTextStream s(&str, QIODevice::WriteOnly);
104       
105       GenerateAstFwd _AstFwd(s);
106       
107       s << ""// THIS FILE IS GENERATED" << endl
108         << "// WARNING! All changes made in this file will be lost!" << endl
109         << endl
110
111         << "#ifndef " << language << "_AST_FWD_INCLUDED" << endl
112         << "#define " << language << "_AST_FWD_INCLUDED" << endl
113         << endl;
114       if (!globalSystem.exportMacroHeader.isEmpty())
115         s << "#include \"" << globalSystem.exportMacroHeader << "\""
116           << endl;
117       
118       s << "namespace " << globalSystem.ns << "{" << endl
119         << endl;
120       
121       _AstFwd();
122       
123       s << endl << "} // end of namespace " << globalSystem.ns << endl
124         << endl
125       
126         << "#endif" << endl
127         << endl;
128       
129       QString oname = globalSystem.language;
130       oname += "ast-fwd.h";
131       
132       format(s, oname);
133     }
134   }
135   { // generate token type
136     QString str;
137     QTextStream s(&str, QIODevice::WriteOnly);
138
139     GenerateTokenType gen(s);
140
141     s << "// THIS FILE IS GENERATED" << endl
142       << "// WARNING! All changes made in this file will be lost!" << endl
143       << endl
144
145       << "#ifndef " << language << "_TOKEN_TYPE_H_INCLUDED" << endl
146       << "#define " << language << "_TOKEN_TYPE_H_INCLUDED" << endl
147       << endl;
148     if (!globalSystem.exportMacroHeader.isEmpty())
149       s << "#include \"" << globalSystem.exportMacroHeader << "\""
150         << endl;
151
152     foreach (const QString& header, globalSystem.astHeaders)
153       s << "#include \"" << header << "\"\n";
154
155     if (!globalSystem.decl.isEmpty())
156       s << globalSystem.decl << endl;
157
158     s << "namespace " << globalSystem.ns << "{" << endl
159       << endl;
160
161     gen();
162
163     s << endl << "} // end of namespace " << globalSystem.ns << endl
164       << endl
165
166       << "#endif" << endl
167       << endl;
168
169     QString oname = globalSystem.language;
170     oname += "tokentype.h";
171
172     format(s, oname);
173   }
174   { // generate the parser decls
175     QString str;
176     QTextStream s(&str, QIODevice::WriteOnly);
177
178     GenerateParserDeclarations __decls(s);
179
180     s << "// THIS FILE IS GENERATED" << endl
181       << "// WARNING! All changes made in this file will be lost!" << endl
182       << endl
183
184       << "#ifndef " << language << "_H_INCLUDED" << endl
185       << "#define " << language << "_H_INCLUDED" << endl
186       << endl;
187     
188     
189     s << "#include \"" << globalSystem.language << "tokentype.h\"" << endl;
190     
191     if(globalSystem.hasLexer)
192       s << "#include \"" << globalSystem.language << "lexer.h\"" << endl;
193
194     if (globalSystem.generateAst)
195       {
196         s << "#include \"" << globalSystem.language << "ast-fwd.h\"" << endl
197           << "#include <kdev-pg-memory-pool.h>" << endl
198           << "#include <kdev-pg-allocator.h>" << endl;
199       }
200
201     if (globalSystem.tokenStream == "KDevPG::TokenStream")
202       s << "#include <kdev-pg-token-stream.h>" << endl;
203     
204     if (globalSystem.needOperatorStack)
205       s << "#include <QtCore/QVector>" << endl;
206     
207     foreach (const QString& header, globalSystem.parserDeclarationHeaders)
208       s << "#include \"" << header << "\"\n";
209
210     s << endl;
211     if (!globalSystem.exportMacroHeader.isEmpty())
212       s << "#include \"" << globalSystem.exportMacroHeader << "\""
213         << endl;
214
215     if (!globalSystem.decl.isEmpty() && !globalSystem.generateAst)
216       s << globalSystem.decl << endl;
217
218     s << "namespace " << globalSystem.ns << "{" << endl
219       << endl;
220
221     __decls();
222
223     s << endl << "} // end of namespace " << globalSystem.ns << endl
224       << endl
225
226       << "#endif" << endl
227       << endl;
228
229     QString oname = globalSystem.language;
230     oname += "parser.h";
231
232     format(s, oname);
233   }
234
235   if (globalSystem.generateAst)
236   { // generate the visitor decls
237     QString str;
238     QTextStream s(&str, QIODevice::WriteOnly);
239
240     GenerateVisitor __visitor(s);
241
242     s << "// THIS FILE IS GENERATED" << endl
243       << "// WARNING! All changes made in this file will be lost!" << endl
244       << endl
245
246       << "#ifndef " << language << "_VISITOR_H_INCLUDED" << endl
247       << "#define " << language << "_VISITOR_H_INCLUDED" << endl
248       << endl
249
250       << "#include \"" << globalSystem.language << "ast.h\"" << endl
251       << endl;
252     if (!globalSystem.exportMacroHeader.isEmpty())
253       s << "#include \"" << globalSystem.exportMacroHeader << "\""
254         << endl;
255
256     s << "namespace " << globalSystem.ns << "{" << endl
257       << endl;
258
259     __visitor();
260
261     s << endl << "} // end of namespace " << globalSystem.ns << endl
262       << endl
263
264       << "#endif" << endl
265       << endl;
266
267     QString oname = globalSystem.language;
268     oname += "visitor.h";
269
270     format(s, oname);
271   }
272
273   if (globalSystem.generateAst)
274   { // generate the default visitor
275     QString str;
276     QTextStream s(&str, QIODevice::WriteOnly);
277
278     GenerateDefaultVisitor __DefaultVisitor(s);
279
280     s << "// THIS FILE IS GENERATED" << endl
281       << "// WARNING! All changes made in this file will be lost!" << endl
282       << endl
283
284       << "#ifndef " << language << "_DEFAULT_VISITOR_H_INCLUDED" << endl
285       << "#define " << language << "_DEFAULT_VISITOR_H_INCLUDED" << endl
286       << endl
287
288       << "#include \"" << globalSystem.language << "visitor.h\"" << endl
289       << endl;
290     if (!globalSystem.exportMacroHeader.isEmpty())
291       s << "#include \"" << globalSystem.exportMacroHeader << "\""
292         << endl;
293
294     s << "namespace " << globalSystem.ns << "{" << endl
295       << endl;
296
297     __DefaultVisitor();
298
299     s << endl << "} // end of namespace " << globalSystem.ns << endl
300       << endl
301
302       << "#endif" << endl
303       << endl;
304
305     QString oname = globalSystem.language;
306     oname += "defaultvisitor.h";
307
308     format(s, oname);
309   }
310
311   if (globalSystem.generateSerializeVisitor)
312   { // generate the serialization visitor
313     QString str;
314     QTextStream s(&str, QIODevice::WriteOnly);
315
316     GenerateSerializeVisitor __serialize_visitor(s);
317
318     s << "// THIS FILE IS GENERATED" << endl
319       << "// WARNING! All changes made in this file will be lost!" << endl
320       << endl
321
322       << "#ifndef " << language << "_SERIALIZATION_H_INCLUDED" << endl
323       << "#define " << language << "_SERIALIZATION_H_INCLUDED" << endl
324       << endl
325
326       << "#include \"" << globalSystem.language << "defaultvisitor.h\"" << endl
327       << endl;
328     if (!globalSystem.exportMacroHeader.isEmpty())
329       s << "#include \"" << globalSystem.exportMacroHeader << "\""
330         << endl;
331
332     s << "#include <QtCore/QTextStream>" << endl
333       << "#include <QtCore/QFile>" << endl
334       << endl
335
336       << "namespace " << globalSystem.ns << "{" << endl
337       << endl;
338
339     __serialize_visitor();
340
341     s << endl << "} // end of namespace " << globalSystem.ns << endl
342       << endl;
343
344     s << "#endif" << endl
345       << endl;
346
347     QString oname = globalSystem.language;
348     oname += "serializevisitor.h";
349
350     format(s, oname);
351   }
352
353   if (globalSystem.generateDebugVisitor)
354   { // generate the debug visitor
355     QString str;
356     QTextStream s(&str, QIODevice::WriteOnly);
357
358     GenerateDebugVisitor __debug_visitor(s);
359
360     s << "// THIS FILE IS GENERATED" << endl
361       << "// WARNING! All changes made in this file will be lost!" << endl
362       << endl
363
364       << "#ifndef " << language << "_DEBUG_VISITOR_H_INCLUDED" << endl
365       << "#define " << language << "_DEBUG_VISITOR_H_INCLUDED" << endl
366       << endl
367
368       << "#include \"" << globalSystem.language << "defaultvisitor.h\"" << endl
369       << endl;
370     if (!globalSystem.exportMacroHeader.isEmpty())
371       s << "#include \"" << globalSystem.exportMacroHeader << "\""
372         << endl;
373
374     s << "#include <kdev-pg-token-stream.h>" << endl;
375     
376     s << "#include <QtCore/QTextStream>" << endl
377       << "#include <QtCore/QDebug>" << endl
378       << endl
379
380       << "namespace " << globalSystem.ns << "{" << endl
381       << endl;
382
383     __debug_visitor();
384
385     s << endl << "} // end of namespace " << globalSystem.ns << endl
386       << endl;
387
388     s << "#endif" << endl
389       << endl;
390
391     QString oname = globalSystem.language;
392     oname += "debugvisitor.h";
393
394     format(s, oname);
395   }
396   if (globalSystem.generateTokenText || globalSystem.generateDebugVisitor)
397   { // generate the token text function
398     QString str;
399     QTextStream s(&str, QIODevice::WriteOnly);
400
401     s << "// THIS FILE IS GENERATED" << endl
402       << "// WARNING! All changes made in this file will be lost!" << endl
403       << endl
404
405       << "#ifndef " << language << "_TOKEN_TEXT_H_INCLUDED" << endl
406       << "#define " << language << "_TOKEN_TEXT_H_INCLUDED" << endl
407       << endl
408       << "#include \"" << language << "tokentype.h\"" << endl
409
410       << "namespace " << globalSystem.ns << "{" << endl
411       << endl
412
413       << "QString " << globalSystem.exportMacro << " tokenText(int token)" << endl << "{" << endl;
414
415     GenerateTokenTexts gen(s);
416     gen();
417
418     s << "}"
419       << endl << "} // end of namespace " << globalSystem.ns << endl
420       << endl;
421
422     s << "#endif" << endl
423       << endl;
424
425     QString oname = globalSystem.language;
426     oname += "tokentext.h";
427
428     format(s, oname);
429   }
430   { // generate the parser bits
431     QString str;
432     QTextStream s(&str, QIODevice::WriteOnly);
433
434     GenerateParserBits __bits(s);
435
436     s << "// THIS FILE IS GENERATED" << endl
437       << "// WARNING! All changes made in this file will be lost!" << endl
438       << endl;
439
440     s << "#include \"" << globalSystem.language << "parser.h\""
441       << endl;
442     
443     if (globalSystem.generateAst)
444     {
445       s << "#include \"" << globalSystem.language << "ast.h\"" << endl;
446     }
447
448     foreach (const QString& header, globalSystem.parserBitsHeaders)
449       s << "#include \"" << header << "\"\n";
450
451     s << endl;
452
453     if (!globalSystem.bits.isEmpty())
454       s << globalSystem.bits << endl;
455
456     s << "namespace " << globalSystem.ns << "{" << endl
457       << endl;
458
459     __bits();
460
461     s << endl << "} // end of namespace " << globalSystem.ns << endl
462       << endl;
463
464     QString oname = globalSystem.language;
465     oname += "parser.cpp";
466
467     format(s, oname);
468   }
469
470   if (globalSystem.generateAst)
471   { // generate the visitor bits
472     QString str;
473     QTextStream s(&str, QIODevice::WriteOnly);
474
475     GenerateVisitorBits __visitor_bits(s);
476
477     s << "// THIS FILE IS GENERATED" << endl
478       << "// WARNING! All changes made in this file will be lost!" << endl
479       << endl
480
481       << "#include \"" << globalSystem.language << "visitor.h\"" << endl
482
483       << endl
484
485       << "namespace " << globalSystem.ns << "{" << endl
486       << endl;
487
488     __visitor_bits();
489
490     s << endl << "} // end of namespace " << globalSystem.ns << endl
491       << endl;
492
493     QString oname = globalSystem.language;
494     oname += "visitor.cpp";
495
496     format(s, oname);
497   }
498
499   if (globalSystem.generateAst)
500   { // generate the default visitor bits
501     QString str;
502     QTextStream s(&str, QIODevice::WriteOnly);
503
504     s << "// THIS FILE IS GENERATED" << endl
505       << "// WARNING! All changes made in this file will be lost!" << endl
506       << endl
507
508       << "#include \"" << globalSystem.language << "defaultvisitor.h\"" << endl
509       << endl
510
511       << "namespace " << globalSystem.ns << "{" << endl
512
513       << endl;
514
515     GenerateDefaultVisitorBitsRule gen(s);
516     for( World::SymbolSet::iterator it = globalSystem.symbols.begin();
517         it != globalSystem.symbols.end(); ++it )
518     {
519       gen(qMakePair(it.key(), *it));
520     }
521
522     s << endl << "} // end of namespace " << globalSystem.ns << endl
523       << endl;
524
525     QString oname = globalSystem.language;
526     oname += "defaultvisitor.cpp";
527
528     format(s, oname);
529   }
530 }
531
532 void generateLexer()
533 {
534   QByteArray language = globalSystem.language.toUpper().toLatin1();
535   bool hasStates = globalSystem.lexerEnvs.size() > 1;
536   
537   { // generate the lexer header
538     QString str;
539     QTextStream s(&str, QIODevice::WriteOnly);
540     
541     s << "// THIS FILE IS GENERATED" << endl
542       << "// WARNING! All changes made in this file will be lost!" << endl
543       << endl
544     
545       << "#ifndef " << language << "_LEXER_H_INCLUDED" << endl
546       << "#define " << language << "_LEXER_H_INCLUDED" << endl
547       << endl
548       
549       << "#include \"" << globalSystem.language << "tokentype.h\"" << endl
550       << endl
551       
552       << "#include <kdev-pg-char-sets.h>" << endl
553       << "#include <kdev-pg-token-stream.h>" << endl
554       << endl;
555       
556     foreach (const QString& header, globalSystem.lexerDeclarationHeaders)
557       s << "#include \"" << header << "\"\n";
558     
559     s << endl << "namespace " << globalSystem.ns << "{" << endl
560       << endl
561       
562       << "class " << globalSystem.exportMacro << " " << globalSystem.tokenStream << " : " 
563       << (globalSystem.lexerBaseClass.isEmpty() ? "" : " public " + globalSystem.lexerBaseClass + ",")
564       << "public " << globalSystem.inputStream << ","
565       << "public TokenTypeWrapper" << endl
566       << "{" << endl
567       << "public:" << endl
568       << "typedef " << (globalSystem.lexerBaseClass.isEmpty() ? globalSystem.tokenStream : globalSystem.lexerBaseClass) << " Base;" << endl
569       << "typedef " << globalSystem.inputStream << " Iterator;" << endl << endl << "private:" << endl;
570       
571     
572     if(hasStates)
573     {
574       foreach(QString state, globalSystem.lexerEnvs.keys())
575         s << "Base::Token& lex" << KDevPG::capitalized(state) << "();" << endl;
576       s << "public:\nenum RuleSet {\n";
577       foreach(QString state, globalSystem.lexerEnvs.keys())
578         s << "State_" << state << ", /*" << globalSystem.lexerEnvs[state].size() << "*/" << endl;
579       s << "State_COUNT\n};\n"
580            "private:\n"
581            "RuleSet m_ruleSet;\n"
582            "public:\n"
583            "inline RuleSet ruleSet()\n{\nreturn m_ruleSet;\n}\n"
584            "void setRuleSet(RuleSet rs);\n";
585       foreach(QString state, globalSystem.lexerEnvs.keys())
586       {
587         s << "inline void enteringRuleSet" << state << "();" << endl;
588         s << "inline void leavingRuleSet" << state << "();" << endl;
589       }
590     }
591       
592     s << "Iterator::PlainIterator spos;" << endl
593       << "bool continueLexeme;" << endl << endl
594       
595       << "public:" << endl << globalSystem.tokenStream << "(const Iterator& iter);" << endl
596       // non-virtual, virtuality will be inherited
597       << "~" << globalSystem.tokenStream << "();"
598       <<  endl << "Base::Token& read();" << endl;
599     
600       /// TODO: not good that it happens in a separate file for the parser but in this file for the lexer
601 #define LEXER_EXTRA_CODE_GEN(name) \
602     if (globalSystem.lexerclassMembers.name.empty() == false) \
603     { \
604       s << "\n// user defined code:" << endl; \
605       GenerateMemberCode gen(s, Settings::MemberItem::PublicDeclaration \
606                                 | Settings::MemberItem::ProtectedDeclaration \
607                                 | Settings::MemberItem::PrivateDeclaration); \
608       for( auto it = globalSystem.lexerclassMembers.name.begin(); \
609       it != globalSystem.lexerclassMembers.name.end(); ++it ) \
610       { \
611         gen(*it); \
612       } \
613     }
614     
615     LEXER_EXTRA_CODE_GEN(declarations)
616     
617     s << "};" << endl << endl << "} // end of namespace " << globalSystem.ns << endl
618       << endl
619       
620       << "#endif" << endl
621       << endl;
622       
623     QString oname = globalSystem.language;
624     oname += "lexer.h";
625         
626     format(s, oname);
627     
628   }
629   { // generate the lexer bits
630     QString str;
631     QTextStream s(&str, QIODevice::WriteOnly);
632     
633     s << "// THIS FILE IS GENERATED" << endl
634       << "// WARNING! All changes made in this file will be lost!" << endl
635       << endl
636     
637       << "#include \"" << globalSystem.language << "lexer.h\"" << endl
638       << endl;
639     
640     foreach (const QString& header, globalSystem.lexerBitsHeaders)
641       s << "#include \"" << header << "\"\n";
642     
643     s << "\n#include <cassert>\n";
644     
645     s << endl << "namespace " << globalSystem.ns << "{" << endl
646       << endl << globalSystem.tokenStream << "::" << globalSystem.tokenStream
647       << "(const " << globalSystem.tokenStream << "::Iterator& iter) : Base(), Iterator(iter), " << (hasStates ? "m_ruleSet(State_start), " : "") << "continueLexeme(false)" << endl
648       << "{";
649     LEXER_EXTRA_CODE_GEN(constructorCode)
650     s << "}" << endl << endl
651       << globalSystem.tokenStream << "::~" << globalSystem.tokenStream
652       << "()\n{";
653     LEXER_EXTRA_CODE_GEN(destructorCode)
654     s << "}" << endl << endl
655             
656       << "#define PP_CONCAT_IMPL(x, y) x ## y\n" // necesarry, otherwise CURRENT_RULE_SET would not get resolved
657          "#define PP_CONCAT(x, y) PP_CONCAT_IMPL(x, y)\n\n"
658          
659          "#define lxCURR_POS (Iterator::plain())\n"
660          "#define lxCURR_IDX (Iterator::plain() - Iterator::begin())\n"
661          "#define lxCONTINUE {continueLexeme = true; return read();}\n"
662          "#define lxLENGTH (Iterator::plain() - Iterator::begin())\n"
663          "#define lxBEGIN_POS (spos)\n"
664          "#define lxBEGIN_IDX (spos - Iterator::begin())\n"
665          "#define lxNAMED_TOKEN(token, X) KDevPG::Token& token(Base::push()); token.kind = Token_##X; token.begin = lxBEGIN_IDX; token.end = lxCURR_IDX - 1;\n"
666          "#define lxTOKEN(X) {lxNAMED_TOKEN(token, X);}\n"
667          "#define lxDONE {return Base::read();}\n"
668          "#define lxRETURN(X) {lxTOKEN(X); lxDONE}\n"
669          "#define lxEOF {Base::Token& _t(Base::push()); _t.kind = Token_EOF;_t.begin = _t.end = Iterator::plain() - Iterator::begin();}\n"
670          "#define lxFINISH {lxEOF lxDONE}\n"
671          "#define yytoken (Base::back())\n"
672          "#define lxFAIL {goto _fail;}\n"
673          "#define lxSKIP {return read();}\n"
674          "#define lxNEXT_CHR(chr) { if(!Iterator::hasNext()) goto _end; chr = Iterator::next(); }\n" << endl;
675     
676     if(hasStates)
677     {
678       s << "#define lxSET_RULE_SET(r) {PP_CONCAT(leavingRuleSet, CURRENT_RULE_SET) (); m_ruleSet = State_##r; enteringRuleSet##r ();}\n" << endl << endl;
679       
680       foreach(QString state, globalSystem.lexerEnvs.keys())
681       {
682         s << "inline void " << globalSystem.tokenStream << "::enteringRuleSet" << state << "() { " << globalSystem.enteringCode[state] << "}" << endl;
683         s << "inline void " << globalSystem.tokenStream << "::leavingRuleSet" << state << "() { " << globalSystem.leavingCode[state] << "}" << endl;
684       }
685       s << "\n"
686            "void " << globalSystem.tokenStream << "::setRuleSet(RuleSet rs)\n"
687            "{\n"
688            "switch(m_ruleSet)\n"
689            "{\n";
690       foreach(QString state, globalSystem.lexerEnvs.keys())
691       {
692         s << "case State_" << state << ":\n"
693              "leavingRuleSet" << state << "();\n"
694              "break;\n";
695       }
696       s << "\ndefault:\n"
697            "assert(0 == \"Invalid rule set\");\n"
698            "}\n\n"
699            "m_ruleSet = rs;\n\n"
700            "switch(m_ruleSet)\n"
701            "{\n";
702       foreach(QString state, globalSystem.lexerEnvs.keys())
703       {
704         s << "case State_" << state << ":\n"
705              "enteringRuleSet" << state << "();\n"
706              "break;\n";
707       }
708       s << "\ndefault:\n"
709            "assert(0 == \"Invalid rule set\");\n"
710            "}\n"
711            "}\n\n";
712     }
713     
714 #define LEXER_CORE_IMPL(name, state, extra) \
715       s << globalSystem.tokenStream << "::Base::Token& " << globalSystem.tokenStream << "::" \
716         << name << "()" << endl << "{" \
717         << extra << "if(!Iterator::hasNext())\n{\nlxFINISH\n}" << endl \
718         << "if(continueLexeme) continueLexeme = false;\nelse spos = plain();\nIterator::PlainIterator lpos = Iterator::plain();\nIterator::Int chr = 0;\nint lstate = 0;\n"; \
719       globalSystem.dfaForNfa[globalSystem.lexerEnvResults[state]]->codegen(s); \
720       s << "/* assert(false);*/\nreturn Base::read();}" << endl << endl;
721     
722     if(hasStates)
723     {
724       foreach(QString state, globalSystem.lexerEnvs.keys())
725       {
726         s << "#define CURRENT_RULE_SET " << state << endl;
727         LEXER_CORE_IMPL("lex" + KDevPG::capitalized(state), state, "")
728         s << "#undef CURRENT_RULE_SET" << endl;
729       }
730       s << globalSystem.tokenStream << "::Base::Token& " << globalSystem.tokenStream
731         << "::read()" << endl << "{" << endl << "if(Base::index() < Base::size())\nreturn Base::read();\nswitch(m_ruleSet)\n{" << endl;
732       foreach(QString state, globalSystem.lexerEnvs.keys())
733         s << "case State_" << state << ": return lex" << capitalized(state) << "();" << endl;
734       s << "default:\nexit(-1);\n}\n}" << endl;
735     }
736     else
737     {
738       LEXER_CORE_IMPL("read", "start", "if(Base::index() < Base::size())\nreturn Base::read();\n")
739     }
740     
741     if(hasStates)
742     {
743       s << "#undef lxSET_RULE_SET\n" << endl;
744     }
745     
746     s << "#undef lxNEXT_CHR\n"
747          "#undef lxFAIl\n"
748          "#undef lxRETURN\n"
749          "#undef lxTOKEN\n"
750          "#undef lxBEGIN_IDX\n"
751          "#undef lxBEGIN_POS\n"
752          "#undef lxLENGTH\n"
753          "#undef lxCONTINUE\n"
754          "#undef lxCURR_IDX\n"
755          "#undef lxCURR_POS\n\n"
756          
757          "#undef PP_CONCAT\n"
758          "#undef PP_CONCAT_IMPL\n" << endl;
759     
760     s << globalSystem.lexerBits << endl
761       << "} // end of namespace " << globalSystem.ns << endl << endl;
762     
763     QString oname = globalSystem.language;
764     oname += "lexer.cpp";
765         
766     format(s, oname);
767   }
768 }
769
770 void generateVisitor(const QString& name, bool inherit_default)
771 {
772   QByteArray language = globalSystem.language.toUpper().toLatin1();
773   for(int i = 0; i != language.size(); ++i)
774   {
775     if(language[i] < '0' || (language[i] > '9' && language[i] < 'A') || language[i] > 'Z')
776       language[i] = '_';
777   }
778   QByteArray upper_name = name.toUpper().toLatin1();
779   
780   {
781     QString str;
782     QTextStream s(&str, QIODevice::WriteOnly);
783     
784     s << "#ifndef " << language << "_" << upper_name << "_H" << endl
785       << "#define " << language << "_" << upper_name << "_H" << endl
786       << endl
787     
788       << "#include \"" << globalSystem.language << (inherit_default ? "default" : "") << "visitor.h\"" << endl
789       << endl;
790     
791     if (!globalSystem.exportMacroHeader.isEmpty())
792       s << "#include \"" << globalSystem.exportMacroHeader << "\""
793         << endl;
794     
795     s << "namespace " << globalSystem.ns << "{" << endl << endl;
796                                                             
797     if (inherit_default)
798     { // generate an empty visitor using the default-visitor
799       
800       GenerateNewVisitor visitor(s, name);
801       
802       visitor();
803     }
804     else
805     { // generate a visitor like the default visitor
806       
807       GenerateDefaultVisitor visitor(s, name);
808           
809       visitor();
810     }
811         
812     s << endl << "} // end of namespace " << globalSystem.ns << endl
813       << endl
814         
815       << "#endif" << endl
816       << endl;
817         
818     QString oname = globalSystem.language;
819     oname += name.toLower() + ".h";
820     
821     format(s, oname);
822   }
823   
824   {
825     QString str;
826     QTextStream s(&str, QIODevice::WriteOnly);
827     
828     s << "#include \"" << globalSystem.language << "defaultvisitor.h\"" << endl
829       << endl
830     
831       << "namespace " << globalSystem.ns << "{" << endl
832     
833       << endl;
834     
835     if(inherit_default)
836     {
837       GenerateNewVisitorBitsRule gen(s, name);
838       for( World::SymbolSet::iterator it = globalSystem.symbols.begin();
839               it != globalSystem.symbols.end(); ++it )
840       {
841         gen(qMakePair(it.key(), *it));
842       }
843     }
844     else
845     {
846       GenerateDefaultVisitorBitsRule gen(s, name);
847       for( World::SymbolSet::iterator it = globalSystem.symbols.begin();
848               it != globalSystem.symbols.end(); ++it )
849       {
850         gen(qMakePair(it.key(), *it));
851       }
852     }
853     
854     s << endl << "} // end of namespace " << globalSystem.ns << endl
855       << endl;
856     
857     QString oname = globalSystem.language;
858     oname += name.toLower() + ".cpp";
859
860     format(s, oname);
861   }
862   
863 }
864
865 }
866
867