source: trunk/yao/share/antlr-2.7.7/antlr/JavaCodeGenerator.java @ 1

Last change on this file since 1 was 1, checked in by lnalod, 15 years ago

Initial import of YAO sources

File size: 144.2 KB
Line 
1package 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/JavaCodeGenerator.java#2 $
8 */
9
10import java.io.IOException;
11import java.util.Enumeration;
12import java.util.Hashtable;
13
14import antlr.collections.impl.BitSet;
15import antlr.collections.impl.Vector;
16
17/**Generate MyParser.java, MyLexer.java and MyParserTokenTypes.java */
18public class JavaCodeGenerator extends CodeGenerator {
19    // non-zero if inside syntactic predicate generation
20        /** Constant to indicate that we shouldn't generate a mapping entry */
21        public static final int NO_MAPPING = -999;
22        /**
23         * Constant to indicate that we should continue mapping based on the
24         *   last mapping seen by the SMAP generator (there may have been
25         *   intermediate mappings generated by nested elements)
26         */
27        public static final int CONTINUE_LAST_MAPPING = -888;
28
29        private JavaCodeGeneratorPrintWriterManager printWriterManager;
30    private int defaultLine = NO_MAPPING;
31
32    protected int syntacticPredLevel = 0;
33
34    // Are we generating ASTs (for parsers and tree parsers) right now?
35    protected boolean genAST = false;
36
37    // Are we saving the text consumed (for lexers) right now?
38    protected boolean saveText = false;
39
40    // Grammar parameters set up to handle different grammar classes.
41    // These are used to get instanceof tests out of code generation
42    String labeledElementType;
43    String labeledElementASTType;
44    String labeledElementInit;
45    String commonExtraArgs;
46    String commonExtraParams;
47    String commonLocalVars;
48    String lt1Value;
49    String exceptionThrown;
50    String throwNoViable;
51
52    /** Tracks the rule being generated.  Used for mapTreeId */
53    RuleBlock currentRule;
54
55    /** Tracks the rule or labeled subrule being generated.  Used for
56     AST generation. */
57    String currentASTResult;
58
59    /** Mapping between the ids used in the current alt, and the
60     * names of variables used to represent their AST values.
61     */
62    Hashtable treeVariableMap = new Hashtable();
63
64    /** Used to keep track of which AST variables have been defined in a rule
65     * (except for the #rule_name and #rule_name_in var's
66     */
67    Hashtable declaredASTVariables = new Hashtable();
68
69    /* Count of unnamed generated variables */
70    int astVarNumber = 1;
71
72    /** Special value used to mark duplicate in treeVariableMap */
73    protected static final String NONUNIQUE = new String();
74
75    public static final int caseSizeThreshold = 127; // ascii is max
76
77    private Vector semPreds;
78
79    /** Create a Java code-generator using the given Grammar.
80     * The caller must still call setTool, setBehavior, and setAnalyzer
81     * before generating code.
82     */
83    public JavaCodeGenerator() {
84        super();
85        charFormatter = new JavaCharFormatter();
86    }
87
88    protected void printAction(String code) {
89        printAction(code, defaultLine);
90    }
91        protected void printAction(String code, int sourceStartLine) {
92        getPrintWriterManager().startMapping(sourceStartLine);
93        super.printAction(code);
94        getPrintWriterManager().endMapping();
95    }
96   
97    public void println(String code) {
98        println(code, defaultLine);
99    }
100        public void println(String code, int sourceStartLine) {
101                if (sourceStartLine > 0 || sourceStartLine == CONTINUE_LAST_MAPPING)
102                        getPrintWriterManager().startSingleSourceLineMapping(sourceStartLine);
103                super.println(code);
104                if (sourceStartLine > 0 || sourceStartLine == CONTINUE_LAST_MAPPING)
105                        getPrintWriterManager().endMapping();
106    }
107   
108    protected void print(String code) {
109        print(code, defaultLine);
110    }
111        protected void print(String code, int sourceStartLine) {
112                if (sourceStartLine > 0 || sourceStartLine == CONTINUE_LAST_MAPPING)
113                        getPrintWriterManager().startMapping(sourceStartLine);
114                super.print(code);
115                if (sourceStartLine > 0 || sourceStartLine == CONTINUE_LAST_MAPPING)
116                        getPrintWriterManager().endMapping();
117    }
118   
119    protected void _print(String code) {
120        _print(code, defaultLine);
121    }
122        protected void _print(String code, int sourceStartLine) {
123                if (sourceStartLine > 0 || sourceStartLine == CONTINUE_LAST_MAPPING)
124                        getPrintWriterManager().startMapping(sourceStartLine);
125        super._print(code);
126                if (sourceStartLine > 0 || sourceStartLine == CONTINUE_LAST_MAPPING)
127                        getPrintWriterManager().endMapping();
128    }
129   
130    protected void _println(String code) {
131        _println(code, defaultLine);
132    }
133        protected void _println(String code, int sourceStartLine) {
134                if (sourceStartLine > 0 || sourceStartLine == CONTINUE_LAST_MAPPING)
135                        getPrintWriterManager().startMapping(sourceStartLine);
136        super._println(code);
137                if (sourceStartLine > 0 || sourceStartLine == CONTINUE_LAST_MAPPING)
138                        getPrintWriterManager().endMapping();
139    }
140
141        /** Adds a semantic predicate string to the sem pred vector
142     These strings will be used to build an array of sem pred names
143     when building a debugging parser.  This method should only be
144     called when the debug option is specified
145     */
146    protected int addSemPred(String predicate) {
147        semPreds.appendElement(predicate);
148        return semPreds.size() - 1;
149    }
150
151    public void exitIfError() {
152        if (antlrTool.hasError()) {
153            antlrTool.fatalError("Exiting due to errors.");
154        }
155    }
156
157    /**Generate the parser, lexer, treeparser, and token types in Java */
158    public void gen() {
159        // Do the code generation
160        try {
161            // Loop over all grammars
162            Enumeration grammarIter = behavior.grammars.elements();
163            while (grammarIter.hasMoreElements()) {
164                Grammar g = (Grammar)grammarIter.nextElement();
165                // Connect all the components to each other
166                g.setGrammarAnalyzer(analyzer);
167                g.setCodeGenerator(this);
168                analyzer.setGrammar(g);
169                // To get right overloading behavior across hetrogeneous grammars
170                setupGrammarParameters(g);
171                g.generate();
172                // print out the grammar with lookahead sets (and FOLLOWs)
173                // System.out.print(g.toString());
174                exitIfError();
175            }
176
177            // Loop over all token managers (some of which are lexers)
178            Enumeration tmIter = behavior.tokenManagers.elements();
179            while (tmIter.hasMoreElements()) {
180                TokenManager tm = (TokenManager)tmIter.nextElement();
181                if (!tm.isReadOnly()) {
182                    // Write the token manager tokens as Java
183                    // this must appear before genTokenInterchange so that
184                    // labels are set on string literals
185                    genTokenTypes(tm);
186                    // Write the token manager tokens as plain text
187                    genTokenInterchange(tm);
188                }
189                exitIfError();
190            }
191        }
192        catch (IOException e) {
193            antlrTool.reportException(e, null);
194        }
195    }
196
197    /** Generate code for the given grammar element.
198     * @param blk The {...} action to generate
199     */
200    public void gen(ActionElement action) {
201        int oldDefaultLine = defaultLine;
202                try {
203                        defaultLine = action.getLine();
204                if (DEBUG_CODE_GENERATOR) System.out.println("genAction(" + action + ")");
205                if (action.isSemPred) {
206                    genSemPred(action.actionText, action.line);
207                }
208                else {
209                    if (grammar.hasSyntacticPredicate) {
210                        println("if ( inputState.guessing==0 ) {");
211                        tabs++;
212                    }
213       
214                                // get the name of the followSet for the current rule so that we
215                    // can replace $FOLLOW in the .g file.
216                    ActionTransInfo tInfo = new ActionTransInfo();
217                    String actionStr = processActionForSpecialSymbols(action.actionText,
218                                                                                                                                  action.getLine(),
219                                                                                                                                  currentRule,
220                                                                                                                                  tInfo);
221       
222                    if (tInfo.refRuleRoot != null) {
223                        // Somebody referenced "#rule", make sure translated var is valid
224                        // assignment to #rule is left as a ref also, meaning that assignments
225                        // with no other refs like "#rule = foo();" still forces this code to be
226                        // generated (unnecessarily).
227                        println(tInfo.refRuleRoot + " = (" + labeledElementASTType + ")currentAST.root;");
228                    }
229       
230                    // dump the translated action
231                    printAction(actionStr);
232       
233                    if (tInfo.assignToRoot) {
234                        // Somebody did a "#rule=", reset internal currentAST.root
235                        println("currentAST.root = " + tInfo.refRuleRoot + ";");
236                        // reset the child pointer too to be last sibling in sibling list
237                        println("currentAST.child = " + tInfo.refRuleRoot + "!=null &&" + tInfo.refRuleRoot + ".getFirstChild()!=null ?", NO_MAPPING);
238                        tabs++;
239                        println(tInfo.refRuleRoot + ".getFirstChild() : " + tInfo.refRuleRoot + ";");
240                        tabs--;
241                        println("currentAST.advanceChildToEnd();");
242                    }
243       
244                    if (grammar.hasSyntacticPredicate) {
245                        tabs--;
246                        println("}", NO_MAPPING);
247                    }
248                }
249            } finally {
250                        defaultLine = oldDefaultLine;
251                }
252    }
253
254    /** Generate code for the given grammar element.
255     * @param blk The "x|y|z|..." block to generate
256     */
257    public void gen(AlternativeBlock blk) {
258        if (DEBUG_CODE_GENERATOR) System.out.println("gen(" + blk + ")");
259        println("{", NO_MAPPING);
260        genBlockPreamble(blk);
261        genBlockInitAction(blk);
262
263        // Tell AST generation to build subrule result
264        String saveCurrentASTResult = currentASTResult;
265        if (blk.getLabel() != null) {
266            currentASTResult = blk.getLabel();
267        }
268
269        boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
270
271        JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, true);
272        genBlockFinish(howToFinish, throwNoViable, blk.getLine());
273
274        println("}", NO_MAPPING);
275
276        // Restore previous AST generation
277        currentASTResult = saveCurrentASTResult;
278    }
279
280    /** Generate code for the given grammar element.
281     * @param blk The block-end element to generate.  Block-end
282     * elements are synthesized by the grammar parser to represent
283     * the end of a block.
284     */
285    public void gen(BlockEndElement end) {
286        if (DEBUG_CODE_GENERATOR) System.out.println("genRuleEnd(" + end + ")");
287    }
288
289    /** Generate code for the given grammar element.
290     * @param blk The character literal reference to generate
291     */
292    public void gen(CharLiteralElement atom) {
293        if (DEBUG_CODE_GENERATOR) System.out.println("genChar(" + atom + ")");
294
295        if (atom.getLabel() != null) {
296            println(atom.getLabel() + " = " + lt1Value + ";", atom.getLine());
297        }
298
299        boolean oldsaveText = saveText;
300        saveText = saveText && atom.getAutoGenType() == GrammarElement.AUTO_GEN_NONE;
301        genMatch(atom);
302        saveText = oldsaveText;
303    }
304
305    /** Generate code for the given grammar element.
306     * @param blk The character-range reference to generate
307     */
308    public void gen(CharRangeElement r) {
309        int oldDefaultLine = defaultLine;
310                try {
311                        defaultLine = r.getLine();
312                if (r.getLabel() != null && syntacticPredLevel == 0) {
313                    println(r.getLabel() + " = " + lt1Value + ";");
314                }
315                boolean flag = ( grammar instanceof LexerGrammar &&
316                    ( !saveText ||
317                    r.getAutoGenType() ==
318                    GrammarElement.AUTO_GEN_BANG ) );
319                if (flag) {
320                    println("_saveIndex=text.length();");
321                }
322       
323                println("matchRange(" + r.beginText + "," + r.endText + ");");
324       
325                if (flag) {
326                    println("text.setLength(_saveIndex);");
327                }
328            } finally {
329                        defaultLine = oldDefaultLine;
330                }
331    }
332
333    /** Generate the lexer Java file */
334    public void gen(LexerGrammar g) throws IOException {
335        int oldDefaultLine = defaultLine;
336                try {
337                        defaultLine = NO_MAPPING;
338                // If debugging, create a new sempred vector for this grammar
339                if (g.debuggingOutput)
340                    semPreds = new Vector();
341       
342                setGrammar(g);
343                if (!(grammar instanceof LexerGrammar)) {
344                    antlrTool.panic("Internal error generating lexer");
345                }
346       
347                // SAS: moved output creation to method so a subclass can change
348                //      how the output is generated (for VAJ interface)
349                currentOutput = getPrintWriterManager().setupOutput(antlrTool, grammar);
350       
351                genAST = false; // no way to gen trees.
352                saveText = true;        // save consumed characters.
353       
354                tabs = 0;
355       
356                // Generate header common to all Java output files
357                genHeader();
358                // Do not use printAction because we assume tabs==0
359               
360                        try {
361                                defaultLine = behavior.getHeaderActionLine("");
362                                println(behavior.getHeaderAction(""));
363                        } finally {
364                                defaultLine = NO_MAPPING;
365                        }
366       
367                // Generate header specific to lexer Java file
368                // println("import java.io.FileInputStream;");
369                println("import java.io.InputStream;");
370                println("import antlr.TokenStreamException;");
371                println("import antlr.TokenStreamIOException;");
372                println("import antlr.TokenStreamRecognitionException;");
373                println("import antlr.CharStreamException;");
374                println("import antlr.CharStreamIOException;");
375                println("import antlr.ANTLRException;");
376                println("import java.io.Reader;");
377                println("import java.util.Hashtable;");
378                println("import antlr." + grammar.getSuperClass() + ";");
379                println("import antlr.InputBuffer;");
380                println("import antlr.ByteBuffer;");
381                println("import antlr.CharBuffer;");
382                println("import antlr.Token;");
383                println("import antlr.CommonToken;");
384                println("import antlr.RecognitionException;");
385                println("import antlr.NoViableAltForCharException;");
386                println("import antlr.MismatchedCharException;");
387                println("import antlr.TokenStream;");
388                println("import antlr.ANTLRHashString;");
389                println("import antlr.LexerSharedInputState;");
390                println("import antlr.collections.impl.BitSet;");
391                println("import antlr.SemanticException;");
392       
393                // Generate user-defined lexer file preamble
394                println(grammar.preambleAction.getText());
395       
396                // Generate lexer class definition
397                String sup = null;
398                if (grammar.superClass != null) {
399                    sup = grammar.superClass;
400                }
401                else {
402                    sup = "antlr." + grammar.getSuperClass();
403                }
404       
405                // print javadoc comment if any
406                if (grammar.comment != null) {
407                    _println(grammar.comment);
408                }
409       
410                        // get prefix (replaces "public" and lets user specify)
411                        String prefix = "public";
412                        Token tprefix = (Token)grammar.options.get("classHeaderPrefix");
413                        if (tprefix != null) {
414                                String p = StringUtils.stripFrontBack(tprefix.getText(), "\"", "\"");
415                                if (p != null) {
416                                        prefix = p;
417                                }
418                        }
419       
420                        print(prefix+" ");
421                        print("class " + grammar.getClassName() + " extends " + sup);
422                        println(" implements " + grammar.tokenManager.getName() + TokenTypesFileSuffix + ", TokenStream");
423                        Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
424                if (tsuffix != null) {
425                    String suffix = StringUtils.stripFrontBack(tsuffix.getText(), "\"", "\"");
426                    if (suffix != null) {
427                        print(", " + suffix);   // must be an interface name for Java
428                    }
429                }
430                println(" {");
431       
432                // Generate user-defined lexer class members
433                print(
434                    processActionForSpecialSymbols(grammar.classMemberAction.getText(), grammar.classMemberAction.getLine(), currentRule, null),
435                    grammar.classMemberAction.getLine()
436                );
437       
438                //
439                // Generate the constructor from InputStream, which in turn
440                // calls the ByteBuffer constructor
441                //
442                println("public " + grammar.getClassName() + "(InputStream in) {");
443                tabs++;
444                println("this(new ByteBuffer(in));");
445                tabs--;
446                println("}");
447       
448                //
449                // Generate the constructor from Reader, which in turn
450                // calls the CharBuffer constructor
451                //
452                println("public " + grammar.getClassName() + "(Reader in) {");
453                tabs++;
454                println("this(new CharBuffer(in));");
455                tabs--;
456                println("}");
457       
458                println("public " + grammar.getClassName() + "(InputBuffer ib) {");
459                tabs++;
460                // if debugging, wrap the input buffer in a debugger
461                if (grammar.debuggingOutput)
462                    println("this(new LexerSharedInputState(new antlr.debug.DebuggingInputBuffer(ib)));");
463                else
464                    println("this(new LexerSharedInputState(ib));");
465                tabs--;
466                println("}");
467       
468                //
469                // Generate the constructor from InputBuffer (char or byte)
470                //
471                println("public " + grammar.getClassName() + "(LexerSharedInputState state) {");
472                tabs++;
473       
474                println("super(state);");
475                // if debugging, set up array variables and call user-overridable
476                //   debugging setup method
477                if (grammar.debuggingOutput) {
478                    println("  ruleNames  = _ruleNames;");
479                    println("  semPredNames = _semPredNames;");
480                    println("  setupDebugging();");
481                }
482       
483                // Generate the setting of various generated options.
484                // These need to be before the literals since ANTLRHashString depends on
485                // the casesensitive stuff.
486                println("caseSensitiveLiterals = " + g.caseSensitiveLiterals + ";");
487                println("setCaseSensitive(" + g.caseSensitive + ");");
488       
489                // Generate the initialization of a hashtable
490                // containing the string literals used in the lexer
491                // The literals variable itself is in CharScanner
492                println("literals = new Hashtable();");
493                Enumeration keys = grammar.tokenManager.getTokenSymbolKeys();
494                while (keys.hasMoreElements()) {
495                    String key = (String)keys.nextElement();
496                    if (key.charAt(0) != '"') {
497                        continue;
498                    }
499                    TokenSymbol sym = grammar.tokenManager.getTokenSymbol(key);
500                    if (sym instanceof StringLiteralSymbol) {
501                        StringLiteralSymbol s = (StringLiteralSymbol)sym;
502                        println("literals.put(new ANTLRHashString(" + s.getId() + ", this), new Integer(" + s.getTokenType() + "));");
503                    }
504                }
505                tabs--;
506       
507                Enumeration ids;
508                println("}");
509       
510                // generate the rule name array for debugging
511                if (grammar.debuggingOutput) {
512                    println("private static final String _ruleNames[] = {");
513       
514                    ids = grammar.rules.elements();
515                    int ruleNum = 0;
516                    while (ids.hasMoreElements()) {
517                        GrammarSymbol sym = (GrammarSymbol)ids.nextElement();
518                        if (sym instanceof RuleSymbol)
519                            println("  \"" + ((RuleSymbol)sym).getId() + "\",");
520                    }
521                    println("};");
522                }
523       
524                // Generate nextToken() rule.
525                // nextToken() is a synthetic lexer rule that is the implicit OR of all
526                // user-defined lexer rules.
527                genNextToken();
528       
529                // Generate code for each rule in the lexer
530                ids = grammar.rules.elements();
531                int ruleNum = 0;
532                while (ids.hasMoreElements()) {
533                    RuleSymbol sym = (RuleSymbol)ids.nextElement();
534                    // Don't generate the synthetic rules
535                    if (!sym.getId().equals("mnextToken")) {
536                        genRule(sym, false, ruleNum++);
537                    }
538                    exitIfError();
539                }
540       
541                // Generate the semantic predicate map for debugging
542                if (grammar.debuggingOutput)
543                    genSemPredMap();
544       
545                // Generate the bitsets used throughout the lexer
546                genBitsets(bitsetsUsed, ((LexerGrammar)grammar).charVocabulary.size());
547       
548                println("");
549                println("}");
550       
551                // Close the lexer output stream
552                getPrintWriterManager().finishOutput();
553            } finally {
554                        defaultLine = oldDefaultLine;
555                }
556    }
557
558    /** Generate code for the given grammar element.
559     * @param blk The (...)+ block to generate
560     */
561    public void gen(OneOrMoreBlock blk) {
562        int oldDefaultLine = defaultLine; 
563        try {
564                defaultLine = blk.getLine();
565                if (DEBUG_CODE_GENERATOR) System.out.println("gen+(" + blk + ")");
566                String label;
567                String cnt;
568                println("{", NO_MAPPING);
569                genBlockPreamble(blk);
570                if (blk.getLabel() != null) {
571                    cnt = "_cnt_" + blk.getLabel();
572                }
573                else {
574                    cnt = "_cnt" + blk.ID;
575                }
576                println("int " + cnt + "=0;");
577                if (blk.getLabel() != null) {
578                    label = blk.getLabel();
579                }
580                else {
581                    label = "_loop" + blk.ID;
582                }
583                println(label + ":");
584                println("do {");
585                tabs++;
586                // generate the init action for ()+ ()* inside the loop
587                // this allows us to do usefull EOF checking...
588                genBlockInitAction(blk);
589       
590                // Tell AST generation to build subrule result
591                String saveCurrentASTResult = currentASTResult;
592                if (blk.getLabel() != null) {
593                    currentASTResult = blk.getLabel();
594                }
595       
596                boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
597       
598                // generate exit test if greedy set to false
599                // and an alt is ambiguous with exit branch
600                // or when lookahead derived purely from end-of-file
601                // Lookahead analysis stops when end-of-file is hit,
602                // returning set {epsilon}.  Since {epsilon} is not
603                // ambig with any real tokens, no error is reported
604                // by deterministic() routines and we have to check
605                // for the case where the lookahead depth didn't get
606                // set to NONDETERMINISTIC (this only happens when the
607                // FOLLOW contains real atoms + epsilon).
608                boolean generateNonGreedyExitPath = false;
609                int nonGreedyExitDepth = grammar.maxk;
610       
611                if (!blk.greedy &&
612                    blk.exitLookaheadDepth <= grammar.maxk &&
613                    blk.exitCache[blk.exitLookaheadDepth].containsEpsilon()) {
614                    generateNonGreedyExitPath = true;
615                    nonGreedyExitDepth = blk.exitLookaheadDepth;
616                }
617                else if (!blk.greedy &&
618                    blk.exitLookaheadDepth == LLkGrammarAnalyzer.NONDETERMINISTIC) {
619                    generateNonGreedyExitPath = true;
620                }
621       
622                // generate exit test if greedy set to false
623                // and an alt is ambiguous with exit branch
624                if (generateNonGreedyExitPath) {
625                    if (DEBUG_CODE_GENERATOR) {
626                        System.out.println("nongreedy (...)+ loop; exit depth is " +
627                                           blk.exitLookaheadDepth);
628                    }
629                    String predictExit =
630                        getLookaheadTestExpression(blk.exitCache,
631                                                   nonGreedyExitDepth);
632                    println("// nongreedy exit test", NO_MAPPING);
633                    println("if ( " + cnt + ">=1 && " + predictExit + ") break " + label + ";", CONTINUE_LAST_MAPPING);
634                }
635       
636                JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
637                genBlockFinish(
638                    howToFinish,
639                    "if ( " + cnt + ">=1 ) { break " + label + "; } else {" + throwNoViable + "}",
640                    blk.getLine()
641                );
642       
643                println(cnt + "++;");
644                tabs--;
645                println("} while (true);");
646                println("}");
647       
648                // Restore previous AST generation
649                currentASTResult = saveCurrentASTResult;
650        } finally {
651                defaultLine = oldDefaultLine;
652        }
653    }
654
655    /** Generate the parser Java file */
656    public void gen(ParserGrammar g) throws IOException {
657        int oldDefaultLine = defaultLine;
658                try {
659                        defaultLine = NO_MAPPING;
660                // if debugging, set up a new vector to keep track of sempred
661                //   strings for this grammar
662                if (g.debuggingOutput)
663                    semPreds = new Vector();
664       
665                setGrammar(g);
666                if (!(grammar instanceof ParserGrammar)) {
667                    antlrTool.panic("Internal error generating parser");
668                }
669       
670                // Open the output stream for the parser and set the currentOutput
671                // SAS: moved file setup so subclass could do it (for VAJ interface)
672                currentOutput = getPrintWriterManager().setupOutput(antlrTool,grammar);
673       
674                genAST = grammar.buildAST;
675       
676                tabs = 0;
677       
678                // Generate the header common to all output files.
679                genHeader();
680                // Do not use printAction because we assume tabs==0
681                        try {
682                                defaultLine = behavior.getHeaderActionLine("");
683                                println(behavior.getHeaderAction(""));
684                        } finally {
685                                defaultLine = NO_MAPPING;
686                        }
687       
688                // Generate header for the parser
689                println("import antlr.TokenBuffer;");
690                println("import antlr.TokenStreamException;");
691                println("import antlr.TokenStreamIOException;");
692                println("import antlr.ANTLRException;");
693                println("import antlr." + grammar.getSuperClass() + ";");
694                println("import antlr.Token;");
695                println("import antlr.TokenStream;");
696                println("import antlr.RecognitionException;");
697                println("import antlr.NoViableAltException;");
698                println("import antlr.MismatchedTokenException;");
699                println("import antlr.SemanticException;");
700                println("import antlr.ParserSharedInputState;");
701                println("import antlr.collections.impl.BitSet;");
702                if ( genAST ) {
703                                println("import antlr.collections.AST;");
704                                println("import java.util.Hashtable;");
705                                println("import antlr.ASTFactory;");
706                    println("import antlr.ASTPair;");
707                    println("import antlr.collections.impl.ASTArray;");
708                }
709                       
710                // Output the user-defined parser preamble
711                println(grammar.preambleAction.getText());
712       
713                // Generate parser class definition
714                String sup = null;
715                if (grammar.superClass != null)
716                    sup = grammar.superClass;
717                else
718                    sup = "antlr." + grammar.getSuperClass();
719       
720                // print javadoc comment if any
721                if (grammar.comment != null) {
722                    _println(grammar.comment);
723                }
724       
725                        // get prefix (replaces "public" and lets user specify)
726                        String prefix = "public";
727                        Token tprefix = (Token)grammar.options.get("classHeaderPrefix");
728                        if (tprefix != null) {
729                                String p = StringUtils.stripFrontBack(tprefix.getText(), "\"", "\"");
730                                if (p != null) {
731                                        prefix = p;
732                                }
733                        }
734       
735                        print(prefix+" ");
736                        print("class " + grammar.getClassName() + " extends " + sup);
737                println("       implements " + grammar.tokenManager.getName() + TokenTypesFileSuffix);
738       
739                Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
740                if (tsuffix != null) {
741                    String suffix = StringUtils.stripFrontBack(tsuffix.getText(), "\"", "\"");
742                    if (suffix != null)
743                        print(", " + suffix);   // must be an interface name for Java
744                }
745                println(" {");
746               
747                // set up an array of all the rule names so the debugger can
748                // keep track of them only by number -- less to store in tree...
749                if (grammar.debuggingOutput) {
750                    println("private static final String _ruleNames[] = {");
751       
752                    Enumeration ids = grammar.rules.elements();
753                    int ruleNum = 0;
754                    while (ids.hasMoreElements()) {
755                        GrammarSymbol sym = (GrammarSymbol)ids.nextElement();
756                        if (sym instanceof RuleSymbol)
757                            println("  \"" + ((RuleSymbol)sym).getId() + "\",");
758                    }
759                    println("};");
760                }
761       
762                // Generate user-defined parser class members
763                print(
764                    processActionForSpecialSymbols(grammar.classMemberAction.getText(), grammar.classMemberAction.getLine(), currentRule, null), 
765                    grammar.classMemberAction.getLine()
766                );
767       
768                // Generate parser class constructor from TokenBuffer
769                println("");
770                println("protected " + grammar.getClassName() + "(TokenBuffer tokenBuf, int k) {");
771                println("  super(tokenBuf,k);");
772                println("  tokenNames = _tokenNames;");
773                // if debugging, set up arrays and call the user-overridable
774                //   debugging setup method
775                if (grammar.debuggingOutput) {
776                    println("  ruleNames  = _ruleNames;");
777                    println("  semPredNames = _semPredNames;");
778                    println("  setupDebugging(tokenBuf);");
779                }
780                        if ( grammar.buildAST ) {
781                                println("  buildTokenTypeASTClassMap();");
782                                println("  astFactory = new ASTFactory(getTokenTypeToASTClassMap());");
783                        }
784                println("}");
785                println("");
786       
787                println("public " + grammar.getClassName() + "(TokenBuffer tokenBuf) {");
788                println("  this(tokenBuf," + grammar.maxk + ");");
789                println("}");
790                println("");
791       
792                // Generate parser class constructor from TokenStream
793                println("protected " + grammar.getClassName() + "(TokenStream lexer, int k) {");
794                println("  super(lexer,k);");
795                println("  tokenNames = _tokenNames;");
796       
797                // if debugging, set up arrays and call the user-overridable
798                //   debugging setup method
799                if (grammar.debuggingOutput) {
800                    println("  ruleNames  = _ruleNames;");
801                    println("  semPredNames = _semPredNames;");
802                    println("  setupDebugging(lexer);");
803                }
804                        if ( grammar.buildAST ) {
805                                println("  buildTokenTypeASTClassMap();");
806                                println("  astFactory = new ASTFactory(getTokenTypeToASTClassMap());");
807                        }
808                println("}");
809                println("");
810       
811                println("public " + grammar.getClassName() + "(TokenStream lexer) {");
812                println("  this(lexer," + grammar.maxk + ");");
813                println("}");
814                println("");
815       
816                println("public " + grammar.getClassName() + "(ParserSharedInputState state) {");
817                println("  super(state," + grammar.maxk + ");");
818                println("  tokenNames = _tokenNames;");
819                        if ( grammar.buildAST ) {
820                                println("  buildTokenTypeASTClassMap();");
821                                println("  astFactory = new ASTFactory(getTokenTypeToASTClassMap());");
822                        }
823                println("}");
824                println("");
825       
826                // Generate code for each rule in the grammar
827                Enumeration ids = grammar.rules.elements();
828                int ruleNum = 0;
829                while (ids.hasMoreElements()) {
830                    GrammarSymbol sym = (GrammarSymbol)ids.nextElement();
831                    if (sym instanceof RuleSymbol) {
832                        RuleSymbol rs = (RuleSymbol)sym;
833                        genRule(rs, rs.references.size() == 0, ruleNum++);
834                    }
835                    exitIfError();
836                }
837       
838                // Generate the token names
839                genTokenStrings();
840       
841                        if ( grammar.buildAST ) {
842                                genTokenASTNodeMap();
843                        }
844       
845                // Generate the bitsets used throughout the grammar
846                genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType());
847       
848                // Generate the semantic predicate map for debugging
849                if (grammar.debuggingOutput)
850                    genSemPredMap();
851       
852                // Close class definition
853                println("");
854                println("}");
855       
856                // Close the parser output stream
857                getPrintWriterManager().finishOutput();
858            } finally {
859                        defaultLine = oldDefaultLine;
860                }
861    }
862
863    /** Generate code for the given grammar element.
864     * @param blk The rule-reference to generate
865     */
866    public void gen(RuleRefElement rr) {
867        int oldDefaultLine = defaultLine;
868                try {
869                        defaultLine = rr.getLine();
870                if (DEBUG_CODE_GENERATOR) System.out.println("genRR(" + rr + ")");
871                RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
872                if (rs == null || !rs.isDefined()) {
873                    // Is this redundant???
874                    antlrTool.error("Rule '" + rr.targetRule + "' is not defined", grammar.getFilename(), rr.getLine(), rr.getColumn());
875                    return;
876                }
877                if (!(rs instanceof RuleSymbol)) {
878                    // Is this redundant???
879                    antlrTool.error("'" + rr.targetRule + "' does not name a grammar rule", grammar.getFilename(), rr.getLine(), rr.getColumn());
880                    return;
881                }
882       
883                genErrorTryForElement(rr);
884       
885                // AST value for labeled rule refs in tree walker.
886                // This is not AST construction;  it is just the input tree node value.
887                if (grammar instanceof TreeWalkerGrammar &&
888                    rr.getLabel() != null &&
889                    syntacticPredLevel == 0) {
890                    println(rr.getLabel() + " = _t==ASTNULL ? null : " + lt1Value + ";");
891                }
892       
893                // if in lexer and ! on rule ref or alt or rule, save buffer index to kill later
894                if (grammar instanceof LexerGrammar && (!saveText || rr.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) {
895                    println("_saveIndex=text.length();");
896                }
897       
898                // Process return value assignment if any
899                printTabs();
900                if (rr.idAssign != null) {
901                    // Warn if the rule has no return type
902                    if (rs.block.returnAction == null) {
903                        antlrTool.warning("Rule '" + rr.targetRule + "' has no return type", grammar.getFilename(), rr.getLine(), rr.getColumn());
904                    }
905                    _print(rr.idAssign + "=");
906                }
907                else {
908                    // Warn about return value if any, but not inside syntactic predicate
909                    if (!(grammar instanceof LexerGrammar) && syntacticPredLevel == 0 && rs.block.returnAction != null) {
910                        antlrTool.warning("Rule '" + rr.targetRule + "' returns a value", grammar.getFilename(), rr.getLine(), rr.getColumn());
911                    }
912                }
913       
914                // Call the rule
915                GenRuleInvocation(rr);
916       
917                // if in lexer and ! on element or alt or rule, save buffer index to kill later
918                if (grammar instanceof LexerGrammar && (!saveText || rr.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) {
919                    println("text.setLength(_saveIndex);");
920                }
921       
922                // if not in a syntactic predicate
923                if (syntacticPredLevel == 0) {
924                    boolean doNoGuessTest = (
925                        grammar.hasSyntacticPredicate &&
926                        (
927                        grammar.buildAST && rr.getLabel() != null ||
928                        (genAST && rr.getAutoGenType() == GrammarElement.AUTO_GEN_NONE)
929                        )
930                        );
931                    if (doNoGuessTest) {
932                        // println("if (inputState.guessing==0) {");
933                        // tabs++;
934                    }
935       
936                    if (grammar.buildAST && rr.getLabel() != null) {
937                        // always gen variable for rule return on labeled rules
938                        println(rr.getLabel() + "_AST = (" + labeledElementASTType + ")returnAST;");
939                    }
940                    if (genAST) {
941                        switch (rr.getAutoGenType()) {
942                            case GrammarElement.AUTO_GEN_NONE:
943                                // println("theASTFactory.addASTChild(currentAST, returnAST);");
944                                println("astFactory.addASTChild(currentAST, returnAST);");
945                                break;
946                            case GrammarElement.AUTO_GEN_CARET:
947                                antlrTool.error("Internal: encountered ^ after rule reference");
948                                break;
949                            default:
950                                break;
951                        }
952                    }
953       
954                    // if a lexer and labeled, Token label defined at rule level, just set it here
955                    if (grammar instanceof LexerGrammar && rr.getLabel() != null) {
956                        println(rr.getLabel() + "=_returnToken;");
957                    }
958       
959                    if (doNoGuessTest) {
960                        // tabs--;
961                        // println("}");
962                    }
963                }
964                genErrorCatchForElement(rr);
965            } finally {
966                        defaultLine = oldDefaultLine;
967                }
968    }
969
970    /** Generate code for the given grammar element.
971     * @param blk The string-literal reference to generate
972     */
973    public void gen(StringLiteralElement atom) {
974        if (DEBUG_CODE_GENERATOR) System.out.println("genString(" + atom + ")");
975
976        // Variable declarations for labeled elements
977        if (atom.getLabel() != null && syntacticPredLevel == 0) {
978            println(atom.getLabel() + " = " + lt1Value + ";", atom.getLine());
979        }
980
981        // AST
982        genElementAST(atom);
983
984        // is there a bang on the literal?
985        boolean oldsaveText = saveText;
986        saveText = saveText && atom.getAutoGenType() == GrammarElement.AUTO_GEN_NONE;
987
988        // matching
989        genMatch(atom);
990
991        saveText = oldsaveText;
992
993        // tack on tree cursor motion if doing a tree walker
994        if (grammar instanceof TreeWalkerGrammar) {
995            println("_t = _t.getNextSibling();", atom.getLine());
996        }
997    }
998
999    /** Generate code for the given grammar element.
1000     * @param r The token-range reference to generate
1001     */
1002    public void gen(TokenRangeElement r) {
1003        genErrorTryForElement(r);
1004        if (r.getLabel() != null && syntacticPredLevel == 0) {
1005            println(r.getLabel() + " = " + lt1Value + ";", r.getLine());
1006        }
1007
1008        // AST
1009        genElementAST(r);
1010
1011        // match
1012        println("matchRange(" + r.beginText + "," + r.endText + ");", r.getLine());
1013        genErrorCatchForElement(r);
1014    }
1015
1016    /** Generate code for the given grammar element.
1017     * @param blk The token-reference to generate
1018     */
1019    public void gen(TokenRefElement atom) {
1020        if (DEBUG_CODE_GENERATOR) System.out.println("genTokenRef(" + atom + ")");
1021        if (grammar instanceof LexerGrammar) {
1022            antlrTool.panic("Token reference found in lexer");
1023        }
1024        genErrorTryForElement(atom);
1025        // Assign Token value to token label variable
1026        if (atom.getLabel() != null && syntacticPredLevel == 0) {
1027            println(atom.getLabel() + " = " + lt1Value + ";", atom.getLine());
1028        }
1029
1030        // AST
1031        genElementAST(atom);
1032        // matching
1033        genMatch(atom);
1034        genErrorCatchForElement(atom);
1035
1036        // tack on tree cursor motion if doing a tree walker
1037        if (grammar instanceof TreeWalkerGrammar) {
1038            println("_t = _t.getNextSibling();", atom.getLine());
1039        }
1040    }
1041
1042    public void gen(TreeElement t) {
1043        int oldDefaultLine = defaultLine;
1044                try {
1045                        defaultLine = t.getLine();
1046                // save AST cursor
1047                println("AST __t" + t.ID + " = _t;");
1048       
1049                // If there is a label on the root, then assign that to the variable
1050                if (t.root.getLabel() != null) {
1051                    println(t.root.getLabel() + " = _t==ASTNULL ? null :(" + labeledElementASTType + ")_t;", t.root.getLine());
1052                }
1053       
1054                // check for invalid modifiers ! and ^ on tree element roots
1055                if ( t.root.getAutoGenType() == GrammarElement.AUTO_GEN_BANG ) {
1056                    antlrTool.error("Suffixing a root node with '!' is not implemented",
1057                                 grammar.getFilename(), t.getLine(), t.getColumn());
1058                    t.root.setAutoGenType(GrammarElement.AUTO_GEN_NONE);
1059                }
1060                if ( t.root.getAutoGenType() == GrammarElement.AUTO_GEN_CARET ) {
1061                    antlrTool.warning("Suffixing a root node with '^' is redundant; already a root",
1062                                 grammar.getFilename(), t.getLine(), t.getColumn());
1063                    t.root.setAutoGenType(GrammarElement.AUTO_GEN_NONE);
1064                }
1065       
1066                // Generate AST variables
1067                genElementAST(t.root);
1068                if (grammar.buildAST) {
1069                    // Save the AST construction state
1070                    println("ASTPair __currentAST" + t.ID + " = currentAST.copy();");
1071                    // Make the next item added a child of the TreeElement root
1072                    println("currentAST.root = currentAST.child;");
1073                    println("currentAST.child = null;");
1074                }
1075       
1076                // match root
1077                if ( t.root instanceof WildcardElement ) {
1078                    println("if ( _t==null ) throw new MismatchedTokenException();", t.root.getLine());
1079                }
1080                else {
1081                    genMatch(t.root);
1082                }
1083                // move to list of children
1084                println("_t = _t.getFirstChild();");
1085       
1086                // walk list of children, generating code for each
1087                for (int i = 0; i < t.getAlternatives().size(); i++) {
1088                    Alternative a = t.getAlternativeAt(i);
1089                    AlternativeElement e = a.head;
1090                    while (e != null) {
1091                        e.generate();
1092                        e = e.next;
1093                    }
1094                }
1095       
1096                if (grammar.buildAST) {
1097                    // restore the AST construction state to that just after the
1098                    // tree root was added
1099                    println("currentAST = __currentAST" + t.ID + ";");
1100                }
1101                // restore AST cursor
1102                println("_t = __t" + t.ID + ";");
1103                // move cursor to sibling of tree just parsed
1104                println("_t = _t.getNextSibling();");
1105             } finally {
1106                        defaultLine = oldDefaultLine;
1107                }
1108    }
1109
1110    /** Generate the tree-parser Java file */
1111    public void gen(TreeWalkerGrammar g) throws IOException {
1112        int oldDefaultLine = defaultLine;
1113                try {
1114                        defaultLine = NO_MAPPING;
1115                // SAS: debugging stuff removed for now...
1116                setGrammar(g);
1117                if (!(grammar instanceof TreeWalkerGrammar)) {
1118                    antlrTool.panic("Internal error generating tree-walker");
1119                }
1120                // Open the output stream for the parser and set the currentOutput
1121                // SAS: move file open to method so subclass can override it
1122                //      (mainly for VAJ interface)
1123                currentOutput = getPrintWriterManager().setupOutput(antlrTool,grammar);
1124       
1125                genAST = grammar.buildAST;
1126                tabs = 0;
1127       
1128                // Generate the header common to all output files.
1129                genHeader();
1130                // Do not use printAction because we assume tabs==0
1131                        try {
1132                                defaultLine = behavior.getHeaderActionLine("");
1133                                println(behavior.getHeaderAction(""));
1134                        } finally {
1135                                defaultLine = NO_MAPPING;
1136                        }
1137       
1138                // Generate header for the parser
1139                println("import antlr." + grammar.getSuperClass() + ";");
1140                println("import antlr.Token;");
1141                println("import antlr.collections.AST;");
1142                println("import antlr.RecognitionException;");
1143                println("import antlr.ANTLRException;");
1144                println("import antlr.NoViableAltException;");
1145                println("import antlr.MismatchedTokenException;");
1146                println("import antlr.SemanticException;");
1147                println("import antlr.collections.impl.BitSet;");
1148                println("import antlr.ASTPair;");
1149                println("import antlr.collections.impl.ASTArray;");
1150       
1151                // Output the user-defined parser premamble
1152                println(grammar.preambleAction.getText());
1153       
1154                // Generate parser class definition
1155                String sup = null;
1156                if (grammar.superClass != null) {
1157                    sup = grammar.superClass;
1158                }
1159                else {
1160                    sup = "antlr." + grammar.getSuperClass();
1161                }
1162                println("");
1163       
1164                // print javadoc comment if any
1165                if (grammar.comment != null) {
1166                    _println(grammar.comment);
1167                }
1168       
1169                        // get prefix (replaces "public" and lets user specify)
1170                        String prefix = "public";
1171                        Token tprefix = (Token)grammar.options.get("classHeaderPrefix");
1172                        if (tprefix != null) {
1173                                String p = StringUtils.stripFrontBack(tprefix.getText(), "\"", "\"");
1174                                if (p != null) {
1175                                        prefix = p;
1176                                }
1177                        }
1178       
1179                        print(prefix+" ");
1180                        print("class " + grammar.getClassName() + " extends " + sup);
1181                println("       implements " + grammar.tokenManager.getName() + TokenTypesFileSuffix);
1182                Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
1183                if (tsuffix != null) {
1184                    String suffix = StringUtils.stripFrontBack(tsuffix.getText(), "\"", "\"");
1185                    if (suffix != null) {
1186                        print(", " + suffix);   // must be an interface name for Java
1187                    }
1188                }
1189                println(" {");
1190       
1191                // Generate user-defined parser class members
1192                print(
1193                    processActionForSpecialSymbols(grammar.classMemberAction.getText(), grammar.classMemberAction.getLine(), currentRule, null),
1194                    grammar.classMemberAction.getLine()
1195                );
1196       
1197                // Generate default parser class constructor
1198                println("public " + grammar.getClassName() + "() {");
1199                tabs++;
1200                println("tokenNames = _tokenNames;");
1201                tabs--;
1202                println("}");
1203                println("");
1204       
1205                // Generate code for each rule in the grammar
1206                Enumeration ids = grammar.rules.elements();
1207                int ruleNum = 0;
1208                String ruleNameInits = "";
1209                while (ids.hasMoreElements()) {
1210                    GrammarSymbol sym = (GrammarSymbol)ids.nextElement();
1211                    if (sym instanceof RuleSymbol) {
1212                        RuleSymbol rs = (RuleSymbol)sym;
1213                        genRule(rs, rs.references.size() == 0, ruleNum++);
1214                    }
1215                    exitIfError();
1216                }
1217       
1218                // Generate the token names
1219                genTokenStrings();
1220       
1221                // Generate the bitsets used throughout the grammar
1222                genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType());
1223       
1224                // Close class definition
1225                println("}");
1226                println("");
1227       
1228                // Close the parser output stream
1229                getPrintWriterManager().finishOutput();
1230            } finally {
1231                        defaultLine = oldDefaultLine;
1232                }
1233    }
1234
1235    /** Generate code for the given grammar element.
1236     * @param wc The wildcard element to generate
1237     */
1238    public void gen(WildcardElement wc) {
1239        int oldDefaultLine = defaultLine;
1240                try {
1241                        defaultLine = wc.getLine();
1242                // Variable assignment for labeled elements
1243                if (wc.getLabel() != null && syntacticPredLevel == 0) {
1244                    println(wc.getLabel() + " = " + lt1Value + ";");
1245                }
1246       
1247                // AST
1248                genElementAST(wc);
1249                // Match anything but EOF
1250                if (grammar instanceof TreeWalkerGrammar) {
1251                    println("if ( _t==null ) throw new MismatchedTokenException();");
1252                }
1253                else if (grammar instanceof LexerGrammar) {
1254                    if (grammar instanceof LexerGrammar &&
1255                        (!saveText || wc.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) {
1256                        println("_saveIndex=text.length();");
1257                    }
1258                    println("matchNot(EOF_CHAR);");
1259                    if (grammar instanceof LexerGrammar &&
1260                        (!saveText || wc.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) {
1261                        println("text.setLength(_saveIndex);"); // kill text atom put in buffer
1262                    }
1263                }
1264                else {
1265                    println("matchNot(" + getValueString(Token.EOF_TYPE) + ");");
1266                }
1267       
1268                // tack on tree cursor motion if doing a tree walker
1269                if (grammar instanceof TreeWalkerGrammar) {
1270                    println("_t = _t.getNextSibling();");
1271                }
1272            } finally {
1273                        defaultLine = oldDefaultLine;
1274                }
1275    }
1276
1277    /** Generate code for the given grammar element.
1278     * @param blk The (...)* block to generate
1279     */
1280    public void gen(ZeroOrMoreBlock blk) {
1281        int oldDefaultLine = defaultLine;
1282                try {
1283                        defaultLine = blk.getLine();
1284                if (DEBUG_CODE_GENERATOR) System.out.println("gen*(" + blk + ")");
1285                println("{");
1286                genBlockPreamble(blk);
1287                String label;
1288                if (blk.getLabel() != null) {
1289                    label = blk.getLabel();
1290                }
1291                else {
1292                    label = "_loop" + blk.ID;
1293                }
1294                println(label + ":");
1295                println("do {");
1296                tabs++;
1297                // generate the init action for ()* inside the loop
1298                // this allows us to do usefull EOF checking...
1299                genBlockInitAction(blk);
1300       
1301                // Tell AST generation to build subrule result
1302                String saveCurrentASTResult = currentASTResult;
1303                if (blk.getLabel() != null) {
1304                    currentASTResult = blk.getLabel();
1305                }
1306       
1307                boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
1308       
1309                // generate exit test if greedy set to false
1310                // and an alt is ambiguous with exit branch
1311                // or when lookahead derived purely from end-of-file
1312                // Lookahead analysis stops when end-of-file is hit,
1313                // returning set {epsilon}.  Since {epsilon} is not
1314                // ambig with any real tokens, no error is reported
1315                // by deterministic() routines and we have to check
1316                // for the case where the lookahead depth didn't get
1317                // set to NONDETERMINISTIC (this only happens when the
1318                // FOLLOW contains real atoms + epsilon).
1319                boolean generateNonGreedyExitPath = false;
1320                int nonGreedyExitDepth = grammar.maxk;
1321       
1322                if (!blk.greedy &&
1323                    blk.exitLookaheadDepth <= grammar.maxk &&
1324                    blk.exitCache[blk.exitLookaheadDepth].containsEpsilon()) {
1325                    generateNonGreedyExitPath = true;
1326                    nonGreedyExitDepth = blk.exitLookaheadDepth;
1327                }
1328                else if (!blk.greedy &&
1329                    blk.exitLookaheadDepth == LLkGrammarAnalyzer.NONDETERMINISTIC) {
1330                    generateNonGreedyExitPath = true;
1331                }
1332                if (generateNonGreedyExitPath) {
1333                    if (DEBUG_CODE_GENERATOR) {
1334                        System.out.println("nongreedy (...)* loop; exit depth is " +
1335                                           blk.exitLookaheadDepth);
1336                    }
1337                    String predictExit =
1338                        getLookaheadTestExpression(blk.exitCache,
1339                                                   nonGreedyExitDepth);
1340                    println("// nongreedy exit test");
1341                    println("if (" + predictExit + ") break " + label + ";");
1342                }
1343       
1344                JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
1345                genBlockFinish(howToFinish, "break " + label + ";", blk.getLine());
1346       
1347                tabs--;
1348                println("} while (true);");
1349                println("}");
1350       
1351                // Restore previous AST generation
1352                currentASTResult = saveCurrentASTResult;
1353        } finally {
1354                        defaultLine = oldDefaultLine;
1355                }
1356    }
1357
1358    /** Generate an alternative.
1359     * @param alt  The alternative to generate
1360     * @param blk The block to which the alternative belongs
1361     */
1362    protected void genAlt(Alternative alt, AlternativeBlock blk) {
1363        // Save the AST generation state, and set it to that of the alt
1364        boolean savegenAST = genAST;
1365        genAST = genAST && alt.getAutoGen();
1366
1367        boolean oldsaveTest = saveText;
1368        saveText = saveText && alt.getAutoGen();
1369
1370        // Reset the variable name map for the alternative
1371        Hashtable saveMap = treeVariableMap;
1372        treeVariableMap = new Hashtable();
1373
1374        // Generate try block around the alt for  error handling
1375        if (alt.exceptionSpec != null) {
1376            println("try {      // for error handling", alt.head.getLine());
1377            tabs++;
1378        }
1379
1380        AlternativeElement elem = alt.head;
1381        while (!(elem instanceof BlockEndElement)) {
1382            elem.generate(); // alt can begin with anything. Ask target to gen.
1383            elem = elem.next;
1384        }
1385
1386        if (genAST) {
1387            if (blk instanceof RuleBlock) {
1388                // Set the AST return value for the rule
1389                RuleBlock rblk = (RuleBlock)blk;
1390                if (grammar.hasSyntacticPredicate) {
1391                    // println("if ( inputState.guessing==0 ) {");
1392                    // tabs++;
1393                }
1394                println(rblk.getRuleName() + "_AST = (" + labeledElementASTType + ")currentAST.root;", CONTINUE_LAST_MAPPING);
1395                if (grammar.hasSyntacticPredicate) {
1396                    // --tabs;
1397                    // println("}");
1398                }
1399            }
1400            else if (blk.getLabel() != null) {
1401                // ### future: also set AST value for labeled subrules.
1402                // println(blk.getLabel() + "_AST = ("+labeledElementASTType+")currentAST.root;");
1403                antlrTool.warning("Labeled subrules not yet supported", grammar.getFilename(), blk.getLine(), blk.getColumn());
1404            }
1405        }
1406
1407        if (alt.exceptionSpec != null) {
1408            // close try block
1409            tabs--;
1410            println("}", NO_MAPPING);
1411            genErrorHandler(alt.exceptionSpec);
1412        }
1413
1414        genAST = savegenAST;
1415        saveText = oldsaveTest;
1416
1417        treeVariableMap = saveMap;
1418    }
1419
1420    /** Generate all the bitsets to be used in the parser or lexer
1421     * Generate the raw bitset data like "long _tokenSet1_data[] = {...};"
1422     * and the BitSet object declarations like "BitSet _tokenSet1 = new BitSet(_tokenSet1_data);"
1423     * Note that most languages do not support object initialization inside a
1424     * class definition, so other code-generators may have to separate the
1425     * bitset declarations from the initializations (e.g., put the initializations
1426     * in the generated constructor instead).
1427     * @param bitsetList The list of bitsets to generate.
1428     * @param maxVocabulary Ensure that each generated bitset can contain at least this value.
1429     */
1430    protected void genBitsets(Vector bitsetList,
1431                              int maxVocabulary
1432                              ) {
1433        println("", NO_MAPPING);
1434        for (int i = 0; i < bitsetList.size(); i++) {
1435            BitSet p = (BitSet)bitsetList.elementAt(i);
1436            // Ensure that generated BitSet is large enough for vocabulary
1437            p.growToInclude(maxVocabulary);
1438            genBitSet(p, i);
1439        }
1440    }
1441
1442    /** Do something simple like:
1443     *  private static final long[] mk_tokenSet_0() {
1444     *    long[] data = { -2305839160922996736L, 63L, 16777216L, 0L, 0L, 0L };
1445     *    return data;
1446     *  }
1447     *  public static final BitSet _tokenSet_0 = new BitSet(mk_tokenSet_0());
1448     *
1449     *  Or, for large bitsets, optimize init so ranges are collapsed into loops.
1450     *  This is most useful for lexers using unicode.
1451     */
1452    private void genBitSet(BitSet p, int id) {
1453        int oldDefaultLine = defaultLine;
1454                try {
1455                        defaultLine = NO_MAPPING;
1456                // initialization data
1457                println(
1458                    "private static final long[] mk" + getBitsetName(id) + "() {"
1459                );
1460                int n = p.lengthInLongWords();
1461                if ( n<BITSET_OPTIMIZE_INIT_THRESHOLD ) {
1462                    println("\tlong[] data = { " + p.toStringOfWords() + "};");
1463                }
1464                else {
1465                    // will init manually, allocate space then set values
1466                    println("\tlong[] data = new long["+n+"];");
1467                    long[] elems = p.toPackedArray();
1468                    for (int i = 0; i < elems.length;) {
1469                                        if ( elems[i]==0 ) {
1470                                                // done automatically by Java, don't waste time/code
1471                                                i++;
1472                                                continue;
1473                                        }
1474                        if ( (i+1)==elems.length || elems[i]!=elems[i+1] ) {
1475                            // last number or no run of numbers, just dump assignment
1476                            println("\tdata["+i+"]="+elems[i]+"L;");
1477                            i++;
1478                        }
1479                        else {
1480                            // scan to find end of run
1481                            int j;
1482                            for (j = i + 1;
1483                                 j < elems.length && elems[j]==elems[i];
1484                                 j++)
1485                            {
1486                            }
1487                            // j-1 is last member of run
1488                            println("\tfor (int i = "+i+"; i<="+(j-1)+"; i++) { data[i]="+
1489                                    elems[i]+"L; }");
1490                            i = j;
1491                        }
1492                    }
1493                }
1494       
1495                println("\treturn data;");
1496                println("}");
1497                // BitSet object
1498                println(
1499                    "public static final BitSet " + getBitsetName(id) + " = new BitSet(" +
1500                    "mk" + getBitsetName(id) + "()" +
1501                    ");"
1502                );
1503            } finally {
1504                        defaultLine = oldDefaultLine;
1505                }
1506    }
1507
1508    /** Generate the finish of a block, using a combination of the info
1509     * returned from genCommonBlock() and the action to perform when
1510     * no alts were taken
1511     * @param howToFinish The return of genCommonBlock()
1512     * @param noViableAction What to generate when no alt is taken
1513     */
1514    private void genBlockFinish(JavaBlockFinishingInfo howToFinish, String noViableAction, int line) {
1515        int oldDefaultLine = defaultLine;
1516                try {
1517                        defaultLine = line;
1518                if (howToFinish.needAnErrorClause &&
1519                    (howToFinish.generatedAnIf || howToFinish.generatedSwitch)) {
1520                    if (howToFinish.generatedAnIf) {
1521                        println("else {");
1522                    }
1523                    else {
1524                        println("{");
1525                    }
1526                    tabs++;
1527                    println(noViableAction);
1528                    tabs--;
1529                    println("}");
1530                }
1531       
1532                if (howToFinish.postscript != null) {
1533                    println(howToFinish.postscript);
1534                }
1535                } finally {
1536                        defaultLine = oldDefaultLine;
1537                }
1538    }
1539
1540    /** Generate the init action for a block, which may be a RuleBlock or a
1541     * plain AlternativeBLock.
1542     * @blk The block for which the preamble is to be generated.
1543     */
1544    protected void genBlockInitAction(AlternativeBlock blk) {
1545        // dump out init action
1546        if (blk.initAction != null) {
1547            printAction(processActionForSpecialSymbols(blk.initAction, blk.getLine(), currentRule, null),blk.getLine());
1548        }
1549    }
1550
1551    /** Generate the header for a block, which may be a RuleBlock or a
1552     * plain AlternativeBLock.  This generates any variable declarations
1553     * and syntactic-predicate-testing variables.
1554     * @blk The block for which the preamble is to be generated.
1555     */
1556    protected void genBlockPreamble(AlternativeBlock blk) {
1557        // define labels for rule blocks.
1558        if (blk instanceof RuleBlock) {
1559            RuleBlock rblk = (RuleBlock)blk;
1560            if (rblk.labeledElements != null) {
1561                for (int i = 0; i < rblk.labeledElements.size(); i++) {
1562                    AlternativeElement a = (AlternativeElement)rblk.labeledElements.elementAt(i);
1563                    int oldDefaultLine = defaultLine;
1564                                        try {
1565                                                defaultLine = a.getLine();
1566                            // System.out.println("looking at labeled element: "+a);
1567                            // Variables for labeled rule refs and
1568                            // subrules are different than variables for
1569                            // grammar atoms.  This test is a little tricky
1570                            // because we want to get all rule refs and ebnf,
1571                            // but not rule blocks or syntactic predicates
1572                            if (
1573                                a instanceof RuleRefElement ||
1574                                a instanceof AlternativeBlock &&
1575                                !(a instanceof RuleBlock) &&
1576                                !(a instanceof SynPredBlock)
1577                            ) {
1578       
1579                                if (
1580                                    !(a instanceof RuleRefElement) &&
1581                                    ((AlternativeBlock)a).not &&
1582                                    analyzer.subruleCanBeInverted(((AlternativeBlock)a), grammar instanceof LexerGrammar)
1583                                ) {
1584                                    // Special case for inverted subrules that
1585                                    // will be inlined.  Treat these like
1586                                    // token or char literal references
1587                                    println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
1588                                    if (grammar.buildAST) {
1589                                        genASTDeclaration(a);
1590                                    }
1591                                }
1592                                else {
1593                                    if (grammar.buildAST) {
1594                                        // Always gen AST variables for
1595                                        // labeled elements, even if the
1596                                        // element itself is marked with !
1597                                        genASTDeclaration(a);
1598                                    }
1599                                    if (grammar instanceof LexerGrammar) {
1600                                        println("Token " + a.getLabel() + "=null;");
1601                                    }
1602                                    if (grammar instanceof TreeWalkerGrammar) {
1603                                        // always generate rule-ref variables
1604                                        // for tree walker
1605                                        println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
1606                                    }
1607                                }
1608                            }
1609                            else {
1610                                // It is a token or literal reference.  Generate the
1611                                // correct variable type for this grammar
1612                                println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
1613       
1614                                // In addition, generate *_AST variables if
1615                                // building ASTs
1616                                if (grammar.buildAST) {
1617                                    if (a instanceof GrammarAtom &&
1618                                        ((GrammarAtom)a).getASTNodeType() != null) {
1619                                        GrammarAtom ga = (GrammarAtom)a;
1620                                        genASTDeclaration(a, ga.getASTNodeType());
1621                                    }
1622                                    else {
1623                                        genASTDeclaration(a);
1624                                    }
1625                                }
1626                            }
1627                                        } finally {
1628                                                defaultLine = oldDefaultLine;
1629                                        }       
1630                }
1631            }
1632        }
1633    }
1634
1635    /** Generate a series of case statements that implement a BitSet test.
1636     * @param p The Bitset for which cases are to be generated
1637     */
1638    protected void genCases(BitSet p, int line) {
1639        int oldDefaultLine = defaultLine;
1640                try {
1641                        defaultLine = line;
1642                if (DEBUG_CODE_GENERATOR) System.out.println("genCases(" + p + ")");
1643                int[] elems;
1644       
1645                elems = p.toArray();
1646                // Wrap cases four-per-line for lexer, one-per-line for parser
1647                int wrap = (grammar instanceof LexerGrammar) ? 4 : 1;
1648                int j = 1;
1649                boolean startOfLine = true;
1650                for (int i = 0; i < elems.length; i++) {
1651                    if (j == 1) {
1652                        print("");
1653                    }
1654                    else {
1655                        _print("  ");
1656                    }
1657                    _print("case " + getValueString(elems[i]) + ":");
1658       
1659                    if (j == wrap) {
1660                        _println("");
1661                        startOfLine = true;
1662                        j = 1;
1663                    }
1664                    else {
1665                        j++;
1666                        startOfLine = false;
1667                    }
1668                }
1669                if (!startOfLine) {
1670                    _println("");
1671                }
1672            } finally {
1673                        defaultLine = oldDefaultLine;
1674                }
1675    }
1676
1677    /**Generate common code for a block of alternatives; return a
1678     * postscript that needs to be generated at the end of the
1679     * block.  Other routines may append else-clauses and such for
1680     * error checking before the postfix is generated.  If the
1681     * grammar is a lexer, then generate alternatives in an order
1682     * where alternatives requiring deeper lookahead are generated
1683     * first, and EOF in the lookahead set reduces the depth of
1684     * the lookahead.  @param blk The block to generate @param
1685     * noTestForSingle If true, then it does not generate a test
1686     * for a single alternative.
1687     */
1688    public JavaBlockFinishingInfo genCommonBlock(AlternativeBlock blk,
1689                                                 boolean noTestForSingle) {
1690        int oldDefaultLine = defaultLine;
1691                try {
1692                        defaultLine = blk.getLine();
1693                int nIF = 0;
1694                boolean createdLL1Switch = false;
1695                int closingBracesOfIFSequence = 0;
1696                JavaBlockFinishingInfo finishingInfo = new JavaBlockFinishingInfo();
1697                if (DEBUG_CODE_GENERATOR) System.out.println("genCommonBlock(" + blk + ")");
1698       
1699                // Save the AST generation state, and set it to that of the block
1700                boolean savegenAST = genAST;
1701                genAST = genAST && blk.getAutoGen();
1702       
1703                boolean oldsaveTest = saveText;
1704                saveText = saveText && blk.getAutoGen();
1705       
1706                // Is this block inverted?  If so, generate special-case code
1707                if (
1708                    blk.not &&
1709                    analyzer.subruleCanBeInverted(blk, grammar instanceof LexerGrammar)
1710                ) {
1711                    if (DEBUG_CODE_GENERATOR) System.out.println("special case: ~(subrule)");
1712                    Lookahead p = analyzer.look(1, blk);
1713                    // Variable assignment for labeled elements
1714                    if (blk.getLabel() != null && syntacticPredLevel == 0) {
1715                        println(blk.getLabel() + " = " + lt1Value + ";");
1716                    }
1717       
1718                    // AST
1719                    genElementAST(blk);
1720       
1721                    String astArgs = "";
1722                    if (grammar instanceof TreeWalkerGrammar) {
1723                        astArgs = "_t,";
1724                    }
1725       
1726                    // match the bitset for the alternative
1727                    println("match(" + astArgs + getBitsetName(markBitsetForGen(p.fset)) + ");");
1728       
1729                    // tack on tree cursor motion if doing a tree walker
1730                    if (grammar instanceof TreeWalkerGrammar) {
1731                        println("_t = _t.getNextSibling();");
1732                    }
1733                    return finishingInfo;
1734                }
1735       
1736                // Special handling for single alt
1737                if (blk.getAlternatives().size() == 1) {
1738                    Alternative alt = blk.getAlternativeAt(0);
1739                    // Generate a warning if there is a synPred for single alt.
1740                    if (alt.synPred != null) {
1741                        antlrTool.warning(
1742                            "Syntactic predicate superfluous for single alternative",
1743                            grammar.getFilename(),
1744                            blk.getAlternativeAt(0).synPred.getLine(),
1745                            blk.getAlternativeAt(0).synPred.getColumn()
1746                        );
1747                    }
1748                    if (noTestForSingle) {
1749                        if (alt.semPred != null) {
1750                            // Generate validating predicate
1751                            genSemPred(alt.semPred, blk.line);
1752                        }
1753                        genAlt(alt, blk);
1754                        return finishingInfo;
1755                    }
1756                }
1757       
1758                // count number of simple LL(1) cases; only do switch for
1759                // many LL(1) cases (no preds, no end of token refs)
1760                // We don't care about exit paths for (...)*, (...)+
1761                // because we don't explicitly have a test for them
1762                // as an alt in the loop.
1763                //
1764                // Also, we now count how many unicode lookahead sets
1765                // there are--they must be moved to DEFAULT or ELSE
1766                // clause.
1767                int nLL1 = 0;
1768                for (int i = 0; i < blk.getAlternatives().size(); i++) {
1769                    Alternative a = blk.getAlternativeAt(i);
1770                    if (suitableForCaseExpression(a)) {
1771                        nLL1++;
1772                    }
1773                }
1774       
1775                // do LL(1) cases
1776                if (nLL1 >= makeSwitchThreshold) {
1777                    // Determine the name of the item to be compared
1778                    String testExpr = lookaheadString(1);
1779                    createdLL1Switch = true;
1780                    // when parsing trees, convert null to valid tree node with NULL lookahead
1781                    if (grammar instanceof TreeWalkerGrammar) {
1782                        println("if (_t==null) _t=ASTNULL;");
1783                    }
1784                    println("switch ( " + testExpr + ") {");
1785                    for (int i = 0; i < blk.alternatives.size(); i++) {
1786                        Alternative alt = blk.getAlternativeAt(i);
1787                        // ignore any non-LL(1) alts, predicated alts,
1788                        // or end-of-token alts for case expressions
1789                        if (!suitableForCaseExpression(alt)) {
1790                            continue;
1791                        }
1792                        Lookahead p = alt.cache[1];
1793                        if (p.fset.degree() == 0 && !p.containsEpsilon()) {
1794                            antlrTool.warning("Alternate omitted due to empty prediction set",
1795                                         grammar.getFilename(),
1796                                         alt.head.getLine(), alt.head.getColumn());
1797                        }
1798                        else {
1799                            genCases(p.fset, alt.head.getLine());
1800                            println("{", alt.head.getLine());
1801                            tabs++;
1802                            genAlt(alt, blk);
1803                            println("break;", NO_MAPPING);
1804                            tabs--;
1805                            println("}", NO_MAPPING);
1806                        }
1807                    }
1808                    println("default:");
1809                    tabs++;
1810                }
1811       
1812                // do non-LL(1) and nondeterministic cases This is tricky in
1813                // the lexer, because of cases like: STAR : '*' ; ASSIGN_STAR
1814                // : "*="; Since nextToken is generated without a loop, then
1815                // the STAR will have end-of-token as it's lookahead set for
1816                // LA(2).  So, we must generate the alternatives containing
1817                // trailing end-of-token in their lookahead sets *after* the
1818                // alternatives without end-of-token.  This implements the
1819                // usual lexer convention that longer matches come before
1820                // shorter ones, e.g.  "*=" matches ASSIGN_STAR not STAR
1821                //
1822                // For non-lexer grammars, this does not sort the alternates
1823                // by depth Note that alts whose lookahead is purely
1824                // end-of-token at k=1 end up as default or else clauses.
1825                int startDepth = (grammar instanceof LexerGrammar) ? grammar.maxk : 0;
1826                for (int altDepth = startDepth; altDepth >= 0; altDepth--) {
1827                    if (DEBUG_CODE_GENERATOR) System.out.println("checking depth " + altDepth);
1828                    for (int i = 0; i < blk.alternatives.size(); i++) {
1829                        Alternative alt = blk.getAlternativeAt(i);
1830                        if (DEBUG_CODE_GENERATOR) System.out.println("genAlt: " + i);
1831                        // if we made a switch above, ignore what we already took care
1832                        // of.  Specifically, LL(1) alts with no preds
1833                        // that do not have end-of-token in their prediction set
1834                        // and that are not giant unicode sets.
1835                        if (createdLL1Switch && suitableForCaseExpression(alt)) {
1836                            if (DEBUG_CODE_GENERATOR) System.out.println("ignoring alt because it was in the switch");
1837                            continue;
1838                        }
1839                        String e;
1840       
1841                        boolean unpredicted = false;
1842       
1843                        if (grammar instanceof LexerGrammar) {
1844                            // Calculate the "effective depth" of the alt,
1845                            // which is the max depth at which
1846                            // cache[depth]!=end-of-token
1847                            int effectiveDepth = alt.lookaheadDepth;
1848                            if (effectiveDepth == GrammarAnalyzer.NONDETERMINISTIC) {
1849                                // use maximum lookahead
1850                                effectiveDepth = grammar.maxk;
1851                            }
1852                            while (effectiveDepth >= 1 &&
1853                                alt.cache[effectiveDepth].containsEpsilon()) {
1854                                effectiveDepth--;
1855                            }
1856                            // Ignore alts whose effective depth is other than
1857                            // the ones we are generating for this iteration.
1858                            if (effectiveDepth != altDepth) {
1859                                if (DEBUG_CODE_GENERATOR)
1860                                    System.out.println("ignoring alt because effectiveDepth!=altDepth;" + effectiveDepth + "!=" + altDepth);
1861                                continue;
1862                            }
1863                            unpredicted = lookaheadIsEmpty(alt, effectiveDepth);
1864                            e = getLookaheadTestExpression(alt, effectiveDepth);
1865                        }
1866                        else {
1867                            unpredicted = lookaheadIsEmpty(alt, grammar.maxk);
1868                            e = getLookaheadTestExpression(alt, grammar.maxk);
1869                        }
1870       
1871                        int oldDefaultLine2 = defaultLine;
1872                                        try {
1873                                                defaultLine = alt.head.getLine();
1874                                // Was it a big unicode range that forced unsuitability
1875                                // for a case expression?
1876                                if (alt.cache[1].fset.degree() > caseSizeThreshold &&
1877                                    suitableForCaseExpression(alt)) {
1878                                    if (nIF == 0) {
1879                                        println("if " + e + " {");
1880                                    }
1881                                    else {
1882                                        println("else if " + e + " {");
1883                                    }
1884                                }
1885                                else if (unpredicted &&
1886                                    alt.semPred == null &&
1887                                    alt.synPred == null) {
1888                                    // The alt has empty prediction set and no
1889                                    // predicate to help out.  if we have not
1890                                    // generated a previous if, just put {...} around
1891                                    // the end-of-token clause
1892                                    if (nIF == 0) {
1893                                        println("{");
1894                                    }
1895                                    else {
1896                                        println("else {");
1897                                    }
1898                                    finishingInfo.needAnErrorClause = false;
1899                                }
1900                                else { // check for sem and syn preds
1901               
1902                                    // Add any semantic predicate expression to the
1903                                    // lookahead test
1904                                    if (alt.semPred != null) {
1905                                        // if debugging, wrap the evaluation of the
1906                                        // predicate in a method translate $ and #
1907                                        // references
1908                                        ActionTransInfo tInfo = new ActionTransInfo();
1909                                        String actionStr =
1910                                            processActionForSpecialSymbols(alt.semPred,
1911                                                                           blk.line,
1912                                                                           currentRule,
1913                                                                           tInfo);
1914                                        // ignore translation info...we don't need to
1915                                        // do anything with it.  call that will inform
1916                                        // SemanticPredicateListeners of the result
1917                                        if (((grammar instanceof ParserGrammar) ||
1918                                            (grammar instanceof LexerGrammar)) &&
1919                                            grammar.debuggingOutput) {
1920                                            e = "(" + e + "&& fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.PREDICTING," +
1921                                                addSemPred(charFormatter.escapeString(actionStr)) + "," + actionStr + "))";
1922                                        }
1923                                        else {
1924                                            e = "(" + e + "&&(" + actionStr + "))";
1925                                        }
1926                                    }
1927               
1928                                    // Generate any syntactic predicates
1929                                    if (nIF > 0) {
1930                                        if (alt.synPred != null) {
1931                                            println("else {", alt.synPred.getLine());
1932                                            tabs++;
1933                                            genSynPred(alt.synPred, e);
1934                                            closingBracesOfIFSequence++;
1935                                        }
1936                                        else {
1937                                            println("else if " + e + " {");
1938                                        }
1939                                    }
1940                                    else {
1941                                        if (alt.synPred != null) {
1942                                            genSynPred(alt.synPred, e);
1943                                        }
1944                                        else {
1945                                            // when parsing trees, convert null to
1946                                            // valid tree node with NULL lookahead.
1947                                            if (grammar instanceof TreeWalkerGrammar) {
1948                                                println("if (_t==null) _t=ASTNULL;");
1949                                            }
1950                                            println("if " + e + " {");
1951                                        }
1952                                    }
1953               
1954                                }
1955                            } finally {
1956                                                defaultLine = oldDefaultLine2;
1957                                        }
1958       
1959                        nIF++;
1960                        tabs++;
1961                        genAlt(alt, blk);
1962                        tabs--;
1963                        println("}");
1964                    }
1965                }
1966                String ps = "";
1967                for (int i = 1; i <= closingBracesOfIFSequence; i++) {
1968                    ps += "}";
1969                }
1970       
1971                // Restore the AST generation state
1972                genAST = savegenAST;
1973       
1974                // restore save text state
1975                saveText = oldsaveTest;
1976       
1977                // Return the finishing info.
1978                if (createdLL1Switch) {
1979                    tabs--;
1980                    finishingInfo.postscript = ps + "}";
1981                    finishingInfo.generatedSwitch = true;
1982                    finishingInfo.generatedAnIf = nIF > 0;
1983                    //return new JavaBlockFinishingInfo(ps+"}",true,nIF>0); // close up switch statement
1984       
1985                }
1986                else {
1987                    finishingInfo.postscript = ps;
1988                    finishingInfo.generatedSwitch = false;
1989                    finishingInfo.generatedAnIf = nIF > 0;
1990                    // return new JavaBlockFinishingInfo(ps, false,nIF>0);
1991                }
1992                return finishingInfo;
1993                } finally {
1994                        defaultLine = oldDefaultLine;
1995                }
1996    }
1997
1998    private static boolean suitableForCaseExpression(Alternative a) {
1999        return
2000            a.lookaheadDepth == 1 &&
2001            a.semPred == null &&
2002            !a.cache[1].containsEpsilon() &&
2003            a.cache[1].fset.degree() <= caseSizeThreshold;
2004    }
2005
2006    /** Generate code to link an element reference into the AST */
2007    private void genElementAST(AlternativeElement el) {
2008        int oldDefaultLine = defaultLine;
2009                try {
2010                        defaultLine = el.getLine();
2011                // handle case where you're not building trees, but are in tree walker.
2012                // Just need to get labels set up.
2013                if (grammar instanceof TreeWalkerGrammar && !grammar.buildAST) {
2014                    String elementRef;
2015                    String astName;
2016       
2017                    // Generate names and declarations of the AST variable(s)
2018                    if (el.getLabel() == null) {
2019                        elementRef = lt1Value;
2020                        // Generate AST variables for unlabeled stuff
2021                        astName = "tmp" + astVarNumber + "_AST";
2022                        astVarNumber++;
2023                        // Map the generated AST variable in the alternate
2024                        mapTreeVariable(el, astName);
2025                        // Generate an "input" AST variable also
2026                        println(labeledElementASTType + " " + astName + "_in = " + elementRef + ";");
2027                    }
2028                    return;
2029                }
2030       
2031                if (grammar.buildAST && syntacticPredLevel == 0) {
2032                    boolean needASTDecl =
2033                        (genAST &&
2034                        (el.getLabel() != null ||
2035                        el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG
2036                        )
2037                        );
2038       
2039                    // RK: if we have a grammar element always generate the decl
2040                    // since some guy can access it from an action and we can't
2041                    // peek ahead (well not without making a mess).
2042                    // I'd prefer taking this out.
2043                    if (el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG &&
2044                        (el instanceof TokenRefElement))
2045                    {
2046                        needASTDecl = true;
2047                    }
2048       
2049                    boolean doNoGuessTest =
2050                        (grammar.hasSyntacticPredicate && needASTDecl);
2051       
2052                    String elementRef;
2053                    String astNameBase;
2054       
2055                    // Generate names and declarations of the AST variable(s)
2056                    if (el.getLabel() != null) {
2057                        elementRef = el.getLabel();
2058                        astNameBase = el.getLabel();
2059                    }
2060                    else {
2061                        elementRef = lt1Value;
2062                        // Generate AST variables for unlabeled stuff
2063                        astNameBase = "tmp" + astVarNumber;
2064                        ;
2065                        astVarNumber++;
2066                    }
2067       
2068                    // Generate the declaration if required.
2069                    if (needASTDecl) {
2070                        // Generate the declaration
2071                        if (el instanceof GrammarAtom) {
2072                            GrammarAtom ga = (GrammarAtom)el;
2073                            if (ga.getASTNodeType() != null) {
2074                                genASTDeclaration(el, astNameBase, ga.getASTNodeType());
2075        //                                              println(ga.getASTNodeType()+" " + astName+" = null;");
2076                            }
2077                            else {
2078                                genASTDeclaration(el, astNameBase, labeledElementASTType);
2079        //                                              println(labeledElementASTType+" " + astName + " = null;");
2080                            }
2081                        }
2082                        else {
2083                            genASTDeclaration(el, astNameBase, labeledElementASTType);
2084        //                                      println(labeledElementASTType+" " + astName + " = null;");
2085                        }
2086                    }
2087       
2088                    // for convenience..
2089                    String astName = astNameBase + "_AST";
2090       
2091                    // Map the generated AST variable in the alternate
2092                    mapTreeVariable(el, astName);
2093                    if (grammar instanceof TreeWalkerGrammar) {
2094                        // Generate an "input" AST variable also
2095                        println(labeledElementASTType + " " + astName + "_in = null;");
2096                    }
2097       
2098                    // Enclose actions with !guessing
2099                    if (doNoGuessTest) {
2100                        // println("if (inputState.guessing==0) {");
2101                        // tabs++;
2102                    }
2103       
2104                    // if something has a label assume it will be used
2105                    // so we must initialize the RefAST
2106                    if (el.getLabel() != null) {
2107                        if (el instanceof GrammarAtom) {
2108                            println(astName + " = " + getASTCreateString((GrammarAtom)el, elementRef) + ";");
2109                        }
2110                        else {
2111                            println(astName + " = " + getASTCreateString(elementRef) + ";");
2112                        }
2113                    }
2114       
2115                    // if it has no label but a declaration exists initialize it.
2116                    if (el.getLabel() == null && needASTDecl) {
2117                        elementRef = lt1Value;
2118                        if (el instanceof GrammarAtom) {
2119                            println(astName + " = " + getASTCreateString((GrammarAtom)el, elementRef) + ";");
2120                        }
2121                        else {
2122                            println(astName + " = " + getASTCreateString(elementRef) + ";");
2123                        }
2124                        // Map the generated AST variable in the alternate
2125                        if (grammar instanceof TreeWalkerGrammar) {
2126                            // set "input" AST variable also
2127                            println(astName + "_in = " + elementRef + ";");
2128                        }
2129                    }
2130       
2131                    if (genAST) {
2132                        switch (el.getAutoGenType()) {
2133                            case GrammarElement.AUTO_GEN_NONE:
2134                                println("astFactory.addASTChild(currentAST, " + astName + ");");
2135                                break;
2136                            case GrammarElement.AUTO_GEN_CARET:
2137                                println("astFactory.makeASTRoot(currentAST, " + astName + ");");
2138                                break;
2139                            default:
2140                                break;
2141                        }
2142                    }
2143                    if (doNoGuessTest) {
2144                        // tabs--;
2145                        // println("}");
2146                    }
2147                }
2148            } finally {
2149                        defaultLine = oldDefaultLine;
2150                }
2151    }
2152
2153    /** Close the try block and generate catch phrases
2154     * if the element has a labeled handler in the rule
2155     */
2156    private void genErrorCatchForElement(AlternativeElement el) {
2157        if (el.getLabel() == null) return;
2158        String r = el.enclosingRuleName;
2159        if (grammar instanceof LexerGrammar) {
2160            r = CodeGenerator.encodeLexerRuleName(el.enclosingRuleName);
2161        }
2162        RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
2163        if (rs == null) {
2164            antlrTool.panic("Enclosing rule not found!");
2165        }
2166        ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
2167        if (ex != null) {
2168            tabs--;
2169            println("}", el.getLine());
2170            genErrorHandler(ex);
2171        }
2172    }
2173
2174    /** Generate the catch phrases for a user-specified error handler */
2175    private void genErrorHandler(ExceptionSpec ex) {
2176        // Each ExceptionHandler in the ExceptionSpec is a separate catch
2177        for (int i = 0; i < ex.handlers.size(); i++) {
2178            ExceptionHandler handler = (ExceptionHandler)ex.handlers.elementAt(i);
2179            int oldDefaultLine = defaultLine;
2180                        try {
2181                                defaultLine = handler.action.getLine();
2182                    // Generate catch phrase
2183                    println("catch (" + handler.exceptionTypeAndName.getText() + ") {", handler.exceptionTypeAndName.getLine());
2184                    tabs++;
2185                    if (grammar.hasSyntacticPredicate) {
2186                        println("if (inputState.guessing==0) {");
2187                        tabs++;
2188                    }
2189       
2190                    // When not guessing, execute user handler action
2191                                ActionTransInfo tInfo = new ActionTransInfo();
2192                    printAction(
2193                        processActionForSpecialSymbols(handler.action.getText(),
2194                                                       handler.action.getLine(),
2195                                                       currentRule, tInfo)
2196                    );
2197       
2198                    if (grammar.hasSyntacticPredicate) {
2199                        tabs--;
2200                        println("} else {");
2201                        tabs++;
2202                        // When guessing, rethrow exception
2203                        println(
2204                            "throw " +
2205                            extractIdOfAction(handler.exceptionTypeAndName) +
2206                    ";"
2207                );
2208                        tabs--;
2209                        println("}");
2210                    }
2211                    // Close catch phrase
2212                    tabs--;
2213                    println("}");
2214                } finally {
2215                                defaultLine = oldDefaultLine;
2216                        }
2217        }
2218    }
2219
2220    /** Generate a try { opening if the element has a labeled handler in the rule */
2221    private void genErrorTryForElement(AlternativeElement el) {
2222        if (el.getLabel() == null) return;
2223        String r = el.enclosingRuleName;
2224        if (grammar instanceof LexerGrammar) {
2225            r = CodeGenerator.encodeLexerRuleName(el.enclosingRuleName);
2226        }
2227        RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
2228        if (rs == null) {
2229            antlrTool.panic("Enclosing rule not found!");
2230        }
2231        ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
2232        if (ex != null) {
2233            println("try { // for error handling", el.getLine());
2234            tabs++;
2235        }
2236    }
2237
2238    protected void genASTDeclaration(AlternativeElement el) {
2239        genASTDeclaration(el, labeledElementASTType);
2240    }
2241
2242    protected void genASTDeclaration(AlternativeElement el, String node_type) {
2243        genASTDeclaration(el, el.getLabel(), node_type);
2244    }
2245
2246    protected void genASTDeclaration(AlternativeElement el, String var_name, String node_type) {
2247        // already declared?
2248        if (declaredASTVariables.contains(el))
2249            return;
2250
2251        // emit code
2252        println(node_type + " " + var_name + "_AST = null;");
2253
2254        // mark as declared
2255        declaredASTVariables.put(el,el);
2256    }
2257
2258    /** Generate a header that is common to all Java files */
2259    protected void genHeader() {
2260        println("// $ANTLR " + Tool.version + ": " +
2261                "\"" + antlrTool.fileMinusPath(antlrTool.grammarFile) + "\"" +
2262                " -> " +
2263                "\"" + grammar.getClassName() + ".java\"$", NO_MAPPING);
2264    }
2265
2266    private void genLiteralsTest() {
2267        println("_ttype = testLiteralsTable(_ttype);");
2268    }
2269
2270    private void genLiteralsTestForPartialToken() {
2271        println("_ttype = testLiteralsTable(new String(text.getBuffer(),_begin,text.length()-_begin),_ttype);");
2272    }
2273
2274    protected void genMatch(BitSet b) {
2275    }
2276
2277    protected void genMatch(GrammarAtom atom) {
2278        if (atom instanceof StringLiteralElement) {
2279            if (grammar instanceof LexerGrammar) {
2280                genMatchUsingAtomText(atom);
2281            }
2282            else {
2283                genMatchUsingAtomTokenType(atom);
2284            }
2285        }
2286        else if (atom instanceof CharLiteralElement) {
2287            if (grammar instanceof LexerGrammar) {
2288                genMatchUsingAtomText(atom);
2289            }
2290            else {
2291                antlrTool.error("cannot ref character literals in grammar: " + atom);
2292            }
2293        }
2294        else if (atom instanceof TokenRefElement) {
2295            genMatchUsingAtomText(atom);
2296        }
2297        else if (atom instanceof WildcardElement) {
2298            gen((WildcardElement)atom);
2299        }
2300    }
2301
2302    protected void genMatchUsingAtomText(GrammarAtom atom) {
2303        int oldDefaultLine = defaultLine;
2304                try {
2305                        defaultLine = atom.getLine();
2306                // match() for trees needs the _t cursor
2307                String astArgs = "";
2308                if (grammar instanceof TreeWalkerGrammar) {
2309                    astArgs = "_t,";
2310                }
2311       
2312                // if in lexer and ! on element, save buffer index to kill later
2313                if (grammar instanceof LexerGrammar && (!saveText || atom.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) {
2314                    println("_saveIndex=text.length();");
2315                }
2316       
2317                print(atom.not ? "matchNot(" : "match(");
2318                _print(astArgs, NO_MAPPING);
2319       
2320                // print out what to match
2321                if (atom.atomText.equals("EOF")) {
2322                    // horrible hack to handle EOF case
2323                    _print("Token.EOF_TYPE");
2324                }
2325                else {
2326                    _print(atom.atomText);
2327                }
2328                _println(");");
2329       
2330                if (grammar instanceof LexerGrammar && (!saveText || atom.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) {
2331                    println("text.setLength(_saveIndex);");             // kill text atom put in buffer
2332                }
2333            } finally {
2334                        defaultLine = oldDefaultLine;
2335                }
2336    }
2337
2338    protected void genMatchUsingAtomTokenType(GrammarAtom atom) {
2339        // match() for trees needs the _t cursor
2340        String astArgs = "";
2341        if (grammar instanceof TreeWalkerGrammar) {
2342            astArgs = "_t,";
2343        }
2344
2345        // If the literal can be mangled, generate the symbolic constant instead
2346        String mangledName = null;
2347        String s = astArgs + getValueString(atom.getType());
2348
2349        // matching
2350        println((atom.not ? "matchNot(" : "match(") + s + ");", atom.getLine());
2351    }
2352
2353    /** Generate the nextToken() rule.  nextToken() is a synthetic
2354     * lexer rule that is the implicit OR of all user-defined
2355     * lexer rules.
2356     */
2357    public void genNextToken() {
2358        int oldDefaultLine = defaultLine;
2359                try {
2360                        defaultLine = NO_MAPPING;
2361                // Are there any public rules?  If not, then just generate a
2362                // fake nextToken().
2363                boolean hasPublicRules = false;
2364                for (int i = 0; i < grammar.rules.size(); i++) {
2365                    RuleSymbol rs = (RuleSymbol)grammar.rules.elementAt(i);
2366                    if (rs.isDefined() && rs.access.equals("public")) {
2367                        hasPublicRules = true;
2368                        break;
2369                    }
2370                }
2371                if (!hasPublicRules) {
2372                    println("");
2373                    println("public Token nextToken() throws TokenStreamException {");
2374                    println("\ttry {uponEOF();}");
2375                    println("\tcatch(CharStreamIOException csioe) {");
2376                    println("\t\tthrow new TokenStreamIOException(csioe.io);");
2377                    println("\t}");
2378                    println("\tcatch(CharStreamException cse) {");
2379                    println("\t\tthrow new TokenStreamException(cse.getMessage());");
2380                    println("\t}");
2381                    println("\treturn new CommonToken(Token.EOF_TYPE, \"\");");
2382                    println("}");
2383                    println("");
2384                    return;
2385                }
2386       
2387                // Create the synthesized nextToken() rule
2388                RuleBlock nextTokenBlk = MakeGrammar.createNextTokenRule(grammar, grammar.rules, "nextToken");
2389                // Define the nextToken rule symbol
2390                RuleSymbol nextTokenRs = new RuleSymbol("mnextToken");
2391                nextTokenRs.setDefined();
2392                nextTokenRs.setBlock(nextTokenBlk);
2393                nextTokenRs.access = "private";
2394                grammar.define(nextTokenRs);
2395                // Analyze the nextToken rule
2396                boolean ok = grammar.theLLkAnalyzer.deterministic(nextTokenBlk);
2397       
2398                // Generate the next token rule
2399                String filterRule = null;
2400                if (((LexerGrammar)grammar).filterMode) {
2401                    filterRule = ((LexerGrammar)grammar).filterRule;
2402                }
2403       
2404                println("");
2405                println("public Token nextToken() throws TokenStreamException {");
2406                tabs++;
2407                println("Token theRetToken=null;");
2408                _println("tryAgain:");
2409                println("for (;;) {");
2410                tabs++;
2411                println("Token _token = null;");
2412                println("int _ttype = Token.INVALID_TYPE;");
2413                if (((LexerGrammar)grammar).filterMode) {
2414                    println("setCommitToPath(false);");
2415                    if (filterRule != null) {
2416                        // Here's a good place to ensure that the filter rule actually exists
2417                        if (!grammar.isDefined(CodeGenerator.encodeLexerRuleName(filterRule))) {
2418                            grammar.antlrTool.error("Filter rule " + filterRule + " does not exist in this lexer");
2419                        }
2420                        else {
2421                            RuleSymbol rs = (RuleSymbol)grammar.getSymbol(CodeGenerator.encodeLexerRuleName(filterRule));
2422                            if (!rs.isDefined()) {
2423                                grammar.antlrTool.error("Filter rule " + filterRule + " does not exist in this lexer");
2424                            }
2425                            else if (rs.access.equals("public")) {
2426                                grammar.antlrTool.error("Filter rule " + filterRule + " must be protected");
2427                            }
2428                        }
2429                        println("int _m;");
2430                        println("_m = mark();");
2431                    }
2432                }
2433                println("resetText();");
2434       
2435                println("try {   // for char stream error handling");
2436                tabs++;
2437       
2438                // Generate try around whole thing to trap scanner errors
2439                println("try {   // for lexical error handling");
2440                tabs++;
2441       
2442                // Test for public lexical rules with empty paths
2443                for (int i = 0; i < nextTokenBlk.getAlternatives().size(); i++) {
2444                    Alternative a = nextTokenBlk.getAlternativeAt(i);
2445                    if (a.cache[1].containsEpsilon()) {
2446                        //String r = a.head.toString();
2447                        RuleRefElement rr = (RuleRefElement)a.head;
2448                        String r = CodeGenerator.decodeLexerRuleName(rr.targetRule);
2449                        antlrTool.warning("public lexical rule "+r+" is optional (can match \"nothing\")");
2450                    }
2451                }
2452       
2453                // Generate the block
2454                String newline = System.getProperty("line.separator");
2455                JavaBlockFinishingInfo howToFinish = genCommonBlock(nextTokenBlk, false);
2456                String errFinish = "if (LA(1)==EOF_CHAR) {uponEOF(); _returnToken = makeToken(Token.EOF_TYPE);}";
2457                errFinish += newline + "\t\t\t\t";
2458                if (((LexerGrammar)grammar).filterMode) {
2459                    if (filterRule == null) {
2460                        errFinish += "else {consume(); continue tryAgain;}";
2461                    }
2462                    else {
2463                        errFinish += "else {" + newline +
2464                            "\t\t\t\t\tcommit();" + newline +
2465                            "\t\t\t\t\ttry {m" + filterRule + "(false);}" + newline +
2466                            "\t\t\t\t\tcatch(RecognitionException e) {" + newline +
2467                            "\t\t\t\t\t // catastrophic failure" + newline +
2468                            "\t\t\t\t\t reportError(e);" + newline +
2469                            "\t\t\t\t\t consume();" + newline +
2470                            "\t\t\t\t\t}" + newline +
2471                            "\t\t\t\t\tcontinue tryAgain;" + newline +
2472                            "\t\t\t\t}";
2473                    }
2474                }
2475                else {
2476                    errFinish += "else {" + throwNoViable + "}";
2477                }
2478                genBlockFinish(howToFinish, errFinish, nextTokenBlk.getLine());
2479       
2480                // at this point a valid token has been matched, undo "mark" that was done
2481                if (((LexerGrammar)grammar).filterMode && filterRule != null) {
2482                    println("commit();");
2483                }
2484       
2485                // Generate literals test if desired
2486                // make sure _ttype is set first; note _returnToken must be
2487                // non-null as the rule was required to create it.
2488                println("if ( _returnToken==null ) continue tryAgain; // found SKIP token");
2489                println("_ttype = _returnToken.getType();");
2490                if (((LexerGrammar)grammar).getTestLiterals()) {
2491                    genLiteralsTest();
2492                }
2493       
2494                // return token created by rule reference in switch
2495                println("_returnToken.setType(_ttype);");
2496                println("return _returnToken;");
2497       
2498                // Close try block
2499                tabs--;
2500                println("}");
2501                println("catch (RecognitionException e) {");
2502                tabs++;
2503                if (((LexerGrammar)grammar).filterMode) {
2504                    if (filterRule == null) {
2505                        println("if ( !getCommitToPath() ) {consume(); continue tryAgain;}");
2506                    }
2507                    else {
2508                        println("if ( !getCommitToPath() ) {");
2509                        tabs++;
2510                        println("rewind(_m);");
2511                        println("resetText();");
2512                        println("try {m" + filterRule + "(false);}");
2513                        println("catch(RecognitionException ee) {");
2514                        println("       // horrendous failure: error in filter rule");
2515                        println("       reportError(ee);");
2516                        println("       consume();");
2517                        println("}");
2518                        println("continue tryAgain;");
2519                        tabs--;
2520                        println("}");
2521                    }
2522                }
2523                if (nextTokenBlk.getDefaultErrorHandler()) {
2524                    println("reportError(e);");
2525                    println("consume();");
2526                }
2527                else {
2528                    // pass on to invoking routine
2529                    println("throw new TokenStreamRecognitionException(e);");
2530                }
2531                tabs--;
2532                println("}");
2533       
2534                // close CharStreamException try
2535                tabs--;
2536                println("}");
2537                println("catch (CharStreamException cse) {");
2538                println("       if ( cse instanceof CharStreamIOException ) {");
2539                println("               throw new TokenStreamIOException(((CharStreamIOException)cse).io);");
2540                println("       }");
2541                println("       else {");
2542                println("               throw new TokenStreamException(cse.getMessage());");
2543                println("       }");
2544                println("}");
2545       
2546                // close for-loop
2547                tabs--;
2548                println("}");
2549       
2550                // close method nextToken
2551                tabs--;
2552                println("}");
2553                println("");
2554            } finally {
2555                        defaultLine = oldDefaultLine;
2556                }
2557    }
2558
2559    /** Gen a named rule block.
2560     * ASTs are generated for each element of an alternative unless
2561     * the rule or the alternative have a '!' modifier.
2562     *
2563     * If an alternative defeats the default tree construction, it
2564     * must set <rule>_AST to the root of the returned AST.
2565     *
2566     * Each alternative that does automatic tree construction, builds
2567     * up root and child list pointers in an ASTPair structure.
2568     *
2569     * A rule finishes by setting the returnAST variable from the
2570     * ASTPair.
2571     *
2572     * @param rule The name of the rule to generate
2573     * @param startSymbol true if the rule is a start symbol (i.e., not referenced elsewhere)
2574     */
2575    public void genRule(RuleSymbol s, boolean startSymbol, int ruleNum) {
2576        tabs = 1;
2577
2578        if (DEBUG_CODE_GENERATOR) System.out.println("genRule(" + s.getId() + ")");
2579        if (!s.isDefined()) {
2580            antlrTool.error("undefined rule: " + s.getId());
2581            return;
2582        }
2583
2584        // Generate rule return type, name, arguments
2585        RuleBlock rblk = s.getBlock();
2586
2587        int oldDefaultLine = defaultLine;
2588                try {
2589                        defaultLine = rblk.getLine();
2590                currentRule = rblk;
2591                currentASTResult = s.getId();
2592       
2593                // clear list of declared ast variables..
2594                declaredASTVariables.clear();
2595       
2596                // Save the AST generation state, and set it to that of the rule
2597                boolean savegenAST = genAST;
2598                genAST = genAST && rblk.getAutoGen();
2599       
2600                // boolean oldsaveTest = saveText;
2601                saveText = rblk.getAutoGen();
2602       
2603                // print javadoc comment if any
2604                if (s.comment != null) {
2605                    _println(s.comment);
2606                                        }
2607       
2608                // Gen method access and final qualifier
2609                print(s.access + " final ");
2610       
2611                // Gen method return type (note lexer return action set at rule creation)
2612                if (rblk.returnAction != null) {
2613                    // Has specified return value
2614                    _print(extractTypeOfAction(rblk.returnAction, rblk.getLine(), rblk.getColumn()) + " ");
2615                }
2616                else {
2617                    // No specified return value
2618                    _print("void ");
2619                }
2620       
2621                // Gen method name
2622                _print(s.getId() + "(");
2623       
2624                // Additional rule parameters common to all rules for this grammar
2625                _print(commonExtraParams);
2626                if (commonExtraParams.length() != 0 && rblk.argAction != null) {
2627                    _print(",");
2628                }
2629       
2630                // Gen arguments
2631                if (rblk.argAction != null) {
2632                    // Has specified arguments
2633                    _println("");
2634                    tabs++;
2635                    println(rblk.argAction);
2636                    tabs--;
2637                    print(")");
2638                }
2639                else {
2640                    // No specified arguments
2641                    _print(")");
2642                }
2643       
2644                // Gen throws clause and open curly
2645                _print(" throws " + exceptionThrown);
2646                if (grammar instanceof ParserGrammar) {
2647                    _print(", TokenStreamException");
2648                }
2649                else if (grammar instanceof LexerGrammar) {
2650                    _print(", CharStreamException, TokenStreamException");
2651                }
2652                // Add user-defined exceptions unless lexer (for now)
2653                if (rblk.throwsSpec != null) {
2654                    if (grammar instanceof LexerGrammar) {
2655                        antlrTool.error("user-defined throws spec not allowed (yet) for lexer rule " + rblk.ruleName);
2656                    }
2657                    else {
2658                        _print(", " + rblk.throwsSpec);
2659                    }
2660                }
2661       
2662                _println(" {");
2663                tabs++;
2664       
2665                // Convert return action to variable declaration
2666                if (rblk.returnAction != null)
2667                    println(rblk.returnAction + ";");
2668       
2669                // print out definitions needed by rules for various grammar types
2670                println(commonLocalVars);
2671       
2672                if (grammar.traceRules) {
2673                    if (grammar instanceof TreeWalkerGrammar) {
2674                        println("traceIn(\"" + s.getId() + "\",_t);");
2675                    }
2676                    else {
2677                        println("traceIn(\"" + s.getId() + "\");");
2678                    }
2679                }
2680       
2681                if (grammar instanceof LexerGrammar) {
2682                    // lexer rule default return value is the rule's token name
2683                    // This is a horrible hack to support the built-in EOF lexer rule.
2684                    if (s.getId().equals("mEOF"))
2685                        println("_ttype = Token.EOF_TYPE;");
2686                    else
2687                        println("_ttype = " + s.getId().substring(1) + ";");
2688                    println("int _saveIndex;");         // used for element! (so we can kill text matched for element)
2689                    /*
2690                                 println("boolean old_saveConsumedInput=saveConsumedInput;");
2691                                 if ( !rblk.getAutoGen() ) {            // turn off "save input" if ! on rule
2692                                 println("saveConsumedInput=false;");
2693                                 }
2694                                 */
2695                }
2696       
2697                // if debugging, write code to mark entry to the rule
2698                if (grammar.debuggingOutput)
2699                    if (grammar instanceof ParserGrammar)
2700                        println("fireEnterRule(" + ruleNum + ",0);");
2701                    else if (grammar instanceof LexerGrammar)
2702                        println("fireEnterRule(" + ruleNum + ",_ttype);");
2703       
2704                // Generate trace code if desired
2705                if (grammar.debuggingOutput || grammar.traceRules) {
2706                    println("try { // debugging");
2707                    tabs++;
2708                }
2709       
2710                // Initialize AST variables
2711                if (grammar instanceof TreeWalkerGrammar) {
2712                    // "Input" value for rule
2713                    println(labeledElementASTType + " " + s.getId() + "_AST_in = (_t == ASTNULL) ? null : (" + labeledElementASTType + ")_t;", NO_MAPPING);
2714                }
2715                if (grammar.buildAST) {
2716                    // Parser member used to pass AST returns from rule invocations
2717                    println("returnAST = null;");
2718                    // Tracks AST construction
2719                    // println("ASTPair currentAST = (inputState.guessing==0) ? new ASTPair() : null;");
2720                    println("ASTPair currentAST = new ASTPair();");
2721                    // User-settable return value for rule.
2722                    println(labeledElementASTType + " " + s.getId() + "_AST = null;");
2723                }
2724       
2725                genBlockPreamble(rblk);
2726                genBlockInitAction(rblk);
2727                println("");
2728       
2729                // Search for an unlabeled exception specification attached to the rule
2730                ExceptionSpec unlabeledUserSpec = rblk.findExceptionSpec("");
2731       
2732                // Generate try block around the entire rule for  error handling
2733                if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler()) {
2734                    println("try {      // for error handling");
2735                    tabs++;
2736                }
2737       
2738                // Generate the alternatives
2739                if (rblk.alternatives.size() == 1) {
2740                    // One alternative -- use simple form
2741                    Alternative alt = rblk.getAlternativeAt(0);
2742                    String pred = alt.semPred;
2743                    if (pred != null)
2744                        genSemPred(pred, currentRule.line);
2745                    if (alt.synPred != null) {
2746                        antlrTool.warning(
2747                            "Syntactic predicate ignored for single alternative",
2748                            grammar.getFilename(),
2749                            alt.synPred.getLine(),
2750                            alt.synPred.getColumn()
2751                        );
2752                    }
2753                    genAlt(alt, rblk);
2754                }
2755                else {
2756                    // Multiple alternatives -- generate complex form
2757                    boolean ok = grammar.theLLkAnalyzer.deterministic(rblk);
2758       
2759                    JavaBlockFinishingInfo howToFinish = genCommonBlock(rblk, false);
2760                    genBlockFinish(howToFinish, throwNoViable, rblk.getLine());
2761                }
2762       
2763                // Generate catch phrase for error handling
2764                if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler()) {
2765                    // Close the try block
2766                    tabs--;
2767                    println("}");
2768                }
2769       
2770                // Generate user-defined or default catch phrases
2771                if (unlabeledUserSpec != null) {
2772                    genErrorHandler(unlabeledUserSpec);
2773                }
2774                else if (rblk.getDefaultErrorHandler()) {
2775                    // Generate default catch phrase
2776                    println("catch (" + exceptionThrown + " ex) {");
2777                    tabs++;
2778                    // Generate code to handle error if not guessing
2779                    if (grammar.hasSyntacticPredicate) {
2780                        println("if (inputState.guessing==0) {");
2781                        tabs++;
2782                    }
2783                    println("reportError(ex);");
2784                    if (!(grammar instanceof TreeWalkerGrammar)) {
2785                        // Generate code to consume until token in k==1 follow set
2786                        Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1, rblk.endNode);
2787                        String followSetName = getBitsetName(markBitsetForGen(follow.fset));
2788                        println("recover(ex," + followSetName + ");");
2789                    }
2790                    else {
2791                        // Just consume one token
2792                        println("if (_t!=null) {_t = _t.getNextSibling();}");
2793                    }
2794                    if (grammar.hasSyntacticPredicate) {
2795                        tabs--;
2796                        // When guessing, rethrow exception
2797                        println("} else {");
2798                        println("  throw ex;");
2799                        println("}");
2800                    }
2801                    // Close catch phrase
2802                    tabs--;
2803                    println("}");
2804                }
2805       
2806                // Squirrel away the AST "return" value
2807                if (grammar.buildAST) {
2808                    println("returnAST = " + s.getId() + "_AST;");
2809                }
2810       
2811                // Set return tree value for tree walkers
2812                if (grammar instanceof TreeWalkerGrammar) {
2813                    println("_retTree = _t;");
2814                }
2815       
2816                // Generate literals test for lexer rules so marked
2817                if (rblk.getTestLiterals()) {
2818                    if (s.access.equals("protected")) {
2819                        genLiteralsTestForPartialToken();
2820                    }
2821                    else {
2822                        genLiteralsTest();
2823                    }
2824                }
2825       
2826                // if doing a lexer rule, dump code to create token if necessary
2827                if (grammar instanceof LexerGrammar) {
2828                    println("if ( _createToken && _token==null && _ttype!=Token.SKIP ) {");
2829                    println("   _token = makeToken(_ttype);");
2830                    println("   _token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));");
2831                    println("}");
2832                    println("_returnToken = _token;");
2833                }
2834       
2835                // Gen the return statement if there is one (lexer has hard-wired return action)
2836                if (rblk.returnAction != null) {
2837                    println("return " + extractIdOfAction(rblk.returnAction, rblk.getLine(), rblk.getColumn()) + ";");
2838                }
2839       
2840                if (grammar.debuggingOutput || grammar.traceRules) {
2841                    tabs--;
2842                    println("} finally { // debugging");
2843                    tabs++;
2844       
2845                    // If debugging, generate calls to mark exit of rule
2846                    if (grammar.debuggingOutput)
2847                        if (grammar instanceof ParserGrammar)
2848                            println("fireExitRule(" + ruleNum + ",0);");
2849                        else if (grammar instanceof LexerGrammar)
2850                            println("fireExitRule(" + ruleNum + ",_ttype);");
2851       
2852                    if (grammar.traceRules) {
2853                        if (grammar instanceof TreeWalkerGrammar) {
2854                            println("traceOut(\"" + s.getId() + "\",_t);");
2855                        }
2856                        else {
2857                            println("traceOut(\"" + s.getId() + "\");");
2858                        }
2859                    }
2860       
2861                    tabs--;
2862                    println("}");
2863                }
2864       
2865                tabs--;
2866                println("}");
2867                println("");
2868       
2869                // Restore the AST generation state
2870                genAST = savegenAST;
2871       
2872                // restore char save state
2873                // saveText = oldsaveTest;
2874            } finally {
2875                        defaultLine = oldDefaultLine;
2876                }
2877    }
2878
2879    private void GenRuleInvocation(RuleRefElement rr) {
2880        int oldDefaultLine = defaultLine;
2881                try {
2882                        defaultLine = rr.getLine();
2883                // dump rule name
2884                        getPrintWriterManager().startSingleSourceLineMapping(rr.getLine());
2885                _print(rr.targetRule + "(");
2886                        getPrintWriterManager().endMapping();
2887       
2888                // lexers must tell rule if it should set _returnToken
2889                if (grammar instanceof LexerGrammar) {
2890                    // if labeled, could access Token, so tell rule to create
2891                    if (rr.getLabel() != null) {
2892                        _print("true");
2893                    }
2894                    else {
2895                        _print("false");
2896                    }
2897                    if (commonExtraArgs.length() != 0 || rr.args != null) {
2898                        _print(",");
2899                    }
2900                }
2901       
2902                // Extra arguments common to all rules for this grammar
2903                _print(commonExtraArgs);
2904                if (commonExtraArgs.length() != 0 && rr.args != null) {
2905                    _print(",");
2906                }
2907       
2908                // Process arguments to method, if any
2909                RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
2910                if (rr.args != null) {
2911                    // When not guessing, execute user arg action
2912                    ActionTransInfo tInfo = new ActionTransInfo();
2913                    String args = processActionForSpecialSymbols(rr.args, 0, currentRule, tInfo);
2914                    if (tInfo.assignToRoot || tInfo.refRuleRoot != null) {
2915                        antlrTool.error("Arguments of rule reference '" + rr.targetRule + "' cannot set or ref #" +
2916                                   currentRule.getRuleName(), grammar.getFilename(), rr.getLine(), rr.getColumn());
2917                    }
2918                    _print(args);
2919       
2920                    // Warn if the rule accepts no arguments
2921                    if (rs.block.argAction == null) {
2922                        antlrTool.warning("Rule '" + rr.targetRule + "' accepts no arguments", grammar.getFilename(), rr.getLine(), rr.getColumn());
2923                    }
2924                }
2925                else {
2926                    // For C++, no warning if rule has parameters, because there may be default
2927                    // values for all of the parameters
2928                    if (rs.block.argAction != null) {
2929                        antlrTool.warning("Missing parameters on reference to rule " + rr.targetRule, grammar.getFilename(), rr.getLine(), rr.getColumn());
2930                    }
2931                }
2932                _println(");");
2933       
2934                // move down to the first child while parsing
2935                if (grammar instanceof TreeWalkerGrammar) {
2936                    println("_t = _retTree;");
2937                }
2938            } finally {
2939                        defaultLine = oldDefaultLine;
2940                }
2941    }
2942
2943    protected void genSemPred(String pred, int line) {
2944        // translate $ and # references
2945        ActionTransInfo tInfo = new ActionTransInfo();
2946        pred = processActionForSpecialSymbols(pred, line, currentRule, tInfo);
2947        // ignore translation info...we don't need to do anything with it.
2948        String escapedPred = charFormatter.escapeString(pred);
2949
2950        // if debugging, wrap the semantic predicate evaluation in a method
2951        // that can tell SemanticPredicateListeners the result
2952        if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) || (grammar instanceof LexerGrammar)))
2953            pred = "fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.VALIDATING,"
2954                + addSemPred(escapedPred) + "," + pred + ")";
2955        println("if (!(" + pred + "))", line);
2956        println("  throw new SemanticException(\"" + escapedPred + "\");", line);
2957    }
2958
2959    /** Write an array of Strings which are the semantic predicate
2960     *  expressions.  The debugger will reference them by number only
2961     */
2962    protected void genSemPredMap() {
2963        Enumeration e = semPreds.elements();
2964        println("private String _semPredNames[] = {", NO_MAPPING);
2965        while (e.hasMoreElements())
2966            println("\"" + e.nextElement() + "\",", NO_MAPPING);
2967        println("};", NO_MAPPING);
2968    }
2969
2970    protected void genSynPred(SynPredBlock blk, String lookaheadExpr) {
2971        int oldDefaultLine = defaultLine;
2972                try {
2973                        defaultLine = blk.getLine();
2974                if (DEBUG_CODE_GENERATOR) System.out.println("gen=>(" + blk + ")");
2975
2976                // Dump synpred result variable
2977                println("boolean synPredMatched" + blk.ID + " = false;");
2978
2979                        // inserted by Ole Kniemeyer, December 9, 2005
2980                        if (grammar instanceof TreeWalkerGrammar) {
2981                                println("if (_t==null) _t=ASTNULL;");
2982                        }
2983                       
2984                // Gen normal lookahead test
2985                println("if (" + lookaheadExpr + ") {");
2986                tabs++;
2987       
2988                // Save input state
2989                if (grammar instanceof TreeWalkerGrammar) {
2990                    println("AST __t" + blk.ID + " = _t;");
2991                }
2992                else {
2993                    println("int _m" + blk.ID + " = mark();");
2994                }
2995       
2996                // Once inside the try, assume synpred works unless exception caught
2997                println("synPredMatched" + blk.ID + " = true;");
2998                println("inputState.guessing++;");
2999       
3000                // if debugging, tell listeners that a synpred has started
3001                if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
3002                    (grammar instanceof LexerGrammar))) {
3003                    println("fireSyntacticPredicateStarted();");
3004                }
3005       
3006                syntacticPredLevel++;
3007                println("try {");
3008                tabs++;
3009                gen((AlternativeBlock)blk);             // gen code to test predicate
3010                tabs--;
3011                //println("System.out.println(\"pred "+blk+" succeeded\");");
3012                println("}");
3013                println("catch (" + exceptionThrown + " pe) {");
3014                tabs++;
3015                println("synPredMatched" + blk.ID + " = false;");
3016                //println("System.out.println(\"pred "+blk+" failed\");");
3017                tabs--;
3018                println("}");
3019       
3020                // Restore input state
3021                if (grammar instanceof TreeWalkerGrammar) {
3022                    println("_t = __t" + blk.ID + ";");
3023                }
3024                else {
3025                    println("rewind(_m" + blk.ID + ");");
3026                }
3027       
3028                _println("inputState.guessing--;");
3029       
3030                // if debugging, tell listeners how the synpred turned out
3031                if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
3032                    (grammar instanceof LexerGrammar))) {
3033                    println("if (synPredMatched" + blk.ID + ")");
3034                    println("  fireSyntacticPredicateSucceeded();");
3035                    println("else");
3036                    println("  fireSyntacticPredicateFailed();");
3037                }
3038       
3039                syntacticPredLevel--;
3040                tabs--;
3041       
3042                // Close lookahead test
3043                println("}");
3044       
3045                // Test synpred result
3046                println("if ( synPredMatched" + blk.ID + " ) {");
3047            } finally {
3048                        defaultLine = oldDefaultLine;
3049                }
3050    }
3051
3052    /** Generate a static array containing the names of the tokens,
3053     * indexed by the token type values.  This static array is used
3054     * to format error messages so that the token identifers or literal
3055     * strings are displayed instead of the token numbers.
3056     *
3057     * If a lexical rule has a paraphrase, use it rather than the
3058     * token label.
3059     */
3060    public void genTokenStrings() {
3061        int oldDefaultLine = defaultLine;
3062                try {
3063                        defaultLine = NO_MAPPING;
3064                // Generate a string for each token.  This creates a static
3065                // array of Strings indexed by token type.
3066                println("");
3067                println("public static final String[] _tokenNames = {");
3068                tabs++;
3069       
3070                // Walk the token vocabulary and generate a Vector of strings
3071                // from the tokens.
3072                Vector v = grammar.tokenManager.getVocabulary();
3073                for (int i = 0; i < v.size(); i++) {
3074                    String s = (String)v.elementAt(i);
3075                    if (s == null) {
3076                        s = "<" + String.valueOf(i) + ">";
3077                    }
3078                    if (!s.startsWith("\"") && !s.startsWith("<")) {
3079                        TokenSymbol ts = (TokenSymbol)grammar.tokenManager.getTokenSymbol(s);
3080                        if (ts != null && ts.getParaphrase() != null) {
3081                            s = StringUtils.stripFrontBack(ts.getParaphrase(), "\"", "\"");
3082                        }
3083                    }
3084                    print(charFormatter.literalString(s));
3085                    if (i != v.size() - 1) {
3086                        _print(",");
3087                    }
3088                    _println("");
3089                }
3090       
3091                // Close the string array initailizer
3092                tabs--;
3093                println("};");
3094            } finally {
3095                        defaultLine = oldDefaultLine;
3096                }
3097    }
3098
3099        /** Create and set Integer token type objects that map
3100         *  to Java Class objects (which AST node to create).
3101     */
3102    protected void genTokenASTNodeMap() {
3103        int oldDefaultLine = defaultLine;
3104                try {
3105                        defaultLine = NO_MAPPING;
3106                        println("");
3107                        println("protected void buildTokenTypeASTClassMap() {");
3108                // Generate a map.put("T","TNode") for each token
3109                        // if heterogeneous node known for that token T.
3110                tabs++;
3111                        boolean generatedNewHashtable = false;
3112                        int n = 0;
3113                // Walk the token vocabulary and generate puts.
3114                        Vector v = grammar.tokenManager.getVocabulary();
3115                        for (int i = 0; i < v.size(); i++) {
3116                                String s = (String)v.elementAt(i);
3117                                if (s != null) {
3118                                        TokenSymbol ts = grammar.tokenManager.getTokenSymbol(s);
3119                                        if (ts != null && ts.getASTNodeType() != null) {
3120                                                n++;
3121                                                if ( !generatedNewHashtable ) {
3122                                                        // only generate if we are going to add a mapping
3123                                                        println("tokenTypeToASTClassMap = new Hashtable();");
3124                                                        generatedNewHashtable = true;
3125                                                }
3126                                                println("tokenTypeToASTClassMap.put(new Integer("+ts.getTokenType()+"), "+
3127                                                                ts.getASTNodeType()+".class);");
3128                                        }
3129                                }
3130                        }
3131       
3132                if ( n==0 ) {
3133                                println("tokenTypeToASTClassMap=null;");
3134                        }
3135                tabs--;
3136                println("};");
3137            } finally {
3138                        defaultLine = oldDefaultLine;
3139                }
3140    }
3141
3142    /** Generate the token types Java file */
3143    protected void genTokenTypes(TokenManager tm) throws IOException {
3144        int oldDefaultLine = defaultLine;
3145                try {
3146                        defaultLine = NO_MAPPING;
3147                // Open the token output Java file and set the currentOutput stream
3148                // SAS: file open was moved to a method so a subclass can override
3149                //      This was mainly for the VAJ interface
3150                currentOutput = getPrintWriterManager().setupOutput(antlrTool, tm.getName() + TokenTypesFileSuffix);
3151       
3152                tabs = 0;
3153       
3154                // Generate the header common to all Java files
3155                genHeader();
3156                // Do not use printAction because we assume tabs==0
3157                        try {
3158                                defaultLine = behavior.getHeaderActionLine("");
3159                                println(behavior.getHeaderAction(""));
3160                        } finally {
3161                                defaultLine = NO_MAPPING;
3162                        }
3163       
3164                // Encapsulate the definitions in an interface.  This can be done
3165                // because they are all constants.
3166                println("public interface " + tm.getName() + TokenTypesFileSuffix + " {");
3167                tabs++;
3168       
3169                // Generate a definition for each token type
3170                Vector v = tm.getVocabulary();
3171       
3172                // Do special tokens manually
3173                println("int EOF = " + Token.EOF_TYPE + ";");
3174                println("int NULL_TREE_LOOKAHEAD = " + Token.NULL_TREE_LOOKAHEAD + ";");
3175       
3176                for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) {
3177                    String s = (String)v.elementAt(i);
3178                    if (s != null) {
3179                        if (s.startsWith("\"")) {
3180                            // a string literal
3181                            StringLiteralSymbol sl = (StringLiteralSymbol)tm.getTokenSymbol(s);
3182                            if (sl == null) {
3183                                antlrTool.panic("String literal " + s + " not in symbol table");
3184                            }
3185                            else if (sl.label != null) {
3186                                println("int " + sl.label + " = " + i + ";");
3187                            }
3188                            else {
3189                                String mangledName = mangleLiteral(s);
3190                                if (mangledName != null) {
3191                                    // We were able to create a meaningful mangled token name
3192                                    println("int " + mangledName + " = " + i + ";");
3193                                    // if no label specified, make the label equal to the mangled name
3194                                    sl.label = mangledName;
3195                                }
3196                                else {
3197                                    println("// " + s + " = " + i);
3198                                }
3199                            }
3200                        }
3201                        else if (!s.startsWith("<")) {
3202                            println("int " + s + " = " + i + ";");
3203                        }
3204                    }
3205                }
3206       
3207                // Close the interface
3208                tabs--;
3209                println("}");
3210       
3211                // Close the tokens output file
3212                getPrintWriterManager().finishOutput();
3213                exitIfError();
3214                } finally {
3215                        defaultLine = oldDefaultLine;
3216                }
3217    }
3218
3219    /** Get a string for an expression to generate creation of an AST subtree.
3220     * @param v A Vector of String, where each element is an expression in the target language yielding an AST node.
3221     */
3222    public String getASTCreateString(Vector v) {
3223        if (v.size() == 0) {
3224            return "";
3225        }
3226        StringBuffer buf = new StringBuffer();
3227        buf.append("(" + labeledElementASTType +
3228                   ")astFactory.make( (new ASTArray(" + v.size() +
3229                   "))");
3230        for (int i = 0; i < v.size(); i++) {
3231            buf.append(".add(" + v.elementAt(i) + ")");
3232        }
3233        buf.append(")");
3234        return buf.toString();
3235    }
3236
3237    /** Get a string for an expression to generate creating of an AST node
3238     * @param atom The grammar node for which you are creating the node
3239     * @param str The arguments to the AST constructor
3240     */
3241    public String getASTCreateString(GrammarAtom atom, String astCtorArgs) {
3242                //System.out.println("getASTCreateString("+atom+","+astCtorArgs+")");
3243                if (atom != null && atom.getASTNodeType() != null) {
3244                        // they specified a type either on the reference or in tokens{} section
3245                        return "("+atom.getASTNodeType()+")"+
3246                                        "astFactory.create("+astCtorArgs+",\""+atom.getASTNodeType()+"\")";
3247        }
3248        else {
3249                        // must be an action or something since not referencing an atom
3250            return getASTCreateString(astCtorArgs);
3251        }
3252    }
3253
3254    /** Get a string for an expression to generate creating of an AST node.
3255         *  Parse the first (possibly only) argument looking for the token type.
3256         *  If the token type is a valid token symbol, ask for it's AST node type
3257         *  and add to the end if only 2 arguments.  The forms are #[T], #[T,"t"],
3258         *  and as of 2.7.2 #[T,"t",ASTclassname].
3259         *
3260     * @param str The arguments to the AST constructor
3261     */
3262    public String getASTCreateString(String astCtorArgs) {
3263        //System.out.println("AST CTOR: "+astCtorArgs);
3264                if ( astCtorArgs==null ) {
3265                        astCtorArgs = "";
3266                }
3267                int nCommas = 0;
3268                for (int i=0; i<astCtorArgs.length(); i++) {
3269                        if ( astCtorArgs.charAt(i)==',' ) {
3270                                nCommas++;
3271                        }
3272                }
3273                //System.out.println("num commas="+nCommas);
3274                if ( nCommas<2 ) { // if 1 or 2 args
3275                        int firstComma = astCtorArgs.indexOf(',');
3276                        int lastComma = astCtorArgs.lastIndexOf(',');
3277                        String tokenName = astCtorArgs;
3278                        if ( nCommas>0 ) {
3279                                tokenName = astCtorArgs.substring(0,firstComma);
3280                        }
3281                        //System.out.println("Checking for ast node type of "+tokenName);
3282                        TokenSymbol ts = grammar.tokenManager.getTokenSymbol(tokenName);
3283                        if ( ts!=null ) {
3284                                String astNodeType = ts.getASTNodeType();
3285                                //System.out.println("node type of "+tokenName+" is "+astNodeType);
3286                                String emptyText = "";
3287                                if ( nCommas==0 ) {
3288                                        // need to add 2nd arg of blank text for token text
3289                                        emptyText = ",\"\"";
3290                                }
3291                                if ( astNodeType!=null ) {
3292                                        return "("+astNodeType+")"+
3293                                                        "astFactory.create("+astCtorArgs+emptyText+",\""+astNodeType+"\")";
3294                                }
3295                // fall through and just do a regular create with cast on front
3296                // if necessary (it differs from default "AST").
3297                        }
3298                        if ( labeledElementASTType.equals("AST") ) {
3299                                return "astFactory.create("+astCtorArgs+")";
3300                        }
3301                        return "("+labeledElementASTType+")"+
3302                                        "astFactory.create("+astCtorArgs+")";
3303                }
3304                // create default type or (since 2.7.2) 3rd arg is classname
3305                return "(" + labeledElementASTType + ")astFactory.create(" + astCtorArgs + ")";
3306    }
3307
3308    protected String getLookaheadTestExpression(Lookahead[] look, int k) {
3309        StringBuffer e = new StringBuffer(100);
3310        boolean first = true;
3311
3312        e.append("(");
3313        for (int i = 1; i <= k; i++) {
3314            BitSet p = look[i].fset;
3315            if (!first) {
3316                e.append(") && (");
3317            }
3318            first = false;
3319
3320            // Syn preds can yield <end-of-syn-pred> (epsilon) lookahead.
3321            // There is no way to predict what that token would be.  Just
3322            // allow anything instead.
3323            if (look[i].containsEpsilon()) {
3324                e.append("true");
3325            }
3326            else {
3327                e.append(getLookaheadTestTerm(i, p));
3328            }
3329        }
3330        e.append(")");
3331
3332        return e.toString();
3333    }
3334
3335    /**Generate a lookahead test expression for an alternate.  This
3336     * will be a series of tests joined by '&&' and enclosed by '()',
3337     * the number of such tests being determined by the depth of the lookahead.
3338     */
3339    protected String getLookaheadTestExpression(Alternative alt, int maxDepth) {
3340        int depth = alt.lookaheadDepth;
3341        if (depth == GrammarAnalyzer.NONDETERMINISTIC) {
3342            // if the decision is nondeterministic, do the best we can: LL(k)
3343            // any predicates that are around will be generated later.
3344            depth = grammar.maxk;
3345        }
3346
3347        if (maxDepth == 0) {
3348            // empty lookahead can result from alt with sem pred
3349            // that can see end of token.  E.g., A : {pred}? ('a')? ;
3350            return "( true )";
3351        }
3352
3353        return "(" + getLookaheadTestExpression(alt.cache, depth) + ")";
3354    }
3355
3356    /**Generate a depth==1 lookahead test expression given the BitSet.
3357     * This may be one of:
3358     * 1) a series of 'x==X||' tests
3359     * 2) a range test using >= && <= where possible,
3360     * 3) a bitset membership test for complex comparisons
3361     * @param k The lookahead level
3362     * @param p The lookahead set for level k
3363     */
3364    protected String getLookaheadTestTerm(int k, BitSet p) {
3365        // Determine the name of the item to be compared
3366        String ts = lookaheadString(k);
3367
3368        // Generate a range expression if possible
3369        int[] elems = p.toArray();
3370        if (elementsAreRange(elems)) {
3371            return getRangeExpression(k, elems);
3372        }
3373
3374        // Generate a bitset membership test if possible
3375        StringBuffer e;
3376        int degree = p.degree();
3377        if (degree == 0) {
3378            return "true";
3379        }
3380
3381        if (degree >= bitsetTestThreshold) {
3382            int bitsetIdx = markBitsetForGen(p);
3383            return getBitsetName(bitsetIdx) + ".member(" + ts + ")";
3384        }
3385
3386        // Otherwise, generate the long-winded series of "x==X||" tests
3387        e = new StringBuffer();
3388        for (int i = 0; i < elems.length; i++) {
3389            // Get the compared-to item (token or character value)
3390            String cs = getValueString(elems[i]);
3391
3392            // Generate the element comparison
3393            if (i > 0) e.append("||");
3394            e.append(ts);
3395            e.append("==");
3396            e.append(cs);
3397        }
3398        return e.toString();
3399    }
3400
3401    /** Return an expression for testing a contiguous renage of elements
3402     * @param k The lookahead level
3403     * @param elems The elements representing the set, usually from BitSet.toArray().
3404     * @return String containing test expression.
3405     */
3406    public String getRangeExpression(int k, int[] elems) {
3407        if (!elementsAreRange(elems)) {
3408            antlrTool.panic("getRangeExpression called with non-range");
3409        }
3410        int begin = elems[0];
3411        int end = elems[elems.length - 1];
3412        return
3413            "(" + lookaheadString(k) + " >= " + getValueString(begin) + " && " +
3414            lookaheadString(k) + " <= " + getValueString(end) + ")";
3415    }
3416
3417    /** getValueString: get a string representation of a token or char value
3418     * @param value The token or char value
3419     */
3420    private String getValueString(int value) {
3421        String cs;
3422        if (grammar instanceof LexerGrammar) {
3423            cs = charFormatter.literalChar(value);
3424        }
3425        else {
3426            TokenSymbol ts = grammar.tokenManager.getTokenSymbolAt(value);
3427            if (ts == null) {
3428                return "" + value; // return token type as string
3429                // tool.panic("vocabulary for token type " + value + " is null");
3430            }
3431            String tId = ts.getId();
3432            if (ts instanceof StringLiteralSymbol) {
3433                // if string literal, use predefined label if any
3434                // if no predefined, try to mangle into LITERAL_xxx.
3435                // if can't mangle, use int value as last resort
3436                StringLiteralSymbol sl = (StringLiteralSymbol)ts;
3437                String label = sl.getLabel();
3438                if (label != null) {
3439                    cs = label;
3440                }
3441                else {
3442                    cs = mangleLiteral(tId);
3443                    if (cs == null) {
3444                        cs = String.valueOf(value);
3445                    }
3446                }
3447            }
3448            else {
3449                cs = tId;
3450            }
3451        }
3452        return cs;
3453    }
3454
3455    /**Is the lookahead for this alt empty? */
3456    protected boolean lookaheadIsEmpty(Alternative alt, int maxDepth) {
3457        int depth = alt.lookaheadDepth;
3458        if (depth == GrammarAnalyzer.NONDETERMINISTIC) {
3459            depth = grammar.maxk;
3460        }
3461        for (int i = 1; i <= depth && i <= maxDepth; i++) {
3462            BitSet p = alt.cache[i].fset;
3463            if (p.degree() != 0) {
3464                return false;
3465            }
3466        }
3467        return true;
3468    }
3469
3470    private String lookaheadString(int k) {
3471        if (grammar instanceof TreeWalkerGrammar) {
3472            return "_t.getType()";
3473        }
3474        return "LA(" + k + ")";
3475    }
3476
3477    /** Mangle a string literal into a meaningful token name.  This is
3478     * only possible for literals that are all characters.  The resulting
3479     * mangled literal name is literalsPrefix with the text of the literal
3480     * appended.
3481     * @return A string representing the mangled literal, or null if not possible.
3482     */
3483    private String mangleLiteral(String s) {
3484        String mangled = antlrTool.literalsPrefix;
3485        for (int i = 1; i < s.length() - 1; i++) {
3486            if (!Character.isLetter(s.charAt(i)) &&
3487                s.charAt(i) != '_') {
3488                return null;
3489            }
3490            mangled += s.charAt(i);
3491        }
3492        if (antlrTool.upperCaseMangledLiterals) {
3493            mangled = mangled.toUpperCase();
3494        }
3495        return mangled;
3496    }
3497
3498    /** Map an identifier to it's corresponding tree-node variable.
3499     * This is context-sensitive, depending on the rule and alternative
3500     * being generated
3501     * @param idParam The identifier name to map
3502     * @return The mapped id (which may be the same as the input), or null if the mapping is invalid due to duplicates
3503     */
3504    public String mapTreeId(String idParam, ActionTransInfo transInfo) {
3505        // if not in an action of a rule, nothing to map.
3506        if (currentRule == null) return idParam;
3507
3508        boolean in_var = false;
3509        String id = idParam;
3510        if (grammar instanceof TreeWalkerGrammar) {
3511            if (!grammar.buildAST) {
3512                in_var = true;
3513            }
3514            // If the id ends with "_in", then map it to the input variable
3515            else if (id.length() > 3 && id.lastIndexOf("_in") == id.length() - 3) {
3516                // Strip off the "_in"
3517                id = id.substring(0, id.length() - 3);
3518                in_var = true;
3519            }
3520        }
3521
3522        // Check the rule labels.  If id is a label, then the output
3523        // variable is label_AST, and the input variable is plain label.
3524        for (int i = 0; i < currentRule.labeledElements.size(); i++) {
3525            AlternativeElement elt = (AlternativeElement)currentRule.labeledElements.elementAt(i);
3526            if (elt.getLabel().equals(id)) {
3527                return in_var ? id : id + "_AST";
3528            }
3529        }
3530
3531        // Failing that, check the id-to-variable map for the alternative.
3532        // If the id is in the map, then output variable is the name in the
3533        // map, and input variable is name_in
3534        String s = (String)treeVariableMap.get(id);
3535        if (s != null) {
3536            if (s == NONUNIQUE) {
3537                // There is more than one element with this id
3538                                antlrTool.error("Ambiguous reference to AST element "+id+
3539                                                                " in rule "+currentRule.getRuleName());
3540
3541                return null;
3542            }
3543            else if (s.equals(currentRule.getRuleName())) {
3544                // a recursive call to the enclosing rule is
3545                // ambiguous with the rule itself.
3546                                antlrTool.error("Ambiguous reference to AST element "+id+
3547                                                                " in rule "+currentRule.getRuleName());
3548                return null;
3549            }
3550            else {
3551                return in_var ? s + "_in" : s;
3552            }
3553        }
3554
3555        // Failing that, check the rule name itself.  Output variable
3556        // is rule_AST; input variable is rule_AST_in (treeparsers).
3557        if (id.equals(currentRule.getRuleName())) {
3558            String r = in_var ? id + "_AST_in" : id + "_AST";
3559            if (transInfo != null) {
3560                if (!in_var) {
3561                    transInfo.refRuleRoot = r;
3562                }
3563            }
3564            return r;
3565        }
3566        else {
3567            // id does not map to anything -- return itself.
3568            return id;
3569        }
3570    }
3571
3572    /** Given an element and the name of an associated AST variable,
3573     * create a mapping between the element "name" and the variable name.
3574     */
3575    private void mapTreeVariable(AlternativeElement e, String name) {
3576        // For tree elements, defer to the root
3577        if (e instanceof TreeElement) {
3578            mapTreeVariable(((TreeElement)e).root, name);
3579            return;
3580        }
3581
3582        // Determine the name of the element, if any, for mapping purposes
3583        String elName = null;
3584
3585        // Don't map labeled items
3586        if (e.getLabel() == null) {
3587            if (e instanceof TokenRefElement) {
3588                // use the token id
3589                elName = ((TokenRefElement)e).atomText;
3590            }
3591            else if (e instanceof RuleRefElement) {
3592                // use the rule name
3593                elName = ((RuleRefElement)e).targetRule;
3594            }
3595        }
3596        // Add the element to the tree variable map if it has a name
3597        if (elName != null) {
3598            if (treeVariableMap.get(elName) != null) {
3599                // Name is already in the map -- mark it as duplicate
3600                treeVariableMap.remove(elName);
3601                treeVariableMap.put(elName, NONUNIQUE);
3602            }
3603            else {
3604                treeVariableMap.put(elName, name);
3605            }
3606        }
3607    }
3608
3609    /** Lexically process $var and tree-specifiers in the action.
3610     *  This will replace #id and #(...) with the appropriate
3611     *  function calls and/or variables etc...
3612     */
3613    protected String processActionForSpecialSymbols(String actionStr,
3614                                                    int line,
3615                                                    RuleBlock currentRule,
3616                                                    ActionTransInfo tInfo) {
3617        if (actionStr == null || actionStr.length() == 0) return null;
3618
3619        // The action trans info tells us (at the moment) whether an
3620        // assignment was done to the rule's tree root.
3621        if (grammar == null)
3622            return actionStr;
3623
3624        // see if we have anything to do...
3625        if ((grammar.buildAST && actionStr.indexOf('#') != -1) ||
3626            grammar instanceof TreeWalkerGrammar ||
3627            ((grammar instanceof LexerGrammar ||
3628            grammar instanceof ParserGrammar)
3629            && actionStr.indexOf('$') != -1)) {
3630            // Create a lexer to read an action and return the translated version
3631            antlr.actions.java.ActionLexer lexer =
3632                                        new antlr.actions.java.ActionLexer(actionStr,
3633                                                                                                           currentRule,
3634                                                                                                           this,
3635                                                                                                           tInfo);
3636
3637            lexer.setLineOffset(line);
3638            lexer.setFilename(grammar.getFilename());
3639            lexer.setTool(antlrTool);
3640
3641            try {
3642                lexer.mACTION(true);
3643                actionStr = lexer.getTokenObject().getText();
3644                // System.out.println("action translated: "+actionStr);
3645                                        // System.out.println("trans info is "+tInfo);
3646            }
3647            catch (RecognitionException ex) {
3648                lexer.reportError(ex);
3649                return actionStr;
3650            }
3651            catch (TokenStreamException tex) {
3652                antlrTool.panic("Error reading action:" + actionStr);
3653                return actionStr;
3654            }
3655            catch (CharStreamException io) {
3656                antlrTool.panic("Error reading action:" + actionStr);
3657                return actionStr;
3658            }
3659        }
3660        return actionStr;
3661    }
3662
3663    private void setupGrammarParameters(Grammar g) {
3664        if (g instanceof ParserGrammar) {
3665            labeledElementASTType = "AST";
3666            if (g.hasOption("ASTLabelType")) {
3667                Token tsuffix = g.getOption("ASTLabelType");
3668                if (tsuffix != null) {
3669                    String suffix = StringUtils.stripFrontBack(tsuffix.getText(), "\"", "\"");
3670                    if (suffix != null) {
3671                        labeledElementASTType = suffix;
3672                    }
3673                }
3674            }
3675            labeledElementType = "Token ";
3676            labeledElementInit = "null";
3677            commonExtraArgs = "";
3678            commonExtraParams = "";
3679            commonLocalVars = "";
3680            lt1Value = "LT(1)";
3681            exceptionThrown = "RecognitionException";
3682            throwNoViable = "throw new NoViableAltException(LT(1), getFilename());";
3683        }
3684        else if (g instanceof LexerGrammar) {
3685            labeledElementType = "char ";
3686            labeledElementInit = "'\\0'";
3687            commonExtraArgs = "";
3688            commonExtraParams = "boolean _createToken";
3689            commonLocalVars = "int _ttype; Token _token=null; int _begin=text.length();";
3690            lt1Value = "LA(1)";
3691            exceptionThrown = "RecognitionException";
3692            throwNoViable = "throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());";
3693        }
3694        else if (g instanceof TreeWalkerGrammar) {
3695            labeledElementASTType = "AST";
3696            labeledElementType = "AST";
3697            if (g.hasOption("ASTLabelType")) {
3698                Token tsuffix = g.getOption("ASTLabelType");
3699                if (tsuffix != null) {
3700                    String suffix = StringUtils.stripFrontBack(tsuffix.getText(), "\"", "\"");
3701                    if (suffix != null) {
3702                        labeledElementASTType = suffix;
3703                        labeledElementType = suffix;
3704                    }
3705                }
3706            }
3707            if (!g.hasOption("ASTLabelType")) {
3708                g.setOption("ASTLabelType", new Token(ANTLRTokenTypes.STRING_LITERAL, "AST"));
3709            }
3710            labeledElementInit = "null";
3711            commonExtraArgs = "_t";
3712            commonExtraParams = "AST _t";
3713            commonLocalVars = "";
3714            lt1Value = "(" + labeledElementASTType + ")_t";
3715            exceptionThrown = "RecognitionException";
3716            throwNoViable = "throw new NoViableAltException(_t);";
3717        }
3718        else {
3719            antlrTool.panic("Unknown grammar type");
3720        }
3721    }
3722   
3723    /**
3724     * Get the printwriter manager that manages output
3725     * @return The print writer manager
3726     */
3727    public JavaCodeGeneratorPrintWriterManager getPrintWriterManager() {
3728        if (printWriterManager == null)
3729                printWriterManager = new DefaultJavaCodeGeneratorPrintWriterManager();
3730        return printWriterManager;
3731    }
3732   
3733    /**
3734     * Set the print writer manager
3735     * @param printWriterManager the new manager
3736     */
3737    public void setPrintWriterManager(JavaCodeGeneratorPrintWriterManager printWriterManager) {
3738        this.printWriterManager = printWriterManager;
3739    }
3740
3741        /** {@inheritDoc} */
3742        public void setTool(Tool tool) {
3743                super.setTool(tool);
3744        }
3745}
Note: See TracBrowser for help on using the repository browser.