1 | package antlr; |
---|
2 | |
---|
3 | /* ANTLR Translator Generator |
---|
4 | * Project led by Terence Parr at http://www.cs.usfca.edu |
---|
5 | * Software rights: http://www.antlr.org/license.html |
---|
6 | * |
---|
7 | * $Id: //depot/code/org.antlr/release/antlr-2.7.7/antlr/CppCodeGenerator.java#2 $ |
---|
8 | */ |
---|
9 | |
---|
10 | // C++ code generator by Pete Wells: pete@yamuna.demon.co.uk |
---|
11 | // #line generation contributed by: Ric Klaren <klaren@cs.utwente.nl> |
---|
12 | |
---|
13 | import java.util.Enumeration; |
---|
14 | import java.util.Hashtable; |
---|
15 | import antlr.collections.impl.BitSet; |
---|
16 | import antlr.collections.impl.Vector; |
---|
17 | import java.io.PrintWriter; //SAS: changed for proper text file io |
---|
18 | import java.io.IOException; |
---|
19 | import java.io.FileWriter; |
---|
20 | |
---|
21 | /** Generate MyParser.cpp, MyParser.hpp, MyLexer.cpp, MyLexer.hpp |
---|
22 | * and MyParserTokenTypes.hpp |
---|
23 | */ |
---|
24 | public class CppCodeGenerator extends CodeGenerator { |
---|
25 | boolean DEBUG_CPP_CODE_GENERATOR = false; |
---|
26 | // non-zero if inside syntactic predicate generation |
---|
27 | protected int syntacticPredLevel = 0; |
---|
28 | |
---|
29 | // Are we generating ASTs (for parsers and tree parsers) right now? |
---|
30 | protected boolean genAST = false; |
---|
31 | |
---|
32 | // Are we saving the text consumed (for lexers) right now? |
---|
33 | protected boolean saveText = false; |
---|
34 | |
---|
35 | // Generate #line's |
---|
36 | protected boolean genHashLines = true; |
---|
37 | // Generate constructors or not |
---|
38 | protected boolean noConstructors = false; |
---|
39 | |
---|
40 | // Used to keep track of lineno in output |
---|
41 | protected int outputLine; |
---|
42 | protected String outputFile; |
---|
43 | |
---|
44 | // Grammar parameters set up to handle different grammar classes. |
---|
45 | // These are used to get instanceof tests out of code generation |
---|
46 | boolean usingCustomAST = false; |
---|
47 | String labeledElementType; |
---|
48 | String labeledElementASTType; // mostly the same as labeledElementType except in parsers |
---|
49 | String labeledElementASTInit; |
---|
50 | String labeledElementInit; |
---|
51 | String commonExtraArgs; |
---|
52 | String commonExtraParams; |
---|
53 | String commonLocalVars; |
---|
54 | String lt1Value; |
---|
55 | String exceptionThrown; |
---|
56 | String throwNoViable; |
---|
57 | |
---|
58 | // Tracks the rule being generated. Used for mapTreeId |
---|
59 | RuleBlock currentRule; |
---|
60 | // Tracks the rule or labeled subrule being generated. Used for AST generation. |
---|
61 | String currentASTResult; |
---|
62 | // Mapping between the ids used in the current alt, and the |
---|
63 | // names of variables used to represent their AST values. |
---|
64 | Hashtable treeVariableMap = new Hashtable(); |
---|
65 | |
---|
66 | /** Used to keep track of which AST variables have been defined in a rule |
---|
67 | * (except for the #rule_name and #rule_name_in var's |
---|
68 | */ |
---|
69 | Hashtable declaredASTVariables = new Hashtable(); |
---|
70 | |
---|
71 | // Count of unnamed generated variables |
---|
72 | int astVarNumber = 1; |
---|
73 | // Special value used to mark duplicate in treeVariableMap |
---|
74 | protected static final String NONUNIQUE = new String(); |
---|
75 | |
---|
76 | public static final int caseSizeThreshold = 127; // ascii is max |
---|
77 | |
---|
78 | private Vector semPreds; |
---|
79 | |
---|
80 | // Used to keep track of which (heterogeneous AST types are used) |
---|
81 | // which need to be set in the ASTFactory of the generated parser |
---|
82 | private Vector astTypes; |
---|
83 | |
---|
84 | private static String namespaceStd = "ANTLR_USE_NAMESPACE(std)"; |
---|
85 | private static String namespaceAntlr = "ANTLR_USE_NAMESPACE(antlr)"; |
---|
86 | private static NameSpace nameSpace = null; |
---|
87 | |
---|
88 | private static final String preIncludeCpp = "pre_include_cpp"; |
---|
89 | private static final String preIncludeHpp = "pre_include_hpp"; |
---|
90 | private static final String postIncludeCpp = "post_include_cpp"; |
---|
91 | private static final String postIncludeHpp = "post_include_hpp"; |
---|
92 | |
---|
93 | /** Create a C++ code-generator using the given Grammar. |
---|
94 | * The caller must still call setTool, setBehavior, and setAnalyzer |
---|
95 | * before generating code. |
---|
96 | */ |
---|
97 | public CppCodeGenerator() { |
---|
98 | super(); |
---|
99 | charFormatter = new CppCharFormatter(); |
---|
100 | } |
---|
101 | /** Adds a semantic predicate string to the sem pred vector |
---|
102 | These strings will be used to build an array of sem pred names |
---|
103 | when building a debugging parser. This method should only be |
---|
104 | called when the debug option is specified |
---|
105 | */ |
---|
106 | protected int addSemPred(String predicate) { |
---|
107 | semPreds.appendElement(predicate); |
---|
108 | return semPreds.size()-1; |
---|
109 | } |
---|
110 | public void exitIfError() |
---|
111 | { |
---|
112 | if (antlrTool.hasError()) |
---|
113 | { |
---|
114 | antlrTool.fatalError("Exiting due to errors."); |
---|
115 | } |
---|
116 | } |
---|
117 | protected int countLines( String s ) |
---|
118 | { |
---|
119 | int lines = 0; |
---|
120 | for( int i = 0; i < s.length(); i++ ) |
---|
121 | { |
---|
122 | if( s.charAt(i) == '\n' ) |
---|
123 | lines++; |
---|
124 | } |
---|
125 | return lines; |
---|
126 | } |
---|
127 | /** Output a String to the currentOutput stream. |
---|
128 | * Ignored if string is null. |
---|
129 | * @param s The string to output |
---|
130 | */ |
---|
131 | protected void _print(String s) |
---|
132 | { |
---|
133 | if (s != null) |
---|
134 | { |
---|
135 | outputLine += countLines(s); |
---|
136 | currentOutput.print(s); |
---|
137 | } |
---|
138 | } |
---|
139 | /** Print an action without leading tabs, attempting to |
---|
140 | * preserve the current indentation level for multi-line actions |
---|
141 | * Ignored if string is null. |
---|
142 | * @param s The action string to output |
---|
143 | */ |
---|
144 | protected void _printAction(String s) |
---|
145 | { |
---|
146 | if (s != null) |
---|
147 | { |
---|
148 | outputLine += countLines(s)+1; |
---|
149 | super._printAction(s); |
---|
150 | } |
---|
151 | } |
---|
152 | /** Print an action stored in a token surrounded by #line stuff */ |
---|
153 | public void printAction(Token t) |
---|
154 | { |
---|
155 | if (t != null) |
---|
156 | { |
---|
157 | genLineNo(t.getLine()); |
---|
158 | printTabs(); |
---|
159 | _printAction(processActionForSpecialSymbols(t.getText(), t.getLine(), |
---|
160 | null, null) ); |
---|
161 | genLineNo2(); |
---|
162 | } |
---|
163 | } |
---|
164 | /** Print a header action by #line stuff also process any tree construction |
---|
165 | * @param name The name of the header part |
---|
166 | */ |
---|
167 | public void printHeaderAction(String name) |
---|
168 | { |
---|
169 | Token a = (antlr.Token)behavior.headerActions.get(name); |
---|
170 | if (a != null) |
---|
171 | { |
---|
172 | genLineNo(a.getLine()); |
---|
173 | println(processActionForSpecialSymbols(a.getText(), a.getLine(), |
---|
174 | null, null) ); |
---|
175 | genLineNo2(); |
---|
176 | } |
---|
177 | } |
---|
178 | /** Output a String followed by newline, to the currentOutput stream. |
---|
179 | * Ignored if string is null. |
---|
180 | * @param s The string to output |
---|
181 | */ |
---|
182 | protected void _println(String s) { |
---|
183 | if (s != null) { |
---|
184 | outputLine += countLines(s)+1; |
---|
185 | currentOutput.println(s); |
---|
186 | } |
---|
187 | } |
---|
188 | /** Output tab indent followed by a String followed by newline, |
---|
189 | * to the currentOutput stream. Ignored if string is null. |
---|
190 | * @param s The string to output |
---|
191 | */ |
---|
192 | protected void println(String s) { |
---|
193 | if (s != null) { |
---|
194 | printTabs(); |
---|
195 | outputLine += countLines(s)+1; |
---|
196 | currentOutput.println(s); |
---|
197 | } |
---|
198 | } |
---|
199 | |
---|
200 | /** Generate a #line or // line depending on options */ |
---|
201 | public void genLineNo(int line) { |
---|
202 | if ( line == 0 ) { |
---|
203 | line++; |
---|
204 | } |
---|
205 | if( genHashLines ) |
---|
206 | _println("#line "+line+" \""+antlrTool.fileMinusPath(antlrTool.grammarFile)+"\""); |
---|
207 | } |
---|
208 | |
---|
209 | /** Generate a #line or // line depending on options */ |
---|
210 | public void genLineNo(GrammarElement el) |
---|
211 | { |
---|
212 | if( el != null ) |
---|
213 | genLineNo(el.getLine()); |
---|
214 | } |
---|
215 | /** Generate a #line or // line depending on options */ |
---|
216 | public void genLineNo(Token t) |
---|
217 | { |
---|
218 | if (t != null) |
---|
219 | genLineNo(t.getLine()); |
---|
220 | } |
---|
221 | /** Generate a #line or // line depending on options */ |
---|
222 | public void genLineNo2() |
---|
223 | { |
---|
224 | if( genHashLines ) |
---|
225 | { |
---|
226 | _println("#line "+(outputLine+1)+" \""+outputFile+"\""); |
---|
227 | } |
---|
228 | } |
---|
229 | /// Bound safe isDigit |
---|
230 | private boolean charIsDigit( String s, int i ) |
---|
231 | { |
---|
232 | return (i < s.length()) && Character.isDigit(s.charAt(i)); |
---|
233 | } |
---|
234 | /** Normalize a string coming from antlr's lexer. E.g. translate java |
---|
235 | * escapes to values. Check their size (multibyte) bomb out if they are |
---|
236 | * multibyte (bit crude). Then reescape to C++ style things. |
---|
237 | * Used to generate strings for match() and matchRange() |
---|
238 | * @param lit the literal string |
---|
239 | * @param isCharLiteral if it's for a character literal |
---|
240 | * (enforced to be one length) and enclosed in ' |
---|
241 | * FIXME: bombing out on mb chars. Should be done in Lexer. |
---|
242 | * FIXME: this is another horrible hack. |
---|
243 | * FIXME: life would be soooo much easier if the stuff from the lexer was |
---|
244 | * normalized in some way. |
---|
245 | */ |
---|
246 | private String convertJavaToCppString( String lit, boolean isCharLiteral ) |
---|
247 | { |
---|
248 | // System.out.println("convertJavaToCppLiteral: "+lit); |
---|
249 | String ret = new String(); |
---|
250 | String s = lit; |
---|
251 | |
---|
252 | int i = 0; |
---|
253 | int val = 0; |
---|
254 | |
---|
255 | if( isCharLiteral ) // verify & strip off quotes |
---|
256 | { |
---|
257 | if( ! lit.startsWith("'") || ! lit.endsWith("'") ) |
---|
258 | antlrTool.error("Invalid character literal: '"+lit+"'"); |
---|
259 | } |
---|
260 | else |
---|
261 | { |
---|
262 | if( ! lit.startsWith("\"") || ! lit.endsWith("\"") ) |
---|
263 | antlrTool.error("Invalid character string: '"+lit+"'"); |
---|
264 | } |
---|
265 | s = lit.substring(1,lit.length()-1); |
---|
266 | |
---|
267 | String prefix=""; |
---|
268 | int maxsize = 255; |
---|
269 | if( grammar instanceof LexerGrammar ) |
---|
270 | { |
---|
271 | // vocab size seems to be 1 bigger than it actually is |
---|
272 | maxsize = ((LexerGrammar)grammar).charVocabulary.size() - 1; |
---|
273 | if( maxsize > 255 ) |
---|
274 | prefix= "L"; |
---|
275 | } |
---|
276 | |
---|
277 | // System.out.println("maxsize "+maxsize+" prefix "+prefix); |
---|
278 | |
---|
279 | while ( i < s.length() ) |
---|
280 | { |
---|
281 | if( s.charAt(i) == '\\' ) |
---|
282 | { |
---|
283 | if( s.length() == i+1 ) |
---|
284 | antlrTool.error("Invalid escape in char literal: '"+lit+"' looking at '"+s.substring(i)+"'"); |
---|
285 | |
---|
286 | // deal with escaped junk |
---|
287 | switch ( s.charAt(i+1) ) { |
---|
288 | case 'a' : |
---|
289 | val = 7; |
---|
290 | i += 2; |
---|
291 | break; |
---|
292 | case 'b' : |
---|
293 | val = 8; |
---|
294 | i += 2; |
---|
295 | break; |
---|
296 | case 't' : |
---|
297 | val = 9; |
---|
298 | i += 2; |
---|
299 | break; |
---|
300 | case 'n' : |
---|
301 | val = 10; |
---|
302 | i += 2; |
---|
303 | break; |
---|
304 | case 'f' : |
---|
305 | val = 12; |
---|
306 | i += 2; |
---|
307 | break; |
---|
308 | case 'r' : |
---|
309 | val = 13; |
---|
310 | i += 2; |
---|
311 | break; |
---|
312 | case '"' : |
---|
313 | case '\'' : |
---|
314 | case '\\' : |
---|
315 | val = s.charAt(i+1); |
---|
316 | i += 2; |
---|
317 | break; |
---|
318 | |
---|
319 | case 'u' : |
---|
320 | // Unicode char \u1234 |
---|
321 | if( i+5 < s.length() ) |
---|
322 | { |
---|
323 | val = Character.digit(s.charAt(i+2), 16) * 16 * 16 * 16 + |
---|
324 | Character.digit(s.charAt(i+3), 16) * 16 * 16 + |
---|
325 | Character.digit(s.charAt(i+4), 16) * 16 + |
---|
326 | Character.digit(s.charAt(i+5), 16); |
---|
327 | i += 6; |
---|
328 | } |
---|
329 | else |
---|
330 | antlrTool.error("Invalid escape in char literal: '"+lit+"' looking at '"+s.substring(i)+"'"); |
---|
331 | break; |
---|
332 | |
---|
333 | case '0' : // \123 |
---|
334 | case '1' : |
---|
335 | case '2' : |
---|
336 | case '3' : |
---|
337 | if( charIsDigit(s, i+2) ) |
---|
338 | { |
---|
339 | if( charIsDigit(s, i+3) ) |
---|
340 | { |
---|
341 | val = (s.charAt(i+1)-'0')*8*8 + (s.charAt(i+2)-'0')*8 + |
---|
342 | (s.charAt(i+3)-'0'); |
---|
343 | i += 4; |
---|
344 | } |
---|
345 | else |
---|
346 | { |
---|
347 | val = (s.charAt(i+1)-'0')*8 + (s.charAt(i+2)-'0'); |
---|
348 | i += 3; |
---|
349 | } |
---|
350 | } |
---|
351 | else |
---|
352 | { |
---|
353 | val = s.charAt(i+1)-'0'; |
---|
354 | i += 2; |
---|
355 | } |
---|
356 | break; |
---|
357 | |
---|
358 | case '4' : |
---|
359 | case '5' : |
---|
360 | case '6' : |
---|
361 | case '7' : |
---|
362 | if ( charIsDigit(s, i+2) ) |
---|
363 | { |
---|
364 | val = (s.charAt(i+1)-'0')*8 + (s.charAt(i+2)-'0'); |
---|
365 | i += 3; |
---|
366 | } |
---|
367 | else |
---|
368 | { |
---|
369 | val = s.charAt(i+1)-'0'; |
---|
370 | i += 2; |
---|
371 | } |
---|
372 | default: |
---|
373 | antlrTool.error("Unhandled escape in char literal: '"+lit+"' looking at '"+s.substring(i)+"'"); |
---|
374 | val = 0; |
---|
375 | } |
---|
376 | } |
---|
377 | else |
---|
378 | val = s.charAt(i++); |
---|
379 | |
---|
380 | if( grammar instanceof LexerGrammar ) |
---|
381 | { |
---|
382 | if( val > maxsize ) // abort if too big |
---|
383 | { |
---|
384 | String offender; |
---|
385 | if( ( 0x20 <= val ) && ( val < 0x7F ) ) |
---|
386 | offender = charFormatter.escapeChar(val,true); |
---|
387 | else |
---|
388 | offender = "0x"+Integer.toString(val,16); |
---|
389 | |
---|
390 | antlrTool.error("Character out of range in "+(isCharLiteral?"char literal":"string constant")+": '"+s+"'"); |
---|
391 | antlrTool.error("Vocabulary size: "+maxsize+" Character "+offender); |
---|
392 | } |
---|
393 | } |
---|
394 | |
---|
395 | if( isCharLiteral ) |
---|
396 | { |
---|
397 | // we should be at end of char literal here.. |
---|
398 | if( i != s.length() ) |
---|
399 | antlrTool.error("Invalid char literal: '"+lit+"'"); |
---|
400 | |
---|
401 | if( maxsize <= 255 ) |
---|
402 | { |
---|
403 | if ( (val <= 255) && (val & 0x80) != 0 ) |
---|
404 | // the joys of sign extension in the support lib *cough* |
---|
405 | // actually the support lib needs to be fixed but that's a bit |
---|
406 | // hairy too. |
---|
407 | ret = "static_cast<unsigned char>('"+charFormatter.escapeChar(val,true)+"')"; |
---|
408 | else |
---|
409 | ret = "'"+charFormatter.escapeChar(val,true)+"'"; |
---|
410 | } |
---|
411 | else |
---|
412 | { |
---|
413 | // so wchar_t is some implementation defined int like thing |
---|
414 | // so this may even lead to having 16 bit or 32 bit cases... |
---|
415 | // I smell some extra grammar options in the future :( |
---|
416 | ret = "L'"+charFormatter.escapeChar(val,true)+"'"; |
---|
417 | } |
---|
418 | } |
---|
419 | else |
---|
420 | ret += charFormatter.escapeChar(val,true); |
---|
421 | } |
---|
422 | if( !isCharLiteral ) |
---|
423 | ret = prefix+"\""+ret+"\""; |
---|
424 | return ret; |
---|
425 | } |
---|
426 | /** Generate the parser, lexer, treeparser, and token types in C++ |
---|
427 | */ |
---|
428 | public void gen() { |
---|
429 | // Do the code generation |
---|
430 | try { |
---|
431 | // Loop over all grammars |
---|
432 | Enumeration grammarIter = behavior.grammars.elements(); |
---|
433 | while (grammarIter.hasMoreElements()) { |
---|
434 | Grammar g = (Grammar)grammarIter.nextElement(); |
---|
435 | if ( g.debuggingOutput ) { |
---|
436 | antlrTool.error(g.getFilename()+": C++ mode does not support -debug"); |
---|
437 | } |
---|
438 | // Connect all the components to each other |
---|
439 | g.setGrammarAnalyzer(analyzer); |
---|
440 | g.setCodeGenerator(this); |
---|
441 | analyzer.setGrammar(g); |
---|
442 | // To get right overloading behavior across hetrogeneous grammars |
---|
443 | setupGrammarParameters(g); |
---|
444 | g.generate(); |
---|
445 | exitIfError(); |
---|
446 | } |
---|
447 | |
---|
448 | // Loop over all token managers (some of which are lexers) |
---|
449 | Enumeration tmIter = behavior.tokenManagers.elements(); |
---|
450 | while (tmIter.hasMoreElements()) { |
---|
451 | TokenManager tm = (TokenManager)tmIter.nextElement(); |
---|
452 | if (!tm.isReadOnly()) { |
---|
453 | // Write the token manager tokens as C++ |
---|
454 | // this must appear before genTokenInterchange so that |
---|
455 | // labels are set on string literals |
---|
456 | genTokenTypes(tm); |
---|
457 | // Write the token manager tokens as plain text |
---|
458 | genTokenInterchange(tm); |
---|
459 | } |
---|
460 | exitIfError(); |
---|
461 | } |
---|
462 | } |
---|
463 | catch (IOException e) { |
---|
464 | antlrTool.reportException(e, null); |
---|
465 | } |
---|
466 | } |
---|
467 | /** Generate code for the given grammar element. |
---|
468 | * @param blk The {...} action to generate |
---|
469 | */ |
---|
470 | public void gen(ActionElement action) { |
---|
471 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genAction("+action+")"); |
---|
472 | if ( action.isSemPred ) { |
---|
473 | genSemPred(action.actionText, action.line); |
---|
474 | } |
---|
475 | else { |
---|
476 | if ( grammar.hasSyntacticPredicate ) { |
---|
477 | println("if ( inputState->guessing==0 ) {"); |
---|
478 | tabs++; |
---|
479 | } |
---|
480 | |
---|
481 | ActionTransInfo tInfo = new ActionTransInfo(); |
---|
482 | String actionStr = processActionForSpecialSymbols(action.actionText, |
---|
483 | action.getLine(), |
---|
484 | currentRule, tInfo); |
---|
485 | |
---|
486 | if ( tInfo.refRuleRoot!=null ) { |
---|
487 | // Somebody referenced "#rule", make sure translated var is valid |
---|
488 | // assignment to #rule is left as a ref also, meaning that assignments |
---|
489 | // with no other refs like "#rule = foo();" still forces this code to be |
---|
490 | // generated (unnecessarily). |
---|
491 | println(tInfo.refRuleRoot + " = "+labeledElementASTType+"(currentAST.root);"); |
---|
492 | } |
---|
493 | |
---|
494 | // dump the translated action |
---|
495 | genLineNo(action); |
---|
496 | printAction(actionStr); |
---|
497 | genLineNo2(); |
---|
498 | |
---|
499 | if ( tInfo.assignToRoot ) { |
---|
500 | // Somebody did a "#rule=", reset internal currentAST.root |
---|
501 | println("currentAST.root = "+tInfo.refRuleRoot+";"); |
---|
502 | // reset the child pointer too to be last sibling in sibling list |
---|
503 | // now use if else in stead of x ? y : z to shut CC 4.2 up. |
---|
504 | println("if ( "+tInfo.refRuleRoot+"!="+labeledElementASTInit+" &&"); |
---|
505 | tabs++; |
---|
506 | println(tInfo.refRuleRoot+"->getFirstChild() != "+labeledElementASTInit+" )"); |
---|
507 | println(" currentAST.child = "+tInfo.refRuleRoot+"->getFirstChild();"); |
---|
508 | tabs--; |
---|
509 | println("else"); |
---|
510 | tabs++; |
---|
511 | println("currentAST.child = "+tInfo.refRuleRoot+";"); |
---|
512 | tabs--; |
---|
513 | println("currentAST.advanceChildToEnd();"); |
---|
514 | } |
---|
515 | |
---|
516 | if ( grammar.hasSyntacticPredicate ) { |
---|
517 | tabs--; |
---|
518 | println("}"); |
---|
519 | } |
---|
520 | } |
---|
521 | } |
---|
522 | |
---|
523 | /** Generate code for the given grammar element. |
---|
524 | * @param blk The "x|y|z|..." block to generate |
---|
525 | */ |
---|
526 | public void gen(AlternativeBlock blk) { |
---|
527 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("gen("+blk+")"); |
---|
528 | println("{"); |
---|
529 | genBlockPreamble(blk); |
---|
530 | genBlockInitAction(blk); |
---|
531 | |
---|
532 | // Tell AST generation to build subrule result |
---|
533 | String saveCurrentASTResult = currentASTResult; |
---|
534 | if (blk.getLabel() != null) { |
---|
535 | currentASTResult = blk.getLabel(); |
---|
536 | } |
---|
537 | |
---|
538 | boolean ok = grammar.theLLkAnalyzer.deterministic(blk); |
---|
539 | |
---|
540 | CppBlockFinishingInfo howToFinish = genCommonBlock(blk, true); |
---|
541 | genBlockFinish(howToFinish, throwNoViable); |
---|
542 | |
---|
543 | println("}"); |
---|
544 | |
---|
545 | // Restore previous AST generation |
---|
546 | currentASTResult = saveCurrentASTResult; |
---|
547 | } |
---|
548 | /** Generate code for the given grammar element. |
---|
549 | * @param blk The block-end element to generate. Block-end |
---|
550 | * elements are synthesized by the grammar parser to represent |
---|
551 | * the end of a block. |
---|
552 | */ |
---|
553 | public void gen(BlockEndElement end) { |
---|
554 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genRuleEnd("+end+")"); |
---|
555 | } |
---|
556 | /** Generate code for the given grammar element. |
---|
557 | * Only called from lexer grammars. |
---|
558 | * @param blk The character literal reference to generate |
---|
559 | */ |
---|
560 | public void gen(CharLiteralElement atom) { |
---|
561 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) |
---|
562 | System.out.println("genChar("+atom+")"); |
---|
563 | |
---|
564 | if ( ! (grammar instanceof LexerGrammar) ) |
---|
565 | antlrTool.error("cannot ref character literals in grammar: "+atom); |
---|
566 | |
---|
567 | if ( atom.getLabel() != null ) { |
---|
568 | println(atom.getLabel() + " = " + lt1Value + ";"); |
---|
569 | } |
---|
570 | |
---|
571 | boolean oldsaveText = saveText; |
---|
572 | saveText = saveText && atom.getAutoGenType() == GrammarElement.AUTO_GEN_NONE; |
---|
573 | |
---|
574 | // if in lexer and ! on element, save buffer index to kill later |
---|
575 | if ( !saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG ) |
---|
576 | println("_saveIndex = text.length();"); |
---|
577 | |
---|
578 | print(atom.not ? "matchNot(" : "match("); |
---|
579 | _print(convertJavaToCppString( atom.atomText, true )); |
---|
580 | _println(" /* charlit */ );"); |
---|
581 | |
---|
582 | if ( !saveText || atom.getAutoGenType() == GrammarElement.AUTO_GEN_BANG ) |
---|
583 | println("text.erase(_saveIndex);"); // kill text atom put in buffer |
---|
584 | |
---|
585 | saveText = oldsaveText; |
---|
586 | } |
---|
587 | /** Generate code for the given grammar element. |
---|
588 | * Only called from lexer grammars. |
---|
589 | * @param blk The character-range reference to generate |
---|
590 | */ |
---|
591 | public void gen(CharRangeElement r) { |
---|
592 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) |
---|
593 | System.out.println("genCharRangeElement("+r.beginText+".."+r.endText+")"); |
---|
594 | |
---|
595 | if ( ! (grammar instanceof LexerGrammar) ) |
---|
596 | antlrTool.error("cannot ref character range in grammar: "+r); |
---|
597 | |
---|
598 | if ( r.getLabel() != null && syntacticPredLevel == 0) { |
---|
599 | println(r.getLabel() + " = " + lt1Value + ";"); |
---|
600 | } |
---|
601 | // Correctly take care of saveIndex stuff... |
---|
602 | boolean save = ( grammar instanceof LexerGrammar && |
---|
603 | ( !saveText || |
---|
604 | r.getAutoGenType() == GrammarElement.AUTO_GEN_BANG ) |
---|
605 | ); |
---|
606 | if (save) |
---|
607 | println("_saveIndex=text.length();"); |
---|
608 | |
---|
609 | println("matchRange("+convertJavaToCppString(r.beginText,true)+ |
---|
610 | ","+convertJavaToCppString(r.endText,true)+");"); |
---|
611 | |
---|
612 | if (save) |
---|
613 | println("text.erase(_saveIndex);"); |
---|
614 | } |
---|
615 | /** Generate the lexer C++ files */ |
---|
616 | public void gen(LexerGrammar g) throws IOException { |
---|
617 | // If debugging, create a new sempred vector for this grammar |
---|
618 | if (g.debuggingOutput) |
---|
619 | semPreds = new Vector(); |
---|
620 | |
---|
621 | if( g.charVocabulary.size() > 256 ) |
---|
622 | antlrTool.warning(g.getFilename()+": Vocabularies of this size still experimental in C++ mode (vocabulary size now: "+g.charVocabulary.size()+")"); |
---|
623 | |
---|
624 | setGrammar(g); |
---|
625 | if (!(grammar instanceof LexerGrammar)) { |
---|
626 | antlrTool.panic("Internal error generating lexer"); |
---|
627 | } |
---|
628 | |
---|
629 | genBody(g); |
---|
630 | genInclude(g); |
---|
631 | } |
---|
632 | /** Generate code for the given grammar element. |
---|
633 | * @param blk The (...)+ block to generate |
---|
634 | */ |
---|
635 | public void gen(OneOrMoreBlock blk) { |
---|
636 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("gen+("+blk+")"); |
---|
637 | String label; |
---|
638 | String cnt; |
---|
639 | println("{ // ( ... )+"); |
---|
640 | genBlockPreamble(blk); |
---|
641 | if ( blk.getLabel() != null ) { |
---|
642 | cnt = "_cnt_"+blk.getLabel(); |
---|
643 | } |
---|
644 | else { |
---|
645 | cnt = "_cnt" + blk.ID; |
---|
646 | } |
---|
647 | println("int "+cnt+"=0;"); |
---|
648 | if ( blk.getLabel() != null ) { |
---|
649 | label = blk.getLabel(); |
---|
650 | } |
---|
651 | else { |
---|
652 | label = "_loop" + blk.ID; |
---|
653 | } |
---|
654 | |
---|
655 | println("for (;;) {"); |
---|
656 | tabs++; |
---|
657 | // generate the init action for ()+ ()* inside the loop |
---|
658 | // this allows us to do usefull EOF checking... |
---|
659 | genBlockInitAction(blk); |
---|
660 | |
---|
661 | // Tell AST generation to build subrule result |
---|
662 | String saveCurrentASTResult = currentASTResult; |
---|
663 | if (blk.getLabel() != null) { |
---|
664 | currentASTResult = blk.getLabel(); |
---|
665 | } |
---|
666 | |
---|
667 | boolean ok = grammar.theLLkAnalyzer.deterministic(blk); |
---|
668 | |
---|
669 | // generate exit test if greedy set to false |
---|
670 | // and an alt is ambiguous with exit branch |
---|
671 | // or when lookahead derived purely from end-of-file |
---|
672 | // Lookahead analysis stops when end-of-file is hit, |
---|
673 | // returning set {epsilon}. Since {epsilon} is not |
---|
674 | // ambig with any real tokens, no error is reported |
---|
675 | // by deterministic() routines and we have to check |
---|
676 | // for the case where the lookahead depth didn't get |
---|
677 | // set to NONDETERMINISTIC (this only happens when the |
---|
678 | // FOLLOW contains real atoms + epsilon). |
---|
679 | boolean generateNonGreedyExitPath = false; |
---|
680 | int nonGreedyExitDepth = grammar.maxk; |
---|
681 | |
---|
682 | if ( !blk.greedy && |
---|
683 | blk.exitLookaheadDepth<=grammar.maxk && |
---|
684 | blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() ) |
---|
685 | { |
---|
686 | generateNonGreedyExitPath = true; |
---|
687 | nonGreedyExitDepth = blk.exitLookaheadDepth; |
---|
688 | } |
---|
689 | else if ( !blk.greedy && |
---|
690 | blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC ) |
---|
691 | { |
---|
692 | generateNonGreedyExitPath = true; |
---|
693 | } |
---|
694 | |
---|
695 | // generate exit test if greedy set to false |
---|
696 | // and an alt is ambiguous with exit branch |
---|
697 | if ( generateNonGreedyExitPath ) { |
---|
698 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) { |
---|
699 | System.out.println("nongreedy (...)+ loop; exit depth is "+ |
---|
700 | blk.exitLookaheadDepth); |
---|
701 | } |
---|
702 | String predictExit = |
---|
703 | getLookaheadTestExpression(blk.exitCache, |
---|
704 | nonGreedyExitDepth); |
---|
705 | println("// nongreedy exit test"); |
---|
706 | println("if ( "+cnt+">=1 && "+predictExit+") goto "+label+";"); |
---|
707 | } |
---|
708 | |
---|
709 | CppBlockFinishingInfo howToFinish = genCommonBlock(blk, false); |
---|
710 | genBlockFinish( |
---|
711 | howToFinish, |
---|
712 | "if ( "+cnt+">=1 ) { goto "+label+"; } else {" + throwNoViable + "}" |
---|
713 | ); |
---|
714 | |
---|
715 | println(cnt+"++;"); |
---|
716 | tabs--; |
---|
717 | println("}"); |
---|
718 | println(label+":;"); |
---|
719 | println("} // ( ... )+"); |
---|
720 | |
---|
721 | // Restore previous AST generation |
---|
722 | currentASTResult = saveCurrentASTResult; |
---|
723 | } |
---|
724 | /** Generate the parser C++ file */ |
---|
725 | public void gen(ParserGrammar g) throws IOException { |
---|
726 | |
---|
727 | // if debugging, set up a new vector to keep track of sempred |
---|
728 | // strings for this grammar |
---|
729 | if (g.debuggingOutput) |
---|
730 | semPreds = new Vector(); |
---|
731 | |
---|
732 | setGrammar(g); |
---|
733 | if (!(grammar instanceof ParserGrammar)) { |
---|
734 | antlrTool.panic("Internal error generating parser"); |
---|
735 | } |
---|
736 | |
---|
737 | genBody(g); |
---|
738 | genInclude(g); |
---|
739 | } |
---|
740 | /** Generate code for the given grammar element. |
---|
741 | * @param blk The rule-reference to generate |
---|
742 | */ |
---|
743 | public void gen(RuleRefElement rr) |
---|
744 | { |
---|
745 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genRR("+rr+")"); |
---|
746 | RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule); |
---|
747 | if (rs == null || !rs.isDefined()) |
---|
748 | { |
---|
749 | // Is this redundant??? |
---|
750 | antlrTool.error("Rule '" + rr.targetRule + "' is not defined", grammar.getFilename(), rr.getLine(), rr.getColumn()); |
---|
751 | return; |
---|
752 | } |
---|
753 | if (!(rs instanceof RuleSymbol)) |
---|
754 | { |
---|
755 | // Is this redundant??? |
---|
756 | antlrTool.error("'" + rr.targetRule + "' does not name a grammar rule", grammar.getFilename(), rr.getLine(), rr.getColumn()); |
---|
757 | return; |
---|
758 | } |
---|
759 | |
---|
760 | genErrorTryForElement(rr); |
---|
761 | |
---|
762 | // AST value for labeled rule refs in tree walker. |
---|
763 | // This is not AST construction; it is just the input tree node value. |
---|
764 | if ( grammar instanceof TreeWalkerGrammar && |
---|
765 | rr.getLabel() != null && |
---|
766 | syntacticPredLevel == 0 ) |
---|
767 | { |
---|
768 | println(rr.getLabel() + " = (_t == ASTNULL) ? "+labeledElementASTInit+" : "+lt1Value+";"); |
---|
769 | } |
---|
770 | |
---|
771 | // if in lexer and ! on rule ref or alt or rule, save buffer index to |
---|
772 | // kill later |
---|
773 | if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) |
---|
774 | { |
---|
775 | println("_saveIndex = text.length();"); |
---|
776 | } |
---|
777 | |
---|
778 | // Process return value assignment if any |
---|
779 | printTabs(); |
---|
780 | if (rr.idAssign != null) |
---|
781 | { |
---|
782 | // Warn if the rule has no return type |
---|
783 | if (rs.block.returnAction == null) |
---|
784 | { |
---|
785 | antlrTool.warning("Rule '" + rr.targetRule + "' has no return type", grammar.getFilename(), rr.getLine(), rr.getColumn()); |
---|
786 | } |
---|
787 | _print(rr.idAssign + "="); |
---|
788 | } else { |
---|
789 | // Warn about return value if any, but not inside syntactic predicate |
---|
790 | if ( !(grammar instanceof LexerGrammar) && syntacticPredLevel == 0 && rs.block.returnAction != null) |
---|
791 | { |
---|
792 | antlrTool.warning("Rule '" + rr.targetRule + "' returns a value", grammar.getFilename(), rr.getLine(), rr.getColumn()); |
---|
793 | } |
---|
794 | } |
---|
795 | |
---|
796 | // Call the rule |
---|
797 | GenRuleInvocation(rr); |
---|
798 | |
---|
799 | // if in lexer and ! on element or alt or rule, save buffer index to kill later |
---|
800 | if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) { |
---|
801 | println("text.erase(_saveIndex);"); |
---|
802 | } |
---|
803 | |
---|
804 | // if not in a syntactic predicate |
---|
805 | if (syntacticPredLevel == 0) |
---|
806 | { |
---|
807 | boolean doNoGuessTest = ( |
---|
808 | grammar.hasSyntacticPredicate && |
---|
809 | ( |
---|
810 | grammar.buildAST && rr.getLabel() != null || |
---|
811 | (genAST && rr.getAutoGenType() == GrammarElement.AUTO_GEN_NONE) |
---|
812 | ) |
---|
813 | ); |
---|
814 | |
---|
815 | if (doNoGuessTest) { |
---|
816 | println("if (inputState->guessing==0) {"); |
---|
817 | tabs++; |
---|
818 | } |
---|
819 | |
---|
820 | if (grammar.buildAST && rr.getLabel() != null) |
---|
821 | { |
---|
822 | // always gen variable for rule return on labeled rules |
---|
823 | // RK: hmm do I know here if the returnAST needs a cast ? |
---|
824 | println(rr.getLabel() + "_AST = returnAST;"); |
---|
825 | } |
---|
826 | |
---|
827 | if (genAST) |
---|
828 | { |
---|
829 | switch (rr.getAutoGenType()) |
---|
830 | { |
---|
831 | case GrammarElement.AUTO_GEN_NONE: |
---|
832 | if( usingCustomAST ) |
---|
833 | println("astFactory->addASTChild(currentAST, "+namespaceAntlr+"RefAST(returnAST));"); |
---|
834 | else |
---|
835 | println("astFactory->addASTChild( currentAST, returnAST );"); |
---|
836 | break; |
---|
837 | case GrammarElement.AUTO_GEN_CARET: |
---|
838 | // FIXME: RK: I'm not so sure this should be an error.. |
---|
839 | // I think it might actually work and be usefull at times. |
---|
840 | antlrTool.error("Internal: encountered ^ after rule reference"); |
---|
841 | break; |
---|
842 | default: |
---|
843 | break; |
---|
844 | } |
---|
845 | } |
---|
846 | |
---|
847 | // if a lexer and labeled, Token label defined at rule level, just set it here |
---|
848 | if ( grammar instanceof LexerGrammar && rr.getLabel() != null ) |
---|
849 | { |
---|
850 | println(rr.getLabel()+"=_returnToken;"); |
---|
851 | } |
---|
852 | |
---|
853 | if (doNoGuessTest) |
---|
854 | { |
---|
855 | tabs--; |
---|
856 | println("}"); |
---|
857 | } |
---|
858 | } |
---|
859 | genErrorCatchForElement(rr); |
---|
860 | } |
---|
861 | /** Generate code for the given grammar element. |
---|
862 | * @param blk The string-literal reference to generate |
---|
863 | */ |
---|
864 | public void gen(StringLiteralElement atom) { |
---|
865 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genString("+atom+")"); |
---|
866 | |
---|
867 | // Variable declarations for labeled elements |
---|
868 | if (atom.getLabel()!=null && syntacticPredLevel == 0) { |
---|
869 | println(atom.getLabel() + " = " + lt1Value + ";"); |
---|
870 | } |
---|
871 | |
---|
872 | // AST |
---|
873 | genElementAST(atom); |
---|
874 | |
---|
875 | // is there a bang on the literal? |
---|
876 | boolean oldsaveText = saveText; |
---|
877 | saveText = saveText && atom.getAutoGenType()==GrammarElement.AUTO_GEN_NONE; |
---|
878 | |
---|
879 | // matching |
---|
880 | genMatch(atom); |
---|
881 | |
---|
882 | saveText = oldsaveText; |
---|
883 | |
---|
884 | // tack on tree cursor motion if doing a tree walker |
---|
885 | if (grammar instanceof TreeWalkerGrammar) { |
---|
886 | println("_t = _t->getNextSibling();"); |
---|
887 | } |
---|
888 | } |
---|
889 | /** Generate code for the given grammar element. |
---|
890 | * @param blk The token-range reference to generate |
---|
891 | */ |
---|
892 | public void gen(TokenRangeElement r) { |
---|
893 | genErrorTryForElement(r); |
---|
894 | if ( r.getLabel()!=null && syntacticPredLevel == 0) { |
---|
895 | println(r.getLabel() + " = " + lt1Value + ";"); |
---|
896 | } |
---|
897 | |
---|
898 | // AST |
---|
899 | genElementAST(r); |
---|
900 | |
---|
901 | // match |
---|
902 | println("matchRange("+r.beginText+","+r.endText+");"); |
---|
903 | genErrorCatchForElement(r); |
---|
904 | } |
---|
905 | /** Generate code for the given grammar element. |
---|
906 | * @param blk The token-reference to generate |
---|
907 | */ |
---|
908 | public void gen(TokenRefElement atom) { |
---|
909 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genTokenRef("+atom+")"); |
---|
910 | if ( grammar instanceof LexerGrammar ) { |
---|
911 | antlrTool.panic("Token reference found in lexer"); |
---|
912 | } |
---|
913 | genErrorTryForElement(atom); |
---|
914 | // Assign Token value to token label variable |
---|
915 | if ( atom.getLabel()!=null && syntacticPredLevel == 0) { |
---|
916 | println(atom.getLabel() + " = " + lt1Value + ";"); |
---|
917 | } |
---|
918 | |
---|
919 | // AST |
---|
920 | genElementAST(atom); |
---|
921 | // matching |
---|
922 | genMatch(atom); |
---|
923 | genErrorCatchForElement(atom); |
---|
924 | |
---|
925 | // tack on tree cursor motion if doing a tree walker |
---|
926 | if (grammar instanceof TreeWalkerGrammar) { |
---|
927 | println("_t = _t->getNextSibling();"); |
---|
928 | } |
---|
929 | } |
---|
930 | public void gen(TreeElement t) { |
---|
931 | // save AST cursor |
---|
932 | println(labeledElementType+" __t" + t.ID + " = _t;"); |
---|
933 | |
---|
934 | // If there is a label on the root, then assign that to the variable |
---|
935 | if (t.root.getLabel() != null) { |
---|
936 | println(t.root.getLabel() + " = (_t == "+labeledElementType+"(ASTNULL)) ? "+labeledElementASTInit+" : _t;"); |
---|
937 | } |
---|
938 | |
---|
939 | // check for invalid modifiers ! and ^ on tree element roots |
---|
940 | if ( t.root.getAutoGenType() == GrammarElement.AUTO_GEN_BANG ) { |
---|
941 | antlrTool.error("Suffixing a root node with '!' is not implemented", |
---|
942 | grammar.getFilename(), t.getLine(), t.getColumn()); |
---|
943 | t.root.setAutoGenType(GrammarElement.AUTO_GEN_NONE); |
---|
944 | } |
---|
945 | if ( t.root.getAutoGenType() == GrammarElement.AUTO_GEN_CARET ) { |
---|
946 | antlrTool.warning("Suffixing a root node with '^' is redundant; already a root", |
---|
947 | grammar.getFilename(), t.getLine(), t.getColumn()); |
---|
948 | t.root.setAutoGenType(GrammarElement.AUTO_GEN_NONE); |
---|
949 | } |
---|
950 | |
---|
951 | // Generate AST variables |
---|
952 | genElementAST(t.root); |
---|
953 | if (grammar.buildAST) { |
---|
954 | // Save the AST construction state |
---|
955 | println(namespaceAntlr+"ASTPair __currentAST" + t.ID + " = currentAST;"); |
---|
956 | // Make the next item added a child of the TreeElement root |
---|
957 | println("currentAST.root = currentAST.child;"); |
---|
958 | println("currentAST.child = "+labeledElementASTInit+";"); |
---|
959 | } |
---|
960 | |
---|
961 | // match root |
---|
962 | if ( t.root instanceof WildcardElement ) { |
---|
963 | println("if ( _t == ASTNULL ) throw "+namespaceAntlr+"MismatchedTokenException();"); |
---|
964 | } |
---|
965 | else { |
---|
966 | genMatch(t.root); |
---|
967 | } |
---|
968 | // move to list of children |
---|
969 | println("_t = _t->getFirstChild();"); |
---|
970 | |
---|
971 | // walk list of children, generating code for each |
---|
972 | for (int i=0; i<t.getAlternatives().size(); i++) { |
---|
973 | Alternative a = t.getAlternativeAt(i); |
---|
974 | AlternativeElement e = a.head; |
---|
975 | while ( e != null ) { |
---|
976 | e.generate(); |
---|
977 | e = e.next; |
---|
978 | } |
---|
979 | } |
---|
980 | |
---|
981 | if (grammar.buildAST) { |
---|
982 | // restore the AST construction state to that just after the |
---|
983 | // tree root was added |
---|
984 | println("currentAST = __currentAST" + t.ID + ";"); |
---|
985 | } |
---|
986 | // restore AST cursor |
---|
987 | println("_t = __t" + t.ID + ";"); |
---|
988 | // move cursor to sibling of tree just parsed |
---|
989 | println("_t = _t->getNextSibling();"); |
---|
990 | } |
---|
991 | /** Generate the tree-parser C++ files */ |
---|
992 | public void gen(TreeWalkerGrammar g) throws IOException { |
---|
993 | setGrammar(g); |
---|
994 | if (!(grammar instanceof TreeWalkerGrammar)) { |
---|
995 | antlrTool.panic("Internal error generating tree-walker"); |
---|
996 | } |
---|
997 | |
---|
998 | genBody(g); |
---|
999 | genInclude(g); |
---|
1000 | } |
---|
1001 | /** Generate code for the given grammar element. |
---|
1002 | * @param wc The wildcard element to generate |
---|
1003 | */ |
---|
1004 | public void gen(WildcardElement wc) { |
---|
1005 | // Variable assignment for labeled elements |
---|
1006 | if (wc.getLabel()!=null && syntacticPredLevel == 0) { |
---|
1007 | println(wc.getLabel() + " = " + lt1Value + ";"); |
---|
1008 | } |
---|
1009 | |
---|
1010 | // AST |
---|
1011 | genElementAST(wc); |
---|
1012 | // Match anything but EOF |
---|
1013 | if (grammar instanceof TreeWalkerGrammar) { |
---|
1014 | println("if ( _t == "+labeledElementASTInit+" ) throw "+namespaceAntlr+"MismatchedTokenException();"); |
---|
1015 | } |
---|
1016 | else if (grammar instanceof LexerGrammar) { |
---|
1017 | if ( grammar instanceof LexerGrammar && |
---|
1018 | (!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) { |
---|
1019 | println("_saveIndex = text.length();"); |
---|
1020 | } |
---|
1021 | println("matchNot(EOF/*_CHAR*/);"); |
---|
1022 | if ( grammar instanceof LexerGrammar && |
---|
1023 | (!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) { |
---|
1024 | println("text.erase(_saveIndex);"); // kill text atom put in buffer |
---|
1025 | } |
---|
1026 | } |
---|
1027 | else { |
---|
1028 | println("matchNot(" + getValueString(Token.EOF_TYPE) + ");"); |
---|
1029 | } |
---|
1030 | |
---|
1031 | // tack on tree cursor motion if doing a tree walker |
---|
1032 | if (grammar instanceof TreeWalkerGrammar) { |
---|
1033 | println("_t = _t->getNextSibling();"); |
---|
1034 | } |
---|
1035 | } |
---|
1036 | /** Generate code for the given grammar element. |
---|
1037 | * @param blk The (...)* block to generate |
---|
1038 | */ |
---|
1039 | public void gen(ZeroOrMoreBlock blk) { |
---|
1040 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("gen*("+blk+")"); |
---|
1041 | println("{ // ( ... )*"); |
---|
1042 | genBlockPreamble(blk); |
---|
1043 | String label; |
---|
1044 | if ( blk.getLabel() != null ) { |
---|
1045 | label = blk.getLabel(); |
---|
1046 | } |
---|
1047 | else { |
---|
1048 | label = "_loop" + blk.ID; |
---|
1049 | } |
---|
1050 | println("for (;;) {"); |
---|
1051 | tabs++; |
---|
1052 | // generate the init action for ()+ ()* inside the loop |
---|
1053 | // this allows us to do usefull EOF checking... |
---|
1054 | genBlockInitAction(blk); |
---|
1055 | |
---|
1056 | // Tell AST generation to build subrule result |
---|
1057 | String saveCurrentASTResult = currentASTResult; |
---|
1058 | if (blk.getLabel() != null) { |
---|
1059 | currentASTResult = blk.getLabel(); |
---|
1060 | } |
---|
1061 | |
---|
1062 | boolean ok = grammar.theLLkAnalyzer.deterministic(blk); |
---|
1063 | |
---|
1064 | // generate exit test if greedy set to false |
---|
1065 | // and an alt is ambiguous with exit branch |
---|
1066 | // or when lookahead derived purely from end-of-file |
---|
1067 | // Lookahead analysis stops when end-of-file is hit, |
---|
1068 | // returning set {epsilon}. Since {epsilon} is not |
---|
1069 | // ambig with any real tokens, no error is reported |
---|
1070 | // by deterministic() routines and we have to check |
---|
1071 | // for the case where the lookahead depth didn't get |
---|
1072 | // set to NONDETERMINISTIC (this only happens when the |
---|
1073 | // FOLLOW contains real atoms + epsilon). |
---|
1074 | boolean generateNonGreedyExitPath = false; |
---|
1075 | int nonGreedyExitDepth = grammar.maxk; |
---|
1076 | |
---|
1077 | if ( !blk.greedy && |
---|
1078 | blk.exitLookaheadDepth<=grammar.maxk && |
---|
1079 | blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() ) |
---|
1080 | { |
---|
1081 | generateNonGreedyExitPath = true; |
---|
1082 | nonGreedyExitDepth = blk.exitLookaheadDepth; |
---|
1083 | } |
---|
1084 | else if ( !blk.greedy && |
---|
1085 | blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC ) |
---|
1086 | { |
---|
1087 | generateNonGreedyExitPath = true; |
---|
1088 | } |
---|
1089 | if ( generateNonGreedyExitPath ) { |
---|
1090 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) { |
---|
1091 | System.out.println("nongreedy (...)* loop; exit depth is "+ |
---|
1092 | blk.exitLookaheadDepth); |
---|
1093 | } |
---|
1094 | String predictExit = |
---|
1095 | getLookaheadTestExpression(blk.exitCache, |
---|
1096 | nonGreedyExitDepth); |
---|
1097 | println("// nongreedy exit test"); |
---|
1098 | println("if ("+predictExit+") goto "+label+";"); |
---|
1099 | } |
---|
1100 | |
---|
1101 | CppBlockFinishingInfo howToFinish = genCommonBlock(blk, false); |
---|
1102 | genBlockFinish(howToFinish, "goto " + label + ";"); |
---|
1103 | |
---|
1104 | tabs--; |
---|
1105 | println("}"); |
---|
1106 | println(label+":;"); |
---|
1107 | println("} // ( ... )*"); |
---|
1108 | |
---|
1109 | // Restore previous AST generation |
---|
1110 | currentASTResult = saveCurrentASTResult; |
---|
1111 | } |
---|
1112 | /** Generate an alternative. |
---|
1113 | * @param alt The alternative to generate |
---|
1114 | * @param blk The block to which the alternative belongs |
---|
1115 | */ |
---|
1116 | protected void genAlt(Alternative alt, AlternativeBlock blk) |
---|
1117 | { |
---|
1118 | // Save the AST generation state, and set it to that of the alt |
---|
1119 | boolean savegenAST = genAST; |
---|
1120 | genAST = genAST && alt.getAutoGen(); |
---|
1121 | |
---|
1122 | boolean oldsaveTest = saveText; |
---|
1123 | saveText = saveText && alt.getAutoGen(); |
---|
1124 | |
---|
1125 | // Reset the variable name map for the alternative |
---|
1126 | Hashtable saveMap = treeVariableMap; |
---|
1127 | treeVariableMap = new Hashtable(); |
---|
1128 | |
---|
1129 | // Generate try block around the alt for error handling |
---|
1130 | if (alt.exceptionSpec != null) { |
---|
1131 | println("try { // for error handling"); |
---|
1132 | tabs++; |
---|
1133 | } |
---|
1134 | |
---|
1135 | AlternativeElement elem = alt.head; |
---|
1136 | while ( !(elem instanceof BlockEndElement) ) { |
---|
1137 | elem.generate(); // alt can begin with anything. Ask target to gen. |
---|
1138 | elem = elem.next; |
---|
1139 | } |
---|
1140 | |
---|
1141 | if ( genAST) |
---|
1142 | { |
---|
1143 | if (blk instanceof RuleBlock) |
---|
1144 | { |
---|
1145 | // Set the AST return value for the rule |
---|
1146 | RuleBlock rblk = (RuleBlock)blk; |
---|
1147 | if( usingCustomAST ) |
---|
1148 | println(rblk.getRuleName() + "_AST = "+labeledElementASTType+"(currentAST.root);"); |
---|
1149 | else |
---|
1150 | println(rblk.getRuleName() + "_AST = currentAST.root;"); |
---|
1151 | } |
---|
1152 | else if (blk.getLabel() != null) { |
---|
1153 | // ### future: also set AST value for labeled subrules. |
---|
1154 | // println(blk.getLabel() + "_AST = "+labeledElementASTType+"(currentAST.root);"); |
---|
1155 | antlrTool.warning("Labeled subrules are not implemented", grammar.getFilename(), blk.getLine(), blk.getColumn()); |
---|
1156 | } |
---|
1157 | } |
---|
1158 | |
---|
1159 | if (alt.exceptionSpec != null) |
---|
1160 | { |
---|
1161 | // close try block |
---|
1162 | tabs--; |
---|
1163 | println("}"); |
---|
1164 | genErrorHandler(alt.exceptionSpec); |
---|
1165 | } |
---|
1166 | |
---|
1167 | genAST = savegenAST; |
---|
1168 | saveText = oldsaveTest; |
---|
1169 | |
---|
1170 | treeVariableMap = saveMap; |
---|
1171 | } |
---|
1172 | /** Generate all the bitsets to be used in the parser or lexer |
---|
1173 | * Generate the raw bitset data like "long _tokenSet1_data[] = {...};" |
---|
1174 | * and the BitSet object declarations like |
---|
1175 | * "BitSet _tokenSet1 = new BitSet(_tokenSet1_data);" |
---|
1176 | * Note that most languages do not support object initialization inside a |
---|
1177 | * class definition, so other code-generators may have to separate the |
---|
1178 | * bitset declarations from the initializations (e.g., put the |
---|
1179 | * initializations in the generated constructor instead). |
---|
1180 | * @param bitsetList The list of bitsets to generate. |
---|
1181 | * @param maxVocabulary Ensure that each generated bitset can contain at |
---|
1182 | * least this value. |
---|
1183 | * @param prefix string glued in from of bitset names used for namespace |
---|
1184 | * qualifications. |
---|
1185 | */ |
---|
1186 | protected void genBitsets( |
---|
1187 | Vector bitsetList, |
---|
1188 | int maxVocabulary, |
---|
1189 | String prefix |
---|
1190 | ) |
---|
1191 | { |
---|
1192 | TokenManager tm = grammar.tokenManager; |
---|
1193 | |
---|
1194 | println(""); |
---|
1195 | |
---|
1196 | for (int i = 0; i < bitsetList.size(); i++) |
---|
1197 | { |
---|
1198 | BitSet p = (BitSet)bitsetList.elementAt(i); |
---|
1199 | // Ensure that generated BitSet is large enough for vocabulary |
---|
1200 | p.growToInclude(maxVocabulary); |
---|
1201 | |
---|
1202 | // initialization data |
---|
1203 | println( |
---|
1204 | "const unsigned long " + prefix + getBitsetName(i) + "_data_" + "[] = { " + |
---|
1205 | p.toStringOfHalfWords() + |
---|
1206 | " };" |
---|
1207 | ); |
---|
1208 | |
---|
1209 | // Dump the contents of the bitset in readable format... |
---|
1210 | String t = "// "; |
---|
1211 | |
---|
1212 | for( int j = 0; j < tm.getVocabulary().size(); j++ ) |
---|
1213 | { |
---|
1214 | if ( p.member( j ) ) |
---|
1215 | { |
---|
1216 | if ( (grammar instanceof LexerGrammar) ) |
---|
1217 | { |
---|
1218 | // only dump out for pure printable ascii. |
---|
1219 | if( ( 0x20 <= j ) && ( j < 0x7F ) && (j != '\\') ) |
---|
1220 | t += charFormatter.escapeChar(j,true)+" "; |
---|
1221 | else |
---|
1222 | t += "0x"+Integer.toString(j,16)+" "; |
---|
1223 | } |
---|
1224 | else |
---|
1225 | t += tm.getTokenStringAt(j)+" "; |
---|
1226 | |
---|
1227 | if( t.length() > 70 ) |
---|
1228 | { |
---|
1229 | println(t); |
---|
1230 | t = "// "; |
---|
1231 | } |
---|
1232 | } |
---|
1233 | } |
---|
1234 | if ( t != "// " ) |
---|
1235 | println(t); |
---|
1236 | |
---|
1237 | // BitSet object |
---|
1238 | println( |
---|
1239 | "const "+namespaceAntlr+"BitSet " + prefix + getBitsetName(i) + "(" + |
---|
1240 | getBitsetName(i) + "_data_," + p.size()/32 + |
---|
1241 | ");" |
---|
1242 | ); |
---|
1243 | } |
---|
1244 | } |
---|
1245 | protected void genBitsetsHeader( |
---|
1246 | Vector bitsetList, |
---|
1247 | int maxVocabulary |
---|
1248 | ) { |
---|
1249 | println(""); |
---|
1250 | for (int i = 0; i < bitsetList.size(); i++) |
---|
1251 | { |
---|
1252 | BitSet p = (BitSet)bitsetList.elementAt(i); |
---|
1253 | // Ensure that generated BitSet is large enough for vocabulary |
---|
1254 | p.growToInclude(maxVocabulary); |
---|
1255 | // initialization data |
---|
1256 | println("static const unsigned long " + getBitsetName(i) + "_data_" + "[];"); |
---|
1257 | // BitSet object |
---|
1258 | println("static const "+namespaceAntlr+"BitSet " + getBitsetName(i) + ";"); |
---|
1259 | } |
---|
1260 | } |
---|
1261 | /** Generate the finish of a block, using a combination of the info |
---|
1262 | * returned from genCommonBlock() and the action to perform when |
---|
1263 | * no alts were taken |
---|
1264 | * @param howToFinish The return of genCommonBlock() |
---|
1265 | * @param noViableAction What to generate when no alt is taken |
---|
1266 | */ |
---|
1267 | private void genBlockFinish(CppBlockFinishingInfo howToFinish, String noViableAction) |
---|
1268 | { |
---|
1269 | if (howToFinish.needAnErrorClause && |
---|
1270 | (howToFinish.generatedAnIf || howToFinish.generatedSwitch)) { |
---|
1271 | if ( howToFinish.generatedAnIf ) { |
---|
1272 | println("else {"); |
---|
1273 | } |
---|
1274 | else { |
---|
1275 | println("{"); |
---|
1276 | } |
---|
1277 | tabs++; |
---|
1278 | println(noViableAction); |
---|
1279 | tabs--; |
---|
1280 | println("}"); |
---|
1281 | } |
---|
1282 | |
---|
1283 | if ( howToFinish.postscript!=null ) { |
---|
1284 | println(howToFinish.postscript); |
---|
1285 | } |
---|
1286 | } |
---|
1287 | /** Generate the initaction for a block, which may be a RuleBlock or a |
---|
1288 | * plain AlternativeBLock. |
---|
1289 | * @blk The block for which the preamble is to be generated. |
---|
1290 | */ |
---|
1291 | protected void genBlockInitAction( AlternativeBlock blk ) |
---|
1292 | { |
---|
1293 | // dump out init action |
---|
1294 | if ( blk.initAction!=null ) { |
---|
1295 | genLineNo(blk); |
---|
1296 | printAction(processActionForSpecialSymbols(blk.initAction, blk.line, |
---|
1297 | currentRule, null) ); |
---|
1298 | genLineNo2(); |
---|
1299 | } |
---|
1300 | } |
---|
1301 | /** Generate the header for a block, which may be a RuleBlock or a |
---|
1302 | * plain AlternativeBlock. This generates any variable declarations |
---|
1303 | * and syntactic-predicate-testing variables. |
---|
1304 | * @blk The block for which the preamble is to be generated. |
---|
1305 | */ |
---|
1306 | protected void genBlockPreamble(AlternativeBlock blk) { |
---|
1307 | // define labels for rule blocks. |
---|
1308 | if ( blk instanceof RuleBlock ) { |
---|
1309 | RuleBlock rblk = (RuleBlock)blk; |
---|
1310 | if ( rblk.labeledElements!=null ) { |
---|
1311 | for (int i=0; i<rblk.labeledElements.size(); i++) { |
---|
1312 | |
---|
1313 | AlternativeElement a = (AlternativeElement)rblk.labeledElements.elementAt(i); |
---|
1314 | //System.out.println("looking at labeled element: "+a); |
---|
1315 | // Variables for labeled rule refs and subrules are different than |
---|
1316 | // variables for grammar atoms. This test is a little tricky because |
---|
1317 | // we want to get all rule refs and ebnf, but not rule blocks or |
---|
1318 | // syntactic predicates |
---|
1319 | if ( |
---|
1320 | a instanceof RuleRefElement || |
---|
1321 | a instanceof AlternativeBlock && |
---|
1322 | !(a instanceof RuleBlock) && |
---|
1323 | !(a instanceof SynPredBlock) ) |
---|
1324 | { |
---|
1325 | if ( !(a instanceof RuleRefElement) && |
---|
1326 | ((AlternativeBlock)a).not && |
---|
1327 | analyzer.subruleCanBeInverted(((AlternativeBlock)a), grammar instanceof LexerGrammar) |
---|
1328 | ) { |
---|
1329 | // Special case for inverted subrules that will be |
---|
1330 | // inlined. Treat these like token or char literal |
---|
1331 | // references |
---|
1332 | println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";"); |
---|
1333 | if (grammar.buildAST) { |
---|
1334 | genASTDeclaration( a ); |
---|
1335 | } |
---|
1336 | } |
---|
1337 | else |
---|
1338 | { |
---|
1339 | if (grammar.buildAST) |
---|
1340 | { |
---|
1341 | // Always gen AST variables for labeled elements, |
---|
1342 | // even if the element itself is marked with ! |
---|
1343 | genASTDeclaration( a ); |
---|
1344 | } |
---|
1345 | if ( grammar instanceof LexerGrammar ) |
---|
1346 | println(namespaceAntlr+"RefToken "+a.getLabel()+";"); |
---|
1347 | |
---|
1348 | if (grammar instanceof TreeWalkerGrammar) { |
---|
1349 | // always generate rule-ref variables for tree walker |
---|
1350 | println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";"); |
---|
1351 | } |
---|
1352 | } |
---|
1353 | } |
---|
1354 | else |
---|
1355 | { |
---|
1356 | // It is a token or literal reference. Generate the |
---|
1357 | // correct variable type for this grammar |
---|
1358 | println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";"); |
---|
1359 | // In addition, generate *_AST variables if building ASTs |
---|
1360 | if (grammar.buildAST) |
---|
1361 | { |
---|
1362 | if (a instanceof GrammarAtom && |
---|
1363 | ((GrammarAtom)a).getASTNodeType() != null ) |
---|
1364 | { |
---|
1365 | GrammarAtom ga = (GrammarAtom)a; |
---|
1366 | genASTDeclaration( a, "Ref"+ga.getASTNodeType() ); |
---|
1367 | } |
---|
1368 | else |
---|
1369 | { |
---|
1370 | genASTDeclaration( a ); |
---|
1371 | } |
---|
1372 | } |
---|
1373 | } |
---|
1374 | } |
---|
1375 | } |
---|
1376 | } |
---|
1377 | } |
---|
1378 | public void genBody(LexerGrammar g) throws IOException |
---|
1379 | { |
---|
1380 | outputFile = grammar.getClassName() + ".cpp"; |
---|
1381 | outputLine = 1; |
---|
1382 | currentOutput = antlrTool.openOutputFile(outputFile); |
---|
1383 | //SAS: changed for proper text file io |
---|
1384 | |
---|
1385 | genAST = false; // no way to gen trees. |
---|
1386 | saveText = true; // save consumed characters. |
---|
1387 | |
---|
1388 | tabs=0; |
---|
1389 | |
---|
1390 | // Generate header common to all C++ output files |
---|
1391 | genHeader(outputFile); |
---|
1392 | |
---|
1393 | printHeaderAction(preIncludeCpp); |
---|
1394 | // Generate header specific to lexer C++ file |
---|
1395 | println("#include \"" + grammar.getClassName() + ".hpp\""); |
---|
1396 | println("#include <antlr/CharBuffer.hpp>"); |
---|
1397 | println("#include <antlr/TokenStreamException.hpp>"); |
---|
1398 | println("#include <antlr/TokenStreamIOException.hpp>"); |
---|
1399 | println("#include <antlr/TokenStreamRecognitionException.hpp>"); |
---|
1400 | println("#include <antlr/CharStreamException.hpp>"); |
---|
1401 | println("#include <antlr/CharStreamIOException.hpp>"); |
---|
1402 | println("#include <antlr/NoViableAltForCharException.hpp>"); |
---|
1403 | if (grammar.debuggingOutput) |
---|
1404 | println("#include <antlr/DebuggingInputBuffer.hpp>"); |
---|
1405 | println(""); |
---|
1406 | printHeaderAction(postIncludeCpp); |
---|
1407 | |
---|
1408 | if (nameSpace != null) |
---|
1409 | nameSpace.emitDeclarations(currentOutput); |
---|
1410 | |
---|
1411 | // Generate user-defined lexer file preamble |
---|
1412 | printAction(grammar.preambleAction); |
---|
1413 | |
---|
1414 | // Generate lexer class definition |
---|
1415 | String sup=null; |
---|
1416 | if ( grammar.superClass!=null ) { |
---|
1417 | sup = grammar.superClass; |
---|
1418 | } |
---|
1419 | else { |
---|
1420 | sup = grammar.getSuperClass(); |
---|
1421 | if (sup.lastIndexOf('.') != -1) |
---|
1422 | sup = sup.substring(sup.lastIndexOf('.')+1); |
---|
1423 | sup = namespaceAntlr + sup; |
---|
1424 | } |
---|
1425 | |
---|
1426 | if( noConstructors ) |
---|
1427 | { |
---|
1428 | println("#if 0"); |
---|
1429 | println("// constructor creation turned of with 'noConstructor' option"); |
---|
1430 | } |
---|
1431 | // |
---|
1432 | // Generate the constructor from InputStream |
---|
1433 | // |
---|
1434 | println(grammar.getClassName() + "::" + grammar.getClassName() + "(" + namespaceStd + "istream& in)"); |
---|
1435 | tabs++; |
---|
1436 | // if debugging, wrap the input buffer in a debugger |
---|
1437 | if (grammar.debuggingOutput) |
---|
1438 | println(": " + sup + "(new "+namespaceAntlr+"DebuggingInputBuffer(new "+namespaceAntlr+"CharBuffer(in)),"+g.caseSensitive+")"); |
---|
1439 | else |
---|
1440 | println(": " + sup + "(new "+namespaceAntlr+"CharBuffer(in),"+g.caseSensitive+")"); |
---|
1441 | tabs--; |
---|
1442 | println("{"); |
---|
1443 | tabs++; |
---|
1444 | |
---|
1445 | // if debugging, set up array variables and call user-overridable |
---|
1446 | // debugging setup method |
---|
1447 | if ( grammar.debuggingOutput ) { |
---|
1448 | println("setRuleNames(_ruleNames);"); |
---|
1449 | println("setSemPredNames(_semPredNames);"); |
---|
1450 | println("setupDebugging();"); |
---|
1451 | } |
---|
1452 | |
---|
1453 | // println("setCaseSensitive("+g.caseSensitive+");"); |
---|
1454 | println("initLiterals();"); |
---|
1455 | tabs--; |
---|
1456 | println("}"); |
---|
1457 | println(""); |
---|
1458 | |
---|
1459 | // Generate the constructor from InputBuffer |
---|
1460 | println(grammar.getClassName() + "::" + grammar.getClassName() + "("+namespaceAntlr+"InputBuffer& ib)"); |
---|
1461 | tabs++; |
---|
1462 | // if debugging, wrap the input buffer in a debugger |
---|
1463 | if (grammar.debuggingOutput) |
---|
1464 | println(": " + sup + "(new "+namespaceAntlr+"DebuggingInputBuffer(ib),"+g.caseSensitive+")"); |
---|
1465 | else |
---|
1466 | println(": " + sup + "(ib,"+g.caseSensitive+")"); |
---|
1467 | tabs--; |
---|
1468 | println("{"); |
---|
1469 | tabs++; |
---|
1470 | |
---|
1471 | // if debugging, set up array variables and call user-overridable |
---|
1472 | // debugging setup method |
---|
1473 | if ( grammar.debuggingOutput ) { |
---|
1474 | println("setRuleNames(_ruleNames);"); |
---|
1475 | println("setSemPredNames(_semPredNames);"); |
---|
1476 | println("setupDebugging();"); |
---|
1477 | } |
---|
1478 | |
---|
1479 | // println("setCaseSensitive("+g.caseSensitive+");"); |
---|
1480 | println("initLiterals();"); |
---|
1481 | tabs--; |
---|
1482 | println("}"); |
---|
1483 | println(""); |
---|
1484 | |
---|
1485 | // Generate the constructor from LexerSharedInputState |
---|
1486 | println(grammar.getClassName() + "::" + grammar.getClassName() + "(const "+namespaceAntlr+"LexerSharedInputState& state)"); |
---|
1487 | tabs++; |
---|
1488 | println(": " + sup + "(state,"+g.caseSensitive+")"); |
---|
1489 | tabs--; |
---|
1490 | println("{"); |
---|
1491 | tabs++; |
---|
1492 | |
---|
1493 | // if debugging, set up array variables and call user-overridable |
---|
1494 | // debugging setup method |
---|
1495 | if ( grammar.debuggingOutput ) { |
---|
1496 | println("setRuleNames(_ruleNames);"); |
---|
1497 | println("setSemPredNames(_semPredNames);"); |
---|
1498 | println("setupDebugging();"); |
---|
1499 | } |
---|
1500 | |
---|
1501 | // println("setCaseSensitive("+g.caseSensitive+");"); |
---|
1502 | println("initLiterals();"); |
---|
1503 | tabs--; |
---|
1504 | println("}"); |
---|
1505 | println(""); |
---|
1506 | |
---|
1507 | if( noConstructors ) |
---|
1508 | { |
---|
1509 | println("// constructor creation turned of with 'noConstructor' option"); |
---|
1510 | println("#endif"); |
---|
1511 | } |
---|
1512 | |
---|
1513 | println("void " + grammar.getClassName() + "::initLiterals()"); |
---|
1514 | println("{"); |
---|
1515 | tabs++; |
---|
1516 | // Generate the initialization of the map |
---|
1517 | // containing the string literals used in the lexer |
---|
1518 | // The literals variable itself is in CharScanner |
---|
1519 | Enumeration keys = grammar.tokenManager.getTokenSymbolKeys(); |
---|
1520 | while ( keys.hasMoreElements() ) { |
---|
1521 | String key = (String)keys.nextElement(); |
---|
1522 | if ( key.charAt(0) != '"' ) { |
---|
1523 | continue; |
---|
1524 | } |
---|
1525 | TokenSymbol sym = grammar.tokenManager.getTokenSymbol(key); |
---|
1526 | if ( sym instanceof StringLiteralSymbol ) { |
---|
1527 | StringLiteralSymbol s = (StringLiteralSymbol)sym; |
---|
1528 | println("literals["+s.getId()+"] = "+s.getTokenType()+";"); |
---|
1529 | } |
---|
1530 | } |
---|
1531 | |
---|
1532 | // Generate the setting of various generated options. |
---|
1533 | tabs--; |
---|
1534 | println("}"); |
---|
1535 | |
---|
1536 | Enumeration ids; |
---|
1537 | // generate the rule name array for debugging |
---|
1538 | if (grammar.debuggingOutput) { |
---|
1539 | println("const char* "+grammar.getClassName()+"::_ruleNames[] = {"); |
---|
1540 | tabs++; |
---|
1541 | |
---|
1542 | ids = grammar.rules.elements(); |
---|
1543 | int ruleNum=0; |
---|
1544 | while ( ids.hasMoreElements() ) { |
---|
1545 | GrammarSymbol sym = (GrammarSymbol) ids.nextElement(); |
---|
1546 | if ( sym instanceof RuleSymbol) |
---|
1547 | println("\""+((RuleSymbol)sym).getId()+"\","); |
---|
1548 | } |
---|
1549 | println("0"); |
---|
1550 | tabs--; |
---|
1551 | println("};"); |
---|
1552 | } |
---|
1553 | |
---|
1554 | // Generate nextToken() rule. |
---|
1555 | // nextToken() is a synthetic lexer rule that is the implicit OR of all |
---|
1556 | // user-defined lexer rules. |
---|
1557 | genNextToken(); |
---|
1558 | |
---|
1559 | // Generate code for each rule in the lexer |
---|
1560 | ids = grammar.rules.elements(); |
---|
1561 | int ruleNum=0; |
---|
1562 | while ( ids.hasMoreElements() ) { |
---|
1563 | RuleSymbol sym = (RuleSymbol) ids.nextElement(); |
---|
1564 | // Don't generate the synthetic rules |
---|
1565 | if (!sym.getId().equals("mnextToken")) { |
---|
1566 | genRule(sym, false, ruleNum++, grammar.getClassName() + "::"); |
---|
1567 | } |
---|
1568 | exitIfError(); |
---|
1569 | } |
---|
1570 | |
---|
1571 | // Generate the semantic predicate map for debugging |
---|
1572 | if (grammar.debuggingOutput) |
---|
1573 | genSemPredMap(grammar.getClassName() + "::"); |
---|
1574 | |
---|
1575 | // Generate the bitsets used throughout the lexer |
---|
1576 | genBitsets(bitsetsUsed, ((LexerGrammar)grammar).charVocabulary.size(), grammar.getClassName() + "::" ); |
---|
1577 | |
---|
1578 | println(""); |
---|
1579 | if (nameSpace != null) |
---|
1580 | nameSpace.emitClosures(currentOutput); |
---|
1581 | |
---|
1582 | // Close the lexer output stream |
---|
1583 | currentOutput.close(); |
---|
1584 | currentOutput = null; |
---|
1585 | } |
---|
1586 | public void genInitFactory( Grammar g ) |
---|
1587 | { |
---|
1588 | // Generate the method to initialize an ASTFactory when we're |
---|
1589 | // building AST's |
---|
1590 | String param_name = "factory "; |
---|
1591 | if( ! g.buildAST ) |
---|
1592 | param_name = ""; |
---|
1593 | |
---|
1594 | println("void "+ g.getClassName() + "::initializeASTFactory( "+namespaceAntlr+"ASTFactory& "+param_name+")"); |
---|
1595 | println("{"); |
---|
1596 | tabs++; |
---|
1597 | |
---|
1598 | if( g.buildAST ) |
---|
1599 | { |
---|
1600 | // sort out custom AST types... synchronize token manager with token |
---|
1601 | // specs on rules (and other stuff we were able to see from |
---|
1602 | // action.g) (imperfect of course) |
---|
1603 | TokenManager tm = grammar.tokenManager; |
---|
1604 | Enumeration tokens = tm.getTokenSymbolKeys(); |
---|
1605 | while( tokens.hasMoreElements() ) |
---|
1606 | { |
---|
1607 | String tok = (String)tokens.nextElement(); |
---|
1608 | TokenSymbol ts = tm.getTokenSymbol(tok); |
---|
1609 | // if we have a custom type and there's not a more local override |
---|
1610 | // of the tokentype then mark this as the type for the tokentype |
---|
1611 | if( ts.getASTNodeType() != null ) |
---|
1612 | { |
---|
1613 | // ensure capacity with this pseudo vector... |
---|
1614 | astTypes.ensureCapacity(ts.getTokenType()); |
---|
1615 | String type = (String)astTypes.elementAt(ts.getTokenType()); |
---|
1616 | if( type == null ) |
---|
1617 | astTypes.setElementAt(ts.getASTNodeType(),ts.getTokenType()); |
---|
1618 | else |
---|
1619 | { |
---|
1620 | // give a warning over action taken if the types are unequal |
---|
1621 | if( ! ts.getASTNodeType().equals(type) ) |
---|
1622 | { |
---|
1623 | antlrTool.warning("Token "+tok+" taking most specific AST type",grammar.getFilename(),1,1); |
---|
1624 | antlrTool.warning(" using "+type+" ignoring "+ts.getASTNodeType(),grammar.getFilename(),1,1); |
---|
1625 | } |
---|
1626 | } |
---|
1627 | } |
---|
1628 | } |
---|
1629 | // now actually write out all the registered types. (except the default |
---|
1630 | // type. |
---|
1631 | for( int i = 0; i < astTypes.size(); i++ ) |
---|
1632 | { |
---|
1633 | String type = (String)astTypes.elementAt(i); |
---|
1634 | if( type != null ) |
---|
1635 | { |
---|
1636 | println("factory.registerFactory("+i |
---|
1637 | +", \""+type+"\", "+type+"::factory);"); |
---|
1638 | } |
---|
1639 | } |
---|
1640 | println("factory.setMaxNodeType("+grammar.tokenManager.maxTokenType()+");"); |
---|
1641 | } |
---|
1642 | tabs--; |
---|
1643 | println("}"); |
---|
1644 | } |
---|
1645 | // FIXME: and so why are we passing here a g param while inside |
---|
1646 | // we merrily use the global grammar. |
---|
1647 | public void genBody(ParserGrammar g) throws IOException |
---|
1648 | { |
---|
1649 | // Open the output stream for the parser and set the currentOutput |
---|
1650 | outputFile = grammar.getClassName() + ".cpp"; |
---|
1651 | outputLine = 1; |
---|
1652 | currentOutput = antlrTool.openOutputFile(outputFile); |
---|
1653 | |
---|
1654 | genAST = grammar.buildAST; |
---|
1655 | |
---|
1656 | tabs = 0; |
---|
1657 | |
---|
1658 | // Generate the header common to all output files. |
---|
1659 | genHeader(outputFile); |
---|
1660 | |
---|
1661 | printHeaderAction(preIncludeCpp); |
---|
1662 | |
---|
1663 | // Generate header for the parser |
---|
1664 | println("#include \"" + grammar.getClassName() + ".hpp\""); |
---|
1665 | println("#include <antlr/NoViableAltException.hpp>"); |
---|
1666 | println("#include <antlr/SemanticException.hpp>"); |
---|
1667 | println("#include <antlr/ASTFactory.hpp>"); |
---|
1668 | |
---|
1669 | printHeaderAction(postIncludeCpp); |
---|
1670 | |
---|
1671 | if (nameSpace != null) |
---|
1672 | nameSpace.emitDeclarations(currentOutput); |
---|
1673 | |
---|
1674 | // Output the user-defined parser preamble |
---|
1675 | printAction(grammar.preambleAction); |
---|
1676 | |
---|
1677 | String sup=null; |
---|
1678 | if ( grammar.superClass!=null ) |
---|
1679 | sup = grammar.superClass; |
---|
1680 | else { |
---|
1681 | sup = grammar.getSuperClass(); |
---|
1682 | if (sup.lastIndexOf('.') != -1) |
---|
1683 | sup = sup.substring(sup.lastIndexOf('.')+1); |
---|
1684 | sup = namespaceAntlr + sup; |
---|
1685 | } |
---|
1686 | |
---|
1687 | // set up an array of all the rule names so the debugger can |
---|
1688 | // keep track of them only by number -- less to store in tree... |
---|
1689 | if (grammar.debuggingOutput) { |
---|
1690 | println("const char* "+grammar.getClassName()+"::_ruleNames[] = {"); |
---|
1691 | tabs++; |
---|
1692 | |
---|
1693 | Enumeration ids = grammar.rules.elements(); |
---|
1694 | int ruleNum=0; |
---|
1695 | while ( ids.hasMoreElements() ) { |
---|
1696 | GrammarSymbol sym = (GrammarSymbol) ids.nextElement(); |
---|
1697 | if ( sym instanceof RuleSymbol) |
---|
1698 | println("\""+((RuleSymbol)sym).getId()+"\","); |
---|
1699 | } |
---|
1700 | println("0"); |
---|
1701 | tabs--; |
---|
1702 | println("};"); |
---|
1703 | } |
---|
1704 | |
---|
1705 | // Generate _initialize function |
---|
1706 | // disabled since it isn't used anymore.. |
---|
1707 | |
---|
1708 | // println("void " + grammar.getClassName() + "::_initialize(void)"); |
---|
1709 | // println("{"); |
---|
1710 | // tabs++; |
---|
1711 | |
---|
1712 | // if debugging, set up arrays and call the user-overridable |
---|
1713 | // debugging setup method |
---|
1714 | // if ( grammar.debuggingOutput ) { |
---|
1715 | // println("setRuleNames(_ruleNames);"); |
---|
1716 | // println("setSemPredNames(_semPredNames);"); |
---|
1717 | // println("setupDebugging();"); |
---|
1718 | // } |
---|
1719 | // tabs--; |
---|
1720 | // println("}"); |
---|
1721 | if( noConstructors ) |
---|
1722 | { |
---|
1723 | println("#if 0"); |
---|
1724 | println("// constructor creation turned of with 'noConstructor' option"); |
---|
1725 | } |
---|
1726 | |
---|
1727 | // Generate parser class constructor from TokenBuffer |
---|
1728 | print(grammar.getClassName() + "::" + grammar.getClassName()); |
---|
1729 | println("("+namespaceAntlr+"TokenBuffer& tokenBuf, int k)"); |
---|
1730 | println(": " + sup + "(tokenBuf,k)"); |
---|
1731 | println("{"); |
---|
1732 | // tabs++; |
---|
1733 | // println("_initialize();"); |
---|
1734 | // tabs--; |
---|
1735 | println("}"); |
---|
1736 | println(""); |
---|
1737 | |
---|
1738 | print(grammar.getClassName() + "::" + grammar.getClassName()); |
---|
1739 | println("("+namespaceAntlr+"TokenBuffer& tokenBuf)"); |
---|
1740 | println(": " + sup + "(tokenBuf," + grammar.maxk + ")"); |
---|
1741 | println("{"); |
---|
1742 | // tabs++; |
---|
1743 | // println("_initialize();"); |
---|
1744 | // tabs--; |
---|
1745 | println("}"); |
---|
1746 | println(""); |
---|
1747 | |
---|
1748 | // Generate parser class constructor from TokenStream |
---|
1749 | print(grammar.getClassName() + "::" + grammar.getClassName()); |
---|
1750 | println("("+namespaceAntlr+"TokenStream& lexer, int k)"); |
---|
1751 | println(": " + sup + "(lexer,k)"); |
---|
1752 | println("{"); |
---|
1753 | // tabs++; |
---|
1754 | // println("_initialize();"); |
---|
1755 | // tabs--; |
---|
1756 | println("}"); |
---|
1757 | println(""); |
---|
1758 | |
---|
1759 | print(grammar.getClassName() + "::" + grammar.getClassName()); |
---|
1760 | println("("+namespaceAntlr+"TokenStream& lexer)"); |
---|
1761 | println(": " + sup + "(lexer," + grammar.maxk + ")"); |
---|
1762 | println("{"); |
---|
1763 | // tabs++; |
---|
1764 | // println("_initialize();"); |
---|
1765 | // tabs--; |
---|
1766 | println("}"); |
---|
1767 | println(""); |
---|
1768 | |
---|
1769 | print(grammar.getClassName() + "::" + grammar.getClassName()); |
---|
1770 | println("(const "+namespaceAntlr+"ParserSharedInputState& state)"); |
---|
1771 | println(": " + sup + "(state," + grammar.maxk + ")"); |
---|
1772 | println("{"); |
---|
1773 | // tabs++; |
---|
1774 | // println("_initialize();"); |
---|
1775 | // tabs--; |
---|
1776 | println("}"); |
---|
1777 | println(""); |
---|
1778 | |
---|
1779 | if( noConstructors ) |
---|
1780 | { |
---|
1781 | println("// constructor creation turned of with 'noConstructor' option"); |
---|
1782 | println("#endif"); |
---|
1783 | } |
---|
1784 | |
---|
1785 | astTypes = new Vector(); |
---|
1786 | |
---|
1787 | // Generate code for each rule in the grammar |
---|
1788 | Enumeration ids = grammar.rules.elements(); |
---|
1789 | int ruleNum=0; |
---|
1790 | while ( ids.hasMoreElements() ) { |
---|
1791 | GrammarSymbol sym = (GrammarSymbol) ids.nextElement(); |
---|
1792 | if ( sym instanceof RuleSymbol) { |
---|
1793 | RuleSymbol rs = (RuleSymbol)sym; |
---|
1794 | genRule(rs, rs.references.size()==0, ruleNum++, grammar.getClassName() + "::"); |
---|
1795 | } |
---|
1796 | exitIfError(); |
---|
1797 | } |
---|
1798 | |
---|
1799 | genInitFactory( g ); |
---|
1800 | |
---|
1801 | // Generate the token names |
---|
1802 | genTokenStrings(grammar.getClassName() + "::"); |
---|
1803 | |
---|
1804 | // Generate the bitsets used throughout the grammar |
---|
1805 | genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType(), grammar.getClassName() + "::" ); |
---|
1806 | |
---|
1807 | // Generate the semantic predicate map for debugging |
---|
1808 | if (grammar.debuggingOutput) |
---|
1809 | genSemPredMap(grammar.getClassName() + "::"); |
---|
1810 | |
---|
1811 | // Close class definition |
---|
1812 | println(""); |
---|
1813 | println(""); |
---|
1814 | if (nameSpace != null) |
---|
1815 | nameSpace.emitClosures(currentOutput); |
---|
1816 | |
---|
1817 | // Close the parser output stream |
---|
1818 | currentOutput.close(); |
---|
1819 | currentOutput = null; |
---|
1820 | } |
---|
1821 | public void genBody(TreeWalkerGrammar g) throws IOException |
---|
1822 | { |
---|
1823 | // Open the output stream for the parser and set the currentOutput |
---|
1824 | outputFile = grammar.getClassName() + ".cpp"; |
---|
1825 | outputLine = 1; |
---|
1826 | currentOutput = antlrTool.openOutputFile(outputFile); |
---|
1827 | //SAS: changed for proper text file io |
---|
1828 | |
---|
1829 | genAST = grammar.buildAST; |
---|
1830 | tabs = 0; |
---|
1831 | |
---|
1832 | // Generate the header common to all output files. |
---|
1833 | genHeader(outputFile); |
---|
1834 | |
---|
1835 | printHeaderAction(preIncludeCpp); |
---|
1836 | |
---|
1837 | // Generate header for the parser |
---|
1838 | println("#include \"" + grammar.getClassName() + ".hpp\""); |
---|
1839 | println("#include <antlr/Token.hpp>"); |
---|
1840 | println("#include <antlr/AST.hpp>"); |
---|
1841 | println("#include <antlr/NoViableAltException.hpp>"); |
---|
1842 | println("#include <antlr/MismatchedTokenException.hpp>"); |
---|
1843 | println("#include <antlr/SemanticException.hpp>"); |
---|
1844 | println("#include <antlr/BitSet.hpp>"); |
---|
1845 | |
---|
1846 | printHeaderAction(postIncludeCpp); |
---|
1847 | |
---|
1848 | if (nameSpace != null) |
---|
1849 | nameSpace.emitDeclarations(currentOutput); |
---|
1850 | |
---|
1851 | // Output the user-defined parser premamble |
---|
1852 | printAction(grammar.preambleAction); |
---|
1853 | |
---|
1854 | // Generate parser class definition |
---|
1855 | String sup = null; |
---|
1856 | if ( grammar.superClass!=null ) { |
---|
1857 | sup = grammar.superClass; |
---|
1858 | } |
---|
1859 | else { |
---|
1860 | sup = grammar.getSuperClass(); |
---|
1861 | if (sup.lastIndexOf('.') != -1) |
---|
1862 | sup = sup.substring(sup.lastIndexOf('.')+1); |
---|
1863 | sup = namespaceAntlr + sup; |
---|
1864 | } |
---|
1865 | if( noConstructors ) |
---|
1866 | { |
---|
1867 | println("#if 0"); |
---|
1868 | println("// constructor creation turned of with 'noConstructor' option"); |
---|
1869 | } |
---|
1870 | |
---|
1871 | // Generate default parser class constructor |
---|
1872 | println(grammar.getClassName() + "::" + grammar.getClassName() + "()"); |
---|
1873 | println("\t: "+namespaceAntlr+"TreeParser() {"); |
---|
1874 | tabs++; |
---|
1875 | // println("setTokenNames(_tokenNames);"); |
---|
1876 | tabs--; |
---|
1877 | println("}"); |
---|
1878 | |
---|
1879 | if( noConstructors ) |
---|
1880 | { |
---|
1881 | println("// constructor creation turned of with 'noConstructor' option"); |
---|
1882 | println("#endif"); |
---|
1883 | } |
---|
1884 | println(""); |
---|
1885 | |
---|
1886 | astTypes = new Vector(); |
---|
1887 | |
---|
1888 | // Generate code for each rule in the grammar |
---|
1889 | Enumeration ids = grammar.rules.elements(); |
---|
1890 | int ruleNum=0; |
---|
1891 | String ruleNameInits = ""; |
---|
1892 | while ( ids.hasMoreElements() ) { |
---|
1893 | GrammarSymbol sym = (GrammarSymbol) ids.nextElement(); |
---|
1894 | if ( sym instanceof RuleSymbol) { |
---|
1895 | RuleSymbol rs = (RuleSymbol)sym; |
---|
1896 | genRule(rs, rs.references.size()==0, ruleNum++, grammar.getClassName() + "::"); |
---|
1897 | } |
---|
1898 | exitIfError(); |
---|
1899 | } |
---|
1900 | |
---|
1901 | // Generate the ASTFactory initialization function |
---|
1902 | genInitFactory( grammar ); |
---|
1903 | // Generate the token names |
---|
1904 | genTokenStrings(grammar.getClassName() + "::"); |
---|
1905 | |
---|
1906 | // Generate the bitsets used throughout the grammar |
---|
1907 | genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType(), grammar.getClassName() + "::" ); |
---|
1908 | |
---|
1909 | // Close class definition |
---|
1910 | println(""); |
---|
1911 | println(""); |
---|
1912 | |
---|
1913 | if (nameSpace != null) |
---|
1914 | nameSpace.emitClosures(currentOutput); |
---|
1915 | |
---|
1916 | // Close the parser output stream |
---|
1917 | currentOutput.close(); |
---|
1918 | currentOutput = null; |
---|
1919 | } |
---|
1920 | /** Generate a series of case statements that implement a BitSet test. |
---|
1921 | * @param p The Bitset for which cases are to be generated |
---|
1922 | */ |
---|
1923 | protected void genCases(BitSet p) { |
---|
1924 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genCases("+p+")"); |
---|
1925 | int[] elems; |
---|
1926 | |
---|
1927 | elems = p.toArray(); |
---|
1928 | // Wrap cases four-per-line for lexer, one-per-line for parser |
---|
1929 | int wrap = 1; //(grammar instanceof LexerGrammar) ? 4 : 1; |
---|
1930 | int j=1; |
---|
1931 | boolean startOfLine = true; |
---|
1932 | for (int i = 0; i < elems.length; i++) { |
---|
1933 | if (j==1) { |
---|
1934 | print(""); |
---|
1935 | } else { |
---|
1936 | _print(" "); |
---|
1937 | } |
---|
1938 | _print("case " + getValueString(elems[i]) + ":"); |
---|
1939 | |
---|
1940 | if (j==wrap) { |
---|
1941 | _println(""); |
---|
1942 | startOfLine = true; |
---|
1943 | j=1; |
---|
1944 | } |
---|
1945 | else { |
---|
1946 | j++; |
---|
1947 | startOfLine = false; |
---|
1948 | } |
---|
1949 | } |
---|
1950 | if (!startOfLine) { |
---|
1951 | _println(""); |
---|
1952 | } |
---|
1953 | } |
---|
1954 | /** Generate common code for a block of alternatives; return a postscript |
---|
1955 | * that needs to be generated at the end of the block. Other routines |
---|
1956 | * may append else-clauses and such for error checking before the postfix |
---|
1957 | * is generated. |
---|
1958 | * If the grammar is a lexer, then generate alternatives in an order where |
---|
1959 | * alternatives requiring deeper lookahead are generated first, and |
---|
1960 | * EOF in the lookahead set reduces the depth of the lookahead. |
---|
1961 | * @param blk The block to generate |
---|
1962 | * @param noTestForSingle If true, then it does not generate a test for a single alternative. |
---|
1963 | */ |
---|
1964 | public CppBlockFinishingInfo genCommonBlock( |
---|
1965 | AlternativeBlock blk, |
---|
1966 | boolean noTestForSingle ) |
---|
1967 | { |
---|
1968 | int nIF=0; |
---|
1969 | boolean createdLL1Switch = false; |
---|
1970 | int closingBracesOfIFSequence = 0; |
---|
1971 | CppBlockFinishingInfo finishingInfo = new CppBlockFinishingInfo(); |
---|
1972 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genCommonBlk("+blk+")"); |
---|
1973 | |
---|
1974 | // Save the AST generation state, and set it to that of the block |
---|
1975 | boolean savegenAST = genAST; |
---|
1976 | genAST = genAST && blk.getAutoGen(); |
---|
1977 | |
---|
1978 | boolean oldsaveTest = saveText; |
---|
1979 | saveText = saveText && blk.getAutoGen(); |
---|
1980 | |
---|
1981 | // Is this block inverted? If so, generate special-case code |
---|
1982 | if ( blk.not && |
---|
1983 | analyzer.subruleCanBeInverted(blk, grammar instanceof LexerGrammar) ) |
---|
1984 | { |
---|
1985 | Lookahead p = analyzer.look(1, blk); |
---|
1986 | // Variable assignment for labeled elements |
---|
1987 | if (blk.getLabel() != null && syntacticPredLevel == 0) { |
---|
1988 | println(blk.getLabel() + " = " + lt1Value + ";"); |
---|
1989 | } |
---|
1990 | |
---|
1991 | // AST |
---|
1992 | genElementAST(blk); |
---|
1993 | |
---|
1994 | String astArgs=""; |
---|
1995 | if (grammar instanceof TreeWalkerGrammar) { |
---|
1996 | if( usingCustomAST ) |
---|
1997 | astArgs=namespaceAntlr+"RefAST"+"(_t),"; |
---|
1998 | else |
---|
1999 | astArgs="_t,"; |
---|
2000 | } |
---|
2001 | |
---|
2002 | // match the bitset for the alternative |
---|
2003 | println("match(" + astArgs + getBitsetName(markBitsetForGen(p.fset)) + ");"); |
---|
2004 | |
---|
2005 | // tack on tree cursor motion if doing a tree walker |
---|
2006 | if (grammar instanceof TreeWalkerGrammar) |
---|
2007 | { |
---|
2008 | println("_t = _t->getNextSibling();"); |
---|
2009 | } |
---|
2010 | return finishingInfo; |
---|
2011 | } |
---|
2012 | |
---|
2013 | // Special handling for single alt |
---|
2014 | if (blk.getAlternatives().size() == 1) |
---|
2015 | { |
---|
2016 | Alternative alt = blk.getAlternativeAt(0); |
---|
2017 | // Generate a warning if there is a synPred for single alt. |
---|
2018 | if (alt.synPred != null) |
---|
2019 | { |
---|
2020 | antlrTool.warning( |
---|
2021 | "Syntactic predicate superfluous for single alternative", |
---|
2022 | grammar.getFilename(), |
---|
2023 | blk.getAlternativeAt(0).synPred.getLine(), |
---|
2024 | blk.getAlternativeAt(0).synPred.getColumn() |
---|
2025 | ); |
---|
2026 | } |
---|
2027 | if (noTestForSingle) |
---|
2028 | { |
---|
2029 | if (alt.semPred != null) |
---|
2030 | { |
---|
2031 | // Generate validating predicate |
---|
2032 | genSemPred(alt.semPred, blk.line); |
---|
2033 | } |
---|
2034 | genAlt(alt, blk); |
---|
2035 | return finishingInfo; |
---|
2036 | } |
---|
2037 | } |
---|
2038 | |
---|
2039 | // count number of simple LL(1) cases; only do switch for |
---|
2040 | // many LL(1) cases (no preds, no end of token refs) |
---|
2041 | // We don't care about exit paths for (...)*, (...)+ |
---|
2042 | // because we don't explicitly have a test for them |
---|
2043 | // as an alt in the loop. |
---|
2044 | // |
---|
2045 | // Also, we now count how many unicode lookahead sets |
---|
2046 | // there are--they must be moved to DEFAULT or ELSE |
---|
2047 | // clause. |
---|
2048 | |
---|
2049 | int nLL1 = 0; |
---|
2050 | for (int i=0; i<blk.getAlternatives().size(); i++) |
---|
2051 | { |
---|
2052 | Alternative a = blk.getAlternativeAt(i); |
---|
2053 | if ( suitableForCaseExpression(a) ) |
---|
2054 | nLL1++; |
---|
2055 | } |
---|
2056 | |
---|
2057 | // do LL(1) cases |
---|
2058 | if ( nLL1 >= makeSwitchThreshold ) |
---|
2059 | { |
---|
2060 | // Determine the name of the item to be compared |
---|
2061 | String testExpr = lookaheadString(1); |
---|
2062 | createdLL1Switch = true; |
---|
2063 | // when parsing trees, convert null to valid tree node with NULL lookahead |
---|
2064 | if ( grammar instanceof TreeWalkerGrammar ) |
---|
2065 | { |
---|
2066 | println("if (_t == "+labeledElementASTInit+" )"); |
---|
2067 | tabs++; |
---|
2068 | println("_t = ASTNULL;"); |
---|
2069 | tabs--; |
---|
2070 | } |
---|
2071 | println("switch ( "+testExpr+") {"); |
---|
2072 | for (int i=0; i<blk.alternatives.size(); i++) |
---|
2073 | { |
---|
2074 | Alternative alt = blk.getAlternativeAt(i); |
---|
2075 | // ignore any non-LL(1) alts, predicated alts or end-of-token alts |
---|
2076 | // or end-of-token alts for case expressions |
---|
2077 | if ( !suitableForCaseExpression(alt) ) |
---|
2078 | { |
---|
2079 | continue; |
---|
2080 | } |
---|
2081 | Lookahead p = alt.cache[1]; |
---|
2082 | if (p.fset.degree() == 0 && !p.containsEpsilon()) |
---|
2083 | { |
---|
2084 | antlrTool.warning("Alternate omitted due to empty prediction set", |
---|
2085 | grammar.getFilename(), |
---|
2086 | alt.head.getLine(), alt.head.getColumn()); |
---|
2087 | } |
---|
2088 | else |
---|
2089 | { |
---|
2090 | genCases(p.fset); |
---|
2091 | println("{"); |
---|
2092 | tabs++; |
---|
2093 | genAlt(alt, blk); |
---|
2094 | println("break;"); |
---|
2095 | tabs--; |
---|
2096 | println("}"); |
---|
2097 | } |
---|
2098 | } |
---|
2099 | println("default:"); |
---|
2100 | tabs++; |
---|
2101 | } |
---|
2102 | |
---|
2103 | // do non-LL(1) and nondeterministic cases |
---|
2104 | // This is tricky in the lexer, because of cases like: |
---|
2105 | // STAR : '*' ; |
---|
2106 | // ASSIGN_STAR : "*="; |
---|
2107 | // Since nextToken is generated without a loop, then the STAR will |
---|
2108 | // have end-of-token as it's lookahead set for LA(2). So, we must generate the |
---|
2109 | // alternatives containing trailing end-of-token in their lookahead sets *after* |
---|
2110 | // the alternatives without end-of-token. This implements the usual |
---|
2111 | // lexer convention that longer matches come before shorter ones, e.g. |
---|
2112 | // "*=" matches ASSIGN_STAR not STAR |
---|
2113 | // |
---|
2114 | // For non-lexer grammars, this does not sort the alternates by depth |
---|
2115 | // Note that alts whose lookahead is purely end-of-token at k=1 end up |
---|
2116 | // as default or else clauses. |
---|
2117 | int startDepth = (grammar instanceof LexerGrammar) ? grammar.maxk : 0; |
---|
2118 | for (int altDepth = startDepth; altDepth >= 0; altDepth--) { |
---|
2119 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("checking depth "+altDepth); |
---|
2120 | for (int i=0; i<blk.alternatives.size(); i++) { |
---|
2121 | Alternative alt = blk.getAlternativeAt(i); |
---|
2122 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genAlt: "+i); |
---|
2123 | // if we made a switch above, ignore what we already took care |
---|
2124 | // of. Specifically, LL(1) alts with no preds |
---|
2125 | // that do not have end-of-token in their prediction set |
---|
2126 | if ( createdLL1Switch && |
---|
2127 | suitableForCaseExpression(alt) ) |
---|
2128 | { |
---|
2129 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) |
---|
2130 | System.out.println("ignoring alt because it was in the switch"); |
---|
2131 | continue; |
---|
2132 | } |
---|
2133 | String e; |
---|
2134 | |
---|
2135 | boolean unpredicted = false; |
---|
2136 | |
---|
2137 | if (grammar instanceof LexerGrammar) { |
---|
2138 | // Calculate the "effective depth" of the alt, which is the max |
---|
2139 | // depth at which cache[depth]!=end-of-token |
---|
2140 | int effectiveDepth = alt.lookaheadDepth; |
---|
2141 | if (effectiveDepth == GrammarAnalyzer.NONDETERMINISTIC) |
---|
2142 | { |
---|
2143 | // use maximum lookahead |
---|
2144 | effectiveDepth = grammar.maxk; |
---|
2145 | } |
---|
2146 | while ( effectiveDepth >= 1 && |
---|
2147 | alt.cache[effectiveDepth].containsEpsilon() ) |
---|
2148 | { |
---|
2149 | effectiveDepth--; |
---|
2150 | } |
---|
2151 | // Ignore alts whose effective depth is other than the ones we |
---|
2152 | // are generating for this iteration. |
---|
2153 | if (effectiveDepth != altDepth) |
---|
2154 | { |
---|
2155 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) |
---|
2156 | System.out.println("ignoring alt because effectiveDepth!=altDepth;"+effectiveDepth+"!="+altDepth); |
---|
2157 | continue; |
---|
2158 | } |
---|
2159 | unpredicted = lookaheadIsEmpty(alt, effectiveDepth); |
---|
2160 | e = getLookaheadTestExpression(alt, effectiveDepth); |
---|
2161 | } |
---|
2162 | else |
---|
2163 | { |
---|
2164 | unpredicted = lookaheadIsEmpty(alt, grammar.maxk); |
---|
2165 | e = getLookaheadTestExpression(alt, grammar.maxk); |
---|
2166 | } |
---|
2167 | |
---|
2168 | // Was it a big unicode range that forced unsuitability |
---|
2169 | // for a case expression? |
---|
2170 | if ( alt.cache[1].fset.degree() > caseSizeThreshold && |
---|
2171 | suitableForCaseExpression(alt)) |
---|
2172 | { |
---|
2173 | if ( nIF==0 ) |
---|
2174 | { |
---|
2175 | // generate this only for the first if the elseif's |
---|
2176 | // are covered by this one |
---|
2177 | if ( grammar instanceof TreeWalkerGrammar ) { |
---|
2178 | println("if (_t == "+labeledElementASTInit+" )"); |
---|
2179 | tabs++; |
---|
2180 | println("_t = ASTNULL;"); |
---|
2181 | tabs--; |
---|
2182 | } |
---|
2183 | println("if " + e + " {"); |
---|
2184 | } |
---|
2185 | else |
---|
2186 | println("else if " + e + " {"); |
---|
2187 | } |
---|
2188 | else if (unpredicted && |
---|
2189 | alt.semPred==null && |
---|
2190 | alt.synPred==null) |
---|
2191 | { |
---|
2192 | // The alt has empty prediction set and no |
---|
2193 | // predicate to help out. if we have not |
---|
2194 | // generated a previous if, just put {...} around |
---|
2195 | // the end-of-token clause |
---|
2196 | if ( nIF==0 ) { |
---|
2197 | println("{"); |
---|
2198 | } |
---|
2199 | else { |
---|
2200 | println("else {"); |
---|
2201 | } |
---|
2202 | finishingInfo.needAnErrorClause = false; |
---|
2203 | } |
---|
2204 | else |
---|
2205 | { |
---|
2206 | // check for sem and syn preds |
---|
2207 | // Add any semantic predicate expression to the lookahead test |
---|
2208 | if ( alt.semPred != null ) { |
---|
2209 | // if debugging, wrap the evaluation of the predicate in a method |
---|
2210 | // |
---|
2211 | // translate $ and # references |
---|
2212 | ActionTransInfo tInfo = new ActionTransInfo(); |
---|
2213 | String actionStr = processActionForSpecialSymbols(alt.semPred, |
---|
2214 | blk.line, |
---|
2215 | currentRule, |
---|
2216 | tInfo); |
---|
2217 | // ignore translation info...we don't need to do anything with it. |
---|
2218 | |
---|
2219 | // call that will inform SemanticPredicateListeners of the |
---|
2220 | // result |
---|
2221 | if ( grammar.debuggingOutput && |
---|
2222 | ((grammar instanceof ParserGrammar) || (grammar instanceof LexerGrammar)) |
---|
2223 | ) |
---|
2224 | e = "("+e+"&& fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.PREDICTING,"+ //FIXME |
---|
2225 | addSemPred(charFormatter.escapeString(actionStr))+","+actionStr+"))"; |
---|
2226 | else |
---|
2227 | e = "("+e+"&&("+actionStr +"))"; |
---|
2228 | } |
---|
2229 | |
---|
2230 | // Generate any syntactic predicates |
---|
2231 | if ( nIF>0 ) { |
---|
2232 | if ( alt.synPred != null ) { |
---|
2233 | println("else {"); |
---|
2234 | tabs++; |
---|
2235 | genSynPred( alt.synPred, e ); |
---|
2236 | closingBracesOfIFSequence++; |
---|
2237 | } |
---|
2238 | else { |
---|
2239 | println("else if " + e + " {"); |
---|
2240 | } |
---|
2241 | } |
---|
2242 | else { |
---|
2243 | if ( alt.synPred != null ) { |
---|
2244 | genSynPred( alt.synPred, e ); |
---|
2245 | } |
---|
2246 | else { |
---|
2247 | // when parsing trees, convert null to valid tree node |
---|
2248 | // with NULL lookahead. |
---|
2249 | if ( grammar instanceof TreeWalkerGrammar ) { |
---|
2250 | println("if (_t == "+labeledElementASTInit+" )"); |
---|
2251 | tabs++; |
---|
2252 | println("_t = ASTNULL;"); |
---|
2253 | tabs--; |
---|
2254 | } |
---|
2255 | println("if " + e + " {"); |
---|
2256 | } |
---|
2257 | } |
---|
2258 | |
---|
2259 | } |
---|
2260 | |
---|
2261 | nIF++; |
---|
2262 | tabs++; |
---|
2263 | genAlt(alt, blk); |
---|
2264 | tabs--; |
---|
2265 | println("}"); |
---|
2266 | } |
---|
2267 | } |
---|
2268 | String ps = ""; |
---|
2269 | for (int i=1; i<=closingBracesOfIFSequence; i++) { |
---|
2270 | tabs--; // does JavaCodeGenerator need this? |
---|
2271 | ps+="}"; |
---|
2272 | } |
---|
2273 | |
---|
2274 | // Restore the AST generation state |
---|
2275 | genAST = savegenAST; |
---|
2276 | |
---|
2277 | // restore save text state |
---|
2278 | saveText=oldsaveTest; |
---|
2279 | |
---|
2280 | // Return the finishing info. |
---|
2281 | if ( createdLL1Switch ) { |
---|
2282 | tabs--; |
---|
2283 | finishingInfo.postscript = ps+"}"; |
---|
2284 | finishingInfo.generatedSwitch = true; |
---|
2285 | finishingInfo.generatedAnIf = nIF>0; |
---|
2286 | //return new CppBlockFinishingInfo(ps+"}",true,nIF>0); // close up switch statement |
---|
2287 | |
---|
2288 | } |
---|
2289 | else { |
---|
2290 | finishingInfo.postscript = ps; |
---|
2291 | finishingInfo.generatedSwitch = false; |
---|
2292 | finishingInfo.generatedAnIf = nIF>0; |
---|
2293 | //return new CppBlockFinishingInfo(ps, false,nIF>0); |
---|
2294 | } |
---|
2295 | return finishingInfo; |
---|
2296 | } |
---|
2297 | |
---|
2298 | private static boolean suitableForCaseExpression(Alternative a) { |
---|
2299 | return a.lookaheadDepth == 1 && |
---|
2300 | a.semPred == null && |
---|
2301 | !a.cache[1].containsEpsilon() && |
---|
2302 | a.cache[1].fset.degree()<=caseSizeThreshold; |
---|
2303 | } |
---|
2304 | |
---|
2305 | /** Generate code to link an element reference into the AST |
---|
2306 | */ |
---|
2307 | private void genElementAST(AlternativeElement el) { |
---|
2308 | |
---|
2309 | // handle case where you're not building trees, but are in tree walker. |
---|
2310 | // Just need to get labels set up. |
---|
2311 | if ( grammar instanceof TreeWalkerGrammar && !grammar.buildAST ) |
---|
2312 | { |
---|
2313 | String elementRef; |
---|
2314 | String astName; |
---|
2315 | |
---|
2316 | // Generate names and declarations of the AST variable(s) |
---|
2317 | if (el.getLabel() == null) |
---|
2318 | { |
---|
2319 | elementRef = lt1Value; |
---|
2320 | // Generate AST variables for unlabeled stuff |
---|
2321 | astName = "tmp" + astVarNumber + "_AST"; |
---|
2322 | astVarNumber++; |
---|
2323 | // Map the generated AST variable in the alternate |
---|
2324 | mapTreeVariable(el, astName); |
---|
2325 | // Generate an "input" AST variable also |
---|
2326 | println(labeledElementASTType+" "+astName+"_in = "+elementRef+";"); |
---|
2327 | } |
---|
2328 | return; |
---|
2329 | } |
---|
2330 | |
---|
2331 | if (grammar.buildAST && syntacticPredLevel == 0) |
---|
2332 | { |
---|
2333 | boolean needASTDecl = |
---|
2334 | ( genAST && (el.getLabel() != null || |
---|
2335 | el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG )); |
---|
2336 | |
---|
2337 | // RK: if we have a grammar element always generate the decl |
---|
2338 | // since some guy can access it from an action and we can't |
---|
2339 | // peek ahead (well not without making a mess). |
---|
2340 | // I'd prefer taking this out. |
---|
2341 | if( el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG && |
---|
2342 | (el instanceof TokenRefElement) ) |
---|
2343 | needASTDecl = true; |
---|
2344 | |
---|
2345 | boolean doNoGuessTest = |
---|
2346 | ( grammar.hasSyntacticPredicate && needASTDecl ); |
---|
2347 | |
---|
2348 | String elementRef; |
---|
2349 | String astNameBase; |
---|
2350 | |
---|
2351 | // Generate names and declarations of the AST variable(s) |
---|
2352 | if (el.getLabel() != null) |
---|
2353 | { |
---|
2354 | // if the element is labeled use that name... |
---|
2355 | elementRef = el.getLabel(); |
---|
2356 | astNameBase = el.getLabel(); |
---|
2357 | } |
---|
2358 | else |
---|
2359 | { |
---|
2360 | // else generate a temporary name... |
---|
2361 | elementRef = lt1Value; |
---|
2362 | // Generate AST variables for unlabeled stuff |
---|
2363 | astNameBase = "tmp" + astVarNumber; |
---|
2364 | astVarNumber++; |
---|
2365 | } |
---|
2366 | |
---|
2367 | // Generate the declaration if required. |
---|
2368 | if ( needASTDecl ) |
---|
2369 | { |
---|
2370 | if ( el instanceof GrammarAtom ) |
---|
2371 | { |
---|
2372 | GrammarAtom ga = (GrammarAtom)el; |
---|
2373 | if ( ga.getASTNodeType()!=null ) |
---|
2374 | { |
---|
2375 | genASTDeclaration( el, astNameBase, "Ref"+ga.getASTNodeType() ); |
---|
2376 | // println("Ref"+ga.getASTNodeType()+" " + astName + ";"); |
---|
2377 | } |
---|
2378 | else |
---|
2379 | { |
---|
2380 | genASTDeclaration( el, astNameBase, labeledElementASTType ); |
---|
2381 | // println(labeledElementASTType+" " + astName + " = "+labeledElementASTInit+";"); |
---|
2382 | } |
---|
2383 | } |
---|
2384 | else |
---|
2385 | { |
---|
2386 | genASTDeclaration( el, astNameBase, labeledElementASTType ); |
---|
2387 | // println(labeledElementASTType+" " + astName + " = "+labeledElementASTInit+";"); |
---|
2388 | } |
---|
2389 | } |
---|
2390 | |
---|
2391 | // for convenience.. |
---|
2392 | String astName = astNameBase + "_AST"; |
---|
2393 | |
---|
2394 | // Map the generated AST variable in the alternate |
---|
2395 | mapTreeVariable(el, astName); |
---|
2396 | if (grammar instanceof TreeWalkerGrammar) |
---|
2397 | { |
---|
2398 | // Generate an "input" AST variable also |
---|
2399 | println(labeledElementASTType+" " + astName + "_in = "+labeledElementASTInit+";"); |
---|
2400 | } |
---|
2401 | |
---|
2402 | // Enclose actions with !guessing |
---|
2403 | if (doNoGuessTest) { |
---|
2404 | println("if ( inputState->guessing == 0 ) {"); |
---|
2405 | tabs++; |
---|
2406 | } |
---|
2407 | |
---|
2408 | // if something has a label assume it will be used |
---|
2409 | // so we must initialize the RefAST |
---|
2410 | if (el.getLabel() != null) |
---|
2411 | { |
---|
2412 | if ( el instanceof GrammarAtom ) |
---|
2413 | { |
---|
2414 | println(astName + " = "+ |
---|
2415 | getASTCreateString((GrammarAtom)el,elementRef) + ";"); |
---|
2416 | } |
---|
2417 | else |
---|
2418 | { |
---|
2419 | println(astName + " = "+ |
---|
2420 | getASTCreateString(elementRef) + ";"); |
---|
2421 | } |
---|
2422 | } |
---|
2423 | |
---|
2424 | // if it has no label but a declaration exists initialize it. |
---|
2425 | if( el.getLabel() == null && needASTDecl ) |
---|
2426 | { |
---|
2427 | elementRef = lt1Value; |
---|
2428 | if ( el instanceof GrammarAtom ) |
---|
2429 | { |
---|
2430 | println(astName + " = "+ |
---|
2431 | getASTCreateString((GrammarAtom)el,elementRef) + ";"); |
---|
2432 | } |
---|
2433 | else |
---|
2434 | { |
---|
2435 | println(astName + " = "+ |
---|
2436 | getASTCreateString(elementRef) + ";"); |
---|
2437 | } |
---|
2438 | // Map the generated AST variable in the alternate |
---|
2439 | if (grammar instanceof TreeWalkerGrammar) |
---|
2440 | { |
---|
2441 | // set "input" AST variable also |
---|
2442 | println(astName + "_in = " + elementRef + ";"); |
---|
2443 | } |
---|
2444 | } |
---|
2445 | |
---|
2446 | if (genAST) |
---|
2447 | { |
---|
2448 | switch (el.getAutoGenType()) |
---|
2449 | { |
---|
2450 | case GrammarElement.AUTO_GEN_NONE: |
---|
2451 | if( usingCustomAST || |
---|
2452 | (el instanceof GrammarAtom && |
---|
2453 | ((GrammarAtom)el).getASTNodeType() != null) ) |
---|
2454 | println("astFactory->addASTChild(currentAST, "+namespaceAntlr+"RefAST("+ astName + "));"); |
---|
2455 | else |
---|
2456 | println("astFactory->addASTChild(currentAST, "+ astName + ");"); |
---|
2457 | // println("astFactory.addASTChild(currentAST, "+namespaceAntlr+"RefAST(" + astName + "));"); |
---|
2458 | break; |
---|
2459 | case GrammarElement.AUTO_GEN_CARET: |
---|
2460 | if( usingCustomAST || |
---|
2461 | (el instanceof GrammarAtom && |
---|
2462 | ((GrammarAtom)el).getASTNodeType() != null) ) |
---|
2463 | println("astFactory->makeASTRoot(currentAST, "+namespaceAntlr+"RefAST(" + astName + "));"); |
---|
2464 | else |
---|
2465 | println("astFactory->makeASTRoot(currentAST, " + astName + ");"); |
---|
2466 | break; |
---|
2467 | default: |
---|
2468 | break; |
---|
2469 | } |
---|
2470 | } |
---|
2471 | if (doNoGuessTest) |
---|
2472 | { |
---|
2473 | tabs--; |
---|
2474 | println("}"); |
---|
2475 | } |
---|
2476 | } |
---|
2477 | } |
---|
2478 | /** Close the try block and generate catch phrases |
---|
2479 | * if the element has a labeled handler in the rule |
---|
2480 | */ |
---|
2481 | private void genErrorCatchForElement(AlternativeElement el) { |
---|
2482 | if (el.getLabel() == null) return; |
---|
2483 | String r = el.enclosingRuleName; |
---|
2484 | if ( grammar instanceof LexerGrammar ) { |
---|
2485 | r = CodeGenerator.encodeLexerRuleName(el.enclosingRuleName); |
---|
2486 | } |
---|
2487 | RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r); |
---|
2488 | if (rs == null) { |
---|
2489 | antlrTool.panic("Enclosing rule not found!"); |
---|
2490 | } |
---|
2491 | ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel()); |
---|
2492 | if (ex != null) { |
---|
2493 | tabs--; |
---|
2494 | println("}"); |
---|
2495 | genErrorHandler(ex); |
---|
2496 | } |
---|
2497 | } |
---|
2498 | /** Generate the catch phrases for a user-specified error handler */ |
---|
2499 | private void genErrorHandler(ExceptionSpec ex) |
---|
2500 | { |
---|
2501 | // Each ExceptionHandler in the ExceptionSpec is a separate catch |
---|
2502 | for (int i = 0; i < ex.handlers.size(); i++) |
---|
2503 | { |
---|
2504 | ExceptionHandler handler = (ExceptionHandler)ex.handlers.elementAt(i); |
---|
2505 | // Generate catch phrase |
---|
2506 | println("catch (" + handler.exceptionTypeAndName.getText() + ") {"); |
---|
2507 | tabs++; |
---|
2508 | if (grammar.hasSyntacticPredicate) { |
---|
2509 | println("if (inputState->guessing==0) {"); |
---|
2510 | tabs++; |
---|
2511 | } |
---|
2512 | |
---|
2513 | // When not guessing, execute user handler action |
---|
2514 | ActionTransInfo tInfo = new ActionTransInfo(); |
---|
2515 | genLineNo(handler.action); |
---|
2516 | printAction( |
---|
2517 | processActionForSpecialSymbols( handler.action.getText(), |
---|
2518 | handler.action.getLine(), |
---|
2519 | currentRule, tInfo ) |
---|
2520 | ); |
---|
2521 | genLineNo2(); |
---|
2522 | |
---|
2523 | if (grammar.hasSyntacticPredicate) |
---|
2524 | { |
---|
2525 | tabs--; |
---|
2526 | println("} else {"); |
---|
2527 | tabs++; |
---|
2528 | // When guessing, rethrow exception |
---|
2529 | println("throw;"); |
---|
2530 | tabs--; |
---|
2531 | println("}"); |
---|
2532 | } |
---|
2533 | // Close catch phrase |
---|
2534 | tabs--; |
---|
2535 | println("}"); |
---|
2536 | } |
---|
2537 | } |
---|
2538 | /** Generate a try { opening if the element has a labeled handler in the rule */ |
---|
2539 | private void genErrorTryForElement(AlternativeElement el) { |
---|
2540 | if (el.getLabel() == null) return; |
---|
2541 | String r = el.enclosingRuleName; |
---|
2542 | if ( grammar instanceof LexerGrammar ) { |
---|
2543 | r = CodeGenerator.encodeLexerRuleName(el.enclosingRuleName); |
---|
2544 | } |
---|
2545 | RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r); |
---|
2546 | if (rs == null) { |
---|
2547 | antlrTool.panic("Enclosing rule not found!"); |
---|
2548 | } |
---|
2549 | ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel()); |
---|
2550 | if (ex != null) { |
---|
2551 | println("try { // for error handling"); |
---|
2552 | tabs++; |
---|
2553 | } |
---|
2554 | } |
---|
2555 | /** Generate a header that is common to all C++ files */ |
---|
2556 | protected void genHeader(String fileName) |
---|
2557 | { |
---|
2558 | println("/* $ANTLR "+antlrTool.version+": "+ |
---|
2559 | "\""+antlrTool.fileMinusPath(antlrTool.grammarFile)+"\""+ |
---|
2560 | " -> "+ |
---|
2561 | "\""+fileName+"\"$ */"); |
---|
2562 | } |
---|
2563 | |
---|
2564 | // these are unique to C++ mode |
---|
2565 | public void genInclude(LexerGrammar g) throws IOException |
---|
2566 | { |
---|
2567 | outputFile = grammar.getClassName() + ".hpp"; |
---|
2568 | outputLine = 1; |
---|
2569 | currentOutput = antlrTool.openOutputFile(outputFile); |
---|
2570 | //SAS: changed for proper text file io |
---|
2571 | |
---|
2572 | genAST = false; // no way to gen trees. |
---|
2573 | saveText = true; // save consumed characters. |
---|
2574 | |
---|
2575 | tabs=0; |
---|
2576 | |
---|
2577 | // Generate a guard wrapper |
---|
2578 | println("#ifndef INC_"+grammar.getClassName()+"_hpp_"); |
---|
2579 | println("#define INC_"+grammar.getClassName()+"_hpp_"); |
---|
2580 | println(""); |
---|
2581 | |
---|
2582 | printHeaderAction(preIncludeHpp); |
---|
2583 | |
---|
2584 | println("#include <antlr/config.hpp>"); |
---|
2585 | |
---|
2586 | // Generate header common to all C++ output files |
---|
2587 | genHeader(outputFile); |
---|
2588 | |
---|
2589 | // Generate header specific to lexer header file |
---|
2590 | println("#include <antlr/CommonToken.hpp>"); |
---|
2591 | println("#include <antlr/InputBuffer.hpp>"); |
---|
2592 | println("#include <antlr/BitSet.hpp>"); |
---|
2593 | println("#include \"" + grammar.tokenManager.getName() + TokenTypesFileSuffix+".hpp\""); |
---|
2594 | |
---|
2595 | // Find the name of the super class |
---|
2596 | String sup=null; |
---|
2597 | if ( grammar.superClass!=null ) { |
---|
2598 | sup = grammar.superClass; |
---|
2599 | |
---|
2600 | println("\n// Include correct superclass header with a header statement for example:"); |
---|
2601 | println("// header \"post_include_hpp\" {"); |
---|
2602 | println("// #include \""+sup+".hpp\""); |
---|
2603 | println("// }"); |
---|
2604 | println("// Or...."); |
---|
2605 | println("// header {"); |
---|
2606 | println("// #include \""+sup+".hpp\""); |
---|
2607 | println("// }\n"); |
---|
2608 | } |
---|
2609 | else { |
---|
2610 | sup = grammar.getSuperClass(); |
---|
2611 | if (sup.lastIndexOf('.') != -1) |
---|
2612 | sup = sup.substring(sup.lastIndexOf('.')+1); |
---|
2613 | println("#include <antlr/"+sup+".hpp>"); |
---|
2614 | sup = namespaceAntlr + sup; |
---|
2615 | } |
---|
2616 | |
---|
2617 | // Do not use printAction because we assume tabs==0 |
---|
2618 | printHeaderAction(postIncludeHpp); |
---|
2619 | |
---|
2620 | if (nameSpace != null) |
---|
2621 | nameSpace.emitDeclarations(currentOutput); |
---|
2622 | |
---|
2623 | printHeaderAction(""); |
---|
2624 | |
---|
2625 | // print javadoc comment if any |
---|
2626 | if ( grammar.comment!=null ) { |
---|
2627 | _println(grammar.comment); |
---|
2628 | } |
---|
2629 | |
---|
2630 | // Generate lexer class definition |
---|
2631 | print("class CUSTOM_API " + grammar.getClassName() + " : public " + sup); |
---|
2632 | println(", public " + grammar.tokenManager.getName() + TokenTypesFileSuffix); |
---|
2633 | |
---|
2634 | Token tsuffix = (Token)grammar.options.get("classHeaderSuffix"); |
---|
2635 | if ( tsuffix != null ) { |
---|
2636 | String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\""); |
---|
2637 | if ( suffix != null ) { |
---|
2638 | print(", "+suffix); // must be an interface name for Java |
---|
2639 | } |
---|
2640 | } |
---|
2641 | println("{"); |
---|
2642 | |
---|
2643 | // Generate user-defined lexer class members |
---|
2644 | if (grammar.classMemberAction != null) { |
---|
2645 | genLineNo(grammar.classMemberAction); |
---|
2646 | print( |
---|
2647 | processActionForSpecialSymbols(grammar.classMemberAction.getText(), |
---|
2648 | grammar.classMemberAction.getLine(), |
---|
2649 | currentRule, null) |
---|
2650 | ); |
---|
2651 | genLineNo2(); |
---|
2652 | } |
---|
2653 | |
---|
2654 | // Generate initLiterals() method |
---|
2655 | tabs=0; |
---|
2656 | println("private:"); |
---|
2657 | tabs=1; |
---|
2658 | println("void initLiterals();"); |
---|
2659 | |
---|
2660 | // Generate getCaseSensitiveLiterals() method |
---|
2661 | tabs=0; |
---|
2662 | println("public:"); |
---|
2663 | tabs=1; |
---|
2664 | println("bool getCaseSensitiveLiterals() const"); |
---|
2665 | println("{"); |
---|
2666 | tabs++; |
---|
2667 | println("return "+g.caseSensitiveLiterals + ";"); |
---|
2668 | tabs--; |
---|
2669 | println("}"); |
---|
2670 | |
---|
2671 | // Make constructors public |
---|
2672 | tabs=0; |
---|
2673 | println("public:"); |
---|
2674 | tabs=1; |
---|
2675 | |
---|
2676 | if( noConstructors ) |
---|
2677 | { |
---|
2678 | tabs = 0; |
---|
2679 | println("#if 0"); |
---|
2680 | println("// constructor creation turned of with 'noConstructor' option"); |
---|
2681 | tabs = 1; |
---|
2682 | } |
---|
2683 | |
---|
2684 | // Generate the constructor from std::istream |
---|
2685 | println(grammar.getClassName() + "(" + namespaceStd + "istream& in);"); |
---|
2686 | |
---|
2687 | // Generate the constructor from InputBuffer |
---|
2688 | println(grammar.getClassName() + "("+namespaceAntlr+"InputBuffer& ib);"); |
---|
2689 | |
---|
2690 | println(grammar.getClassName() + "(const "+namespaceAntlr+"LexerSharedInputState& state);"); |
---|
2691 | if( noConstructors ) |
---|
2692 | { |
---|
2693 | tabs = 0; |
---|
2694 | println("// constructor creation turned of with 'noConstructor' option"); |
---|
2695 | println("#endif"); |
---|
2696 | tabs = 1; |
---|
2697 | } |
---|
2698 | |
---|
2699 | // Generate nextToken() rule. |
---|
2700 | // nextToken() is a synthetic lexer rule that is the implicit OR of all |
---|
2701 | // user-defined lexer rules. |
---|
2702 | println(namespaceAntlr+"RefToken nextToken();"); |
---|
2703 | |
---|
2704 | // Generate code for each rule in the lexer |
---|
2705 | Enumeration ids = grammar.rules.elements(); |
---|
2706 | while ( ids.hasMoreElements() ) { |
---|
2707 | RuleSymbol sym = (RuleSymbol) ids.nextElement(); |
---|
2708 | // Don't generate the synthetic rules |
---|
2709 | if (!sym.getId().equals("mnextToken")) { |
---|
2710 | genRuleHeader(sym, false); |
---|
2711 | } |
---|
2712 | exitIfError(); |
---|
2713 | } |
---|
2714 | |
---|
2715 | // Make the rest private |
---|
2716 | tabs=0; |
---|
2717 | println("private:"); |
---|
2718 | tabs=1; |
---|
2719 | |
---|
2720 | // generate the rule name array for debugging |
---|
2721 | if ( grammar.debuggingOutput ) { |
---|
2722 | println("static const char* _ruleNames[];"); |
---|
2723 | } |
---|
2724 | |
---|
2725 | // Generate the semantic predicate map for debugging |
---|
2726 | if (grammar.debuggingOutput) |
---|
2727 | println("static const char* _semPredNames[];"); |
---|
2728 | |
---|
2729 | // Generate the bitsets used throughout the lexer |
---|
2730 | genBitsetsHeader(bitsetsUsed, ((LexerGrammar)grammar).charVocabulary.size()); |
---|
2731 | |
---|
2732 | tabs=0; |
---|
2733 | println("};"); |
---|
2734 | println(""); |
---|
2735 | if (nameSpace != null) |
---|
2736 | nameSpace.emitClosures(currentOutput); |
---|
2737 | |
---|
2738 | // Generate a guard wrapper |
---|
2739 | println("#endif /*INC_"+grammar.getClassName()+"_hpp_*/"); |
---|
2740 | |
---|
2741 | // Close the lexer output stream |
---|
2742 | currentOutput.close(); |
---|
2743 | currentOutput = null; |
---|
2744 | } |
---|
2745 | public void genInclude(ParserGrammar g) throws IOException |
---|
2746 | { |
---|
2747 | // Open the output stream for the parser and set the currentOutput |
---|
2748 | outputFile = grammar.getClassName() + ".hpp"; |
---|
2749 | outputLine = 1; |
---|
2750 | currentOutput = antlrTool.openOutputFile(outputFile); |
---|
2751 | //SAS: changed for proper text file io |
---|
2752 | |
---|
2753 | genAST = grammar.buildAST; |
---|
2754 | |
---|
2755 | tabs = 0; |
---|
2756 | |
---|
2757 | // Generate a guard wrapper |
---|
2758 | println("#ifndef INC_"+grammar.getClassName()+"_hpp_"); |
---|
2759 | println("#define INC_"+grammar.getClassName()+"_hpp_"); |
---|
2760 | println(""); |
---|
2761 | printHeaderAction(preIncludeHpp); |
---|
2762 | println("#include <antlr/config.hpp>"); |
---|
2763 | |
---|
2764 | // Generate the header common to all output files. |
---|
2765 | genHeader(outputFile); |
---|
2766 | |
---|
2767 | // Generate header for the parser |
---|
2768 | println("#include <antlr/TokenStream.hpp>"); |
---|
2769 | println("#include <antlr/TokenBuffer.hpp>"); |
---|
2770 | println("#include \"" + grammar.tokenManager.getName() + TokenTypesFileSuffix+".hpp\""); |
---|
2771 | |
---|
2772 | // Generate parser class definition |
---|
2773 | String sup=null; |
---|
2774 | if ( grammar.superClass!=null ) { |
---|
2775 | sup = grammar.superClass; |
---|
2776 | println("\n// Include correct superclass header with a header statement for example:"); |
---|
2777 | println("// header \"post_include_hpp\" {"); |
---|
2778 | println("// #include \""+sup+".hpp\""); |
---|
2779 | println("// }"); |
---|
2780 | println("// Or...."); |
---|
2781 | println("// header {"); |
---|
2782 | println("// #include \""+sup+".hpp\""); |
---|
2783 | println("// }\n"); |
---|
2784 | } |
---|
2785 | else { |
---|
2786 | sup = grammar.getSuperClass(); |
---|
2787 | if (sup.lastIndexOf('.') != -1) |
---|
2788 | sup = sup.substring(sup.lastIndexOf('.')+1); |
---|
2789 | println("#include <antlr/"+sup+".hpp>"); |
---|
2790 | sup = namespaceAntlr + sup; |
---|
2791 | } |
---|
2792 | println(""); |
---|
2793 | |
---|
2794 | // Do not use printAction because we assume tabs==0 |
---|
2795 | printHeaderAction(postIncludeHpp); |
---|
2796 | |
---|
2797 | if (nameSpace != null) |
---|
2798 | nameSpace.emitDeclarations(currentOutput); |
---|
2799 | |
---|
2800 | printHeaderAction(""); |
---|
2801 | |
---|
2802 | // print javadoc comment if any |
---|
2803 | if ( grammar.comment!=null ) { |
---|
2804 | _println(grammar.comment); |
---|
2805 | } |
---|
2806 | |
---|
2807 | // generate the actual class definition |
---|
2808 | print("class CUSTOM_API " + grammar.getClassName() + " : public " + sup); |
---|
2809 | println(", public " + grammar.tokenManager.getName() + TokenTypesFileSuffix); |
---|
2810 | |
---|
2811 | Token tsuffix = (Token)grammar.options.get("classHeaderSuffix"); |
---|
2812 | if ( tsuffix != null ) { |
---|
2813 | String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\""); |
---|
2814 | if ( suffix != null ) |
---|
2815 | print(", "+suffix); // must be an interface name for Java |
---|
2816 | } |
---|
2817 | println("{"); |
---|
2818 | |
---|
2819 | // set up an array of all the rule names so the debugger can |
---|
2820 | // keep track of them only by number -- less to store in tree... |
---|
2821 | if (grammar.debuggingOutput) { |
---|
2822 | println("public: static const char* _ruleNames[];"); |
---|
2823 | } |
---|
2824 | // Generate user-defined parser class members |
---|
2825 | if (grammar.classMemberAction != null) { |
---|
2826 | genLineNo(grammar.classMemberAction.getLine()); |
---|
2827 | print( |
---|
2828 | processActionForSpecialSymbols(grammar.classMemberAction.getText(), |
---|
2829 | grammar.classMemberAction.getLine(), |
---|
2830 | currentRule, null) |
---|
2831 | ); |
---|
2832 | genLineNo2(); |
---|
2833 | } |
---|
2834 | println("public:"); |
---|
2835 | tabs = 1; |
---|
2836 | println("void initializeASTFactory( "+namespaceAntlr+"ASTFactory& factory );"); |
---|
2837 | // println("// called from constructors"); |
---|
2838 | // println("void _initialize( void );"); |
---|
2839 | |
---|
2840 | // Generate parser class constructor from TokenBuffer |
---|
2841 | tabs=0; |
---|
2842 | if( noConstructors ) |
---|
2843 | { |
---|
2844 | println("#if 0"); |
---|
2845 | println("// constructor creation turned of with 'noConstructor' option"); |
---|
2846 | } |
---|
2847 | println("protected:"); |
---|
2848 | tabs=1; |
---|
2849 | println(grammar.getClassName() + "("+namespaceAntlr+"TokenBuffer& tokenBuf, int k);"); |
---|
2850 | tabs=0; |
---|
2851 | println("public:"); |
---|
2852 | tabs=1; |
---|
2853 | println(grammar.getClassName() + "("+namespaceAntlr+"TokenBuffer& tokenBuf);"); |
---|
2854 | |
---|
2855 | // Generate parser class constructor from TokenStream |
---|
2856 | tabs=0; |
---|
2857 | println("protected:"); |
---|
2858 | tabs=1; |
---|
2859 | println(grammar.getClassName()+"("+namespaceAntlr+"TokenStream& lexer, int k);"); |
---|
2860 | tabs=0; |
---|
2861 | println("public:"); |
---|
2862 | tabs=1; |
---|
2863 | println(grammar.getClassName()+"("+namespaceAntlr+"TokenStream& lexer);"); |
---|
2864 | |
---|
2865 | println(grammar.getClassName()+"(const "+namespaceAntlr+"ParserSharedInputState& state);"); |
---|
2866 | if( noConstructors ) |
---|
2867 | { |
---|
2868 | tabs = 0; |
---|
2869 | println("// constructor creation turned of with 'noConstructor' option"); |
---|
2870 | println("#endif"); |
---|
2871 | tabs = 1; |
---|
2872 | } |
---|
2873 | |
---|
2874 | println("int getNumTokens() const"); |
---|
2875 | println("{"); tabs++; |
---|
2876 | println("return "+grammar.getClassName()+"::NUM_TOKENS;"); |
---|
2877 | tabs--; println("}"); |
---|
2878 | println("const char* getTokenName( int type ) const"); |
---|
2879 | println("{"); tabs++; |
---|
2880 | println("if( type > getNumTokens() ) return 0;"); |
---|
2881 | println("return "+grammar.getClassName()+"::tokenNames[type];"); |
---|
2882 | tabs--; println("}"); |
---|
2883 | println("const char* const* getTokenNames() const"); |
---|
2884 | println("{"); tabs++; |
---|
2885 | println("return "+grammar.getClassName()+"::tokenNames;"); |
---|
2886 | tabs--; println("}"); |
---|
2887 | |
---|
2888 | // Generate code for each rule in the grammar |
---|
2889 | Enumeration ids = grammar.rules.elements(); |
---|
2890 | while ( ids.hasMoreElements() ) { |
---|
2891 | GrammarSymbol sym = (GrammarSymbol) ids.nextElement(); |
---|
2892 | if ( sym instanceof RuleSymbol) { |
---|
2893 | RuleSymbol rs = (RuleSymbol)sym; |
---|
2894 | genRuleHeader(rs, rs.references.size()==0); |
---|
2895 | } |
---|
2896 | exitIfError(); |
---|
2897 | } |
---|
2898 | |
---|
2899 | // RK: when we are using a custom ast override Parser::getAST to return |
---|
2900 | // the custom AST type. Ok, this does not work anymore with newer |
---|
2901 | // compilers gcc 3.2.x and up. The reference counter is probably |
---|
2902 | // getting in the way. |
---|
2903 | // So now we just patch the return type back to RefAST |
---|
2904 | tabs = 0; println("public:"); tabs = 1; |
---|
2905 | println(namespaceAntlr+"RefAST getAST()"); |
---|
2906 | println("{"); |
---|
2907 | if( usingCustomAST ) |
---|
2908 | { |
---|
2909 | tabs++; |
---|
2910 | println("return "+namespaceAntlr+"RefAST(returnAST);"); |
---|
2911 | tabs--; |
---|
2912 | } |
---|
2913 | else |
---|
2914 | { |
---|
2915 | tabs++; |
---|
2916 | println("return returnAST;"); |
---|
2917 | tabs--; |
---|
2918 | } |
---|
2919 | println("}"); |
---|
2920 | println(""); |
---|
2921 | |
---|
2922 | tabs=0; println("protected:"); tabs=1; |
---|
2923 | println(labeledElementASTType+" returnAST;"); |
---|
2924 | |
---|
2925 | // Make the rest private |
---|
2926 | tabs=0; |
---|
2927 | println("private:"); |
---|
2928 | tabs=1; |
---|
2929 | |
---|
2930 | // Generate the token names |
---|
2931 | println("static const char* tokenNames[];"); |
---|
2932 | // and how many there are of them |
---|
2933 | _println("#ifndef NO_STATIC_CONSTS"); |
---|
2934 | println("static const int NUM_TOKENS = "+grammar.tokenManager.getVocabulary().size()+";"); |
---|
2935 | _println("#else"); |
---|
2936 | println("enum {"); |
---|
2937 | println("\tNUM_TOKENS = "+grammar.tokenManager.getVocabulary().size()); |
---|
2938 | println("};"); |
---|
2939 | _println("#endif"); |
---|
2940 | |
---|
2941 | // Generate the bitsets used throughout the grammar |
---|
2942 | genBitsetsHeader(bitsetsUsed, grammar.tokenManager.maxTokenType()); |
---|
2943 | |
---|
2944 | // Generate the semantic predicate map for debugging |
---|
2945 | if (grammar.debuggingOutput) |
---|
2946 | println("static const char* _semPredNames[];"); |
---|
2947 | |
---|
2948 | // Close class definition |
---|
2949 | tabs=0; |
---|
2950 | println("};"); |
---|
2951 | println(""); |
---|
2952 | if (nameSpace != null) |
---|
2953 | nameSpace.emitClosures(currentOutput); |
---|
2954 | |
---|
2955 | // Generate a guard wrapper |
---|
2956 | println("#endif /*INC_"+grammar.getClassName()+"_hpp_*/"); |
---|
2957 | |
---|
2958 | // Close the parser output stream |
---|
2959 | currentOutput.close(); |
---|
2960 | currentOutput = null; |
---|
2961 | } |
---|
2962 | public void genInclude(TreeWalkerGrammar g) throws IOException |
---|
2963 | { |
---|
2964 | // Open the output stream for the parser and set the currentOutput |
---|
2965 | outputFile = grammar.getClassName() + ".hpp"; |
---|
2966 | outputLine = 1; |
---|
2967 | currentOutput = antlrTool.openOutputFile(outputFile); |
---|
2968 | //SAS: changed for proper text file io |
---|
2969 | |
---|
2970 | genAST = grammar.buildAST; |
---|
2971 | tabs = 0; |
---|
2972 | |
---|
2973 | // Generate a guard wrapper |
---|
2974 | println("#ifndef INC_"+grammar.getClassName()+"_hpp_"); |
---|
2975 | println("#define INC_"+grammar.getClassName()+"_hpp_"); |
---|
2976 | println(""); |
---|
2977 | printHeaderAction(preIncludeHpp); |
---|
2978 | println("#include <antlr/config.hpp>"); |
---|
2979 | println("#include \"" + grammar.tokenManager.getName() + TokenTypesFileSuffix+".hpp\""); |
---|
2980 | |
---|
2981 | // Generate the header common to all output files. |
---|
2982 | genHeader(outputFile); |
---|
2983 | |
---|
2984 | // Find the name of the super class |
---|
2985 | String sup=null; |
---|
2986 | if ( grammar.superClass!=null ) { |
---|
2987 | sup = grammar.superClass; |
---|
2988 | println("\n// Include correct superclass header with a header statement for example:"); |
---|
2989 | println("// header \"post_include_hpp\" {"); |
---|
2990 | println("// #include \""+sup+".hpp\""); |
---|
2991 | println("// }"); |
---|
2992 | println("// Or...."); |
---|
2993 | println("// header {"); |
---|
2994 | println("// #include \""+sup+".hpp\""); |
---|
2995 | println("// }\n"); |
---|
2996 | } |
---|
2997 | else { |
---|
2998 | sup = grammar.getSuperClass(); |
---|
2999 | if (sup.lastIndexOf('.') != -1) |
---|
3000 | sup = sup.substring(sup.lastIndexOf('.')+1); |
---|
3001 | println("#include <antlr/"+sup+".hpp>"); |
---|
3002 | sup = namespaceAntlr + sup; |
---|
3003 | } |
---|
3004 | println(""); |
---|
3005 | |
---|
3006 | // Generate header for the parser |
---|
3007 | // |
---|
3008 | // Do not use printAction because we assume tabs==0 |
---|
3009 | printHeaderAction(postIncludeHpp); |
---|
3010 | |
---|
3011 | if (nameSpace != null) |
---|
3012 | nameSpace.emitDeclarations(currentOutput); |
---|
3013 | |
---|
3014 | printHeaderAction(""); |
---|
3015 | |
---|
3016 | // print javadoc comment if any |
---|
3017 | if ( grammar.comment!=null ) { |
---|
3018 | _println(grammar.comment); |
---|
3019 | } |
---|
3020 | |
---|
3021 | // Generate parser class definition |
---|
3022 | print("class CUSTOM_API " + grammar.getClassName() + " : public "+sup); |
---|
3023 | println(", public " + grammar.tokenManager.getName() + TokenTypesFileSuffix); |
---|
3024 | |
---|
3025 | Token tsuffix = (Token)grammar.options.get("classHeaderSuffix"); |
---|
3026 | if ( tsuffix != null ) { |
---|
3027 | String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\""); |
---|
3028 | if ( suffix != null ) { |
---|
3029 | print(", "+suffix); // must be an interface name for Java |
---|
3030 | } |
---|
3031 | } |
---|
3032 | println("{"); |
---|
3033 | |
---|
3034 | // Generate user-defined parser class members |
---|
3035 | if (grammar.classMemberAction != null) { |
---|
3036 | genLineNo(grammar.classMemberAction.getLine()); |
---|
3037 | print( |
---|
3038 | processActionForSpecialSymbols(grammar.classMemberAction.getText(), |
---|
3039 | grammar.classMemberAction.getLine(), |
---|
3040 | currentRule, null) |
---|
3041 | ); |
---|
3042 | genLineNo2(); |
---|
3043 | } |
---|
3044 | |
---|
3045 | // Generate default parser class constructor |
---|
3046 | tabs=0; |
---|
3047 | println("public:"); |
---|
3048 | |
---|
3049 | if( noConstructors ) |
---|
3050 | { |
---|
3051 | println("#if 0"); |
---|
3052 | println("// constructor creation turned of with 'noConstructor' option"); |
---|
3053 | } |
---|
3054 | tabs=1; |
---|
3055 | println(grammar.getClassName() + "();"); |
---|
3056 | if( noConstructors ) |
---|
3057 | { |
---|
3058 | tabs = 0; |
---|
3059 | println("#endif"); |
---|
3060 | tabs = 1; |
---|
3061 | } |
---|
3062 | |
---|
3063 | // Generate declaration for the initializeFactory method |
---|
3064 | println("static void initializeASTFactory( "+namespaceAntlr+"ASTFactory& factory );"); |
---|
3065 | |
---|
3066 | println("int getNumTokens() const"); |
---|
3067 | println("{"); tabs++; |
---|
3068 | println("return "+grammar.getClassName()+"::NUM_TOKENS;"); |
---|
3069 | tabs--; println("}"); |
---|
3070 | println("const char* getTokenName( int type ) const"); |
---|
3071 | println("{"); tabs++; |
---|
3072 | println("if( type > getNumTokens() ) return 0;"); |
---|
3073 | println("return "+grammar.getClassName()+"::tokenNames[type];"); |
---|
3074 | tabs--; println("}"); |
---|
3075 | println("const char* const* getTokenNames() const"); |
---|
3076 | println("{"); tabs++; |
---|
3077 | println("return "+grammar.getClassName()+"::tokenNames;"); |
---|
3078 | tabs--; println("}"); |
---|
3079 | |
---|
3080 | // Generate code for each rule in the grammar |
---|
3081 | Enumeration ids = grammar.rules.elements(); |
---|
3082 | String ruleNameInits = ""; |
---|
3083 | while ( ids.hasMoreElements() ) { |
---|
3084 | GrammarSymbol sym = (GrammarSymbol) ids.nextElement(); |
---|
3085 | if ( sym instanceof RuleSymbol) { |
---|
3086 | RuleSymbol rs = (RuleSymbol)sym; |
---|
3087 | genRuleHeader(rs, rs.references.size()==0); |
---|
3088 | } |
---|
3089 | exitIfError(); |
---|
3090 | } |
---|
3091 | tabs = 0; println("public:"); tabs = 1; |
---|
3092 | println(namespaceAntlr+"RefAST getAST()"); |
---|
3093 | println("{"); |
---|
3094 | if( usingCustomAST ) |
---|
3095 | { |
---|
3096 | tabs++; |
---|
3097 | println("return "+namespaceAntlr+"RefAST(returnAST);"); |
---|
3098 | tabs--; |
---|
3099 | } |
---|
3100 | else |
---|
3101 | { |
---|
3102 | tabs++; |
---|
3103 | println("return returnAST;"); |
---|
3104 | tabs--; |
---|
3105 | } |
---|
3106 | println("}"); |
---|
3107 | println(""); |
---|
3108 | |
---|
3109 | tabs=0; println("protected:"); tabs=1; |
---|
3110 | println(labeledElementASTType+" returnAST;"); |
---|
3111 | println(labeledElementASTType+" _retTree;"); |
---|
3112 | |
---|
3113 | // Make the rest private |
---|
3114 | tabs=0; |
---|
3115 | println("private:"); |
---|
3116 | tabs=1; |
---|
3117 | |
---|
3118 | // Generate the token names |
---|
3119 | println("static const char* tokenNames[];"); |
---|
3120 | // and how many there are of them |
---|
3121 | _println("#ifndef NO_STATIC_CONSTS"); |
---|
3122 | println("static const int NUM_TOKENS = "+grammar.tokenManager.getVocabulary().size()+";"); |
---|
3123 | _println("#else"); |
---|
3124 | println("enum {"); |
---|
3125 | println("\tNUM_TOKENS = "+grammar.tokenManager.getVocabulary().size()); |
---|
3126 | println("};"); |
---|
3127 | _println("#endif"); |
---|
3128 | |
---|
3129 | // Generate the bitsets used throughout the grammar |
---|
3130 | genBitsetsHeader(bitsetsUsed, grammar.tokenManager.maxTokenType()); |
---|
3131 | |
---|
3132 | // Close class definition |
---|
3133 | tabs=0; |
---|
3134 | println("};"); |
---|
3135 | println(""); |
---|
3136 | if (nameSpace != null) |
---|
3137 | nameSpace.emitClosures(currentOutput); |
---|
3138 | |
---|
3139 | // Generate a guard wrapper |
---|
3140 | println("#endif /*INC_"+grammar.getClassName()+"_hpp_*/"); |
---|
3141 | |
---|
3142 | // Close the parser output stream |
---|
3143 | currentOutput.close(); |
---|
3144 | currentOutput = null; |
---|
3145 | } |
---|
3146 | /// for convenience |
---|
3147 | protected void genASTDeclaration( AlternativeElement el ) { |
---|
3148 | genASTDeclaration( el, labeledElementASTType ); |
---|
3149 | } |
---|
3150 | /// for convenience |
---|
3151 | protected void genASTDeclaration( AlternativeElement el, String node_type ) { |
---|
3152 | genASTDeclaration( el, el.getLabel(), node_type ); |
---|
3153 | } |
---|
3154 | /// Generate (if not already done) a declaration for the AST for el. |
---|
3155 | protected void genASTDeclaration( AlternativeElement el, String var_name, String node_type ) { |
---|
3156 | // already declared? |
---|
3157 | if( declaredASTVariables.contains(el) ) |
---|
3158 | return; |
---|
3159 | |
---|
3160 | String init = labeledElementASTInit; |
---|
3161 | |
---|
3162 | if (el instanceof GrammarAtom && |
---|
3163 | ((GrammarAtom)el).getASTNodeType() != null ) |
---|
3164 | init = "Ref"+((GrammarAtom)el).getASTNodeType()+"("+labeledElementASTInit+")"; |
---|
3165 | |
---|
3166 | // emit code |
---|
3167 | println(node_type+" " + var_name + "_AST = "+init+";"); |
---|
3168 | |
---|
3169 | // mark as declared |
---|
3170 | declaredASTVariables.put(el, el); |
---|
3171 | } |
---|
3172 | private void genLiteralsTest() { |
---|
3173 | println("_ttype = testLiteralsTable(_ttype);"); |
---|
3174 | } |
---|
3175 | private void genLiteralsTestForPartialToken() { |
---|
3176 | println("_ttype = testLiteralsTable(text.substr(_begin, text.length()-_begin),_ttype);"); |
---|
3177 | } |
---|
3178 | protected void genMatch(BitSet b) { |
---|
3179 | } |
---|
3180 | protected void genMatch(GrammarAtom atom) { |
---|
3181 | if ( atom instanceof StringLiteralElement ) { |
---|
3182 | if ( grammar instanceof LexerGrammar ) { |
---|
3183 | genMatchUsingAtomText(atom); |
---|
3184 | } |
---|
3185 | else { |
---|
3186 | genMatchUsingAtomTokenType(atom); |
---|
3187 | } |
---|
3188 | } |
---|
3189 | else if ( atom instanceof CharLiteralElement ) { |
---|
3190 | // Lexer case is handled in the gen( CharLiteralElement x ) |
---|
3191 | antlrTool.error("cannot ref character literals in grammar: "+atom); |
---|
3192 | } |
---|
3193 | else if ( atom instanceof TokenRefElement ) { |
---|
3194 | genMatchUsingAtomTokenType(atom); |
---|
3195 | } else if (atom instanceof WildcardElement) { |
---|
3196 | gen((WildcardElement)atom); |
---|
3197 | } |
---|
3198 | } |
---|
3199 | protected void genMatchUsingAtomText(GrammarAtom atom) { |
---|
3200 | // match() for trees needs the _t cursor |
---|
3201 | String astArgs=""; |
---|
3202 | if (grammar instanceof TreeWalkerGrammar) { |
---|
3203 | if( usingCustomAST ) |
---|
3204 | astArgs=namespaceAntlr+"RefAST"+"(_t),"; |
---|
3205 | else |
---|
3206 | astArgs="_t,"; |
---|
3207 | } |
---|
3208 | |
---|
3209 | // if in lexer and ! on element, save buffer index to kill later |
---|
3210 | if ( grammar instanceof LexerGrammar && (!saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) { |
---|
3211 | println("_saveIndex = text.length();"); |
---|
3212 | } |
---|
3213 | |
---|
3214 | print(atom.not ? "matchNot(" : "match("); |
---|
3215 | _print(astArgs); |
---|
3216 | |
---|
3217 | // print out what to match |
---|
3218 | if (atom.atomText.equals("EOF")) { |
---|
3219 | // horrible hack to handle EOF case |
---|
3220 | _print(namespaceAntlr+"Token::EOF_TYPE"); |
---|
3221 | } |
---|
3222 | else |
---|
3223 | { |
---|
3224 | if( grammar instanceof LexerGrammar ) // lexer needs special handling |
---|
3225 | { |
---|
3226 | String cppstring = convertJavaToCppString( atom.atomText, false ); |
---|
3227 | _print(cppstring); |
---|
3228 | } |
---|
3229 | else |
---|
3230 | _print(atom.atomText); |
---|
3231 | } |
---|
3232 | |
---|
3233 | _println(");"); |
---|
3234 | |
---|
3235 | if ( grammar instanceof LexerGrammar && (!saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) { |
---|
3236 | println("text.erase(_saveIndex);"); // kill text atom put in buffer |
---|
3237 | } |
---|
3238 | } |
---|
3239 | protected void genMatchUsingAtomTokenType(GrammarAtom atom) { |
---|
3240 | // match() for trees needs the _t cursor |
---|
3241 | String astArgs=""; |
---|
3242 | if (grammar instanceof TreeWalkerGrammar) { |
---|
3243 | if( usingCustomAST ) |
---|
3244 | astArgs=namespaceAntlr+"RefAST"+"(_t),"; |
---|
3245 | else |
---|
3246 | astArgs="_t,"; |
---|
3247 | } |
---|
3248 | |
---|
3249 | // If the literal can be mangled, generate the symbolic constant instead |
---|
3250 | String s = astArgs + getValueString(atom.getType()); |
---|
3251 | |
---|
3252 | // matching |
---|
3253 | println( (atom.not ? "matchNot(" : "match(") + s + ");"); |
---|
3254 | } |
---|
3255 | /** Generate the nextToken() rule. |
---|
3256 | * nextToken() is a synthetic lexer rule that is the implicit OR of all |
---|
3257 | * user-defined lexer rules. |
---|
3258 | * @param RuleBlock |
---|
3259 | */ |
---|
3260 | public void genNextToken() { |
---|
3261 | // Are there any public rules? If not, then just generate a |
---|
3262 | // fake nextToken(). |
---|
3263 | boolean hasPublicRules = false; |
---|
3264 | for (int i = 0; i < grammar.rules.size(); i++) { |
---|
3265 | RuleSymbol rs = (RuleSymbol)grammar.rules.elementAt(i); |
---|
3266 | if ( rs.isDefined() && rs.access.equals("public") ) { |
---|
3267 | hasPublicRules = true; |
---|
3268 | break; |
---|
3269 | } |
---|
3270 | } |
---|
3271 | if (!hasPublicRules) { |
---|
3272 | println(""); |
---|
3273 | println(namespaceAntlr+"RefToken "+grammar.getClassName()+"::nextToken() { return "+namespaceAntlr+"RefToken(new "+namespaceAntlr+"CommonToken("+namespaceAntlr+"Token::EOF_TYPE, \"\")); }"); |
---|
3274 | println(""); |
---|
3275 | return; |
---|
3276 | } |
---|
3277 | |
---|
3278 | // Create the synthesized nextToken() rule |
---|
3279 | RuleBlock nextTokenBlk = MakeGrammar.createNextTokenRule(grammar, grammar.rules, "nextToken"); |
---|
3280 | // Define the nextToken rule symbol |
---|
3281 | RuleSymbol nextTokenRs = new RuleSymbol("mnextToken"); |
---|
3282 | nextTokenRs.setDefined(); |
---|
3283 | nextTokenRs.setBlock(nextTokenBlk); |
---|
3284 | nextTokenRs.access = "private"; |
---|
3285 | grammar.define(nextTokenRs); |
---|
3286 | // Analyze the nextToken rule |
---|
3287 | boolean ok = grammar.theLLkAnalyzer.deterministic(nextTokenBlk); |
---|
3288 | |
---|
3289 | // Generate the next token rule |
---|
3290 | String filterRule=null; |
---|
3291 | if ( ((LexerGrammar)grammar).filterMode ) { |
---|
3292 | filterRule = ((LexerGrammar)grammar).filterRule; |
---|
3293 | } |
---|
3294 | |
---|
3295 | println(""); |
---|
3296 | println(namespaceAntlr+"RefToken "+grammar.getClassName()+"::nextToken()"); |
---|
3297 | println("{"); |
---|
3298 | tabs++; |
---|
3299 | println(namespaceAntlr+"RefToken theRetToken;"); |
---|
3300 | println("for (;;) {"); |
---|
3301 | tabs++; |
---|
3302 | println(namespaceAntlr+"RefToken theRetToken;"); |
---|
3303 | println("int _ttype = "+namespaceAntlr+"Token::INVALID_TYPE;"); |
---|
3304 | if ( ((LexerGrammar)grammar).filterMode ) { |
---|
3305 | println("setCommitToPath(false);"); |
---|
3306 | if ( filterRule!=null ) { |
---|
3307 | // Here's a good place to ensure that the filter rule actually exists |
---|
3308 | if ( !grammar.isDefined(CodeGenerator.encodeLexerRuleName(filterRule)) ) { |
---|
3309 | grammar.antlrTool.error("Filter rule "+filterRule+" does not exist in this lexer"); |
---|
3310 | } |
---|
3311 | else { |
---|
3312 | RuleSymbol rs = (RuleSymbol)grammar.getSymbol(CodeGenerator.encodeLexerRuleName(filterRule)); |
---|
3313 | if ( !rs.isDefined() ) { |
---|
3314 | grammar.antlrTool.error("Filter rule "+filterRule+" does not exist in this lexer"); |
---|
3315 | } |
---|
3316 | else if ( rs.access.equals("public") ) { |
---|
3317 | grammar.antlrTool.error("Filter rule "+filterRule+" must be protected"); |
---|
3318 | } |
---|
3319 | } |
---|
3320 | println("int _m;"); |
---|
3321 | println("_m = mark();"); |
---|
3322 | } |
---|
3323 | } |
---|
3324 | println("resetText();"); |
---|
3325 | |
---|
3326 | // Generate try around whole thing to trap scanner errors |
---|
3327 | println("try { // for lexical and char stream error handling"); |
---|
3328 | tabs++; |
---|
3329 | |
---|
3330 | // Test for public lexical rules with empty paths |
---|
3331 | for (int i=0; i<nextTokenBlk.getAlternatives().size(); i++) { |
---|
3332 | Alternative a = nextTokenBlk.getAlternativeAt(i); |
---|
3333 | if ( a.cache[1].containsEpsilon() ) { |
---|
3334 | antlrTool.warning("found optional path in nextToken()"); |
---|
3335 | } |
---|
3336 | } |
---|
3337 | |
---|
3338 | // Generate the block |
---|
3339 | String newline = System.getProperty("line.separator"); |
---|
3340 | CppBlockFinishingInfo howToFinish = genCommonBlock(nextTokenBlk, false); |
---|
3341 | String errFinish = "if (LA(1)==EOF_CHAR)"+newline+ |
---|
3342 | "\t\t\t\t{"+newline+"\t\t\t\t\tuponEOF();"+newline+ |
---|
3343 | "\t\t\t\t\t_returnToken = makeToken("+namespaceAntlr+"Token::EOF_TYPE);"+ |
---|
3344 | newline+"\t\t\t\t}"; |
---|
3345 | errFinish += newline+"\t\t\t\t"; |
---|
3346 | if ( ((LexerGrammar)grammar).filterMode ) { |
---|
3347 | if ( filterRule==null ) { |
---|
3348 | errFinish += "else {consume(); goto tryAgain;}"; |
---|
3349 | } |
---|
3350 | else { |
---|
3351 | errFinish += "else {"+newline+ |
---|
3352 | "\t\t\t\t\tcommit();"+newline+ |
---|
3353 | "\t\t\t\t\ttry {m"+filterRule+"(false);}"+newline+ |
---|
3354 | "\t\t\t\t\tcatch("+namespaceAntlr+"RecognitionException& e) {"+newline+ |
---|
3355 | "\t\t\t\t\t // catastrophic failure"+newline+ |
---|
3356 | "\t\t\t\t\t reportError(e);"+newline+ |
---|
3357 | "\t\t\t\t\t consume();"+newline+ |
---|
3358 | "\t\t\t\t\t}"+newline+ |
---|
3359 | "\t\t\t\t\tgoto tryAgain;"+newline+ |
---|
3360 | "\t\t\t\t}"; |
---|
3361 | } |
---|
3362 | } |
---|
3363 | else { |
---|
3364 | errFinish += "else {"+throwNoViable+"}"; |
---|
3365 | } |
---|
3366 | genBlockFinish(howToFinish, errFinish); |
---|
3367 | |
---|
3368 | // at this point a valid token has been matched, undo "mark" that was done |
---|
3369 | if ( ((LexerGrammar)grammar).filterMode && filterRule!=null ) { |
---|
3370 | println("commit();"); |
---|
3371 | } |
---|
3372 | |
---|
3373 | // Generate literals test if desired |
---|
3374 | // make sure _ttype is set first; note _returnToken must be |
---|
3375 | // non-null as the rule was required to create it. |
---|
3376 | println("if ( !_returnToken )"+newline+ |
---|
3377 | "\t\t\t\tgoto tryAgain; // found SKIP token"+newline); |
---|
3378 | println("_ttype = _returnToken->getType();"); |
---|
3379 | if ( ((LexerGrammar)grammar).getTestLiterals()) { |
---|
3380 | genLiteralsTest(); |
---|
3381 | } |
---|
3382 | |
---|
3383 | // return token created by rule reference in switch |
---|
3384 | println("_returnToken->setType(_ttype);"); |
---|
3385 | println("return _returnToken;"); |
---|
3386 | |
---|
3387 | // Close try block |
---|
3388 | tabs--; |
---|
3389 | println("}"); |
---|
3390 | println("catch ("+namespaceAntlr+"RecognitionException& e) {"); |
---|
3391 | tabs++; |
---|
3392 | if ( ((LexerGrammar)grammar).filterMode ) { |
---|
3393 | if ( filterRule==null ) { |
---|
3394 | println("if ( !getCommitToPath() ) {"); |
---|
3395 | tabs++; |
---|
3396 | println("consume();"); |
---|
3397 | println("goto tryAgain;"); |
---|
3398 | tabs--; |
---|
3399 | println("}"); |
---|
3400 | } |
---|
3401 | else { |
---|
3402 | println("if ( !getCommitToPath() ) {"); |
---|
3403 | tabs++; |
---|
3404 | println("rewind(_m);"); |
---|
3405 | println("resetText();"); |
---|
3406 | println("try {m"+filterRule+"(false);}"); |
---|
3407 | println("catch("+namespaceAntlr+"RecognitionException& ee) {"); |
---|
3408 | println(" // horrendous failure: error in filter rule"); |
---|
3409 | println(" reportError(ee);"); |
---|
3410 | println(" consume();"); |
---|
3411 | println("}"); |
---|
3412 | // println("goto tryAgain;"); |
---|
3413 | tabs--; |
---|
3414 | println("}"); |
---|
3415 | println("else"); |
---|
3416 | } |
---|
3417 | } |
---|
3418 | if ( nextTokenBlk.getDefaultErrorHandler() ) { |
---|
3419 | println("{"); |
---|
3420 | tabs++; |
---|
3421 | println("reportError(e);"); |
---|
3422 | println("consume();"); |
---|
3423 | tabs--; |
---|
3424 | println("}"); |
---|
3425 | } |
---|
3426 | else { |
---|
3427 | // pass on to invoking routine |
---|
3428 | tabs++; |
---|
3429 | println("throw "+namespaceAntlr+"TokenStreamRecognitionException(e);"); |
---|
3430 | tabs--; |
---|
3431 | } |
---|
3432 | |
---|
3433 | // close CharStreamException try |
---|
3434 | tabs--; |
---|
3435 | println("}"); |
---|
3436 | println("catch ("+namespaceAntlr+"CharStreamIOException& csie) {"); |
---|
3437 | println("\tthrow "+namespaceAntlr+"TokenStreamIOException(csie.io);"); |
---|
3438 | println("}"); |
---|
3439 | println("catch ("+namespaceAntlr+"CharStreamException& cse) {"); |
---|
3440 | println("\tthrow "+namespaceAntlr+"TokenStreamException(cse.getMessage());"); |
---|
3441 | println("}"); |
---|
3442 | |
---|
3443 | // close for-loop |
---|
3444 | _println("tryAgain:;"); |
---|
3445 | tabs--; |
---|
3446 | println("}"); |
---|
3447 | |
---|
3448 | // close method nextToken |
---|
3449 | tabs--; |
---|
3450 | println("}"); |
---|
3451 | println(""); |
---|
3452 | } |
---|
3453 | /** Gen a named rule block. |
---|
3454 | * ASTs are generated for each element of an alternative unless |
---|
3455 | * the rule or the alternative have a '!' modifier. |
---|
3456 | * |
---|
3457 | * If an alternative defeats the default tree construction, it |
---|
3458 | * must set <rule>_AST to the root of the returned AST. |
---|
3459 | * |
---|
3460 | * Each alternative that does automatic tree construction, builds |
---|
3461 | * up root and child list pointers in an ASTPair structure. |
---|
3462 | * |
---|
3463 | * A rule finishes by setting the returnAST variable from the |
---|
3464 | * ASTPair. |
---|
3465 | * |
---|
3466 | * @param rule The name of the rule to generate |
---|
3467 | * @param startSymbol true if the rule is a start symbol (i.e., not referenced elsewhere) |
---|
3468 | */ |
---|
3469 | public void genRule(RuleSymbol s, boolean startSymbol, int ruleNum, String prefix) { |
---|
3470 | // tabs=1; // JavaCodeGenerator needs this |
---|
3471 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genRule("+ s.getId() +")"); |
---|
3472 | if ( !s.isDefined() ) { |
---|
3473 | antlrTool.error("undefined rule: "+ s.getId()); |
---|
3474 | return; |
---|
3475 | } |
---|
3476 | |
---|
3477 | // Generate rule return type, name, arguments |
---|
3478 | RuleBlock rblk = s.getBlock(); |
---|
3479 | |
---|
3480 | currentRule = rblk; |
---|
3481 | currentASTResult = s.getId(); |
---|
3482 | |
---|
3483 | // clear list of declared ast variables.. |
---|
3484 | declaredASTVariables.clear(); |
---|
3485 | |
---|
3486 | // Save the AST generation state, and set it to that of the rule |
---|
3487 | boolean savegenAST = genAST; |
---|
3488 | genAST = genAST && rblk.getAutoGen(); |
---|
3489 | |
---|
3490 | // boolean oldsaveTest = saveText; |
---|
3491 | saveText = rblk.getAutoGen(); |
---|
3492 | |
---|
3493 | // print javadoc comment if any |
---|
3494 | if ( s.comment!=null ) { |
---|
3495 | _println(s.comment); |
---|
3496 | } |
---|
3497 | |
---|
3498 | // Gen method return type (note lexer return action set at rule creation) |
---|
3499 | if (rblk.returnAction != null) |
---|
3500 | { |
---|
3501 | // Has specified return value |
---|
3502 | _print(extractTypeOfAction(rblk.returnAction, rblk.getLine(), rblk.getColumn()) + " "); |
---|
3503 | } else { |
---|
3504 | // No specified return value |
---|
3505 | _print("void "); |
---|
3506 | } |
---|
3507 | |
---|
3508 | // Gen method name |
---|
3509 | _print(prefix + s.getId() + "("); |
---|
3510 | |
---|
3511 | // Additional rule parameters common to all rules for this grammar |
---|
3512 | _print(commonExtraParams); |
---|
3513 | if (commonExtraParams.length() != 0 && rblk.argAction != null ) { |
---|
3514 | _print(","); |
---|
3515 | } |
---|
3516 | |
---|
3517 | // Gen arguments |
---|
3518 | if (rblk.argAction != null) |
---|
3519 | { |
---|
3520 | // Has specified arguments |
---|
3521 | _println(""); |
---|
3522 | // FIXME: make argAction also a token? Hmmmmm |
---|
3523 | // genLineNo(rblk); |
---|
3524 | tabs++; |
---|
3525 | |
---|
3526 | // Process arguments for default arguments |
---|
3527 | // newer gcc's don't accept these in two places (header/cpp) |
---|
3528 | // |
---|
3529 | // Old appraoch with StringBuffer gave trouble with gcj. |
---|
3530 | // |
---|
3531 | // RK: Actually this breaks with string default arguments containing |
---|
3532 | // a comma's or equal signs. Then again the old StringBuffer method |
---|
3533 | // suffered from the same. |
---|
3534 | String oldarg = rblk.argAction; |
---|
3535 | String newarg = ""; |
---|
3536 | |
---|
3537 | String comma = ""; |
---|
3538 | int eqpos = oldarg.indexOf( '=' ); |
---|
3539 | if( eqpos != -1 ) |
---|
3540 | { |
---|
3541 | int cmpos = 0; |
---|
3542 | while( cmpos != -1 && eqpos != -1 ) |
---|
3543 | { |
---|
3544 | newarg = newarg + comma + oldarg.substring( 0, eqpos ).trim(); |
---|
3545 | comma = ", "; |
---|
3546 | cmpos = oldarg.indexOf( ',', eqpos ); |
---|
3547 | if( cmpos != -1 ) |
---|
3548 | { |
---|
3549 | // cut off part we just handled |
---|
3550 | oldarg = oldarg.substring( cmpos+1 ).trim(); |
---|
3551 | eqpos = oldarg.indexOf( '=' ); |
---|
3552 | if( eqpos == -1 ) |
---|
3553 | newarg = newarg+comma+oldarg; |
---|
3554 | } |
---|
3555 | } |
---|
3556 | } |
---|
3557 | else |
---|
3558 | newarg = oldarg; |
---|
3559 | |
---|
3560 | println( newarg ); |
---|
3561 | |
---|
3562 | // println(rblk.argAction); |
---|
3563 | tabs--; |
---|
3564 | print(") "); |
---|
3565 | // genLineNo2(); // gcc gives error on the brace... hope it works for the others too |
---|
3566 | } else { |
---|
3567 | // No specified arguments |
---|
3568 | _print(") "); |
---|
3569 | } |
---|
3570 | _println("{"); |
---|
3571 | tabs++; |
---|
3572 | |
---|
3573 | if (grammar.traceRules) { |
---|
3574 | if ( grammar instanceof TreeWalkerGrammar ) { |
---|
3575 | if ( usingCustomAST ) |
---|
3576 | println("Tracer traceInOut(this,\""+ s.getId() +"\","+namespaceAntlr+"RefAST"+"(_t));"); |
---|
3577 | else |
---|
3578 | println("Tracer traceInOut(this,\""+ s.getId() +"\",_t);"); |
---|
3579 | } |
---|
3580 | else { |
---|
3581 | println("Tracer traceInOut(this, \""+ s.getId() +"\");"); |
---|
3582 | } |
---|
3583 | } |
---|
3584 | |
---|
3585 | // Convert return action to variable declaration |
---|
3586 | if (rblk.returnAction != null) |
---|
3587 | { |
---|
3588 | genLineNo(rblk); |
---|
3589 | println(rblk.returnAction + ";"); |
---|
3590 | genLineNo2(); |
---|
3591 | } |
---|
3592 | |
---|
3593 | // print out definitions needed by rules for various grammar types |
---|
3594 | if (!commonLocalVars.equals("")) |
---|
3595 | println(commonLocalVars); |
---|
3596 | |
---|
3597 | if ( grammar instanceof LexerGrammar ) { |
---|
3598 | // RK: why is this here? It seems not supported in the rest of the |
---|
3599 | // tool. |
---|
3600 | // lexer rule default return value is the rule's token name |
---|
3601 | // This is a horrible hack to support the built-in EOF lexer rule. |
---|
3602 | if (s.getId().equals("mEOF")) |
---|
3603 | println("_ttype = "+namespaceAntlr+"Token::EOF_TYPE;"); |
---|
3604 | else |
---|
3605 | println("_ttype = "+ s.getId().substring(1)+";"); |
---|
3606 | println(namespaceStd+"string::size_type _saveIndex;"); // used for element! (so we can kill text matched for element) |
---|
3607 | /* |
---|
3608 | println("boolean old_saveConsumedInput=saveConsumedInput;"); |
---|
3609 | if ( !rblk.getAutoGen() ) { // turn off "save input" if ! on rule |
---|
3610 | println("saveConsumedInput=false;"); |
---|
3611 | } |
---|
3612 | */ |
---|
3613 | } |
---|
3614 | |
---|
3615 | // if debugging, write code to mark entry to the rule |
---|
3616 | if ( grammar.debuggingOutput) |
---|
3617 | if (grammar instanceof ParserGrammar) |
---|
3618 | println("fireEnterRule(" + ruleNum + ",0);"); |
---|
3619 | else if (grammar instanceof LexerGrammar) |
---|
3620 | println("fireEnterRule(" + ruleNum + ",_ttype);"); |
---|
3621 | |
---|
3622 | // Generate trace code if desired |
---|
3623 | // if ( grammar.debuggingOutput || grammar.traceRules) { |
---|
3624 | // println("try { // debugging"); |
---|
3625 | // tabs++; |
---|
3626 | // } |
---|
3627 | |
---|
3628 | // Initialize AST variables |
---|
3629 | if (grammar instanceof TreeWalkerGrammar) { |
---|
3630 | // "Input" value for rule |
---|
3631 | // println(labeledElementASTType+" " + s.getId() + "_AST_in = "+labeledElementASTType+"(_t);"); |
---|
3632 | println(labeledElementASTType+" " + s.getId() + "_AST_in = (_t == "+labeledElementASTType+"(ASTNULL)) ? "+labeledElementASTInit+" : _t;"); |
---|
3633 | } |
---|
3634 | if (grammar.buildAST) { |
---|
3635 | // Parser member used to pass AST returns from rule invocations |
---|
3636 | println("returnAST = "+labeledElementASTInit+";"); |
---|
3637 | // Tracks AST construction |
---|
3638 | println(namespaceAntlr+"ASTPair currentAST;"); // = new ASTPair();"); |
---|
3639 | // User-settable return value for rule. |
---|
3640 | println(labeledElementASTType+" " + s.getId() + "_AST = "+labeledElementASTInit+";"); |
---|
3641 | } |
---|
3642 | |
---|
3643 | genBlockPreamble(rblk); |
---|
3644 | genBlockInitAction(rblk); |
---|
3645 | println(""); |
---|
3646 | |
---|
3647 | // Search for an unlabeled exception specification attached to the rule |
---|
3648 | ExceptionSpec unlabeledUserSpec = rblk.findExceptionSpec(""); |
---|
3649 | |
---|
3650 | // Generate try block around the entire rule for error handling |
---|
3651 | if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler() ) { |
---|
3652 | println("try { // for error handling"); |
---|
3653 | tabs++; |
---|
3654 | } |
---|
3655 | |
---|
3656 | // Generate the alternatives |
---|
3657 | if ( rblk.alternatives.size()==1 ) |
---|
3658 | { |
---|
3659 | // One alternative -- use simple form |
---|
3660 | Alternative alt = rblk.getAlternativeAt(0); |
---|
3661 | String pred = alt.semPred; |
---|
3662 | if ( pred!=null ) |
---|
3663 | genSemPred(pred, currentRule.line); |
---|
3664 | if (alt.synPred != null) { |
---|
3665 | antlrTool.warning( |
---|
3666 | "Syntactic predicate ignored for single alternative", |
---|
3667 | grammar.getFilename(), |
---|
3668 | alt.synPred.getLine(), |
---|
3669 | alt.synPred.getColumn() |
---|
3670 | ); |
---|
3671 | } |
---|
3672 | genAlt(alt, rblk); |
---|
3673 | } |
---|
3674 | else |
---|
3675 | { |
---|
3676 | // Multiple alternatives -- generate complex form |
---|
3677 | boolean ok = grammar.theLLkAnalyzer.deterministic(rblk); |
---|
3678 | |
---|
3679 | CppBlockFinishingInfo howToFinish = genCommonBlock(rblk, false); |
---|
3680 | genBlockFinish(howToFinish, throwNoViable); |
---|
3681 | } |
---|
3682 | |
---|
3683 | // Generate catch phrase for error handling |
---|
3684 | if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler() ) { |
---|
3685 | // Close the try block |
---|
3686 | tabs--; |
---|
3687 | println("}"); |
---|
3688 | } |
---|
3689 | |
---|
3690 | // Generate user-defined or default catch phrases |
---|
3691 | if (unlabeledUserSpec != null) |
---|
3692 | { |
---|
3693 | genErrorHandler(unlabeledUserSpec); |
---|
3694 | } |
---|
3695 | else if (rblk.getDefaultErrorHandler()) |
---|
3696 | { |
---|
3697 | // Generate default catch phrase |
---|
3698 | println("catch (" + exceptionThrown + "& ex) {"); |
---|
3699 | tabs++; |
---|
3700 | // Generate code to handle error if not guessing |
---|
3701 | if (grammar.hasSyntacticPredicate) { |
---|
3702 | println("if( inputState->guessing == 0 ) {"); |
---|
3703 | tabs++; |
---|
3704 | } |
---|
3705 | println("reportError(ex);"); |
---|
3706 | if ( !(grammar instanceof TreeWalkerGrammar) ) |
---|
3707 | { |
---|
3708 | // Generate code to consume until token in k==1 follow set |
---|
3709 | Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1, rblk.endNode); |
---|
3710 | String followSetName = getBitsetName(markBitsetForGen(follow.fset)); |
---|
3711 | println("recover(ex," + followSetName + ");"); |
---|
3712 | } |
---|
3713 | else |
---|
3714 | { |
---|
3715 | // Just consume one token |
---|
3716 | println("if ( _t != "+labeledElementASTInit+" )"); |
---|
3717 | tabs++; |
---|
3718 | println("_t = _t->getNextSibling();"); |
---|
3719 | tabs--; |
---|
3720 | } |
---|
3721 | if (grammar.hasSyntacticPredicate) |
---|
3722 | { |
---|
3723 | tabs--; |
---|
3724 | // When guessing, rethrow exception |
---|
3725 | println("} else {"); |
---|
3726 | tabs++; |
---|
3727 | println("throw;"); |
---|
3728 | tabs--; |
---|
3729 | println("}"); |
---|
3730 | } |
---|
3731 | // Close catch phrase |
---|
3732 | tabs--; |
---|
3733 | println("}"); |
---|
3734 | } |
---|
3735 | |
---|
3736 | // Squirrel away the AST "return" value |
---|
3737 | if (grammar.buildAST) { |
---|
3738 | println("returnAST = " + s.getId() + "_AST;"); |
---|
3739 | } |
---|
3740 | |
---|
3741 | // Set return tree value for tree walkers |
---|
3742 | if ( grammar instanceof TreeWalkerGrammar ) { |
---|
3743 | println("_retTree = _t;"); |
---|
3744 | } |
---|
3745 | |
---|
3746 | // Generate literals test for lexer rules so marked |
---|
3747 | if (rblk.getTestLiterals()) { |
---|
3748 | if ( s.access.equals("protected") ) { |
---|
3749 | genLiteralsTestForPartialToken(); |
---|
3750 | } |
---|
3751 | else { |
---|
3752 | genLiteralsTest(); |
---|
3753 | } |
---|
3754 | } |
---|
3755 | |
---|
3756 | // if doing a lexer rule, dump code to create token if necessary |
---|
3757 | if ( grammar instanceof LexerGrammar ) { |
---|
3758 | println("if ( _createToken && _token=="+namespaceAntlr+"nullToken && _ttype!="+namespaceAntlr+"Token::SKIP ) {"); |
---|
3759 | println(" _token = makeToken(_ttype);"); |
---|
3760 | println(" _token->setText(text.substr(_begin, text.length()-_begin));"); |
---|
3761 | println("}"); |
---|
3762 | println("_returnToken = _token;"); |
---|
3763 | // It should be easy for an optimizing compiler to realize this does nothing |
---|
3764 | // but it avoids the warning about the variable being unused. |
---|
3765 | println("_saveIndex=0;"); |
---|
3766 | } |
---|
3767 | |
---|
3768 | // Gen the return statement if there is one (lexer has hard-wired return action) |
---|
3769 | if (rblk.returnAction != null) { |
---|
3770 | println("return " + extractIdOfAction(rblk.returnAction, rblk.getLine(), rblk.getColumn()) + ";"); |
---|
3771 | } |
---|
3772 | |
---|
3773 | // if ( grammar.debuggingOutput || grammar.traceRules) { |
---|
3774 | //// tabs--; |
---|
3775 | //// println("} finally { // debugging"); |
---|
3776 | //// tabs++; |
---|
3777 | // |
---|
3778 | // // Generate trace code if desired |
---|
3779 | // if ( grammar.debuggingOutput) |
---|
3780 | // if (grammar instanceof ParserGrammar) |
---|
3781 | // println("fireExitRule(" + ruleNum + ",0);"); |
---|
3782 | // else if (grammar instanceof LexerGrammar) |
---|
3783 | // println("fireExitRule(" + ruleNum + ",_ttype);"); |
---|
3784 | // |
---|
3785 | //// if (grammar.traceRules) { |
---|
3786 | //// if ( grammar instanceof TreeWalkerGrammar ) { |
---|
3787 | //// println("traceOut(\""+ s.getId() +"\",_t);"); |
---|
3788 | //// } |
---|
3789 | //// else { |
---|
3790 | //// println("traceOut(\""+ s.getId() +"\");"); |
---|
3791 | //// } |
---|
3792 | //// } |
---|
3793 | //// |
---|
3794 | //// tabs--; |
---|
3795 | //// println("}"); |
---|
3796 | // } |
---|
3797 | |
---|
3798 | tabs--; |
---|
3799 | println("}"); |
---|
3800 | println(""); |
---|
3801 | |
---|
3802 | // Restore the AST generation state |
---|
3803 | genAST = savegenAST; |
---|
3804 | |
---|
3805 | // restore char save state |
---|
3806 | // saveText = oldsaveTest; |
---|
3807 | } |
---|
3808 | public void genRuleHeader(RuleSymbol s, boolean startSymbol) { |
---|
3809 | tabs=1; |
---|
3810 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genRuleHeader("+ s.getId() +")"); |
---|
3811 | if ( !s.isDefined() ) { |
---|
3812 | antlrTool.error("undefined rule: "+ s.getId()); |
---|
3813 | return; |
---|
3814 | } |
---|
3815 | |
---|
3816 | // Generate rule return type, name, arguments |
---|
3817 | RuleBlock rblk = s.getBlock(); |
---|
3818 | currentRule = rblk; |
---|
3819 | currentASTResult = s.getId(); |
---|
3820 | |
---|
3821 | // Save the AST generation state, and set it to that of the rule |
---|
3822 | boolean savegenAST = genAST; |
---|
3823 | genAST = genAST && rblk.getAutoGen(); |
---|
3824 | |
---|
3825 | // boolean oldsaveTest = saveText; |
---|
3826 | saveText = rblk.getAutoGen(); |
---|
3827 | |
---|
3828 | // Gen method access |
---|
3829 | print(s.access + ": "); |
---|
3830 | |
---|
3831 | // Gen method return type (note lexer return action set at rule creation) |
---|
3832 | if (rblk.returnAction != null) |
---|
3833 | { |
---|
3834 | // Has specified return value |
---|
3835 | _print(extractTypeOfAction(rblk.returnAction, rblk.getLine(), rblk.getColumn()) + " "); |
---|
3836 | } else { |
---|
3837 | // No specified return value |
---|
3838 | _print("void "); |
---|
3839 | } |
---|
3840 | |
---|
3841 | // Gen method name |
---|
3842 | _print(s.getId() + "("); |
---|
3843 | |
---|
3844 | // Additional rule parameters common to all rules for this grammar |
---|
3845 | _print(commonExtraParams); |
---|
3846 | if (commonExtraParams.length() != 0 && rblk.argAction != null ) { |
---|
3847 | _print(","); |
---|
3848 | } |
---|
3849 | |
---|
3850 | // Gen arguments |
---|
3851 | if (rblk.argAction != null) |
---|
3852 | { |
---|
3853 | // Has specified arguments |
---|
3854 | _println(""); |
---|
3855 | tabs++; |
---|
3856 | println(rblk.argAction); |
---|
3857 | tabs--; |
---|
3858 | print(")"); |
---|
3859 | } else { |
---|
3860 | // No specified arguments |
---|
3861 | _print(")"); |
---|
3862 | } |
---|
3863 | _println(";"); |
---|
3864 | |
---|
3865 | tabs--; |
---|
3866 | |
---|
3867 | // Restore the AST generation state |
---|
3868 | genAST = savegenAST; |
---|
3869 | |
---|
3870 | // restore char save state |
---|
3871 | // saveText = oldsaveTest; |
---|
3872 | } |
---|
3873 | private void GenRuleInvocation(RuleRefElement rr) { |
---|
3874 | // dump rule name |
---|
3875 | _print(rr.targetRule + "("); |
---|
3876 | |
---|
3877 | // lexers must tell rule if it should set _returnToken |
---|
3878 | if ( grammar instanceof LexerGrammar ) { |
---|
3879 | // if labeled, could access Token, so tell rule to create |
---|
3880 | if ( rr.getLabel() != null ) { |
---|
3881 | _print("true"); |
---|
3882 | } |
---|
3883 | else { |
---|
3884 | _print("false"); |
---|
3885 | } |
---|
3886 | if (commonExtraArgs.length() != 0 || rr.args!=null ) { |
---|
3887 | _print(","); |
---|
3888 | } |
---|
3889 | } |
---|
3890 | |
---|
3891 | // Extra arguments common to all rules for this grammar |
---|
3892 | _print(commonExtraArgs); |
---|
3893 | if (commonExtraArgs.length() != 0 && rr.args!=null ) { |
---|
3894 | _print(","); |
---|
3895 | } |
---|
3896 | |
---|
3897 | // Process arguments to method, if any |
---|
3898 | RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule); |
---|
3899 | if (rr.args != null) |
---|
3900 | { |
---|
3901 | // When not guessing, execute user arg action |
---|
3902 | ActionTransInfo tInfo = new ActionTransInfo(); |
---|
3903 | // FIXME: fix line number passed to processActionForTreeSpecifiers here.. |
---|
3904 | // this one might be a bit off.. |
---|
3905 | String args = processActionForSpecialSymbols(rr.args, rr.line, |
---|
3906 | currentRule, tInfo); |
---|
3907 | if ( tInfo.assignToRoot || tInfo.refRuleRoot!=null ) |
---|
3908 | { |
---|
3909 | antlrTool.error("Arguments of rule reference '" + rr.targetRule + "' cannot set or ref #"+ |
---|
3910 | currentRule.getRuleName()+" on line "+rr.getLine()); |
---|
3911 | } |
---|
3912 | _print(args); |
---|
3913 | |
---|
3914 | // Warn if the rule accepts no arguments |
---|
3915 | if (rs.block.argAction == null) |
---|
3916 | { |
---|
3917 | antlrTool.warning("Rule '" + rr.targetRule + "' accepts no arguments", |
---|
3918 | grammar.getFilename(), |
---|
3919 | rr.getLine(), rr.getColumn()); |
---|
3920 | } |
---|
3921 | } |
---|
3922 | else |
---|
3923 | { |
---|
3924 | // For C++, no warning if rule has parameters, because there may be default |
---|
3925 | // values for all of the parameters |
---|
3926 | //if (rs.block.argAction != null) { |
---|
3927 | // tool.warning("Missing parameters on reference to rule "+rr.targetRule, rr.getLine()); |
---|
3928 | //} |
---|
3929 | } |
---|
3930 | _println(");"); |
---|
3931 | |
---|
3932 | // move down to the first child while parsing |
---|
3933 | if ( grammar instanceof TreeWalkerGrammar ) { |
---|
3934 | println("_t = _retTree;"); |
---|
3935 | } |
---|
3936 | } |
---|
3937 | protected void genSemPred(String pred, int line) { |
---|
3938 | // translate $ and # references |
---|
3939 | ActionTransInfo tInfo = new ActionTransInfo(); |
---|
3940 | pred = processActionForSpecialSymbols(pred, line, currentRule, tInfo); |
---|
3941 | // ignore translation info...we don't need to do anything with it. |
---|
3942 | String escapedPred = charFormatter.escapeString(pred); |
---|
3943 | |
---|
3944 | // if debugging, wrap the semantic predicate evaluation in a method |
---|
3945 | // that can tell SemanticPredicateListeners the result |
---|
3946 | if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) || |
---|
3947 | (grammar instanceof LexerGrammar))) |
---|
3948 | pred = "fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.VALIDATING," //FIXME |
---|
3949 | + addSemPred(escapedPred) + "," + pred + ")"; |
---|
3950 | println("if (!(" + pred + "))"); |
---|
3951 | tabs++; |
---|
3952 | println("throw "+namespaceAntlr+"SemanticException(\"" + escapedPred + "\");"); |
---|
3953 | tabs--; |
---|
3954 | } |
---|
3955 | /** Write an array of Strings which are the semantic predicate |
---|
3956 | * expressions. The debugger will reference them by number only |
---|
3957 | */ |
---|
3958 | protected void genSemPredMap(String prefix) { |
---|
3959 | Enumeration e = semPreds.elements(); |
---|
3960 | println("const char* " + prefix + "_semPredNames[] = {"); |
---|
3961 | tabs++; |
---|
3962 | while(e.hasMoreElements()) |
---|
3963 | println("\""+e.nextElement()+"\","); |
---|
3964 | println("0"); |
---|
3965 | tabs--; |
---|
3966 | println("};"); |
---|
3967 | } |
---|
3968 | protected void genSynPred(SynPredBlock blk, String lookaheadExpr) { |
---|
3969 | if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("gen=>("+blk+")"); |
---|
3970 | |
---|
3971 | // Dump synpred result variable |
---|
3972 | println("bool synPredMatched" + blk.ID + " = false;"); |
---|
3973 | |
---|
3974 | if( grammar instanceof TreeWalkerGrammar ) { |
---|
3975 | println("if (_t == "+labeledElementASTInit+" )"); |
---|
3976 | tabs++; |
---|
3977 | println("_t = ASTNULL;"); |
---|
3978 | tabs--; |
---|
3979 | } |
---|
3980 | |
---|
3981 | // Gen normal lookahead test |
---|
3982 | println("if (" + lookaheadExpr + ") {"); |
---|
3983 | tabs++; |
---|
3984 | |
---|
3985 | // Save input state |
---|
3986 | if ( grammar instanceof TreeWalkerGrammar ) { |
---|
3987 | println(labeledElementType + " __t" + blk.ID + " = _t;"); |
---|
3988 | } |
---|
3989 | else { |
---|
3990 | println("int _m" + blk.ID + " = mark();"); |
---|
3991 | } |
---|
3992 | |
---|
3993 | // Once inside the try, assume synpred works unless exception caught |
---|
3994 | println("synPredMatched" + blk.ID + " = true;"); |
---|
3995 | println("inputState->guessing++;"); |
---|
3996 | |
---|
3997 | // if debugging, tell listeners that a synpred has started |
---|
3998 | if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) || |
---|
3999 | (grammar instanceof LexerGrammar))) { |
---|
4000 | println("fireSyntacticPredicateStarted();"); |
---|
4001 | } |
---|
4002 | |
---|
4003 | syntacticPredLevel++; |
---|
4004 | println("try {"); |
---|
4005 | tabs++; |
---|
4006 | gen((AlternativeBlock)blk); // gen code to test predicate |
---|
4007 | tabs--; |
---|
4008 | //println("System.out.println(\"pred "+blk+" succeeded\");"); |
---|
4009 | println("}"); |
---|
4010 | println("catch (" + exceptionThrown + "& pe) {"); |
---|
4011 | tabs++; |
---|
4012 | println("synPredMatched"+blk.ID+" = false;"); |
---|
4013 | //println("System.out.println(\"pred "+blk+" failed\");"); |
---|
4014 | tabs--; |
---|
4015 | println("}"); |
---|
4016 | |
---|
4017 | // Restore input state |
---|
4018 | if ( grammar instanceof TreeWalkerGrammar ) { |
---|
4019 | println("_t = __t"+blk.ID+";"); |
---|
4020 | } |
---|
4021 | else { |
---|
4022 | println("rewind(_m"+blk.ID+");"); |
---|
4023 | } |
---|
4024 | |
---|
4025 | println("inputState->guessing--;"); |
---|
4026 | |
---|
4027 | // if debugging, tell listeners how the synpred turned out |
---|
4028 | if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) || |
---|
4029 | (grammar instanceof LexerGrammar))) { |
---|
4030 | println("if (synPredMatched" + blk.ID +")"); |
---|
4031 | println(" fireSyntacticPredicateSucceeded();"); |
---|
4032 | println("else"); |
---|
4033 | println(" fireSyntacticPredicateFailed();"); |
---|
4034 | } |
---|
4035 | |
---|
4036 | syntacticPredLevel--; |
---|
4037 | tabs--; |
---|
4038 | |
---|
4039 | // Close lookahead test |
---|
4040 | println("}"); |
---|
4041 | |
---|
4042 | // Test synpred result |
---|
4043 | println("if ( synPredMatched"+blk.ID+" ) {"); |
---|
4044 | } |
---|
4045 | /** Generate a static array containing the names of the tokens, |
---|
4046 | * indexed by the token type values. This static array is used |
---|
4047 | * to format error messages so that the token identifers or literal |
---|
4048 | * strings are displayed instead of the token numbers. |
---|
4049 | * |
---|
4050 | * If a lexical rule has a paraphrase, use it rather than the |
---|
4051 | * token label. |
---|
4052 | */ |
---|
4053 | public void genTokenStrings(String prefix) { |
---|
4054 | // Generate a string for each token. This creates a static |
---|
4055 | // array of Strings indexed by token type. |
---|
4056 | // println(""); |
---|
4057 | println("const char* " + prefix + "tokenNames[] = {"); |
---|
4058 | tabs++; |
---|
4059 | |
---|
4060 | // Walk the token vocabulary and generate a Vector of strings |
---|
4061 | // from the tokens. |
---|
4062 | Vector v = grammar.tokenManager.getVocabulary(); |
---|
4063 | for (int i = 0; i < v.size(); i++) |
---|
4064 | { |
---|
4065 | String s = (String)v.elementAt(i); |
---|
4066 | if (s == null) |
---|
4067 | { |
---|
4068 | s = "<"+String.valueOf(i)+">"; |
---|
4069 | } |
---|
4070 | if ( !s.startsWith("\"") && !s.startsWith("<") ) { |
---|
4071 | TokenSymbol ts = (TokenSymbol)grammar.tokenManager.getTokenSymbol(s); |
---|
4072 | if ( ts!=null && ts.getParaphrase()!=null ) { |
---|
4073 | s = StringUtils.stripFrontBack(ts.getParaphrase(), "\"", "\""); |
---|
4074 | } |
---|
4075 | } |
---|
4076 | print(charFormatter.literalString(s)); |
---|
4077 | _println(","); |
---|
4078 | } |
---|
4079 | println("0"); |
---|
4080 | |
---|
4081 | // Close the string array initailizer |
---|
4082 | tabs--; |
---|
4083 | println("};"); |
---|
4084 | } |
---|
4085 | /** Generate the token types C++ file */ |
---|
4086 | protected void genTokenTypes(TokenManager tm) throws IOException { |
---|
4087 | // Open the token output header file and set the currentOutput stream |
---|
4088 | outputFile = tm.getName() + TokenTypesFileSuffix+".hpp"; |
---|
4089 | outputLine = 1; |
---|
4090 | currentOutput = antlrTool.openOutputFile(outputFile); |
---|
4091 | //SAS: changed for proper text file io |
---|
4092 | |
---|
4093 | tabs = 0; |
---|
4094 | |
---|
4095 | // Generate a guard wrapper |
---|
4096 | println("#ifndef INC_"+tm.getName()+TokenTypesFileSuffix+"_hpp_"); |
---|
4097 | println("#define INC_"+tm.getName()+TokenTypesFileSuffix+"_hpp_"); |
---|
4098 | println(""); |
---|
4099 | |
---|
4100 | if (nameSpace != null) |
---|
4101 | nameSpace.emitDeclarations(currentOutput); |
---|
4102 | |
---|
4103 | // Generate the header common to all C++ files |
---|
4104 | genHeader(outputFile); |
---|
4105 | |
---|
4106 | // Encapsulate the definitions in an interface. This can be done |
---|
4107 | // because they are all constants. |
---|
4108 | println(""); |
---|
4109 | println("#ifndef CUSTOM_API"); |
---|
4110 | println("# define CUSTOM_API"); |
---|
4111 | println("#endif"); |
---|
4112 | println(""); |
---|
4113 | // In the case that the .hpp is included from C source (flexLexer!) |
---|
4114 | // we just turn things into a plain enum |
---|
4115 | println("#ifdef __cplusplus"); |
---|
4116 | println("struct CUSTOM_API " + tm.getName() + TokenTypesFileSuffix+" {"); |
---|
4117 | println("#endif"); |
---|
4118 | tabs++; |
---|
4119 | println("enum {"); |
---|
4120 | tabs++; |
---|
4121 | |
---|
4122 | // Generate a definition for each token type |
---|
4123 | Vector v = tm.getVocabulary(); |
---|
4124 | |
---|
4125 | // Do special tokens manually |
---|
4126 | println("EOF_ = " + Token.EOF_TYPE + ","); |
---|
4127 | |
---|
4128 | // Move the other special token to the end, so we can solve |
---|
4129 | // the superfluous comma problem easily |
---|
4130 | |
---|
4131 | for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) { |
---|
4132 | String s = (String)v.elementAt(i); |
---|
4133 | if (s != null) { |
---|
4134 | if ( s.startsWith("\"") ) { |
---|
4135 | // a string literal |
---|
4136 | StringLiteralSymbol sl = (StringLiteralSymbol)tm.getTokenSymbol(s); |
---|
4137 | if ( sl==null ) { |
---|
4138 | antlrTool.panic("String literal "+s+" not in symbol table"); |
---|
4139 | } |
---|
4140 | else if ( sl.label != null ) { |
---|
4141 | println(sl.label + " = " + i + ","); |
---|
4142 | } |
---|
4143 | else { |
---|
4144 | String mangledName = mangleLiteral(s); |
---|
4145 | if (mangledName != null) { |
---|
4146 | // We were able to create a meaningful mangled token name |
---|
4147 | println(mangledName + " = " + i + ","); |
---|
4148 | // if no label specified, make the label equal to the mangled name |
---|
4149 | sl.label = mangledName; |
---|
4150 | } |
---|
4151 | else { |
---|
4152 | println("// " + s + " = " + i); |
---|
4153 | } |
---|
4154 | } |
---|
4155 | } |
---|
4156 | else if ( !s.startsWith("<") ) { |
---|
4157 | println(s + " = " + i + ","); |
---|
4158 | } |
---|
4159 | } |
---|
4160 | } |
---|
4161 | |
---|
4162 | // Moved from above |
---|
4163 | println("NULL_TREE_LOOKAHEAD = " + Token.NULL_TREE_LOOKAHEAD); |
---|
4164 | |
---|
4165 | // Close the enum |
---|
4166 | tabs--; |
---|
4167 | println("};"); |
---|
4168 | |
---|
4169 | // Close the interface |
---|
4170 | tabs--; |
---|
4171 | println("#ifdef __cplusplus"); |
---|
4172 | println("};"); |
---|
4173 | println("#endif"); |
---|
4174 | |
---|
4175 | if (nameSpace != null) |
---|
4176 | nameSpace.emitClosures(currentOutput); |
---|
4177 | |
---|
4178 | // Generate a guard wrapper |
---|
4179 | println("#endif /*INC_"+tm.getName()+TokenTypesFileSuffix+"_hpp_*/"); |
---|
4180 | |
---|
4181 | // Close the tokens output file |
---|
4182 | currentOutput.close(); |
---|
4183 | currentOutput = null; |
---|
4184 | exitIfError(); |
---|
4185 | } |
---|
4186 | /** Process a string for an simple expression for use in xx/action.g |
---|
4187 | * it is used to cast simple tokens/references to the right type for |
---|
4188 | * the generated language. Basically called for every element in |
---|
4189 | * the vector to getASTCreateString(vector V) |
---|
4190 | * @param str A String. |
---|
4191 | */ |
---|
4192 | public String processStringForASTConstructor( String str ) |
---|
4193 | { |
---|
4194 | if( usingCustomAST && |
---|
4195 | ((grammar instanceof TreeWalkerGrammar) || |
---|
4196 | (grammar instanceof ParserGrammar)) && |
---|
4197 | !(grammar.tokenManager.tokenDefined(str) ) ) |
---|
4198 | { |
---|
4199 | // System.out.println("processStringForASTConstructor: "+str+" with cast"); |
---|
4200 | return namespaceAntlr+"RefAST("+str+")"; |
---|
4201 | } |
---|
4202 | else |
---|
4203 | { |
---|
4204 | // System.out.println("processStringForASTConstructor: "+str); |
---|
4205 | return str; |
---|
4206 | } |
---|
4207 | } |
---|
4208 | /** Get a string for an expression to generate creation of an AST subtree. |
---|
4209 | * @param v A Vector of String, where each element is an expression |
---|
4210 | * in the target language yielding an AST node. |
---|
4211 | */ |
---|
4212 | public String getASTCreateString(Vector v) { |
---|
4213 | if (v.size() == 0) { |
---|
4214 | return ""; |
---|
4215 | } |
---|
4216 | StringBuffer buf = new StringBuffer(); |
---|
4217 | // the labeledElementASTType here can probably be a cast or nothing |
---|
4218 | // in the case of ! usingCustomAST |
---|
4219 | buf.append(labeledElementASTType+ |
---|
4220 | "(astFactory->make((new "+namespaceAntlr+ |
---|
4221 | "ASTArray("+v.size()+"))"); |
---|
4222 | for (int i = 0; i < v.size(); i++) { |
---|
4223 | buf.append("->add("+ v.elementAt(i) + ")"); |
---|
4224 | } |
---|
4225 | buf.append("))"); |
---|
4226 | return buf.toString(); |
---|
4227 | } |
---|
4228 | /** Get a string for an expression to generate creating of an AST node |
---|
4229 | * @param str The arguments to the AST constructor |
---|
4230 | */ |
---|
4231 | public String getASTCreateString(GrammarAtom atom, String str) { |
---|
4232 | if ( atom!=null && atom.getASTNodeType() != null ) { |
---|
4233 | |
---|
4234 | // this atom is using a heterogeneous AST type. (and maybe a local |
---|
4235 | // override we can't see at the TokenManager level) |
---|
4236 | // make note of the factory needed to generate it.. |
---|
4237 | // later this is inserted into the initializeFactory method. |
---|
4238 | astTypes.ensureCapacity(atom.getType()); |
---|
4239 | String type = (String)astTypes.elementAt(atom.getType()); |
---|
4240 | if( type == null ) |
---|
4241 | astTypes.setElementAt(atom.getASTNodeType(),atom.getType()); |
---|
4242 | else |
---|
4243 | { |
---|
4244 | // give a warning over action taken if the types are unequal |
---|
4245 | if( ! atom.getASTNodeType().equals(type) ) |
---|
4246 | { |
---|
4247 | antlrTool.warning("Attempt to redefine AST type for "+atom.getText(),grammar.getFilename(),atom.getLine(),atom.getColumn()); |
---|
4248 | antlrTool.warning(" from \""+type+"\" to \""+atom.getASTNodeType()+"\" sticking to \""+type+"\"",grammar.getFilename(),atom.getLine(),atom.getColumn()); |
---|
4249 | } |
---|
4250 | else |
---|
4251 | astTypes.setElementAt(atom.getASTNodeType(),atom.getType()); |
---|
4252 | } |
---|
4253 | // after above init the factory knows what to generate... |
---|
4254 | return "astFactory->create("+str+")"; |
---|
4255 | } |
---|
4256 | else |
---|
4257 | { |
---|
4258 | // FIXME: This is *SO* ugly! but it will have to do for now... |
---|
4259 | // 2.7.2 will have better I hope |
---|
4260 | // this is due to the usage of getASTCreateString from inside |
---|
4261 | // actions/cpp/action.g |
---|
4262 | boolean is_constructor = false; |
---|
4263 | if( str.indexOf(',') != -1 ) |
---|
4264 | is_constructor = grammar.tokenManager.tokenDefined(str.substring(0,str.indexOf(','))); |
---|
4265 | |
---|
4266 | // System.out.println("getAstCreateString(as): "+str+" "+grammar.tokenManager.tokenDefined(str)); |
---|
4267 | if( usingCustomAST && |
---|
4268 | (grammar instanceof TreeWalkerGrammar) && |
---|
4269 | !(grammar.tokenManager.tokenDefined(str) ) && |
---|
4270 | ! is_constructor ) |
---|
4271 | return "astFactory->create("+namespaceAntlr+"RefAST("+str+"))"; |
---|
4272 | else |
---|
4273 | return "astFactory->create("+str+")"; |
---|
4274 | } |
---|
4275 | } |
---|
4276 | |
---|
4277 | /** Get a string for an expression to generate creating of an AST node |
---|
4278 | * @param str The arguments to the AST constructor |
---|
4279 | */ |
---|
4280 | public String getASTCreateString(String str) { |
---|
4281 | // System.out.println("getAstCreateString(str): "+str+" "+grammar.tokenManager.tokenDefined(str)); |
---|
4282 | if( usingCustomAST ) |
---|
4283 | return labeledElementASTType+"(astFactory->create("+namespaceAntlr+"RefAST("+str+")))"; |
---|
4284 | else |
---|
4285 | return "astFactory->create("+str+")"; |
---|
4286 | } |
---|
4287 | |
---|
4288 | protected String getLookaheadTestExpression(Lookahead[] look, int k) { |
---|
4289 | StringBuffer e = new StringBuffer(100); |
---|
4290 | boolean first = true; |
---|
4291 | |
---|
4292 | e.append("("); |
---|
4293 | for (int i = 1; i <= k; i++) { |
---|
4294 | BitSet p = look[i].fset; |
---|
4295 | if (!first) { |
---|
4296 | e.append(") && ("); |
---|
4297 | } |
---|
4298 | first = false; |
---|
4299 | |
---|
4300 | // Syn preds can yield <end-of-syn-pred> (epsilon) lookahead. |
---|
4301 | // There is no way to predict what that token would be. Just |
---|
4302 | // allow anything instead. |
---|
4303 | if (look[i].containsEpsilon()) { |
---|
4304 | e.append("true"); |
---|
4305 | } else { |
---|
4306 | e.append(getLookaheadTestTerm(i, p)); |
---|
4307 | } |
---|
4308 | } |
---|
4309 | e.append(")"); |
---|
4310 | |
---|
4311 | return e.toString(); |
---|
4312 | } |
---|
4313 | /** Generate a lookahead test expression for an alternate. This |
---|
4314 | * will be a series of tests joined by '&&' and enclosed by '()', |
---|
4315 | * the number of such tests being determined by the depth of the lookahead. |
---|
4316 | */ |
---|
4317 | protected String getLookaheadTestExpression(Alternative alt, int maxDepth) { |
---|
4318 | int depth = alt.lookaheadDepth; |
---|
4319 | if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) { |
---|
4320 | // if the decision is nondeterministic, do the best we can: LL(k) |
---|
4321 | // any predicates that are around will be generated later. |
---|
4322 | depth = grammar.maxk; |
---|
4323 | } |
---|
4324 | |
---|
4325 | if ( maxDepth==0 ) { |
---|
4326 | // empty lookahead can result from alt with sem pred |
---|
4327 | // that can see end of token. E.g., A : {pred}? ('a')? ; |
---|
4328 | return "true"; |
---|
4329 | } |
---|
4330 | |
---|
4331 | /* |
---|
4332 | boolean first = true; |
---|
4333 | for (int i=1; i<=depth && i<=maxDepth; i++) { |
---|
4334 | BitSet p = alt.cache[i].fset; |
---|
4335 | if (!first) { |
---|
4336 | e.append(") && ("); |
---|
4337 | } |
---|
4338 | first = false; |
---|
4339 | |
---|
4340 | // Syn preds can yield <end-of-syn-pred> (epsilon) lookahead. |
---|
4341 | // There is no way to predict what that token would be. Just |
---|
4342 | // allow anything instead. |
---|
4343 | if ( alt.cache[i].containsEpsilon() ) { |
---|
4344 | e.append("true"); |
---|
4345 | } |
---|
4346 | else { |
---|
4347 | e.append(getLookaheadTestTerm(i, p)); |
---|
4348 | } |
---|
4349 | } |
---|
4350 | |
---|
4351 | e.append(")"); |
---|
4352 | */ |
---|
4353 | |
---|
4354 | return "(" + getLookaheadTestExpression(alt.cache,depth) + ")"; |
---|
4355 | } |
---|
4356 | /**Generate a depth==1 lookahead test expression given the BitSet. |
---|
4357 | * This may be one of: |
---|
4358 | * 1) a series of 'x==X||' tests |
---|
4359 | * 2) a range test using >= && <= where possible, |
---|
4360 | * 3) a bitset membership test for complex comparisons |
---|
4361 | * @param k The lookahead level |
---|
4362 | * @param p The lookahead set for level k |
---|
4363 | */ |
---|
4364 | protected String getLookaheadTestTerm(int k, BitSet p) { |
---|
4365 | // Determine the name of the item to be compared |
---|
4366 | String ts = lookaheadString(k); |
---|
4367 | |
---|
4368 | // Generate a range expression if possible |
---|
4369 | int[] elems = p.toArray(); |
---|
4370 | if (elementsAreRange(elems)) { |
---|
4371 | return getRangeExpression(k, elems); |
---|
4372 | } |
---|
4373 | |
---|
4374 | // Generate a bitset membership test if possible |
---|
4375 | StringBuffer e; |
---|
4376 | int degree = p.degree(); |
---|
4377 | if ( degree == 0 ) { |
---|
4378 | return "true"; |
---|
4379 | } |
---|
4380 | |
---|
4381 | if (degree >= bitsetTestThreshold) { |
---|
4382 | int bitsetIdx = markBitsetForGen(p); |
---|
4383 | return getBitsetName(bitsetIdx) + ".member(" + ts + ")"; |
---|
4384 | } |
---|
4385 | |
---|
4386 | // Otherwise, generate the long-winded series of "x==X||" tests |
---|
4387 | e = new StringBuffer(); |
---|
4388 | for (int i = 0; i < elems.length; i++) { |
---|
4389 | // Get the compared-to item (token or character value) |
---|
4390 | String cs = getValueString(elems[i]); |
---|
4391 | |
---|
4392 | // Generate the element comparison |
---|
4393 | if( i > 0 ) e.append(" || "); |
---|
4394 | e.append(ts); |
---|
4395 | e.append(" == "); |
---|
4396 | e.append(cs); |
---|
4397 | } |
---|
4398 | return e.toString(); |
---|
4399 | } |
---|
4400 | /** Return an expression for testing a contiguous renage of elements |
---|
4401 | * @param k The lookahead level |
---|
4402 | * @param elems The elements representing the set, usually from BitSet.toArray(). |
---|
4403 | * @return String containing test expression. |
---|
4404 | */ |
---|
4405 | public String getRangeExpression(int k, int[] elems) { |
---|
4406 | if (!elementsAreRange(elems)) { |
---|
4407 | antlrTool.panic("getRangeExpression called with non-range"); |
---|
4408 | } |
---|
4409 | int begin = elems[0]; |
---|
4410 | int end = elems[elems.length-1]; |
---|
4411 | return |
---|
4412 | "(" + lookaheadString(k) + " >= " + getValueString(begin) + " && " + |
---|
4413 | lookaheadString(k) + " <= " + getValueString(end) + ")"; |
---|
4414 | } |
---|
4415 | /** getValueString: get a string representation of a token or char value |
---|
4416 | * @param value The token or char value |
---|
4417 | */ |
---|
4418 | private String getValueString(int value) { |
---|
4419 | String cs; |
---|
4420 | if ( grammar instanceof LexerGrammar ) { |
---|
4421 | cs = charFormatter.literalChar(value); |
---|
4422 | } |
---|
4423 | else |
---|
4424 | { |
---|
4425 | TokenSymbol ts = grammar.tokenManager.getTokenSymbolAt(value); |
---|
4426 | if ( ts == null ) { |
---|
4427 | return ""+value; // return token type as string |
---|
4428 | // tool.panic("vocabulary for token type " + value + " is null"); |
---|
4429 | } |
---|
4430 | String tId = ts.getId(); |
---|
4431 | if ( ts instanceof StringLiteralSymbol ) { |
---|
4432 | // if string literal, use predefined label if any |
---|
4433 | // if no predefined, try to mangle into LITERAL_xxx. |
---|
4434 | // if can't mangle, use int value as last resort |
---|
4435 | StringLiteralSymbol sl = (StringLiteralSymbol)ts; |
---|
4436 | String label = sl.getLabel(); |
---|
4437 | if ( label!=null ) { |
---|
4438 | cs = label; |
---|
4439 | } |
---|
4440 | else { |
---|
4441 | cs = mangleLiteral(tId); |
---|
4442 | if (cs == null) { |
---|
4443 | cs = String.valueOf(value); |
---|
4444 | } |
---|
4445 | } |
---|
4446 | } |
---|
4447 | else { |
---|
4448 | if ( tId.equals("EOF") ) |
---|
4449 | cs = namespaceAntlr+"Token::EOF_TYPE"; |
---|
4450 | else |
---|
4451 | cs = tId; |
---|
4452 | } |
---|
4453 | } |
---|
4454 | return cs; |
---|
4455 | } |
---|
4456 | /**Is the lookahead for this alt empty? */ |
---|
4457 | protected boolean lookaheadIsEmpty(Alternative alt, int maxDepth) { |
---|
4458 | int depth = alt.lookaheadDepth; |
---|
4459 | if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) { |
---|
4460 | depth = grammar.maxk; |
---|
4461 | } |
---|
4462 | for (int i=1; i<=depth && i<=maxDepth; i++) { |
---|
4463 | BitSet p = alt.cache[i].fset; |
---|
4464 | if (p.degree() != 0) { |
---|
4465 | return false; |
---|
4466 | } |
---|
4467 | } |
---|
4468 | return true; |
---|
4469 | } |
---|
4470 | private String lookaheadString(int k) { |
---|
4471 | if (grammar instanceof TreeWalkerGrammar) { |
---|
4472 | return "_t->getType()"; |
---|
4473 | } |
---|
4474 | return "LA(" + k + ")"; |
---|
4475 | } |
---|
4476 | /** Mangle a string literal into a meaningful token name. This is |
---|
4477 | * only possible for literals that are all characters. The resulting |
---|
4478 | * mangled literal name is literalsPrefix with the text of the literal |
---|
4479 | * appended. |
---|
4480 | * @return A string representing the mangled literal, or null if not possible. |
---|
4481 | */ |
---|
4482 | private String mangleLiteral(String s) { |
---|
4483 | String mangled = antlrTool.literalsPrefix; |
---|
4484 | for (int i = 1; i < s.length()-1; i++) { |
---|
4485 | if (!Character.isLetter(s.charAt(i)) && |
---|
4486 | s.charAt(i) != '_') { |
---|
4487 | return null; |
---|
4488 | } |
---|
4489 | mangled += s.charAt(i); |
---|
4490 | } |
---|
4491 | if ( antlrTool.upperCaseMangledLiterals ) { |
---|
4492 | mangled = mangled.toUpperCase(); |
---|
4493 | } |
---|
4494 | return mangled; |
---|
4495 | } |
---|
4496 | /** Map an identifier to it's corresponding tree-node variable. |
---|
4497 | * This is context-sensitive, depending on the rule and alternative |
---|
4498 | * being generated |
---|
4499 | * @param idParam The identifier name to map |
---|
4500 | * @return The mapped id (which may be the same as the input), or null if the mapping is invalid due to duplicates |
---|
4501 | */ |
---|
4502 | public String mapTreeId(String idParam, ActionTransInfo transInfo) { |
---|
4503 | // if not in an action of a rule, nothing to map. |
---|
4504 | if ( currentRule==null ) return idParam; |
---|
4505 | // System.out.print("mapTreeId: "+idParam+" "+currentRule.getRuleName()+" "); |
---|
4506 | |
---|
4507 | boolean in_var = false; |
---|
4508 | String id = idParam; |
---|
4509 | if (grammar instanceof TreeWalkerGrammar) |
---|
4510 | { |
---|
4511 | // RK: hmmm this seems odd. If buildAST is false it translates |
---|
4512 | // #rulename_in to 'rulename_in' else to 'rulename_AST_in' which indeed |
---|
4513 | // exists. disabling for now.. and hope it doesn't blow up somewhere. |
---|
4514 | if ( !grammar.buildAST ) |
---|
4515 | { |
---|
4516 | in_var = true; |
---|
4517 | // System.out.println("in_var1"); |
---|
4518 | } |
---|
4519 | // If the id ends with "_in", then map it to the input variable |
---|
4520 | // else |
---|
4521 | if (id.length() > 3 && id.lastIndexOf("_in") == id.length()-3) |
---|
4522 | { |
---|
4523 | // Strip off the "_in" |
---|
4524 | id = id.substring(0, id.length()-3); |
---|
4525 | in_var = true; |
---|
4526 | // System.out.println("in_var2"); |
---|
4527 | } |
---|
4528 | } |
---|
4529 | // System.out.print(in_var+"\t"); |
---|
4530 | |
---|
4531 | // Check the rule labels. If id is a label, then the output |
---|
4532 | // variable is label_AST, and the input variable is plain label. |
---|
4533 | for (int i = 0; i < currentRule.labeledElements.size(); i++) |
---|
4534 | { |
---|
4535 | AlternativeElement elt = (AlternativeElement)currentRule.labeledElements.elementAt(i); |
---|
4536 | if (elt.getLabel().equals(id)) |
---|
4537 | { |
---|
4538 | // if( in_var ) |
---|
4539 | // System.out.println("returning (vec) "+(in_var ? id : id + "_AST")); |
---|
4540 | return in_var ? id : id + "_AST"; |
---|
4541 | } |
---|
4542 | } |
---|
4543 | |
---|
4544 | // Failing that, check the id-to-variable map for the alternative. |
---|
4545 | // If the id is in the map, then output variable is the name in the |
---|
4546 | // map, and input variable is name_in |
---|
4547 | String s = (String)treeVariableMap.get(id); |
---|
4548 | if (s != null) |
---|
4549 | { |
---|
4550 | if (s == NONUNIQUE) |
---|
4551 | { |
---|
4552 | // if( in_var ) |
---|
4553 | // System.out.println("returning null (nonunique)"); |
---|
4554 | // There is more than one element with this id |
---|
4555 | antlrTool.error("Ambiguous reference to AST element "+id+ |
---|
4556 | " in rule "+currentRule.getRuleName()); |
---|
4557 | return null; |
---|
4558 | } |
---|
4559 | else if (s.equals(currentRule.getRuleName())) |
---|
4560 | { |
---|
4561 | // a recursive call to the enclosing rule is |
---|
4562 | // ambiguous with the rule itself. |
---|
4563 | // if( in_var ) |
---|
4564 | // System.out.println("returning null (rulename)"); |
---|
4565 | antlrTool.error("Ambiguous reference to AST element "+id+ |
---|
4566 | " in rule "+currentRule.getRuleName()); |
---|
4567 | return null; |
---|
4568 | } |
---|
4569 | else |
---|
4570 | { |
---|
4571 | // if( in_var ) |
---|
4572 | // System.out.println("returning "+(in_var?s+"_in":s)); |
---|
4573 | return in_var ? s + "_in" : s; |
---|
4574 | } |
---|
4575 | } |
---|
4576 | |
---|
4577 | // System.out.println("Last check: "+id+" == "+currentRule.getRuleName()); |
---|
4578 | // Failing that, check the rule name itself. Output variable |
---|
4579 | // is rule_AST; input variable is rule_AST_in (treeparsers). |
---|
4580 | if( id.equals(currentRule.getRuleName()) ) |
---|
4581 | { |
---|
4582 | String r = in_var ? id + "_AST_in" : id + "_AST"; |
---|
4583 | if ( transInfo!=null ) { |
---|
4584 | if ( !in_var ) { |
---|
4585 | transInfo.refRuleRoot = r; |
---|
4586 | } |
---|
4587 | } |
---|
4588 | // if( in_var ) |
---|
4589 | // System.out.println("returning (r) "+r); |
---|
4590 | return r; |
---|
4591 | } |
---|
4592 | else |
---|
4593 | { |
---|
4594 | // if( in_var ) |
---|
4595 | // System.out.println("returning (last) "+id); |
---|
4596 | // id does not map to anything -- return itself. |
---|
4597 | return id; |
---|
4598 | } |
---|
4599 | } |
---|
4600 | /** Given an element and the name of an associated AST variable, |
---|
4601 | * create a mapping between the element "name" and the variable name. |
---|
4602 | */ |
---|
4603 | private void mapTreeVariable(AlternativeElement e, String name) |
---|
4604 | { |
---|
4605 | // For tree elements, defer to the root |
---|
4606 | if (e instanceof TreeElement) { |
---|
4607 | mapTreeVariable( ((TreeElement)e).root, name); |
---|
4608 | return; |
---|
4609 | } |
---|
4610 | |
---|
4611 | // Determine the name of the element, if any, for mapping purposes |
---|
4612 | String elName = null; |
---|
4613 | |
---|
4614 | // Don't map labeled items |
---|
4615 | if (e.getLabel() == null) { |
---|
4616 | if (e instanceof TokenRefElement) { |
---|
4617 | // use the token id |
---|
4618 | elName = ((TokenRefElement)e).atomText; |
---|
4619 | } |
---|
4620 | else if (e instanceof RuleRefElement) { |
---|
4621 | // use the rule name |
---|
4622 | elName = ((RuleRefElement)e).targetRule; |
---|
4623 | } |
---|
4624 | } |
---|
4625 | // Add the element to the tree variable map if it has a name |
---|
4626 | if (elName != null) { |
---|
4627 | if (treeVariableMap.get(elName) != null) { |
---|
4628 | // Name is already in the map -- mark it as duplicate |
---|
4629 | treeVariableMap.remove(elName); |
---|
4630 | treeVariableMap.put(elName, NONUNIQUE); |
---|
4631 | } |
---|
4632 | else { |
---|
4633 | treeVariableMap.put(elName, name); |
---|
4634 | } |
---|
4635 | } |
---|
4636 | } |
---|
4637 | |
---|
4638 | /** Lexically process tree-specifiers in the action. |
---|
4639 | * This will replace #id and #(...) with the appropriate |
---|
4640 | * function calls and/or variables. |
---|
4641 | */ |
---|
4642 | protected String processActionForSpecialSymbols(String actionStr, |
---|
4643 | int line, |
---|
4644 | RuleBlock currentRule, |
---|
4645 | ActionTransInfo tInfo) |
---|
4646 | { |
---|
4647 | if ( actionStr==null || actionStr.length()==0 ) |
---|
4648 | return null; |
---|
4649 | |
---|
4650 | // The action trans info tells us (at the moment) whether an |
---|
4651 | // assignment was done to the rule's tree root. |
---|
4652 | if (grammar==null) |
---|
4653 | return actionStr; |
---|
4654 | |
---|
4655 | if ((grammar.buildAST && actionStr.indexOf('#') != -1) || |
---|
4656 | grammar instanceof TreeWalkerGrammar || |
---|
4657 | ((grammar instanceof LexerGrammar || |
---|
4658 | grammar instanceof ParserGrammar) |
---|
4659 | && actionStr.indexOf('$') != -1) ) |
---|
4660 | { |
---|
4661 | // Create a lexer to read an action and return the translated version |
---|
4662 | antlr.actions.cpp.ActionLexer lexer = |
---|
4663 | new antlr.actions.cpp.ActionLexer(actionStr, currentRule, this, tInfo); |
---|
4664 | lexer.setLineOffset(line); |
---|
4665 | lexer.setFilename(grammar.getFilename()); |
---|
4666 | lexer.setTool(antlrTool); |
---|
4667 | |
---|
4668 | try { |
---|
4669 | lexer.mACTION(true); |
---|
4670 | actionStr = lexer.getTokenObject().getText(); |
---|
4671 | // System.out.println("action translated: "+actionStr); |
---|
4672 | // System.out.println("trans info is "+tInfo); |
---|
4673 | } |
---|
4674 | catch (RecognitionException ex) { |
---|
4675 | lexer.reportError(ex); |
---|
4676 | return actionStr; |
---|
4677 | } |
---|
4678 | catch (TokenStreamException tex) { |
---|
4679 | antlrTool.panic("Error reading action:"+actionStr); |
---|
4680 | return actionStr; |
---|
4681 | } |
---|
4682 | catch (CharStreamException io) { |
---|
4683 | antlrTool.panic("Error reading action:"+actionStr); |
---|
4684 | return actionStr; |
---|
4685 | } |
---|
4686 | } |
---|
4687 | return actionStr; |
---|
4688 | } |
---|
4689 | |
---|
4690 | private String fixNameSpaceOption( String ns ) |
---|
4691 | { |
---|
4692 | ns = StringUtils.stripFrontBack(ns,"\"","\""); |
---|
4693 | if( ns.length() > 2 && |
---|
4694 | !ns.substring(ns.length()-2, ns.length()).equals("::") ) |
---|
4695 | ns += "::"; |
---|
4696 | return ns; |
---|
4697 | } |
---|
4698 | |
---|
4699 | private void setupGrammarParameters(Grammar g) { |
---|
4700 | if (g instanceof ParserGrammar || |
---|
4701 | g instanceof LexerGrammar || |
---|
4702 | g instanceof TreeWalkerGrammar |
---|
4703 | ) |
---|
4704 | { |
---|
4705 | /* RK: options also have to be added to Grammar.java and for options |
---|
4706 | * on the file level entries have to be defined in |
---|
4707 | * DefineGrammarSymbols.java and passed around via 'globals' in |
---|
4708 | * antlrTool.java |
---|
4709 | */ |
---|
4710 | if( antlrTool.nameSpace != null ) |
---|
4711 | nameSpace = antlrTool.nameSpace; |
---|
4712 | |
---|
4713 | if( antlrTool.namespaceStd != null ) |
---|
4714 | namespaceStd = fixNameSpaceOption(antlrTool.namespaceStd); |
---|
4715 | |
---|
4716 | if( antlrTool.namespaceAntlr != null ) |
---|
4717 | namespaceAntlr = fixNameSpaceOption(antlrTool.namespaceAntlr); |
---|
4718 | |
---|
4719 | genHashLines = antlrTool.genHashLines; |
---|
4720 | |
---|
4721 | /* let grammar level options override filelevel ones... |
---|
4722 | */ |
---|
4723 | if( g.hasOption("namespace") ) { |
---|
4724 | Token t = g.getOption("namespace"); |
---|
4725 | if( t != null ) { |
---|
4726 | nameSpace = new NameSpace(t.getText()); |
---|
4727 | } |
---|
4728 | } |
---|
4729 | if( g.hasOption("namespaceAntlr") ) { |
---|
4730 | Token t = g.getOption("namespaceAntlr"); |
---|
4731 | if( t != null ) { |
---|
4732 | String ns = StringUtils.stripFrontBack(t.getText(),"\"","\""); |
---|
4733 | if ( ns != null ) { |
---|
4734 | if( ns.length() > 2 && |
---|
4735 | !ns.substring(ns.length()-2, ns.length()).equals("::") ) |
---|
4736 | ns += "::"; |
---|
4737 | namespaceAntlr = ns; |
---|
4738 | } |
---|
4739 | } |
---|
4740 | } |
---|
4741 | if( g.hasOption("namespaceStd") ) { |
---|
4742 | Token t = g.getOption("namespaceStd"); |
---|
4743 | if( t != null ) { |
---|
4744 | String ns = StringUtils.stripFrontBack(t.getText(),"\"","\""); |
---|
4745 | if ( ns != null ) { |
---|
4746 | if( ns.length() > 2 && |
---|
4747 | !ns.substring(ns.length()-2, ns.length()).equals("::") ) |
---|
4748 | ns += "::"; |
---|
4749 | namespaceStd = ns; |
---|
4750 | } |
---|
4751 | } |
---|
4752 | } |
---|
4753 | if( g.hasOption("genHashLines") ) { |
---|
4754 | Token t = g.getOption("genHashLines"); |
---|
4755 | if( t != null ) { |
---|
4756 | String val = StringUtils.stripFrontBack(t.getText(),"\"","\""); |
---|
4757 | genHashLines = val.equals("true"); |
---|
4758 | } |
---|
4759 | } |
---|
4760 | noConstructors = antlrTool.noConstructors; // get the default |
---|
4761 | if( g.hasOption("noConstructors") ) { |
---|
4762 | Token t = g.getOption("noConstructors"); |
---|
4763 | if( (t != null) && !(t.getText().equals("true") || t.getText().equals("false"))) |
---|
4764 | antlrTool.error("noConstructors option must be true or false", antlrTool.getGrammarFile(), t.getLine(), t.getColumn()); |
---|
4765 | noConstructors = t.getText().equals("true"); |
---|
4766 | } |
---|
4767 | } |
---|
4768 | if (g instanceof ParserGrammar) { |
---|
4769 | labeledElementASTType = namespaceAntlr+"RefAST"; |
---|
4770 | labeledElementASTInit = namespaceAntlr+"nullAST"; |
---|
4771 | if ( g.hasOption("ASTLabelType") ) { |
---|
4772 | Token tsuffix = g.getOption("ASTLabelType"); |
---|
4773 | if ( tsuffix != null ) { |
---|
4774 | String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\""); |
---|
4775 | if ( suffix != null ) { |
---|
4776 | usingCustomAST = true; |
---|
4777 | labeledElementASTType = suffix; |
---|
4778 | labeledElementASTInit = suffix+"("+namespaceAntlr+"nullAST)"; |
---|
4779 | } |
---|
4780 | } |
---|
4781 | } |
---|
4782 | labeledElementType = namespaceAntlr+"RefToken "; |
---|
4783 | labeledElementInit = namespaceAntlr+"nullToken"; |
---|
4784 | commonExtraArgs = ""; |
---|
4785 | commonExtraParams = ""; |
---|
4786 | commonLocalVars = ""; |
---|
4787 | lt1Value = "LT(1)"; |
---|
4788 | exceptionThrown = namespaceAntlr+"RecognitionException"; |
---|
4789 | throwNoViable = "throw "+namespaceAntlr+"NoViableAltException(LT(1), getFilename());"; |
---|
4790 | } |
---|
4791 | else if (g instanceof LexerGrammar) { |
---|
4792 | labeledElementType = "char "; |
---|
4793 | labeledElementInit = "'\\0'"; |
---|
4794 | commonExtraArgs = ""; |
---|
4795 | commonExtraParams = "bool _createToken"; |
---|
4796 | commonLocalVars = "int _ttype; "+namespaceAntlr+"RefToken _token; "+namespaceStd+"string::size_type _begin = text.length();"; |
---|
4797 | lt1Value = "LA(1)"; |
---|
4798 | exceptionThrown = namespaceAntlr+"RecognitionException"; |
---|
4799 | throwNoViable = "throw "+namespaceAntlr+"NoViableAltForCharException(LA(1), getFilename(), getLine(), getColumn());"; |
---|
4800 | } |
---|
4801 | else if (g instanceof TreeWalkerGrammar) { |
---|
4802 | labeledElementInit = namespaceAntlr+"nullAST"; |
---|
4803 | labeledElementASTInit = namespaceAntlr+"nullAST"; |
---|
4804 | labeledElementASTType = namespaceAntlr+"RefAST"; |
---|
4805 | labeledElementType = namespaceAntlr+"RefAST"; |
---|
4806 | commonExtraParams = namespaceAntlr+"RefAST _t"; |
---|
4807 | throwNoViable = "throw "+namespaceAntlr+"NoViableAltException(_t);"; |
---|
4808 | lt1Value = "_t"; |
---|
4809 | if ( g.hasOption("ASTLabelType") ) { |
---|
4810 | Token tsuffix = g.getOption("ASTLabelType"); |
---|
4811 | if ( tsuffix != null ) { |
---|
4812 | String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\""); |
---|
4813 | if ( suffix != null ) { |
---|
4814 | usingCustomAST = true; |
---|
4815 | labeledElementASTType = suffix; |
---|
4816 | labeledElementType = suffix; |
---|
4817 | labeledElementInit = suffix+"("+namespaceAntlr+"nullAST)"; |
---|
4818 | labeledElementASTInit = labeledElementInit; |
---|
4819 | commonExtraParams = suffix+" _t"; |
---|
4820 | throwNoViable = "throw "+namespaceAntlr+"NoViableAltException("+namespaceAntlr+"RefAST(_t));"; |
---|
4821 | lt1Value = "_t"; |
---|
4822 | } |
---|
4823 | } |
---|
4824 | } |
---|
4825 | if ( !g.hasOption("ASTLabelType") ) { |
---|
4826 | g.setOption("ASTLabelType", new Token(ANTLRTokenTypes.STRING_LITERAL,namespaceAntlr+"RefAST")); |
---|
4827 | } |
---|
4828 | commonExtraArgs = "_t"; |
---|
4829 | commonLocalVars = ""; |
---|
4830 | exceptionThrown = namespaceAntlr+"RecognitionException"; |
---|
4831 | } |
---|
4832 | else { |
---|
4833 | antlrTool.panic("Unknown grammar type"); |
---|
4834 | } |
---|
4835 | } |
---|
4836 | } |
---|