1324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver/* 2324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * [The "BSD license"] 3324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Copyright (c) 2010 Terence Parr 4324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * All rights reserved. 5324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 6324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Redistribution and use in source and binary forms, with or without 7324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * modification, are permitted provided that the following conditions 8324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * are met: 9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 1. Redistributions of source code must retain the above copyright 10324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * notice, this list of conditions and the following disclaimer. 11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 2. Redistributions in binary form must reproduce the above copyright 12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * notice, this list of conditions and the following disclaimer in the 13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * documentation and/or other materials provided with the distribution. 14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 3. The name of the author may not be used to endorse or promote products 15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * derived from this software without specific prior written permission. 16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 28324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverpackage org.antlr.codegen; 29324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 31324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.Tool; 32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.analysis.DFA; 33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.analysis.*; 34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.grammar.v3.ANTLRLexer; 35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.grammar.v3.ANTLRParser; 36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.grammar.v3.ActionTranslator; 37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.grammar.v3.CodeGenTreeWalker; 38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.misc.BitSet; 39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.misc.*; 40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.runtime.*; 41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.runtime.tree.CommonTreeNodeStream; 42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.antlr.tool.*; 43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport org.stringtemplate.v4.*; 44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport java.io.IOException; 46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport java.io.Writer; 47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport java.util.*; 48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver/** ANTLR's code generator. 50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Generate recognizers derived from grammars. Language independence 52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * achieved through the use of STGroup objects. All output 53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * strings are completely encapsulated in the group files such as Java.stg. 54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Some computations are done that are unused by a particular language. 55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * This generator just computes and sets the values into the templates; 56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * the templates are free to use or not use the information. 57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * To make a new code generation target, define X.stg for language X 59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * by copying from existing Y.stg most closely releated to your language; 60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * e.g., to do CSharp.stg copy Java.stg. The template group file has a 61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * bunch of templates that are needed by the code generator. You can add 62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * a new target w/o even recompiling ANTLR itself. The language=X option 63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * in a grammar file dictates which templates get loaded/used. 64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Some language like C need both parser files and header files. Java needs 66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * to have a separate file for the cyclic DFA as ANTLR generates bytecodes 67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * directly (which cannot be in the generated parser Java file). To facilitate 68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * this, 69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * cyclic can be in same file, but header, output must be searpate. recognizer 71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * is in outptufile. 72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverpublic class CodeGenerator { 74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** When generating SWITCH statements, some targets might need to limit 75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * the size (based upon the number of case labels). Generally, this 76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * limit will be hit only for lexers where wildcard in a UNICODE 77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * vocabulary environment would generate a SWITCH with 65000 labels. 78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public final static int MSCL_DEFAULT = 300; 80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public static int MAX_SWITCH_CASE_LABELS = MSCL_DEFAULT; 81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public final static int MSA_DEFAULT = 3; 82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public static int MIN_SWITCH_ALTS = MSA_DEFAULT; 83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public boolean GENERATE_SWITCHES_WHEN_POSSIBLE = true; 84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public static boolean LAUNCH_ST_INSPECTOR = false; 85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public final static int MADSI_DEFAULT = 60; // do lots of states inline (needed for expression rules) 86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public static int MAX_ACYCLIC_DFA_STATES_INLINE = MADSI_DEFAULT; 87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public static String classpathTemplateRootDirectoryName = 89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver "org/antlr/codegen/templates"; 90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Which grammar are we generating code for? Each generator 92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * is attached to a specific grammar. 93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public Grammar grammar; 95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** What language are we generating? */ 97324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected String language; 98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** The target specifies how to write out files and do other language 100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * specific actions. 101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public Target target = null; 103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Where are the templates this generator should use to generate code? */ 105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected STGroup templates; 106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** The basic output templates without AST or templates stuff; this will be 108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * the templates loaded for the language such as Java.stg *and* the Dbg 109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * stuff if turned on. This is used for generating syntactic predicates. 110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected STGroup baseTemplates; 112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected ST recognizerST; 114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected ST outputFileST; 115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected ST headerFileST; 116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Used to create unique labels */ 118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected int uniqueLabelNumber = 1; 119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** A reference to the ANTLR tool so we can learn about output directories 121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * and such. 122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected Tool tool; 124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Generate debugging event method calls */ 126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected boolean debug; 127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Create a Tracer object and make the recognizer invoke this. */ 129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected boolean trace; 130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Track runtime parsing information about decisions etc... 132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * This requires the debugging event mechanism to work. 133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected boolean profile; 135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected int lineWidth = 72; 137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** I have factored out the generation of acyclic DFAs to separate class */ 139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public ACyclicDFACodeGenerator acyclicDFAGenerator = 140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver new ACyclicDFACodeGenerator(this); 141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** I have factored out the generation of cyclic DFAs to separate class */ 143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /* 144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public CyclicDFACodeGenerator cyclicDFAGenerator = 145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver new CyclicDFACodeGenerator(this); 146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public static final String VOCAB_FILE_EXTENSION = ".tokens"; 149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected final static String vocabFilePattern = 150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver "<tokens:{it|<it.name>=<it.type>\n}>" + 151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver "<literals:{it|<it.name>=<it.type>\n}>"; 152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public CodeGenerator(Tool tool, Grammar grammar, String language) { 154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver this.tool = tool; 155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver this.grammar = grammar; 156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver this.language = language; 157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver target = loadLanguageTarget(language); 158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public static Target loadLanguageTarget(String language) { 161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Target target = null; 162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String targetName = "org.antlr.codegen."+language+"Target"; 163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver try { 164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Class c = Class.forName(targetName); 165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver target = (Target)c.newInstance(); 166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver catch (ClassNotFoundException cnfe) { 168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver target = new Target(); // use default 169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver catch (InstantiationException ie) { 171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.error(ErrorManager.MSG_CANNOT_CREATE_TARGET_GENERATOR, 172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver targetName, 173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ie); 174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver catch (IllegalAccessException cnfe) { 176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.error(ErrorManager.MSG_CANNOT_CREATE_TARGET_GENERATOR, 177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver targetName, 178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver cnfe); 179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return target; 181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** load the main language.stg template group file */ 184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void loadTemplates(String language) { 185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String langDir = classpathTemplateRootDirectoryName+"/"+language; 186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver STGroup coreTemplates = new STGroupFile(langDir+"/"+language+".stg"); 187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver baseTemplates = coreTemplates; 189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( coreTemplates ==null ) { 190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.error(ErrorManager.MSG_MISSING_CODE_GEN_TEMPLATES, 191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver language); 192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return; 193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // dynamically add subgroups that act like filters to apply to 196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // their supergroup. E.g., Java:Dbg:AST:ASTParser::ASTDbg. 197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String outputOption = (String)grammar.getOption("output"); 198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( outputOption!=null && outputOption.equals("AST") ) { 199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( debug && grammar.type!=Grammar.LEXER ) { 200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver STGroup dbgTemplates = new STGroupFile(langDir+"/Dbg.stg"); 201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dbgTemplates.importTemplates(coreTemplates); 202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver baseTemplates = dbgTemplates; 203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver STGroup astTemplates = new STGroupFile(langDir+"/AST.stg"); 204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astTemplates.importTemplates(dbgTemplates); 205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver STGroup astParserTemplates = astTemplates; 206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( grammar.type==Grammar.TREE_PARSER ) { 207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astParserTemplates = new STGroupFile(langDir+"/ASTTreeParser.stg"); 208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astParserTemplates.importTemplates(astTemplates); 209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astParserTemplates = new STGroupFile(langDir+"/ASTParser.stg"); 212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astParserTemplates.importTemplates(astTemplates); 213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver STGroup astDbgTemplates = new STGroupFile(langDir+"/ASTDbg.stg"); 215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astDbgTemplates.importTemplates(astParserTemplates); 216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver templates = astDbgTemplates; 217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dbgTemplates.iterateAcrossValues = true; // ST v3 compatibility with Maps 218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astDbgTemplates.iterateAcrossValues = true; 219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astParserTemplates.iterateAcrossValues = true; 220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver STGroup astTemplates = new STGroupFile(langDir+"/AST.stg"); 223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astTemplates.importTemplates(coreTemplates); 224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver STGroup astParserTemplates = astTemplates; 225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( grammar.type==Grammar.TREE_PARSER ) { 226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astParserTemplates = new STGroupFile(langDir+"/ASTTreeParser.stg"); 227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astParserTemplates.importTemplates(astTemplates); 228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astParserTemplates = new STGroupFile(langDir+"/ASTParser.stg"); 231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astParserTemplates.importTemplates(astTemplates); 232324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 233324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver templates = astParserTemplates; 234324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astTemplates.iterateAcrossValues = true; // ST v3 compatibility with Maps 235324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver astParserTemplates.iterateAcrossValues = true; 236324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 237324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 238324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else if ( outputOption!=null && outputOption.equals("template") ) { 239324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( debug && grammar.type!=Grammar.LEXER ) { 240324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver STGroup dbgTemplates = new STGroupFile(langDir+"/Dbg.stg"); 241324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dbgTemplates.importTemplates(coreTemplates); 242324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver baseTemplates = dbgTemplates; 243324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver STGroup stTemplates = new STGroupFile(langDir+"/ST.stg"); 244324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stTemplates.importTemplates(dbgTemplates); 245324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver templates = stTemplates; 246324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dbgTemplates.iterateAcrossValues = true; 247324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 248324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 249324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver STGroup stTemplates = new STGroupFile(langDir+"/ST.stg"); 250324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stTemplates.importTemplates(coreTemplates); 251324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver templates = stTemplates; 252324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 253324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver templates.iterateAcrossValues = true; // ST v3 compatibility with Maps 254324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 255324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else if ( debug && grammar.type!=Grammar.LEXER ) { 256324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver STGroup dbgTemplates = new STGroupFile(langDir+"/Dbg.stg"); 257324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dbgTemplates.importTemplates(coreTemplates); 258324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver templates = dbgTemplates; 259324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver baseTemplates = templates; 260324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver baseTemplates.iterateAcrossValues = true; // ST v3 compatibility with Maps 261324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 262324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 263324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver templates = coreTemplates; 264324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver coreTemplates.iterateAcrossValues = true; // ST v3 compatibility with Maps 265324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 266324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 267324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 268324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Given the grammar to which we are attached, walk the AST associated 269324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * with that grammar to create NFAs. Then create the DFAs for all 270324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * decision points in the grammar by converting the NFAs to DFAs. 271324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Finally, walk the AST again to generate code. 272324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 273324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Either 1 or 2 files are written: 274324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 275324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * recognizer: the main parser/lexer/treewalker item 276324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * header file: language like C/C++ need extern definitions 277324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 278324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * The target, such as JavaTarget, dictates which files get written. 279324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 280324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public ST genRecognizer() { 281324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //System.out.println("### generate "+grammar.name+" recognizer"); 282324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // LOAD OUTPUT TEMPLATES 283324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver loadTemplates(language); 284324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( templates==null ) { 285324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return null; 286324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 287324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 288324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // CREATE NFA FROM GRAMMAR, CREATE DFA FROM NFA 289324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( ErrorManager.doNotAttemptAnalysis() ) { 290324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return null; 291324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 292324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver target.performGrammarAnalysis(this, grammar); 293324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 294324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 295324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // some grammar analysis errors will not yield reliable DFA 296324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( ErrorManager.doNotAttemptCodeGen() ) { 297324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return null; 298324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 299324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 300324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // OPTIMIZE DFA 301324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver DFAOptimizer optimizer = new DFAOptimizer(grammar); 302324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver optimizer.optimize(); 303324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 304324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // OUTPUT FILE (contains recognizerST) 305324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST = templates.getInstanceOf("outputFile"); 306324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 307324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // HEADER FILE 308324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( templates.isDefined("headerFile") ) { 309324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST = templates.getInstanceOf("headerFile"); 310324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 311324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 312324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // create a dummy to avoid null-checks all over code generator 313324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST = new ST(templates,"xyz"); 314324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("cyclicDFAs", (Object)null); // it normally sees this from outputFile 315324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //headerFileST.impl.name = "dummy-header-file"; 316324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 317324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 318324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver boolean filterMode = grammar.getOption("filter")!=null && 319324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar.getOption("filter").equals("true"); 320324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver boolean canBacktrack = grammar.getSyntacticPredicates()!=null || 321324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar.composite.getRootGrammar().atLeastOneBacktrackOption || 322324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver filterMode; 323324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 324324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // TODO: move this down further because generating the recognizer 325324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // alters the model with info on who uses predefined properties etc... 326324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // The actions here might refer to something. 327324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 328324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // The only two possible output files are available at this point. 329324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // Verify action scopes are ok for target and dump actions into output 330324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // Templates can say <actions.parser.header> for example. 331324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Map<String, Map<String, Object>> actions = grammar.getActions(); 332324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver verifyActionScopesOkForTarget(actions); 333324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // translate $x::y references 334324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver translateActionAttributeReferences(actions); 335324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 336324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST gateST = templates.getInstanceOf("actionGate"); 337324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( filterMode ) { 338324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // if filtering, we need to set actions to execute at backtracking 339324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // level 1 not 0. 340324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver gateST = templates.getInstanceOf("filteringActionGate"); 341324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 342324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar.setSynPredGateIfNotAlready(gateST); 343324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 344324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("actions", actions); 345324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("actions", actions); 346324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 347324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("buildTemplate", new Boolean(grammar.buildTemplate())); 348324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("buildTemplate", new Boolean(grammar.buildTemplate())); 349324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("buildAST", new Boolean(grammar.buildAST())); 350324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("buildAST", new Boolean(grammar.buildAST())); 351324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 352324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("rewriteMode", Boolean.valueOf(grammar.rewriteMode())); 353324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("rewriteMode", Boolean.valueOf(grammar.rewriteMode())); 354324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 355324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("backtracking", Boolean.valueOf(canBacktrack)); 356324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("backtracking", Boolean.valueOf(canBacktrack)); 357324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // turn on memoize attribute at grammar level so we can create ruleMemo. 358324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // each rule has memoize attr that hides this one, indicating whether 359324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // it needs to save results 360324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String memoize = (String)grammar.getOption("memoize"); 361324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("memoize", 362324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver (grammar.atLeastOneRuleMemoizes || 363324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Boolean.valueOf(memoize != null && memoize.equals("true")) && 364324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver canBacktrack)); 365324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("memoize", 366324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver (grammar.atLeastOneRuleMemoizes || 367324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Boolean.valueOf(memoize != null && memoize.equals("true")) && 368324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver canBacktrack)); 369324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 370324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 371324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("trace", Boolean.valueOf(trace)); 372324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("trace", Boolean.valueOf(trace)); 373324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 374324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("profile", Boolean.valueOf(profile)); 375324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("profile", Boolean.valueOf(profile)); 376324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 377324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // RECOGNIZER 378324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( grammar.type==Grammar.LEXER ) { 379324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver recognizerST = templates.getInstanceOf("lexer"); 380324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("LEXER", Boolean.valueOf(true)); 381324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("LEXER", Boolean.valueOf(true)); 382324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver recognizerST.add("filterMode", 383324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Boolean.valueOf(filterMode)); 384324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 385324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else if ( grammar.type==Grammar.PARSER || 386324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar.type==Grammar.COMBINED ) 387324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 388324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver recognizerST = templates.getInstanceOf("parser"); 389324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("PARSER", Boolean.valueOf(true)); 390324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("PARSER", Boolean.valueOf(true)); 391324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 392324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 393324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver recognizerST = templates.getInstanceOf("treeParser"); 394324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("TREE_PARSER", Boolean.valueOf(true)); 395324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("TREE_PARSER", Boolean.valueOf(true)); 396324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver recognizerST.add("filterMode", 397324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Boolean.valueOf(filterMode)); 398324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 399324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("recognizer", recognizerST); 400324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("recognizer", recognizerST); 401324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("actionScope", 402324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar.getDefaultActionScope(grammar.type)); 403324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("actionScope", 404324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar.getDefaultActionScope(grammar.type)); 405324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 406324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String targetAppropriateFileNameString = 407324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver target.getTargetStringLiteralFromString(grammar.getFileName()); 408324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("fileName", targetAppropriateFileNameString); 409324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("fileName", targetAppropriateFileNameString); 410324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("ANTLRVersion", tool.VERSION); 411324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("ANTLRVersion", tool.VERSION); 412324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("generatedTimestamp", Tool.getCurrentTimeStamp()); 413324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("generatedTimestamp", Tool.getCurrentTimeStamp()); 414324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 415324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // GENERATE RECOGNIZER 416324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // Walk the AST holding the input grammar, this time generating code 417324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // Decisions are generated by using the precomputed DFAs 418324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // Fill in the various templates with data 419324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver CodeGenTreeWalker gen = new CodeGenTreeWalker(new CommonTreeNodeStream(grammar.getGrammarTree())); 420324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver try { 421324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver gen.grammar_( 422324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar, 423324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver recognizerST, 424324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST, 425324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST); 426324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 427324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver catch (RecognitionException re) { 428324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.error(ErrorManager.MSG_BAD_AST_STRUCTURE, 429324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver re); 430324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 431324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 432324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver genTokenTypeConstants(recognizerST); 433324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver genTokenTypeConstants(outputFileST); 434324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver genTokenTypeConstants(headerFileST); 435324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 436324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( grammar.type!=Grammar.LEXER ) { 437324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver genTokenTypeNames(recognizerST); 438324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver genTokenTypeNames(outputFileST); 439324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver genTokenTypeNames(headerFileST); 440324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 441324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 442324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // Now that we know what synpreds are used, we can set into template 443324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Set synpredNames = null; 444324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( grammar.synPredNamesUsedInDFA.size()>0 ) { 445324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver synpredNames = grammar.synPredNamesUsedInDFA; 446324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 447324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("synpreds", synpredNames); 448324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("synpreds", synpredNames); 449324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 450324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // all recognizers can see Grammar object 451324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver recognizerST.add("grammar", grammar); 452324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 453324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if (LAUNCH_ST_INSPECTOR) { 454324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.inspect(); 455324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( templates.isDefined("headerFile") ) headerFileST.inspect(); 456324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 457324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 458324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // WRITE FILES 459324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver try { 460324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver target.genRecognizerFile(tool,this,grammar,outputFileST); 461324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( templates.isDefined("headerFile") ) { 462324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST extST = templates.getInstanceOf("headerFileExtension"); 463324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver target.genRecognizerHeaderFile(tool,this,grammar,headerFileST,extST.render()); 464324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 465324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // write out the vocab interchange file; used by antlr, 466324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // does not change per target 467324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST tokenVocabSerialization = genTokenVocabOutput(); 468324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String vocabFileName = getVocabFileName(); 469324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( vocabFileName!=null ) { 470324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver write(tokenVocabSerialization, vocabFileName); 471324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 472324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //System.out.println(outputFileST.getDOTForDependencyGraph(false)); 473324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 474324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver catch (IOException ioe) { 475324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.error(ErrorManager.MSG_CANNOT_WRITE_FILE, ioe); 476324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 477324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /* 478324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver System.out.println("num obj.prop refs: "+ ASTExpr.totalObjPropRefs); 479324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver System.out.println("num reflection lookups: "+ ASTExpr.totalReflectionLookups); 480324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 481324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 482324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return outputFileST; 483324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 484324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 485324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Some targets will have some extra scopes like C++ may have 486324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * '@headerfile:name {action}' or something. Make sure the 487324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * target likes the scopes in action table. 488324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 489324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected void verifyActionScopesOkForTarget(Map actions) { 490324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Set actionScopeKeySet = actions.keySet(); 491324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (Iterator it = actionScopeKeySet.iterator(); it.hasNext();) { 492324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String scope = (String)it.next(); 493324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( !target.isValidActionScope(grammar.type, scope) ) { 494324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // get any action from the scope to get error location 495324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Map scopeActions = (Map)actions.get(scope); 496324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver GrammarAST actionAST = 497324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver (GrammarAST)scopeActions.values().iterator().next(); 498324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.grammarError( 499324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.MSG_INVALID_ACTION_SCOPE,grammar, 500324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionAST.getToken(),scope, 501324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar.getGrammarTypeString()); 502324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 503324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 504324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 505324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 506324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Actions may reference $x::y attributes, call translateAction on 507324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * each action and replace that action in the Map. 508324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 509324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected void translateActionAttributeReferences(Map actions) { 510324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Set actionScopeKeySet = actions.keySet(); 511324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (Iterator it = actionScopeKeySet.iterator(); it.hasNext();) { 512324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String scope = (String)it.next(); 513324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Map scopeActions = (Map)actions.get(scope); 514324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver translateActionAttributeReferencesForSingleScope(null,scopeActions); 515324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 516324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 517324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 518324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Use for translating rule @init{...} actions that have no scope */ 519324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void translateActionAttributeReferencesForSingleScope( 520324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Rule r, 521324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Map scopeActions) 522324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 523324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String ruleName=null; 524324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( r!=null ) { 525324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ruleName = r.name; 526324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 527324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Set actionNameSet = scopeActions.keySet(); 528324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (Iterator nameIT = actionNameSet.iterator(); nameIT.hasNext();) { 529324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String name = (String) nameIT.next(); 530324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver GrammarAST actionAST = (GrammarAST)scopeActions.get(name); 531324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver List chunks = translateAction(ruleName,actionAST); 532324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver scopeActions.put(name, chunks); // replace with translation 533324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 534324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 535324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 536324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Error recovery in ANTLR recognizers. 537324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 538324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Based upon original ideas: 539324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 540324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Algorithms + Data Structures = Programs by Niklaus Wirth 541324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 542324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * and 543324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 544324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * A note on error recovery in recursive descent parsers: 545324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * http://portal.acm.org/citation.cfm?id=947902.947905 546324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 547324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Later, Josef Grosch had some good ideas: 548324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Efficient and Comfortable Error Recovery in Recursive Descent Parsers: 549324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * ftp://www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip 550324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 551324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Like Grosch I implemented local FOLLOW sets that are combined at run-time 552324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * upon error to avoid parsing overhead. 553324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 554324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void generateLocalFOLLOW(GrammarAST referencedElementNode, 555324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String referencedElementName, 556324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String enclosingRuleName, 557324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int elementIndex) 558324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 559324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /* 560324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver System.out.println("compute FOLLOW "+grammar.name+"."+referencedElementNode.toString()+ 561324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver " for "+referencedElementName+"#"+elementIndex +" in "+ 562324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver enclosingRuleName+ 563324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver " line="+referencedElementNode.getLine()); 564324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 565324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver NFAState followingNFAState = referencedElementNode.followingNFAState; 566324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver LookaheadSet follow = null; 567324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( followingNFAState!=null ) { 568324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // compute follow for this element and, as side-effect, track 569324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // the rule LOOK sensitivity. 570324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver follow = grammar.FIRST(followingNFAState); 571324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 572324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 573324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( follow==null ) { 574324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.internalError("no follow state or cannot compute follow"); 575324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver follow = new LookaheadSet(); 576324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 577324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( follow.member(Label.EOF) ) { 578324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // TODO: can we just remove? Seems needed here: 579324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // compilation_unit : global_statement* EOF 580324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // Actually i guess we resync to EOF regardless 581324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver follow.remove(Label.EOF); 582324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 583324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //System.out.println(" "+follow); 584324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 585324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver List tokenTypeList = null; 586324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver long[] words = null; 587324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( follow.tokenTypeSet==null ) { 588324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver words = new long[1]; 589324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver tokenTypeList = new ArrayList(); 590324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 591324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 592324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver BitSet bits = BitSet.of(follow.tokenTypeSet); 593324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver words = bits.toPackedArray(); 594324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver tokenTypeList = follow.tokenTypeSet.toList(); 595324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 596324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // use the target to convert to hex strings (typically) 597324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String[] wordStrings = new String[words.length]; 598324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (int j = 0; j < words.length; j++) { 599324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver long w = words[j]; 600324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver wordStrings[j] = target.getTarget64BitStringFromValue(w); 601324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 602324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver recognizerST.addAggr("bitsets.{name,inName,bits,tokenTypes,tokenIndex}", 603324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver referencedElementName, 604324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver enclosingRuleName, 605324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver wordStrings, 606324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver tokenTypeList, 607324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Utils.integer(elementIndex)); 608324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.addAggr("bitsets.{name,inName,bits,tokenTypes,tokenIndex}", 609324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver referencedElementName, 610324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver enclosingRuleName, 611324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver wordStrings, 612324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver tokenTypeList, 613324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Utils.integer(elementIndex)); 614324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.addAggr("bitsets.{name,inName,bits,tokenTypes,tokenIndex}", 615324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver referencedElementName, 616324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver enclosingRuleName, 617324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver wordStrings, 618324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver tokenTypeList, 619324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Utils.integer(elementIndex)); 620324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 621324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 622324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // L O O K A H E A D D E C I S I O N G E N E R A T I O N 623324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 624324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Generate code that computes the predicted alt given a DFA. The 625324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * recognizerST can be either the main generated recognizerTemplate 626324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * for storage in the main parser file or a separate file. It's up to 627324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * the code that ultimately invokes the codegen.g grammar rule. 628324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 629324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Regardless, the output file and header file get a copy of the DFAs. 630324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 631324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public ST genLookaheadDecision(ST recognizerST, 632324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver DFA dfa) 633324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 634324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST decisionST; 635324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // If we are doing inline DFA and this one is acyclic and LL(*) 636324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // I have to check for is-non-LL(*) because if non-LL(*) the cyclic 637324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // check is not done by DFA.verify(); that is, verify() avoids 638324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // doesStateReachAcceptState() if non-LL(*) 639324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( dfa.canInlineDecision() ) { 640324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver decisionST = 641324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver acyclicDFAGenerator.genFixedLookaheadDecision(getTemplates(), dfa); 642324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 643324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 644324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // generate any kind of DFA here (cyclic or acyclic) 645324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dfa.createStateTables(this); 646324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver outputFileST.add("cyclicDFAs", dfa); 647324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver headerFileST.add("cyclicDFAs", dfa); 648324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver decisionST = templates.getInstanceOf("dfaDecision"); 649324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String description = dfa.getNFADecisionStartState().getDescription(); 650324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver description = target.getTargetStringLiteralFromString(description); 651324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( description!=null ) { 652324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver decisionST.add("description", description); 653324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 654324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver decisionST.add("decisionNumber", 655324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Utils.integer(dfa.getDecisionNumber())); 656324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 657324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return decisionST; 658324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 659324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 660324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** A special state is huge (too big for state tables) or has a predicated 661324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * edge. Generate a simple if-then-else. Cannot be an accept state as 662324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * they have no emanating edges. Don't worry about switch vs if-then-else 663324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * because if you get here, the state is super complicated and needs an 664324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * if-then-else. This is used by the new DFA scheme created June 2006. 665324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 666324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public ST generateSpecialState(DFAState s) { 667324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST stateST; 668324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateST = templates.getInstanceOf("cyclicDFAState"); 669324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateST.add("needErrorClause", Boolean.valueOf(true)); 670324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateST.add("semPredState", 671324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Boolean.valueOf(s.isResolvedWithPredicates())); 672324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateST.add("stateNumber", s.stateNumber); 673324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateST.add("decisionNumber", s.dfa.decisionNumber); 674324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 675324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver boolean foundGatedPred = false; 676324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST eotST = null; 677324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (int i = 0; i < s.getNumberOfTransitions(); i++) { 678324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Transition edge = (Transition) s.transition(i); 679324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST edgeST; 680324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( edge.label.getAtom()==Label.EOT ) { 681324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // this is the default clause; has to held until last 682324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST = templates.getInstanceOf("eotDFAEdge"); 683324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateST.remove("needErrorClause"); 684324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eotST = edgeST; 685324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 686324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 687324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST = templates.getInstanceOf("cyclicDFAEdge"); 688324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST exprST = 689324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver genLabelExpr(templates,edge,1); 690324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("labelExpr", exprST); 691324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 692324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("edgeNumber", Utils.integer(i + 1)); 693324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("targetStateNumber", 694324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Utils.integer(edge.target.stateNumber)); 695324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // stick in any gated predicates for any edge if not already a pred 696324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( !edge.label.isSemanticPredicate() ) { 697324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver DFAState t = (DFAState)edge.target; 698324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver SemanticContext preds = t.getGatedPredicatesInNFAConfigurations(); 699324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( preds!=null ) { 700324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver foundGatedPred = true; 701324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST predST = preds.genExpr(this, 702324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver getTemplates(), 703324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver t.dfa); 704324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver edgeST.add("predicates", predST.render()); 705324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 706324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 707324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( edge.label.getAtom()!=Label.EOT ) { 708324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateST.add("edges", edgeST); 709324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 710324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 711324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( foundGatedPred ) { 712324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // state has >= 1 edge with a gated pred (syn or sem) 713324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // must rewind input first, set flag. 714324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateST.add("semPredState", new Boolean(foundGatedPred)); 715324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 716324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( eotST!=null ) { 717324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver stateST.add("edges", eotST); 718324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 719324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return stateST; 720324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 721324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 722324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Generate an expression for traversing an edge. */ 723324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected ST genLabelExpr(STGroup templates, 724324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Transition edge, 725324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int k) 726324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 727324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Label label = edge.label; 728324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( label.isSemanticPredicate() ) { 729324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return genSemanticPredicateExpr(templates, edge); 730324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 731324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( label.isSet() ) { 732324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return genSetExpr(templates, label.getSet(), k, true); 733324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 734324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // must be simple label 735324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST eST = templates.getInstanceOf("lookaheadTest"); 736324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST.add("atom", getTokenTypeAsTargetLabel(label.getAtom())); 737324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST.add("atomAsInt", Utils.integer(label.getAtom())); 738324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST.add("k", Utils.integer(k)); 739324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return eST; 740324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 741324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 742324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected ST genSemanticPredicateExpr(STGroup templates, 743324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Transition edge) 744324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 745324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver DFA dfa = ((DFAState)edge.target).dfa; // which DFA are we in 746324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Label label = edge.label; 747324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver SemanticContext semCtx = label.getSemanticContext(); 748324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return semCtx.genExpr(this,templates,dfa); 749324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 750324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 751324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** For intervals such as [3..3, 30..35], generate an expression that 752324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * tests the lookahead similar to LA(1)==3 || (LA(1)>=30&&LA(1)<=35) 753324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 754324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public ST genSetExpr(STGroup templates, 755324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver IntSet set, 756324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int k, 757324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver boolean partOfDFA) 758324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 759324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( !(set instanceof IntervalSet) ) { 760324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver throw new IllegalArgumentException("unable to generate expressions for non IntervalSet objects"); 761324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 762324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver IntervalSet iset = (IntervalSet)set; 763324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( iset.getIntervals()==null || iset.getIntervals().size()==0 ) { 764324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST emptyST = new ST(templates, ""); 765324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver emptyST.impl.name = "empty-set-expr"; 766324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return emptyST; 767324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 768324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String testSTName = "lookaheadTest"; 769324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String testRangeSTName = "lookaheadRangeTest"; 770324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( !partOfDFA ) { 771324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver testSTName = "isolatedLookaheadTest"; 772324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver testRangeSTName = "isolatedLookaheadRangeTest"; 773324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 774324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST setST = templates.getInstanceOf("setTest"); 775324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Iterator iter = iset.getIntervals().iterator(); 776324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int rangeNumber = 1; 777324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver while (iter.hasNext()) { 778324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Interval I = (Interval) iter.next(); 779324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int a = I.a; 780324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int b = I.b; 781324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST eST; 782324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( a==b ) { 783324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST = templates.getInstanceOf(testSTName); 784324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST.add("atom", getTokenTypeAsTargetLabel(a)); 785324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST.add("atomAsInt", Utils.integer(a)); 786324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //eST.add("k",Utils.integer(k)); 787324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 788324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 789324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST = templates.getInstanceOf(testRangeSTName); 790324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST.add("lower", getTokenTypeAsTargetLabel(a)); 791324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST.add("lowerAsInt", Utils.integer(a)); 792324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST.add("upper", getTokenTypeAsTargetLabel(b)); 793324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST.add("upperAsInt", Utils.integer(b)); 794324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST.add("rangeNumber", Utils.integer(rangeNumber)); 795324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 796324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver eST.add("k", Utils.integer(k)); 797324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver setST.add("ranges", eST); 798324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver rangeNumber++; 799324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 800324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return setST; 801324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 802324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 803324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // T O K E N D E F I N I T I O N G E N E R A T I O N 804324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 805324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Set attributes tokens and literals attributes in the incoming 806324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * code template. This is not the token vocab interchange file, but 807324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * rather a list of token type ID needed by the recognizer. 808324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 809324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected void genTokenTypeConstants(ST code) { 810324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // make constants for the token types 811324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Iterator tokenIDs = grammar.getTokenIDs().iterator(); 812324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver while (tokenIDs.hasNext()) { 813324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String tokenID = (String) tokenIDs.next(); 814324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int tokenType = grammar.getTokenType(tokenID); 815324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( tokenType==Label.EOF || 816324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver tokenType>=Label.MIN_TOKEN_TYPE ) 817324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 818324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // don't do FAUX labels 'cept EOF 819324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver code.addAggr("tokens.{name,type}", tokenID, Utils.integer(tokenType)); 820324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 821324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 822324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 823324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 824324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Generate a token names table that maps token type to a printable 825324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * name: either the label like INT or the literal like "begin". 826324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 827324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected void genTokenTypeNames(ST code) { 828324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (int t=Label.MIN_TOKEN_TYPE; t<=grammar.getMaxTokenType(); t++) { 829324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String tokenName = grammar.getTokenDisplayName(t); 830324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( tokenName!=null ) { 831324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver tokenName=target.getTargetStringLiteralFromString(tokenName, true); 832324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver code.add("tokenNames", tokenName); 833324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 834324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 835324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 836324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 837324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Get a meaningful name for a token type useful during code generation. 838324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Literals without associated names are converted to the string equivalent 839324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * of their integer values. Used to generate x==ID and x==34 type comparisons 840324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * etc... Essentially we are looking for the most obvious way to refer 841324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * to a token type in the generated code. If in the lexer, return the 842324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * char literal translated to the target language. For example, ttype=10 843324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * will yield '\n' from the getTokenDisplayName method. That must 844324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * be converted to the target languages literals. For most C-derived 845324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * languages no translation is needed. 846324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 847324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public String getTokenTypeAsTargetLabel(int ttype) { 848324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( grammar.type==Grammar.LEXER ) { 849324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String name = grammar.getTokenDisplayName(ttype); 850324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return target.getTargetCharLiteralFromANTLRCharLiteral(this,name); 851324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 852324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return target.getTokenTypeAsTargetLabel(this,ttype); 853324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 854324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 855324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Generate a token vocab file with all the token names/types. For example: 856324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * ID=7 857324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * FOR=8 858324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 'for'=8 859324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 860324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * This is independent of the target language; used by antlr internally 861324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 862324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected ST genTokenVocabOutput() { 863324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST vocabFileST = new ST(vocabFilePattern); 864324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver vocabFileST.add("literals",(Object)null); // "define" literals arg 865324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver vocabFileST.add("tokens",(Object)null); 866324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver vocabFileST.impl.name = "vocab-file"; 867324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // make constants for the token names 868324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Iterator tokenIDs = grammar.getTokenIDs().iterator(); 869324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver while (tokenIDs.hasNext()) { 870324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String tokenID = (String) tokenIDs.next(); 871324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int tokenType = grammar.getTokenType(tokenID); 872324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( tokenType>=Label.MIN_TOKEN_TYPE ) { 873324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver vocabFileST.addAggr("tokens.{name,type}", tokenID, Utils.integer(tokenType)); 874324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 875324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 876324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 877324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // now dump the strings 878324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Iterator literals = grammar.getStringLiterals().iterator(); 879324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver while (literals.hasNext()) { 880324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String literal = (String) literals.next(); 881324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int tokenType = grammar.getTokenType(literal); 882324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( tokenType>=Label.MIN_TOKEN_TYPE ) { 883324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver vocabFileST.addAggr("tokens.{name,type}", literal, Utils.integer(tokenType)); 884324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 885324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 886324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 887324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return vocabFileST; 888324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 889324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 890324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public List translateAction(String ruleName, 891324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver GrammarAST actionTree) 892324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 893324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( actionTree.getType()==ANTLRParser.ARG_ACTION ) { 894324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return translateArgAction(ruleName, actionTree); 895324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 896324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ActionTranslator translator = new ActionTranslator(this,ruleName,actionTree); 897324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver List chunks = translator.translateToChunks(); 898324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver chunks = target.postProcessAction(chunks, actionTree.token); 899324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return chunks; 900324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 901324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 902324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Translate an action like [3,"foo",a[3]] and return a List of the 903324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * translated actions. Because actions are themselves translated to a list 904324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * of chunks, must cat together into a ST>. Don't translate 905324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * to strings early as we need to eval templates in context. 906324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 907324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public List<ST> translateArgAction(String ruleName, 908324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver GrammarAST actionTree) 909324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 910324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String actionText = actionTree.token.getText(); 911324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver List<String> args = getListOfArgumentsFromAction(actionText,','); 912324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver List<ST> translatedArgs = new ArrayList<ST>(); 913324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (String arg : args) { 914324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( arg!=null ) { 915324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Token actionToken = 916324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver new CommonToken(ANTLRParser.ACTION,arg); 917324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ActionTranslator translator = 918324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver new ActionTranslator(this,ruleName, 919324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionToken, 920324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionTree.outerAltNum); 921324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver List chunks = translator.translateToChunks(); 922324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver chunks = target.postProcessAction(chunks, actionToken); 923324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST catST = new ST(templates, "<chunks>"); 924324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver catST.add("chunks", chunks); 925324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver translatedArgs.add(catST); 926324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 927324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 928324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( translatedArgs.size()==0 ) { 929324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return null; 930324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 931324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return translatedArgs; 932324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 933324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 934324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public static List<String> getListOfArgumentsFromAction(String actionText, 935324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int separatorChar) 936324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 937324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver List<String> args = new ArrayList<String>(); 938324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver getListOfArgumentsFromAction(actionText, 0, -1, separatorChar, args); 939324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return args; 940324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 941324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 942324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Given an arg action like 943324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 944324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * [x, (*a).foo(21,33), 3.2+1, '\n', 945324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * "a,oo\nick", {bl, "fdkj"eck}, ["cat\n,", x, 43]] 946324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 947324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * convert to a list of arguments. Allow nested square brackets etc... 948324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Set separatorChar to ';' or ',' or whatever you want. 949324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 950324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public static int getListOfArgumentsFromAction(String actionText, 951324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int start, 952324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int targetChar, 953324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int separatorChar, 954324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver List<String> args) 955324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 956324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( actionText==null ) { 957324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return -1; 958324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 959324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionText = actionText.replaceAll("//.*\n", ""); 960324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int n = actionText.length(); 961324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //System.out.println("actionText@"+start+"->"+(char)targetChar+"="+actionText.substring(start,n)); 962324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int p = start; 963324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int last = p; 964324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver while ( p<n && actionText.charAt(p)!=targetChar ) { 965324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int c = actionText.charAt(p); 966324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver switch ( c ) { 967324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver case '\'' : 968324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p++; 969324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver while ( p<n && actionText.charAt(p)!='\'' ) { 970324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( actionText.charAt(p)=='\\' && (p+1)<n && 971324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionText.charAt(p+1)=='\'' ) 972324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 973324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p++; // skip escaped quote 974324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 975324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p++; 976324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 977324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p++; 978324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver break; 979324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver case '"' : 980324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p++; 981324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver while ( p<n && actionText.charAt(p)!='\"' ) { 982324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( actionText.charAt(p)=='\\' && (p+1)<n && 983324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionText.charAt(p+1)=='\"' ) 984324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 985324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p++; // skip escaped quote 986324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 987324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p++; 988324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 989324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p++; 990324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver break; 991324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver case '(' : 992324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p = getListOfArgumentsFromAction(actionText,p+1,')',separatorChar,args); 993324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver break; 994324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver case '{' : 995324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p = getListOfArgumentsFromAction(actionText,p+1,'}',separatorChar,args); 996324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver break; 997324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver case '<' : 998324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( actionText.indexOf('>',p+1)>=p ) { 999324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // do we see a matching '>' ahead? if so, hope it's a generic 1000324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // and not less followed by expr with greater than 1001324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p = getListOfArgumentsFromAction(actionText,p+1,'>',separatorChar,args); 1002324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1003324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 1004324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p++; // treat as normal char 1005324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1006324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver break; 1007324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver case '[' : 1008324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p = getListOfArgumentsFromAction(actionText,p+1,']',separatorChar,args); 1009324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver break; 1010324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver default : 1011324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( c==separatorChar && targetChar==-1 ) { 1012324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String arg = actionText.substring(last, p); 1013324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //System.out.println("arg="+arg); 1014324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver args.add(arg.trim()); 1015324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver last = p+1; 1016324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1017324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p++; 1018324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver break; 1019324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1020324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1021324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( targetChar==-1 && p<=n ) { 1022324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String arg = actionText.substring(last, p).trim(); 1023324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //System.out.println("arg="+arg); 1024324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( arg.length()>0 ) { 1025324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver args.add(arg.trim()); 1026324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1027324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1028324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver p++; 1029324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return p; 1030324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1031324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1032324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Given a template constructor action like %foo(a={...}) in 1033324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * an action, translate it to the appropriate template constructor 1034324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * from the templateLib. This translates a *piece* of the action. 1035324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 1036324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public ST translateTemplateConstructor(String ruleName, 1037324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int outerAltNum, 1038324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Token actionToken, 1039324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String templateActionText) 1040324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 1041324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // first, parse with antlr.g 1042324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //System.out.println("translate template: "+templateActionText); 1043324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ANTLRLexer lexer = new ANTLRLexer(new ANTLRStringStream(templateActionText)); 1044324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver lexer.setFileName(grammar.getFileName()); 1045324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ANTLRParser parser = ANTLRParser.createParser(new CommonTokenStream(lexer)); 1046324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver parser.setFileName(grammar.getFileName()); 1047324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ANTLRParser.rewrite_template_return parseResult = null; 1048324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver try { 1049324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver parseResult = parser.rewrite_template(); 1050324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1051324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver catch (RecognitionException re) { 1052324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.grammarError(ErrorManager.MSG_INVALID_TEMPLATE_ACTION, 1053324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar, 1054324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionToken, 1055324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver templateActionText); 1056324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1057324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver catch (Exception tse) { 1058324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.internalError("can't parse template action",tse); 1059324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1060324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver GrammarAST rewriteTree = (GrammarAST)parseResult.getTree(); 1061324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1062324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // then translate via codegen.g 1063324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver CodeGenTreeWalker gen = new CodeGenTreeWalker(new CommonTreeNodeStream(rewriteTree)); 1064324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver gen.init(grammar); 1065324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver gen.setCurrentRuleName(ruleName); 1066324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver gen.setOuterAltNum(outerAltNum); 1067324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST st = null; 1068324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver try { 1069324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver st = gen.rewrite_template(); 1070324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1071324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver catch (RecognitionException re) { 1072324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.error(ErrorManager.MSG_BAD_AST_STRUCTURE, 1073324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver re); 1074324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1075324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return st; 1076324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1077324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1078324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1079324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void issueInvalidScopeError(String x, 1080324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String y, 1081324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Rule enclosingRule, 1082324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Token actionToken, 1083324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int outerAltNum) 1084324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 1085324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //System.out.println("error $"+x+"::"+y); 1086324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Rule r = grammar.getRule(x); 1087324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver AttributeScope scope = grammar.getGlobalScope(x); 1088324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( scope==null ) { 1089324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( r!=null ) { 1090324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver scope = r.ruleScope; // if not global, might be rule scope 1091324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1092324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1093324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( scope==null ) { 1094324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.grammarError(ErrorManager.MSG_UNKNOWN_DYNAMIC_SCOPE, 1095324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar, 1096324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionToken, 1097324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver x); 1098324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1099324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else if ( scope.getAttribute(y)==null ) { 1100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.grammarError(ErrorManager.MSG_UNKNOWN_DYNAMIC_SCOPE_ATTRIBUTE, 1101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar, 1102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionToken, 1103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver x, 1104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver y); 1105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void issueInvalidAttributeError(String x, 1109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String y, 1110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Rule enclosingRule, 1111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Token actionToken, 1112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int outerAltNum) 1113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 1114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //System.out.println("error $"+x+"."+y); 1115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( enclosingRule==null ) { 1116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // action not in a rule 1117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.grammarError(ErrorManager.MSG_ATTRIBUTE_REF_NOT_IN_RULE, 1118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar, 1119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionToken, 1120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver x, 1121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver y); 1122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return; 1123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // action is in a rule 1126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Grammar.LabelElementPair label = enclosingRule.getRuleLabel(x); 1127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( label!=null || enclosingRule.getRuleRefsInAlt(x, outerAltNum)!=null ) { 1129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // $rulelabel.attr or $ruleref.attr; must be unknown attr 1130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String refdRuleName = x; 1131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( label!=null ) { 1132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver refdRuleName = enclosingRule.getRuleLabel(x).referencedRuleName; 1133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Rule refdRule = grammar.getRule(refdRuleName); 1135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver AttributeScope scope = refdRule.getAttributeScope(y); 1136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( scope==null ) { 1137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.grammarError(ErrorManager.MSG_UNKNOWN_RULE_ATTRIBUTE, 1138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar, 1139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionToken, 1140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver refdRuleName, 1141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver y); 1142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else if ( scope.isParameterScope ) { 1144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.grammarError(ErrorManager.MSG_INVALID_RULE_PARAMETER_REF, 1145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar, 1146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionToken, 1147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver refdRuleName, 1148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver y); 1149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else if ( scope.isDynamicRuleScope ) { 1151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.grammarError(ErrorManager.MSG_INVALID_RULE_SCOPE_ATTRIBUTE_REF, 1152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar, 1153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionToken, 1154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver refdRuleName, 1155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver y); 1156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void issueInvalidAttributeError(String x, 1162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Rule enclosingRule, 1163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Token actionToken, 1164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int outerAltNum) 1165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 1166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //System.out.println("error $"+x); 1167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( enclosingRule==null ) { 1168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // action not in a rule 1169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.grammarError(ErrorManager.MSG_ATTRIBUTE_REF_NOT_IN_RULE, 1170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar, 1171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionToken, 1172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver x); 1173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return; 1174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // action is in a rule 1177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Grammar.LabelElementPair label = enclosingRule.getRuleLabel(x); 1178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver AttributeScope scope = enclosingRule.getAttributeScope(x); 1179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( label!=null || 1181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver enclosingRule.getRuleRefsInAlt(x, outerAltNum)!=null || 1182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver enclosingRule.name.equals(x) ) 1183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 1184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.grammarError(ErrorManager.MSG_ISOLATED_RULE_SCOPE, 1185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar, 1186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionToken, 1187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver x); 1188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else if ( scope!=null && scope.isDynamicRuleScope ) { 1190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.grammarError(ErrorManager.MSG_ISOLATED_RULE_ATTRIBUTE, 1191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar, 1192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionToken, 1193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver x); 1194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else { 1196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ErrorManager.grammarError(ErrorManager.MSG_UNKNOWN_SIMPLE_ATTRIBUTE, 1197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar, 1198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver actionToken, 1199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver x); 1200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // M I S C 1204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public STGroup getTemplates() { 1206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return templates; 1207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public STGroup getBaseTemplates() { 1210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return baseTemplates; 1211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void setDebug(boolean debug) { 1214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver this.debug = debug; 1215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void setTrace(boolean trace) { 1218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver this.trace = trace; 1219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void setProfile(boolean profile) { 1222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver this.profile = profile; 1223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( profile ) { 1224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver setDebug(true); // requires debug events 1225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public ST getRecognizerST() { 1229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return outputFileST; 1230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1232324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Generate TParser.java and TLexer.java from T.g if combined, else 1233324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * just use T.java as output regardless of type. 1234324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 1235324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public String getRecognizerFileName(String name, int type) { 1236324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ST extST = templates.getInstanceOf("codeFileExtension"); 1237324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String recognizerName = grammar.getRecognizerName(); 1238324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return recognizerName+extST.render(); 1239324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /* 1240324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver String suffix = ""; 1241324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( type==Grammar.COMBINED || 1242324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver (type==Grammar.LEXER && !grammar.implicitLexer) ) 1243324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver { 1244324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver suffix = Grammar.grammarTypeToFileNameSuffix[type]; 1245324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1246324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return name+suffix+extST.toString(); 1247324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 1248324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1249324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1250324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** What is the name of the vocab file generated for this grammar? 1251324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Returns null if no .tokens file should be generated. 1252324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 1253324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public String getVocabFileName() { 1254324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( grammar.isBuiltFromString() ) { 1255324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return null; 1256324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1257324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return grammar.name+VOCAB_FILE_EXTENSION; 1258324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1259324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1260324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public void write(ST code, String fileName) throws IOException { 1261324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //long start = System.currentTimeMillis(); 1262324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Writer w = tool.getOutputFile(grammar, fileName); 1263324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // Write the output to a StringWriter 1264324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver STWriter wr = new AutoIndentWriter(w); 1265324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver wr.setLineWidth(lineWidth); 1266324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver code.write(wr); 1267324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver w.close(); 1268324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //long stop = System.currentTimeMillis(); 1269324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver //System.out.println("render time for "+fileName+": "+(int)(stop-start)+"ms"); 1270324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1271324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1272324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** You can generate a switch rather than if-then-else for a DFA state 1273324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * if there are no semantic predicates and the number of edge label 1274324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * values is small enough; e.g., don't generate a switch for a state 1275324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * containing an edge label such as 20..52330 (the resulting byte codes 1276324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * would overflow the method 65k limit probably). 1277324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 1278324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver protected boolean canGenerateSwitch(DFAState s) { 1279324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( !GENERATE_SWITCHES_WHEN_POSSIBLE ) { 1280324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return false; 1281324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1282324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int size = 0; 1283324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for (int i = 0; i < s.getNumberOfTransitions(); i++) { 1284324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Transition edge = (Transition) s.transition(i); 1285324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( edge.label.isSemanticPredicate() ) { 1286324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return false; 1287324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1288324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // can't do a switch if the edges are going to require predicates 1289324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( edge.label.getAtom()==Label.EOT ) { 1290324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver int EOTPredicts = ((DFAState)edge.target).getUniquelyPredictedAlt(); 1291324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( EOTPredicts==NFA.INVALID_ALT_NUMBER ) { 1292324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // EOT target has to be a predicate then; no unique alt 1293324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return false; 1294324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1295324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1296324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // if target is a state with gated preds, we need to use preds on 1297324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver // this edge then to reach it. 1298324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( ((DFAState)edge.target).getGatedPredicatesInNFAConfigurations()!=null ) { 1299324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return false; 1300324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1301324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver size += edge.label.getSet().size(); 1302324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1303324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if ( s.getNumberOfTransitions()<MIN_SWITCH_ALTS || 1304324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver size>MAX_SWITCH_CASE_LABELS ) { 1305324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return false; 1306324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1307324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return true; 1308324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1309324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1310324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver /** Create a label to track a token / rule reference's result. 1311324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Technically, this is a place where I break model-view separation 1312324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * as I am creating a variable name that could be invalid in a 1313324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * target language, however, label ::= <ID><INT> is probably ok in 1314324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * all languages we care about. 1315324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */ 1316324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver public String createUniqueLabel(String name) { 1317324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return new StringBuffer() 1318324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver .append(name).append(uniqueLabelNumber++).toString(); 1319324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 1320324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver} 1321