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/DiagnosticCodeGenerator.java#2 $ |
---|
8 | */ |
---|
9 | |
---|
10 | import java.util.Enumeration; |
---|
11 | |
---|
12 | import antlr.collections.impl.BitSet; |
---|
13 | import antlr.collections.impl.Vector; |
---|
14 | |
---|
15 | import java.io.PrintWriter; //SAS: changed for proper text file io |
---|
16 | import java.io.IOException; |
---|
17 | import java.io.FileWriter; |
---|
18 | |
---|
19 | /**Generate MyParser.txt, MyLexer.txt and MyParserTokenTypes.txt */ |
---|
20 | public class DiagnosticCodeGenerator extends CodeGenerator { |
---|
21 | /** non-zero if inside syntactic predicate generation */ |
---|
22 | protected int syntacticPredLevel = 0; |
---|
23 | |
---|
24 | /** true during lexer generation, false during parser generation */ |
---|
25 | protected boolean doingLexRules = false; |
---|
26 | |
---|
27 | /** Create a Diagnostic code-generator using the given Grammar |
---|
28 | * The caller must still call setTool, setBehavior, and setAnalyzer |
---|
29 | * before generating code. |
---|
30 | */ |
---|
31 | public DiagnosticCodeGenerator() { |
---|
32 | super(); |
---|
33 | charFormatter = new JavaCharFormatter(); |
---|
34 | } |
---|
35 | |
---|
36 | /**Generate the parser, lexer, and token types documentation */ |
---|
37 | public void gen() { |
---|
38 | |
---|
39 | // Do the code generation |
---|
40 | try { |
---|
41 | // Loop over all grammars |
---|
42 | Enumeration grammarIter = behavior.grammars.elements(); |
---|
43 | while (grammarIter.hasMoreElements()) { |
---|
44 | Grammar g = (Grammar)grammarIter.nextElement(); |
---|
45 | |
---|
46 | // Connect all the components to each other |
---|
47 | g.setGrammarAnalyzer(analyzer); |
---|
48 | g.setCodeGenerator(this); |
---|
49 | analyzer.setGrammar(g); |
---|
50 | |
---|
51 | // To get right overloading behavior across hetrogeneous grammars |
---|
52 | g.generate(); |
---|
53 | |
---|
54 | if (antlrTool.hasError()) { |
---|
55 | antlrTool.panic("Exiting due to errors."); |
---|
56 | } |
---|
57 | |
---|
58 | } |
---|
59 | |
---|
60 | // Loop over all token managers (some of which are lexers) |
---|
61 | Enumeration tmIter = behavior.tokenManagers.elements(); |
---|
62 | while (tmIter.hasMoreElements()) { |
---|
63 | TokenManager tm = (TokenManager)tmIter.nextElement(); |
---|
64 | if (!tm.isReadOnly()) { |
---|
65 | // Write the token manager tokens as Java |
---|
66 | genTokenTypes(tm); |
---|
67 | } |
---|
68 | } |
---|
69 | } |
---|
70 | catch (IOException e) { |
---|
71 | antlrTool.reportException(e, null); |
---|
72 | } |
---|
73 | } |
---|
74 | |
---|
75 | /** Generate code for the given grammar element. |
---|
76 | * @param blk The {...} action to generate |
---|
77 | */ |
---|
78 | public void gen(ActionElement action) { |
---|
79 | if (action.isSemPred) { |
---|
80 | // handled elsewhere |
---|
81 | } |
---|
82 | else { |
---|
83 | print("ACTION: "); |
---|
84 | _printAction(action.actionText); |
---|
85 | } |
---|
86 | } |
---|
87 | |
---|
88 | /** Generate code for the given grammar element. |
---|
89 | * @param blk The "x|y|z|..." block to generate |
---|
90 | */ |
---|
91 | public void gen(AlternativeBlock blk) { |
---|
92 | println("Start of alternative block."); |
---|
93 | tabs++; |
---|
94 | genBlockPreamble(blk); |
---|
95 | |
---|
96 | boolean ok = grammar.theLLkAnalyzer.deterministic(blk); |
---|
97 | if (!ok) { |
---|
98 | println("Warning: This alternative block is non-deterministic"); |
---|
99 | } |
---|
100 | genCommonBlock(blk); |
---|
101 | tabs--; |
---|
102 | } |
---|
103 | |
---|
104 | /** Generate code for the given grammar element. |
---|
105 | * @param blk The block-end element to generate. Block-end |
---|
106 | * elements are synthesized by the grammar parser to represent |
---|
107 | * the end of a block. |
---|
108 | */ |
---|
109 | public void gen(BlockEndElement end) { |
---|
110 | // no-op |
---|
111 | } |
---|
112 | |
---|
113 | /** Generate code for the given grammar element. |
---|
114 | * @param blk The character literal reference to generate |
---|
115 | */ |
---|
116 | public void gen(CharLiteralElement atom) { |
---|
117 | print("Match character "); |
---|
118 | if (atom.not) { |
---|
119 | _print("NOT "); |
---|
120 | } |
---|
121 | _print(atom.atomText); |
---|
122 | if (atom.label != null) { |
---|
123 | _print(", label=" + atom.label); |
---|
124 | } |
---|
125 | _println(""); |
---|
126 | } |
---|
127 | |
---|
128 | /** Generate code for the given grammar element. |
---|
129 | * @param blk The character-range reference to generate |
---|
130 | */ |
---|
131 | public void gen(CharRangeElement r) { |
---|
132 | print("Match character range: " + r.beginText + ".." + r.endText); |
---|
133 | if (r.label != null) { |
---|
134 | _print(", label = " + r.label); |
---|
135 | } |
---|
136 | _println(""); |
---|
137 | } |
---|
138 | |
---|
139 | /** Generate the lexer TXT file */ |
---|
140 | public void gen(LexerGrammar g) throws IOException { |
---|
141 | setGrammar(g); |
---|
142 | antlrTool.reportProgress("Generating " + grammar.getClassName() + TokenTypesFileExt); |
---|
143 | currentOutput = antlrTool.openOutputFile(grammar.getClassName() + TokenTypesFileExt); |
---|
144 | //SAS: changed for proper text file io |
---|
145 | |
---|
146 | tabs = 0; |
---|
147 | doingLexRules = true; |
---|
148 | |
---|
149 | // Generate header common to all TXT output files |
---|
150 | genHeader(); |
---|
151 | |
---|
152 | // Output the user-defined lexer premamble |
---|
153 | println(""); |
---|
154 | println("*** Lexer Preamble Action."); |
---|
155 | println("This action will appear before the declaration of your lexer class:"); |
---|
156 | tabs++; |
---|
157 | println(grammar.preambleAction.getText()); |
---|
158 | tabs--; |
---|
159 | println("*** End of Lexer Preamble Action"); |
---|
160 | |
---|
161 | // Generate lexer class definition |
---|
162 | println(""); |
---|
163 | println("*** Your lexer class is called '" + grammar.getClassName() + "' and is a subclass of '" + grammar.getSuperClass() + "'."); |
---|
164 | |
---|
165 | // Generate user-defined parser class members |
---|
166 | println(""); |
---|
167 | println("*** User-defined lexer class members:"); |
---|
168 | println("These are the member declarations that you defined for your class:"); |
---|
169 | tabs++; |
---|
170 | printAction(grammar.classMemberAction.getText()); |
---|
171 | tabs--; |
---|
172 | println("*** End of user-defined lexer class members"); |
---|
173 | |
---|
174 | // Generate string literals |
---|
175 | println(""); |
---|
176 | println("*** String literals used in the parser"); |
---|
177 | println("The following string literals were used in the parser."); |
---|
178 | println("An actual code generator would arrange to place these literals"); |
---|
179 | println("into a table in the generated lexer, so that actions in the"); |
---|
180 | println("generated lexer could match token text against the literals."); |
---|
181 | println("String literals used in the lexer are not listed here, as they"); |
---|
182 | println("are incorporated into the mainstream lexer processing."); |
---|
183 | tabs++; |
---|
184 | // Enumerate all of the symbols and look for string literal symbols |
---|
185 | Enumeration ids = grammar.getSymbols(); |
---|
186 | while (ids.hasMoreElements()) { |
---|
187 | GrammarSymbol sym = (GrammarSymbol)ids.nextElement(); |
---|
188 | // Only processing string literals -- reject other symbol entries |
---|
189 | if (sym instanceof StringLiteralSymbol) { |
---|
190 | StringLiteralSymbol s = (StringLiteralSymbol)sym; |
---|
191 | println(s.getId() + " = " + s.getTokenType()); |
---|
192 | } |
---|
193 | } |
---|
194 | tabs--; |
---|
195 | println("*** End of string literals used by the parser"); |
---|
196 | |
---|
197 | // Generate nextToken() rule. |
---|
198 | // nextToken() is a synthetic lexer rule that is the implicit OR of all |
---|
199 | // user-defined lexer rules. |
---|
200 | genNextToken(); |
---|
201 | |
---|
202 | // Generate code for each rule in the lexer |
---|
203 | println(""); |
---|
204 | println("*** User-defined Lexer rules:"); |
---|
205 | tabs++; |
---|
206 | |
---|
207 | ids = grammar.rules.elements(); |
---|
208 | while (ids.hasMoreElements()) { |
---|
209 | RuleSymbol rs = (RuleSymbol)ids.nextElement(); |
---|
210 | if (!rs.id.equals("mnextToken")) { |
---|
211 | genRule(rs); |
---|
212 | } |
---|
213 | } |
---|
214 | |
---|
215 | tabs--; |
---|
216 | println(""); |
---|
217 | println("*** End User-defined Lexer rules:"); |
---|
218 | |
---|
219 | // Close the lexer output file |
---|
220 | currentOutput.close(); |
---|
221 | currentOutput = null; |
---|
222 | doingLexRules = false; |
---|
223 | } |
---|
224 | |
---|
225 | /** Generate code for the given grammar element. |
---|
226 | * @param blk The (...)+ block to generate |
---|
227 | */ |
---|
228 | public void gen(OneOrMoreBlock blk) { |
---|
229 | println("Start ONE-OR-MORE (...)+ block:"); |
---|
230 | tabs++; |
---|
231 | genBlockPreamble(blk); |
---|
232 | boolean ok = grammar.theLLkAnalyzer.deterministic(blk); |
---|
233 | if (!ok) { |
---|
234 | println("Warning: This one-or-more block is non-deterministic"); |
---|
235 | } |
---|
236 | genCommonBlock(blk); |
---|
237 | tabs--; |
---|
238 | println("End ONE-OR-MORE block."); |
---|
239 | } |
---|
240 | |
---|
241 | /** Generate the parser TXT file */ |
---|
242 | public void gen(ParserGrammar g) throws IOException { |
---|
243 | setGrammar(g); |
---|
244 | // Open the output stream for the parser and set the currentOutput |
---|
245 | antlrTool.reportProgress("Generating " + grammar.getClassName() + TokenTypesFileExt); |
---|
246 | currentOutput = antlrTool.openOutputFile(grammar.getClassName() + TokenTypesFileExt); |
---|
247 | //SAS: changed for proper text file io |
---|
248 | |
---|
249 | tabs = 0; |
---|
250 | |
---|
251 | // Generate the header common to all output files. |
---|
252 | genHeader(); |
---|
253 | |
---|
254 | // Output the user-defined parser premamble |
---|
255 | println(""); |
---|
256 | println("*** Parser Preamble Action."); |
---|
257 | println("This action will appear before the declaration of your parser class:"); |
---|
258 | tabs++; |
---|
259 | println(grammar.preambleAction.getText()); |
---|
260 | tabs--; |
---|
261 | println("*** End of Parser Preamble Action"); |
---|
262 | |
---|
263 | // Generate parser class definition |
---|
264 | println(""); |
---|
265 | println("*** Your parser class is called '" + grammar.getClassName() + "' and is a subclass of '" + grammar.getSuperClass() + "'."); |
---|
266 | |
---|
267 | // Generate user-defined parser class members |
---|
268 | println(""); |
---|
269 | println("*** User-defined parser class members:"); |
---|
270 | println("These are the member declarations that you defined for your class:"); |
---|
271 | tabs++; |
---|
272 | printAction(grammar.classMemberAction.getText()); |
---|
273 | tabs--; |
---|
274 | println("*** End of user-defined parser class members"); |
---|
275 | |
---|
276 | // Generate code for each rule in the grammar |
---|
277 | println(""); |
---|
278 | println("*** Parser rules:"); |
---|
279 | tabs++; |
---|
280 | |
---|
281 | // Enumerate the parser rules |
---|
282 | Enumeration rules = grammar.rules.elements(); |
---|
283 | while (rules.hasMoreElements()) { |
---|
284 | println(""); |
---|
285 | // Get the rules from the list and downcast it to proper type |
---|
286 | GrammarSymbol sym = (GrammarSymbol)rules.nextElement(); |
---|
287 | // Only process parser rules |
---|
288 | if (sym instanceof RuleSymbol) { |
---|
289 | genRule((RuleSymbol)sym); |
---|
290 | } |
---|
291 | } |
---|
292 | tabs--; |
---|
293 | println(""); |
---|
294 | println("*** End of parser rules"); |
---|
295 | |
---|
296 | println(""); |
---|
297 | println("*** End of parser"); |
---|
298 | |
---|
299 | // Close the parser output stream |
---|
300 | currentOutput.close(); |
---|
301 | currentOutput = null; |
---|
302 | } |
---|
303 | |
---|
304 | /** Generate code for the given grammar element. |
---|
305 | * @param blk The rule-reference to generate |
---|
306 | */ |
---|
307 | public void gen(RuleRefElement rr) { |
---|
308 | RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule); |
---|
309 | |
---|
310 | // Generate the actual rule description |
---|
311 | print("Rule Reference: " + rr.targetRule); |
---|
312 | if (rr.idAssign != null) { |
---|
313 | _print(", assigned to '" + rr.idAssign + "'"); |
---|
314 | } |
---|
315 | if (rr.args != null) { |
---|
316 | _print(", arguments = " + rr.args); |
---|
317 | } |
---|
318 | _println(""); |
---|
319 | |
---|
320 | // Perform diagnostics |
---|
321 | if (rs == null || !rs.isDefined()) { |
---|
322 | println("Rule '" + rr.targetRule + "' is referenced, but that rule is not defined."); |
---|
323 | println("\tPerhaps the rule is misspelled, or you forgot to define it."); |
---|
324 | return; |
---|
325 | } |
---|
326 | if (!(rs instanceof RuleSymbol)) { |
---|
327 | // Should this ever happen?? |
---|
328 | println("Rule '" + rr.targetRule + "' is referenced, but that is not a grammar rule."); |
---|
329 | return; |
---|
330 | } |
---|
331 | if (rr.idAssign != null) { |
---|
332 | // Warn if the rule has no return type |
---|
333 | if (rs.block.returnAction == null) { |
---|
334 | println("Error: You assigned from Rule '" + rr.targetRule + "', but that rule has no return type."); |
---|
335 | } |
---|
336 | } |
---|
337 | else { |
---|
338 | // Warn about return value if any, but not inside syntactic predicate |
---|
339 | if (!(grammar instanceof LexerGrammar) && syntacticPredLevel == 0 && rs.block.returnAction != null) { |
---|
340 | println("Warning: Rule '" + rr.targetRule + "' returns a value"); |
---|
341 | } |
---|
342 | } |
---|
343 | if (rr.args != null && rs.block.argAction == null) { |
---|
344 | println("Error: Rule '" + rr.targetRule + "' accepts no arguments."); |
---|
345 | } |
---|
346 | } |
---|
347 | |
---|
348 | /** Generate code for the given grammar element. |
---|
349 | * @param blk The string-literal reference to generate |
---|
350 | */ |
---|
351 | public void gen(StringLiteralElement atom) { |
---|
352 | print("Match string literal "); |
---|
353 | _print(atom.atomText); |
---|
354 | if (atom.label != null) { |
---|
355 | _print(", label=" + atom.label); |
---|
356 | } |
---|
357 | _println(""); |
---|
358 | } |
---|
359 | |
---|
360 | /** Generate code for the given grammar element. |
---|
361 | * @param blk The token-range reference to generate |
---|
362 | */ |
---|
363 | public void gen(TokenRangeElement r) { |
---|
364 | print("Match token range: " + r.beginText + ".." + r.endText); |
---|
365 | if (r.label != null) { |
---|
366 | _print(", label = " + r.label); |
---|
367 | } |
---|
368 | _println(""); |
---|
369 | } |
---|
370 | |
---|
371 | /** Generate code for the given grammar element. |
---|
372 | * @param blk The token-reference to generate |
---|
373 | */ |
---|
374 | public void gen(TokenRefElement atom) { |
---|
375 | print("Match token "); |
---|
376 | if (atom.not) { |
---|
377 | _print("NOT "); |
---|
378 | } |
---|
379 | _print(atom.atomText); |
---|
380 | if (atom.label != null) { |
---|
381 | _print(", label=" + atom.label); |
---|
382 | } |
---|
383 | _println(""); |
---|
384 | } |
---|
385 | |
---|
386 | public void gen(TreeElement t) { |
---|
387 | print("Tree reference: " + t); |
---|
388 | } |
---|
389 | |
---|
390 | /** Generate the tree-walker TXT file */ |
---|
391 | public void gen(TreeWalkerGrammar g) throws IOException { |
---|
392 | setGrammar(g); |
---|
393 | // Open the output stream for the parser and set the currentOutput |
---|
394 | antlrTool.reportProgress("Generating " + grammar.getClassName() + TokenTypesFileExt); |
---|
395 | currentOutput = antlrTool.openOutputFile(grammar.getClassName() + TokenTypesFileExt); |
---|
396 | //SAS: changed for proper text file io |
---|
397 | |
---|
398 | tabs = 0; |
---|
399 | |
---|
400 | // Generate the header common to all output files. |
---|
401 | genHeader(); |
---|
402 | |
---|
403 | // Output the user-defined parser premamble |
---|
404 | println(""); |
---|
405 | println("*** Tree-walker Preamble Action."); |
---|
406 | println("This action will appear before the declaration of your tree-walker class:"); |
---|
407 | tabs++; |
---|
408 | println(grammar.preambleAction.getText()); |
---|
409 | tabs--; |
---|
410 | println("*** End of tree-walker Preamble Action"); |
---|
411 | |
---|
412 | // Generate tree-walker class definition |
---|
413 | println(""); |
---|
414 | println("*** Your tree-walker class is called '" + grammar.getClassName() + "' and is a subclass of '" + grammar.getSuperClass() + "'."); |
---|
415 | |
---|
416 | // Generate user-defined tree-walker class members |
---|
417 | println(""); |
---|
418 | println("*** User-defined tree-walker class members:"); |
---|
419 | println("These are the member declarations that you defined for your class:"); |
---|
420 | tabs++; |
---|
421 | printAction(grammar.classMemberAction.getText()); |
---|
422 | tabs--; |
---|
423 | println("*** End of user-defined tree-walker class members"); |
---|
424 | |
---|
425 | // Generate code for each rule in the grammar |
---|
426 | println(""); |
---|
427 | println("*** tree-walker rules:"); |
---|
428 | tabs++; |
---|
429 | |
---|
430 | // Enumerate the tree-walker rules |
---|
431 | Enumeration rules = grammar.rules.elements(); |
---|
432 | while (rules.hasMoreElements()) { |
---|
433 | println(""); |
---|
434 | // Get the rules from the list and downcast it to proper type |
---|
435 | GrammarSymbol sym = (GrammarSymbol)rules.nextElement(); |
---|
436 | // Only process tree-walker rules |
---|
437 | if (sym instanceof RuleSymbol) { |
---|
438 | genRule((RuleSymbol)sym); |
---|
439 | } |
---|
440 | } |
---|
441 | tabs--; |
---|
442 | println(""); |
---|
443 | println("*** End of tree-walker rules"); |
---|
444 | |
---|
445 | println(""); |
---|
446 | println("*** End of tree-walker"); |
---|
447 | |
---|
448 | // Close the tree-walker output stream |
---|
449 | currentOutput.close(); |
---|
450 | currentOutput = null; |
---|
451 | } |
---|
452 | |
---|
453 | /** Generate a wildcard element */ |
---|
454 | public void gen(WildcardElement wc) { |
---|
455 | print("Match wildcard"); |
---|
456 | if (wc.getLabel() != null) { |
---|
457 | _print(", label = " + wc.getLabel()); |
---|
458 | } |
---|
459 | _println(""); |
---|
460 | } |
---|
461 | |
---|
462 | /** Generate code for the given grammar element. |
---|
463 | * @param blk The (...)* block to generate |
---|
464 | */ |
---|
465 | public void gen(ZeroOrMoreBlock blk) { |
---|
466 | println("Start ZERO-OR-MORE (...)+ block:"); |
---|
467 | tabs++; |
---|
468 | genBlockPreamble(blk); |
---|
469 | boolean ok = grammar.theLLkAnalyzer.deterministic(blk); |
---|
470 | if (!ok) { |
---|
471 | println("Warning: This zero-or-more block is non-deterministic"); |
---|
472 | } |
---|
473 | genCommonBlock(blk); |
---|
474 | tabs--; |
---|
475 | println("End ZERO-OR-MORE block."); |
---|
476 | } |
---|
477 | |
---|
478 | protected void genAlt(Alternative alt) { |
---|
479 | for ( |
---|
480 | AlternativeElement elem = alt.head; |
---|
481 | !(elem instanceof BlockEndElement); |
---|
482 | elem = elem.next |
---|
483 | ) { |
---|
484 | elem.generate(); |
---|
485 | } |
---|
486 | if (alt.getTreeSpecifier() != null) { |
---|
487 | println("AST will be built as: " + alt.getTreeSpecifier().getText()); |
---|
488 | } |
---|
489 | } |
---|
490 | |
---|
491 | /** Generate the header for a block, which may be a RuleBlock or a |
---|
492 | * plain AlternativeBLock. This generates any variable declarations, |
---|
493 | * init-actions, and syntactic-predicate-testing variables. |
---|
494 | * @blk The block for which the preamble is to be generated. |
---|
495 | */ |
---|
496 | protected void genBlockPreamble(AlternativeBlock blk) { |
---|
497 | // dump out init action |
---|
498 | if (blk.initAction != null) { |
---|
499 | printAction("Init action: " + blk.initAction); |
---|
500 | } |
---|
501 | } |
---|
502 | |
---|
503 | /**Generate common code for a block of alternatives; return a postscript |
---|
504 | * that needs to be generated at the end of the block. Other routines |
---|
505 | * may append else-clauses and such for error checking before the postfix |
---|
506 | * is generated. |
---|
507 | */ |
---|
508 | public void genCommonBlock(AlternativeBlock blk) { |
---|
509 | boolean singleAlt = (blk.alternatives.size() == 1); |
---|
510 | |
---|
511 | println("Start of an alternative block."); |
---|
512 | tabs++; |
---|
513 | println("The lookahead set for this block is:"); |
---|
514 | tabs++; |
---|
515 | genLookaheadSetForBlock(blk); |
---|
516 | tabs--; |
---|
517 | |
---|
518 | if (singleAlt) { |
---|
519 | println("This block has a single alternative"); |
---|
520 | if (blk.getAlternativeAt(0).synPred != null) { |
---|
521 | // Generate a warning if there is one alt and it has a synPred |
---|
522 | println("Warning: you specified a syntactic predicate for this alternative,"); |
---|
523 | println("and it is the only alternative of a block and will be ignored."); |
---|
524 | } |
---|
525 | } |
---|
526 | else { |
---|
527 | println("This block has multiple alternatives:"); |
---|
528 | tabs++; |
---|
529 | } |
---|
530 | |
---|
531 | for (int i = 0; i < blk.alternatives.size(); i++) { |
---|
532 | Alternative alt = blk.getAlternativeAt(i); |
---|
533 | AlternativeElement elem = alt.head; |
---|
534 | |
---|
535 | // Print lookahead set for alternate |
---|
536 | println(""); |
---|
537 | if (i != 0) { |
---|
538 | print("Otherwise, "); |
---|
539 | } |
---|
540 | else { |
---|
541 | print(""); |
---|
542 | } |
---|
543 | _println("Alternate(" + (i + 1) + ") will be taken IF:"); |
---|
544 | println("The lookahead set: "); |
---|
545 | tabs++; |
---|
546 | genLookaheadSetForAlt(alt); |
---|
547 | tabs--; |
---|
548 | if (alt.semPred != null || alt.synPred != null) { |
---|
549 | print("is matched, AND "); |
---|
550 | } |
---|
551 | else { |
---|
552 | println("is matched."); |
---|
553 | } |
---|
554 | |
---|
555 | // Dump semantic predicates |
---|
556 | if (alt.semPred != null) { |
---|
557 | _println("the semantic predicate:"); |
---|
558 | tabs++; |
---|
559 | println(alt.semPred); |
---|
560 | if (alt.synPred != null) { |
---|
561 | print("is true, AND "); |
---|
562 | } |
---|
563 | else { |
---|
564 | println("is true."); |
---|
565 | } |
---|
566 | } |
---|
567 | |
---|
568 | // Dump syntactic predicate |
---|
569 | if (alt.synPred != null) { |
---|
570 | _println("the syntactic predicate:"); |
---|
571 | tabs++; |
---|
572 | genSynPred(alt.synPred); |
---|
573 | tabs--; |
---|
574 | println("is matched."); |
---|
575 | } |
---|
576 | |
---|
577 | // Dump the alternative |
---|
578 | genAlt(alt); |
---|
579 | } |
---|
580 | println(""); |
---|
581 | println("OTHERWISE, a NoViableAlt exception will be thrown"); |
---|
582 | println(""); |
---|
583 | |
---|
584 | if (!singleAlt) { |
---|
585 | tabs--; |
---|
586 | println("End of alternatives"); |
---|
587 | } |
---|
588 | tabs--; |
---|
589 | println("End of alternative block."); |
---|
590 | } |
---|
591 | |
---|
592 | /** Generate a textual representation of the follow set |
---|
593 | * for a block. |
---|
594 | * @param blk The rule block of interest |
---|
595 | */ |
---|
596 | public void genFollowSetForRuleBlock(RuleBlock blk) { |
---|
597 | Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1, blk.endNode); |
---|
598 | printSet(grammar.maxk, 1, follow); |
---|
599 | } |
---|
600 | |
---|
601 | /** Generate a header that is common to all TXT files */ |
---|
602 | protected void genHeader() { |
---|
603 | println("ANTLR-generated file resulting from grammar " + antlrTool.grammarFile); |
---|
604 | println("Diagnostic output"); |
---|
605 | println(""); |
---|
606 | println("Terence Parr, MageLang Institute"); |
---|
607 | println("with John Lilley, Empathy Software"); |
---|
608 | println("ANTLR Version " + antlrTool.version + "; 1989-2005"); |
---|
609 | println(""); |
---|
610 | println("*** Header Action."); |
---|
611 | println("This action will appear at the top of all generated files."); |
---|
612 | tabs++; |
---|
613 | printAction(behavior.getHeaderAction("")); |
---|
614 | tabs--; |
---|
615 | println("*** End of Header Action"); |
---|
616 | println(""); |
---|
617 | } |
---|
618 | |
---|
619 | /**Generate the lookahead set for an alternate. */ |
---|
620 | protected void genLookaheadSetForAlt(Alternative alt) { |
---|
621 | if (doingLexRules && alt.cache[1].containsEpsilon()) { |
---|
622 | println("MATCHES ALL"); |
---|
623 | return; |
---|
624 | } |
---|
625 | int depth = alt.lookaheadDepth; |
---|
626 | if (depth == GrammarAnalyzer.NONDETERMINISTIC) { |
---|
627 | // if the decision is nondeterministic, do the best we can: LL(k) |
---|
628 | // any predicates that are around will be generated later. |
---|
629 | depth = grammar.maxk; |
---|
630 | } |
---|
631 | for (int i = 1; i <= depth; i++) { |
---|
632 | Lookahead lookahead = alt.cache[i]; |
---|
633 | printSet(depth, i, lookahead); |
---|
634 | } |
---|
635 | } |
---|
636 | |
---|
637 | /** Generate a textual representation of the lookahead set |
---|
638 | * for a block. |
---|
639 | * @param blk The block of interest |
---|
640 | */ |
---|
641 | public void genLookaheadSetForBlock(AlternativeBlock blk) { |
---|
642 | // Find the maximal lookahead depth over all alternatives |
---|
643 | int depth = 0; |
---|
644 | for (int i = 0; i < blk.alternatives.size(); i++) { |
---|
645 | Alternative alt = blk.getAlternativeAt(i); |
---|
646 | if (alt.lookaheadDepth == GrammarAnalyzer.NONDETERMINISTIC) { |
---|
647 | depth = grammar.maxk; |
---|
648 | break; |
---|
649 | } |
---|
650 | else if (depth < alt.lookaheadDepth) { |
---|
651 | depth = alt.lookaheadDepth; |
---|
652 | } |
---|
653 | } |
---|
654 | |
---|
655 | for (int i = 1; i <= depth; i++) { |
---|
656 | Lookahead lookahead = grammar.theLLkAnalyzer.look(i, blk); |
---|
657 | printSet(depth, i, lookahead); |
---|
658 | } |
---|
659 | } |
---|
660 | |
---|
661 | /** Generate the nextToken rule. |
---|
662 | * nextToken is a synthetic lexer rule that is the implicit OR of all |
---|
663 | * user-defined lexer rules. |
---|
664 | */ |
---|
665 | public void genNextToken() { |
---|
666 | println(""); |
---|
667 | println("*** Lexer nextToken rule:"); |
---|
668 | println("The lexer nextToken rule is synthesized from all of the user-defined"); |
---|
669 | println("lexer rules. It logically consists of one big alternative block with"); |
---|
670 | println("each user-defined rule being an alternative."); |
---|
671 | println(""); |
---|
672 | |
---|
673 | // Create the synthesized rule block for nextToken consisting |
---|
674 | // of an alternate block containing all the user-defined lexer rules. |
---|
675 | RuleBlock blk = MakeGrammar.createNextTokenRule(grammar, grammar.rules, "nextToken"); |
---|
676 | |
---|
677 | // Define the nextToken rule symbol |
---|
678 | RuleSymbol nextTokenRs = new RuleSymbol("mnextToken"); |
---|
679 | nextTokenRs.setDefined(); |
---|
680 | nextTokenRs.setBlock(blk); |
---|
681 | nextTokenRs.access = "private"; |
---|
682 | grammar.define(nextTokenRs); |
---|
683 | |
---|
684 | // Analyze the synthesized block |
---|
685 | if (!grammar.theLLkAnalyzer.deterministic(blk)) { |
---|
686 | println("The grammar analyzer has determined that the synthesized"); |
---|
687 | println("nextToken rule is non-deterministic (i.e., it has ambiguities)"); |
---|
688 | println("This means that there is some overlap of the character"); |
---|
689 | println("lookahead for two or more of your lexer rules."); |
---|
690 | } |
---|
691 | |
---|
692 | genCommonBlock(blk); |
---|
693 | |
---|
694 | println("*** End of nextToken lexer rule."); |
---|
695 | } |
---|
696 | |
---|
697 | /** Generate code for a named rule block |
---|
698 | * @param s The RuleSymbol describing the rule to generate |
---|
699 | */ |
---|
700 | public void genRule(RuleSymbol s) { |
---|
701 | println(""); |
---|
702 | String ruleType = (doingLexRules ? "Lexer" : "Parser"); |
---|
703 | println("*** " + ruleType + " Rule: " + s.getId()); |
---|
704 | if (!s.isDefined()) { |
---|
705 | println("This rule is undefined."); |
---|
706 | println("This means that the rule was referenced somewhere in the grammar,"); |
---|
707 | println("but a definition for the rule was not encountered."); |
---|
708 | println("It is also possible that syntax errors during the parse of"); |
---|
709 | println("your grammar file prevented correct processing of the rule."); |
---|
710 | println("*** End " + ruleType + " Rule: " + s.getId()); |
---|
711 | return; |
---|
712 | } |
---|
713 | tabs++; |
---|
714 | |
---|
715 | if (s.access.length() != 0) { |
---|
716 | println("Access: " + s.access); |
---|
717 | } |
---|
718 | |
---|
719 | // Get rule return type and arguments |
---|
720 | RuleBlock rblk = s.getBlock(); |
---|
721 | |
---|
722 | // Gen method return value(s) |
---|
723 | if (rblk.returnAction != null) { |
---|
724 | println("Return value(s): " + rblk.returnAction); |
---|
725 | if (doingLexRules) { |
---|
726 | println("Error: you specified return value(s) for a lexical rule."); |
---|
727 | println("\tLexical rules have an implicit return type of 'int'."); |
---|
728 | } |
---|
729 | } |
---|
730 | else { |
---|
731 | if (doingLexRules) { |
---|
732 | println("Return value: lexical rule returns an implicit token type"); |
---|
733 | } |
---|
734 | else { |
---|
735 | println("Return value: none"); |
---|
736 | } |
---|
737 | } |
---|
738 | |
---|
739 | // Gen arguments |
---|
740 | if (rblk.argAction != null) { |
---|
741 | println("Arguments: " + rblk.argAction); |
---|
742 | } |
---|
743 | |
---|
744 | // Dump any init-action |
---|
745 | genBlockPreamble(rblk); |
---|
746 | |
---|
747 | // Analyze the rule |
---|
748 | boolean ok = grammar.theLLkAnalyzer.deterministic(rblk); |
---|
749 | if (!ok) { |
---|
750 | println("Error: This rule is non-deterministic"); |
---|
751 | } |
---|
752 | |
---|
753 | // Dump the alternates of the rule |
---|
754 | genCommonBlock(rblk); |
---|
755 | |
---|
756 | // Search for an unlabeled exception specification attached to the rule |
---|
757 | ExceptionSpec unlabeledUserSpec = rblk.findExceptionSpec(""); |
---|
758 | |
---|
759 | // Generate user-defined or default catch phrases |
---|
760 | if (unlabeledUserSpec != null) { |
---|
761 | println("You specified error-handler(s) for this rule:"); |
---|
762 | tabs++; |
---|
763 | for (int i = 0; i < unlabeledUserSpec.handlers.size(); i++) { |
---|
764 | if (i != 0) { |
---|
765 | println(""); |
---|
766 | } |
---|
767 | |
---|
768 | ExceptionHandler handler = (ExceptionHandler)unlabeledUserSpec.handlers.elementAt(i); |
---|
769 | println("Error-handler(" + (i + 1) + ") catches [" + handler.exceptionTypeAndName.getText() + "] and executes:"); |
---|
770 | printAction(handler.action.getText()); |
---|
771 | } |
---|
772 | tabs--; |
---|
773 | println("End error-handlers."); |
---|
774 | } |
---|
775 | else if (!doingLexRules) { |
---|
776 | println("Default error-handling will be generated, which catches all"); |
---|
777 | println("parser exceptions and consumes tokens until the follow-set is seen."); |
---|
778 | } |
---|
779 | |
---|
780 | // Dump the follow set |
---|
781 | // Doesn't seem to work for lexical rules... |
---|
782 | if (!doingLexRules) { |
---|
783 | println("The follow set for this rule is:"); |
---|
784 | tabs++; |
---|
785 | genFollowSetForRuleBlock(rblk); |
---|
786 | tabs--; |
---|
787 | } |
---|
788 | |
---|
789 | tabs--; |
---|
790 | println("*** End " + ruleType + " Rule: " + s.getId()); |
---|
791 | } |
---|
792 | |
---|
793 | /** Generate the syntactic predicate. This basically generates |
---|
794 | * the alternative block, buts tracks if we are inside a synPred |
---|
795 | * @param blk The syntactic predicate block |
---|
796 | */ |
---|
797 | protected void genSynPred(SynPredBlock blk) { |
---|
798 | syntacticPredLevel++; |
---|
799 | gen((AlternativeBlock)blk); |
---|
800 | syntacticPredLevel--; |
---|
801 | } |
---|
802 | |
---|
803 | /** Generate the token types TXT file */ |
---|
804 | protected void genTokenTypes(TokenManager tm) throws IOException { |
---|
805 | // Open the token output TXT file and set the currentOutput stream |
---|
806 | antlrTool.reportProgress("Generating " + tm.getName() + TokenTypesFileSuffix + TokenTypesFileExt); |
---|
807 | currentOutput = antlrTool.openOutputFile(tm.getName() + TokenTypesFileSuffix + TokenTypesFileExt); |
---|
808 | //SAS: changed for proper text file io |
---|
809 | tabs = 0; |
---|
810 | |
---|
811 | // Generate the header common to all diagnostic files |
---|
812 | genHeader(); |
---|
813 | |
---|
814 | // Generate a string for each token. This creates a static |
---|
815 | // array of Strings indexed by token type. |
---|
816 | println(""); |
---|
817 | println("*** Tokens used by the parser"); |
---|
818 | println("This is a list of the token numeric values and the corresponding"); |
---|
819 | println("token identifiers. Some tokens are literals, and because of that"); |
---|
820 | println("they have no identifiers. Literals are double-quoted."); |
---|
821 | tabs++; |
---|
822 | |
---|
823 | // Enumerate all the valid token types |
---|
824 | Vector v = tm.getVocabulary(); |
---|
825 | for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) { |
---|
826 | String s = (String)v.elementAt(i); |
---|
827 | if (s != null) { |
---|
828 | println(s + " = " + i); |
---|
829 | } |
---|
830 | } |
---|
831 | |
---|
832 | // Close the interface |
---|
833 | tabs--; |
---|
834 | println("*** End of tokens used by the parser"); |
---|
835 | |
---|
836 | // Close the tokens output file |
---|
837 | currentOutput.close(); |
---|
838 | currentOutput = null; |
---|
839 | } |
---|
840 | |
---|
841 | /** Get a string for an expression to generate creation of an AST subtree. |
---|
842 | * @param v A Vector of String, where each element is an expression in the target language yielding an AST node. |
---|
843 | */ |
---|
844 | public String getASTCreateString(Vector v) { |
---|
845 | return "***Create an AST from a vector here***" + System.getProperty("line.separator"); |
---|
846 | } |
---|
847 | |
---|
848 | /** Get a string for an expression to generate creating of an AST node |
---|
849 | * @param str The arguments to the AST constructor |
---|
850 | */ |
---|
851 | public String getASTCreateString(GrammarAtom atom, String str) { |
---|
852 | return "[" + str + "]"; |
---|
853 | } |
---|
854 | |
---|
855 | /// unused. |
---|
856 | protected String processActionForSpecialSymbols(String actionStr, |
---|
857 | int line, |
---|
858 | RuleBlock currentRule, |
---|
859 | ActionTransInfo tInfo) { |
---|
860 | return actionStr; |
---|
861 | } |
---|
862 | |
---|
863 | /** Map an identifier to it's corresponding tree-node variable. |
---|
864 | * This is context-sensitive, depending on the rule and alternative |
---|
865 | * being generated |
---|
866 | * @param id The identifier name to map |
---|
867 | * @param forInput true if the input tree node variable is to be returned, otherwise the output variable is returned. |
---|
868 | */ |
---|
869 | public String mapTreeId(String id, ActionTransInfo tInfo) { |
---|
870 | return id; |
---|
871 | } |
---|
872 | |
---|
873 | /** Format a lookahead or follow set. |
---|
874 | * @param depth The depth of the entire lookahead/follow |
---|
875 | * @param k The lookahead level to print |
---|
876 | * @param lookahead The lookahead/follow set to print |
---|
877 | */ |
---|
878 | public void printSet(int depth, int k, Lookahead lookahead) { |
---|
879 | int numCols = 5; |
---|
880 | |
---|
881 | int[] elems = lookahead.fset.toArray(); |
---|
882 | |
---|
883 | if (depth != 1) { |
---|
884 | print("k==" + k + ": {"); |
---|
885 | } |
---|
886 | else { |
---|
887 | print("{ "); |
---|
888 | } |
---|
889 | if (elems.length > numCols) { |
---|
890 | _println(""); |
---|
891 | tabs++; |
---|
892 | print(""); |
---|
893 | } |
---|
894 | |
---|
895 | int column = 0; |
---|
896 | for (int i = 0; i < elems.length; i++) { |
---|
897 | column++; |
---|
898 | if (column > numCols) { |
---|
899 | _println(""); |
---|
900 | print(""); |
---|
901 | column = 0; |
---|
902 | } |
---|
903 | if (doingLexRules) { |
---|
904 | _print(charFormatter.literalChar(elems[i])); |
---|
905 | } |
---|
906 | else { |
---|
907 | _print((String)grammar.tokenManager.getVocabulary().elementAt(elems[i])); |
---|
908 | } |
---|
909 | if (i != elems.length - 1) { |
---|
910 | _print(", "); |
---|
911 | } |
---|
912 | } |
---|
913 | |
---|
914 | if (elems.length > numCols) { |
---|
915 | _println(""); |
---|
916 | tabs--; |
---|
917 | print(""); |
---|
918 | } |
---|
919 | _println(" }"); |
---|
920 | } |
---|
921 | } |
---|