CodeGenerator.java
上传用户:afrynkmhm
上传日期:2007-01-06
资源大小:1262k
文件大小:21k
源码类别:

编译器/解释器

开发平台:

Others

  1. package antlr;
  2. /* ANTLR Translator Generator
  3.  * Project led by Terence Parr at http://www.jGuru.com
  4.  * Software rights: http://www.antlr.org/RIGHTS.html
  5.  *
  6.  * $Id: //depot/code/org.antlr/release/antlr-2.7.0/antlr/CodeGenerator.java#1 $
  7.  */
  8. import java.io.PrintWriter; // SAS: for proper text i/o
  9. import java.io.IOException;
  10. import java.io.FileWriter;  // SAS: for proper text i/o
  11. import antlr.collections.impl.Vector;
  12. import antlr.collections.impl.BitSet;
  13. /**A generic ANTLR code generator.  All code generators
  14.  * Derive from this class.
  15.  *
  16.  * <p>
  17.  * A CodeGenerator knows about a Grammar data structure and
  18.  * a grammar analyzer.  The Grammar is walked to generate the
  19.  * appropriate code for both a parser and lexer (if present).
  20.  * This interface may change slightly so that the lexer is
  21.  * itself living inside of a Grammar object (in which case,
  22.  * this class generates only one recognizer).  The main method
  23.  * to call is <tt>gen()</tt>, which initiates all code gen.
  24.  *
  25.  * <p>
  26.  * The interaction of the code generator with the analyzer is
  27.  * simple: each subrule block calls deterministic() before generating
  28.  * code for the block.  Method deterministic() sets lookahead caches
  29.  * in each Alternative object.  Technically, a code generator
  30.  * doesn't need the grammar analyzer if all lookahead analysis
  31.  * is done at runtime, but this would result in a slower parser.
  32.  *
  33.  * <p>
  34.  * This class provides a set of support utilities to handle argument
  35.  * list parsing and so on.
  36.  *
  37.  * @author  Terence Parr, John Lilley
  38.  * @version 2.00a
  39.  * @see     antlr.JavaCodeGenerator
  40.  * @see     antlr.DiagnosticCodeGenerator
  41.  * @see     antlr.LLkAnalyzer
  42.  * @see     antlr.Grammar
  43.  * @see     antlr.AlternativeElement
  44.  * @see     antlr.Lookahead
  45.  */
  46. public abstract class CodeGenerator {
  47.     /** Current tab indentation for code output */
  48.     protected int tabs=0;
  49.     /** Current output Stream */
  50.     transient protected PrintWriter currentOutput; // SAS: for proper text i/o
  51.     /** The grammar for which we generate code */
  52.     protected Grammar grammar = null;
  53.     /** List of all bitsets that must be dumped.  These are Vectors of BitSet. */
  54.     protected Vector bitsetsUsed;
  55.     /** The antlr Tool */
  56.     protected Tool tool;
  57.     /** The grammar behavior */
  58.     protected DefineGrammarSymbols behavior;
  59.     /** The LLk analyzer */
  60.     protected LLkGrammarAnalyzer analyzer;
  61.     /** Object used to format characters in the target language.
  62.      * subclass must initialize this to the language-specific formatter
  63.      */
  64.     protected CharFormatter charFormatter;
  65.     /** Use option "codeGenDebug" to generate debugging output */
  66.     protected boolean DEBUG_CODE_GENERATOR = false;
  67.     /** Default values for code-generation thresholds */
  68.     protected static final int DEFAULT_MAKE_SWITCH_THRESHOLD = 2;
  69.     protected static final int DEFAULT_BITSET_TEST_THRESHOLD = 4;
  70.     /** This is a hint for the language-specific code generator.
  71.      * A switch() or language-specific equivalent will be generated instead
  72.      * of a series of if/else statements for blocks with number of alternates
  73.      * greater than or equal to this number of non-predicated LL(1) alternates.
  74.      * This is modified by the grammar option "codeGenMakeSwitchThreshold"
  75.      */
  76.     protected int makeSwitchThreshold = DEFAULT_MAKE_SWITCH_THRESHOLD;
  77.     /** This is a hint for the language-specific code generator.
  78.      * A bitset membership test will be generated instead of an
  79.      * ORed series of LA(k) comparisions for lookahead sets with
  80.      * degree greater than or equal to this value.
  81.      * This is modified by the grammar option "codeGenBitsetTestThreshold"
  82.      */
  83.     protected int bitsetTestThreshold = DEFAULT_BITSET_TEST_THRESHOLD;
  84.     private static boolean OLD_ACTION_TRANSLATOR = true;
  85.     public static String TokenTypesFileSuffix = "TokenTypes";
  86.     public static String TokenTypesFileExt = ".txt";
  87.     /** Construct code generator base class */
  88.     public CodeGenerator() {}
  89.     /** Output a String to the currentOutput stream.
  90.      * Ignored if string is null.
  91.      * @param s The string to output
  92.      */
  93.     protected void _print(String s) {
  94. if (s != null) {
  95.     currentOutput.print(s);
  96. }
  97.     }
  98.     /** Print an action without leading tabs, attempting to
  99.      * preserve the current indentation level for multi-line actions
  100.      * Ignored if string is null.
  101.      * @param s The action string to output
  102.      */
  103.     protected void _printAction(String s) {
  104. if (s == null) {
  105.     return;
  106. }
  107. // Skip leading newlines, tabs and spaces
  108. int start = 0;
  109. while (start < s.length() && Character.isSpaceChar(s.charAt(start)) )
  110.     {
  111. start++;
  112.     }
  113. // Skip leading newlines, tabs and spaces
  114. int end = s.length()-1;
  115. while ( end > start && Character.isSpaceChar(s.charAt(end)) ) 
  116.     {
  117. end--;
  118.     }
  119. char c=0;
  120. for (int i = start; i <= end;)
  121.     {
  122. c = s.charAt(i);
  123. i++;
  124. boolean newline = false;
  125. switch (c)
  126.     {
  127.     case 'n':
  128. newline=true;
  129. break;
  130.     case 'r':
  131. if ( i<=end && s.charAt(i)=='n' ) {
  132.     i++;
  133. }
  134. newline=true;
  135. break;
  136.     default: 
  137. currentOutput.print(c); 
  138. break;
  139.     }
  140. if ( newline ) {
  141.     currentOutput.println(); 
  142.     printTabs();
  143. // Absorb leading whitespace
  144.     while (i <= end && Character.isSpaceChar(s.charAt(i)) ) {
  145. i++;
  146.     }
  147.     newline=false;
  148. }
  149.     }
  150. currentOutput.println();
  151.     }
  152.     /** Output a String followed by newline, to the currentOutput stream.
  153.      * Ignored if string is null.
  154.      * @param s The string to output
  155.      */
  156.     protected void _println(String s) {
  157. if (s != null) {
  158.     currentOutput.println(s);
  159. }
  160.     }
  161.     /** Test if a set element array represents a contiguous range.
  162.      * @param elems The array of elements representing the set, usually from BitSet.toArray().
  163.      * @return true if the elements are a contiguous range (with two or more).
  164.      */
  165.     public static boolean elementsAreRange(int[] elems) {
  166. if (elems.length==0) {
  167.     return false;
  168. }
  169. int begin = elems[0];
  170. int end = elems[elems.length-1];
  171. if ( elems.length<=2 ) {
  172.     // Not enough elements for a range expression
  173.     return false;
  174. }
  175. if ( end-begin+1 > elems.length ) {
  176.     // The set does not represent a contiguous range
  177.     return false;
  178. }
  179. int v = begin+1;
  180. for (int i=1; i<elems.length-1; i++) {
  181.     if ( v != elems[i] ) {
  182. // The set does not represent a contiguous range
  183. return false;
  184.     }
  185.     v++;
  186. }
  187. return true;
  188.     }
  189.     /** Get the identifier portion of an argument-action token.
  190.      * The ID of an action is assumed to be a trailing identifier.
  191.      * Specific code-generators may want to override this
  192.      * if the language has unusual declaration syntax.
  193.      * @param t The action token
  194.      * @return A string containing the text of the identifier
  195.      */
  196.     protected String extractIdOfAction(Token t) {
  197. return extractIdOfAction(t.getText(), t.getLine());
  198.     }
  199.     /** Get the identifier portion of an argument-action.
  200.      * The ID of an action is assumed to be a trailing identifier.
  201.      * Specific code-generators may want to override this
  202.      * if the language has unusual declaration syntax.
  203.      * @param s The action text
  204.      * @param line Line used for error reporting.
  205.      * @return A string containing the text of the identifier
  206.      */
  207.     protected String extractIdOfAction(String s, int line) {
  208. s = removeAssignmentFromDeclaration(s);
  209. // Search back from the end for a non alphanumeric.  That marks the
  210. // beginning of the identifier
  211. for (int i = s.length()-2; i >=0; i--)
  212.     {
  213. // TODO: make this work for language-independent identifiers?
  214. if (!Character.isLetterOrDigit(s.charAt(i)) && s.charAt(i) != '_')
  215.     {
  216. // Found end of type part
  217. return s.substring(i+1);
  218.     }
  219.     }
  220. // Something is bogus, but we cannot parse the language-specific
  221. // actions any better.  The compiler will have to catch the problem.
  222. tool.warning("Ill-formed action", grammar.getFilename(), line);
  223. return "";
  224.     }
  225.     /** Get the type string out of an argument-action token.
  226.      * The type of an action is assumed to precede a trailing identifier
  227.      * Specific code-generators may want to override this
  228.      * if the language has unusual declaration syntax.
  229.      * @param t The action token
  230.      * @return A string containing the text of the type
  231.      */
  232.     protected String extractTypeOfAction(Token t) {
  233. return extractTypeOfAction(t.getText(), t.getLine());
  234.     }
  235.     /** Get the type portion of an argument-action.
  236.      * The type of an action is assumed to precede a trailing identifier
  237.      * Specific code-generators may want to override this
  238.      * if the language has unusual declaration syntax.
  239.      * @param s The action text
  240.      * @param line Line used for error reporting.
  241.      * @return A string containing the text of the type
  242.      */
  243.     protected String extractTypeOfAction(String s, int line) {
  244. s = removeAssignmentFromDeclaration(s);
  245. // Search back from the end for a non alphanumeric.  That marks the
  246. // beginning of the identifier
  247. for (int i = s.length()-2; i >=0; i--)
  248.     {
  249. // TODO: make this work for language-independent identifiers?
  250. if (!Character.isLetterOrDigit(s.charAt(i)) && s.charAt(i) != '_')
  251.     {
  252. // Found end of type part
  253. return s.substring(0,i+1);
  254.     }
  255.     }
  256. // Something is bogus, but we cannot parse the language-specific
  257. // actions any better.  The compiler will have to catch the problem.
  258. tool.warning("Ill-formed action", grammar.getFilename(), line);
  259. return "";
  260.     }
  261.     /** Generate the code for all grammars
  262.      */
  263.     public abstract void gen();
  264.     /** Generate code for the given grammar element.
  265.      * @param action The {...} action to generate
  266.      */
  267.     public abstract void gen(ActionElement action);
  268.     /** Generate code for the given grammar element.
  269.      * @param blk The "x|y|z|..." block to generate
  270.      */
  271.     public abstract void gen(AlternativeBlock blk);
  272.     /** Generate code for the given grammar element.
  273.      * @param end The block-end element to generate.  Block-end
  274.      * elements are synthesized by the grammar parser to represent
  275.      * the end of a block.
  276.      */
  277.     public abstract void gen(BlockEndElement end);
  278.     /** Generate code for the given grammar element.
  279.      * @param atom The character literal reference to generate
  280.      */
  281.     public abstract void gen(CharLiteralElement atom);
  282.     /** Generate code for the given grammar element.
  283.      * @param r The character-range reference to generate
  284.      */
  285.     public abstract void gen(CharRangeElement r);
  286.     /** Generate the code for a parser */
  287.     public abstract void gen(LexerGrammar g) throws IOException;
  288.     /** Generate code for the given grammar element.
  289.      * @param blk The (...)+ block to generate
  290.      */
  291.     public abstract void gen(OneOrMoreBlock blk);
  292.     /** Generate the code for a parser */
  293.     public abstract void gen(ParserGrammar g) throws IOException;
  294.     /** Generate code for the given grammar element.
  295.      * @param rr The rule-reference to generate
  296.      */
  297.     public abstract void gen(RuleRefElement rr);
  298.     /** Generate code for the given grammar element.
  299.      * @param atom The string-literal reference to generate
  300.      */
  301.     public abstract void gen(StringLiteralElement atom);
  302.     /** Generate code for the given grammar element.
  303.      * @param r The token-range reference to generate
  304.      */
  305.     public abstract void gen(TokenRangeElement r);
  306.     /** Generate code for the given grammar element.
  307.      * @param atom The token-reference to generate
  308.      */
  309.     public abstract void gen(TokenRefElement atom);
  310.     /** Generate code for the given grammar element.
  311.      * @param blk The tree to generate code for.
  312.      */
  313.     public abstract void gen(TreeElement t);
  314.     /** Generate the code for a parser */
  315.     public abstract void gen(TreeWalkerGrammar g) throws IOException;
  316.     /** Generate code for the given grammar element.
  317.      * @param wc The wildcard element to generate
  318.      */
  319.     public abstract void gen(WildcardElement wc);
  320.     /** Generate code for the given grammar element.
  321.      * @param blk The (...)* block to generate
  322.      */
  323.     public abstract void gen(ZeroOrMoreBlock blk);
  324.     /** Generate the token types as a text file for persistence across shared lexer/parser */
  325.     protected void genTokenInterchange(TokenManager tm) throws IOException {
  326. // Open the token output Java file and set the currentOutput stream
  327. String fName = tm.getName() + TokenTypesFileSuffix+TokenTypesFileExt;
  328. currentOutput = antlr.Tool.openOutputFile(fName);
  329. println("// $ANTLR "+Tool.version+": "+
  330. Tool.fileMinusPath(tool.grammarFile)+
  331. " -> "+
  332. fName+
  333. "$");
  334. tabs = 0;
  335. // Header
  336. println(tm.getName() + "    // output token vocab name");
  337. // Generate a definition for each token type
  338. Vector v = tm.getVocabulary();
  339. for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) {
  340.     String s = (String)v.elementAt(i);
  341.     if ( DEBUG_CODE_GENERATOR ) {
  342. System.out.println("gen persistence file entry for: "+s);
  343.     }
  344.     if (s != null && !s.startsWith("<") ) {
  345. // if literal, find label
  346. if ( s.startsWith(""") ) {
  347.     StringLiteralSymbol sl = (StringLiteralSymbol)tm.getTokenSymbol(s);
  348.     if ( sl!=null && sl.label != null ) {
  349. print(sl.label+"=");
  350.     }
  351.     println(s + "=" + i);
  352. }
  353. else {
  354.     print(s);
  355.     // check for a paraphrase
  356.     TokenSymbol ts = (TokenSymbol)tm.getTokenSymbol(s);
  357.     if ( ts==null ) {
  358. tool.warning("undefined token symbol: "+s);
  359.     }
  360.     else {
  361. if ( ts.getParaphrase()!=null ) {
  362.     print("("+ts.getParaphrase()+")");
  363. }
  364.     }
  365.     println("=" + i);
  366. }
  367.     }
  368. }
  369. // Close the tokens output file
  370. currentOutput.close();
  371. currentOutput = null;
  372.     }
  373.     /** Get a string for an expression to generate creation of an AST subtree.
  374.      * @param v A Vector of String, where each element is an expression in the target language yielding an AST node.
  375.      */
  376.     public abstract String getASTCreateString(Vector v);
  377.     /** Get a string for an expression to generate creating of an AST node
  378.      * @param str The text of the arguments to the AST construction
  379.      */
  380.     public abstract String getASTCreateString(GrammarAtom atom, String str);
  381.     /** Given the index of a bitset in the bitset list, generate a unique name.
  382.      * Specific code-generators may want to override this
  383.      * if the language does not allow '_' or numerals in identifiers.
  384.      * @param index  The index of the bitset in the bitset list.
  385.      */
  386.     protected String getBitsetName(int index)
  387.     {
  388. return "_tokenSet_" + index;
  389.     }
  390.     public static String lexerRuleName(String id) {
  391. return "m"+id;
  392.     }
  393.     /** Map an identifier to it's corresponding tree-node variable.
  394.      * This is context-sensitive, depending on the rule and alternative
  395.      * being generated
  396.      * @param id The identifier name to map
  397.      * @param forInput true if the input tree node variable is to be returned, otherwise the output variable is returned.
  398.      * @return The mapped id (which may be the same as the input), or null if the mapping is invalid due to duplicates
  399.      */
  400.     public abstract String mapTreeId(String id, ActionTransInfo tInfo);
  401.     /** Add a bitset to the list of bitsets to be generated.
  402.      * if the bitset is already in the list, ignore the request.
  403.      * Always adds the bitset to the end of the list, so the
  404.      * caller can rely on the position of bitsets in the list.
  405.      * The returned position can be used to format the bitset 
  406.      * name, since it is invariant.
  407.      * @param p Bit set to mark for code generation
  408.      * @param forParser true if the bitset is used for the parser, false for the lexer
  409.      * @return The position of the bitset in the list.
  410.      */
  411.     protected int markBitsetForGen(BitSet p) {
  412. // Is the bitset (or an identical one) already marked for gen?
  413. for (int i = 0; i < bitsetsUsed.size(); i++)
  414.     {
  415. BitSet set = (BitSet)bitsetsUsed.elementAt(i);
  416. if (p.equals(set))
  417.     {
  418. // Use the identical one already stored
  419. return i;
  420.     }
  421.     }
  422. // Add the new bitset
  423. bitsetsUsed.appendElement(p.clone());
  424. return bitsetsUsed.size()-1;
  425.     }
  426.     /** Output tab indent followed by a String, to the currentOutput stream.
  427.      * Ignored if string is null.
  428.      * @param s The string to output.  
  429.      */
  430.     protected void print(String s) {
  431. if (s != null) {
  432.     printTabs();
  433.     currentOutput.print(s);
  434. }
  435.     }
  436.     /** Print an action with leading tabs, attempting to
  437.      * preserve the current indentation level for multi-line actions
  438.      * Ignored if string is null.
  439.      * @param s The action string to output
  440.      */
  441.     protected void printAction(String s) { 
  442. if (s != null) {
  443.     printTabs();
  444.     _printAction(s);
  445. }
  446.     }
  447.     /** Output tab indent followed by a String followed by newline,
  448.      * to the currentOutput stream.  Ignored if string is null.
  449.      * @param s The string to output
  450.      */
  451.     protected void println(String s) {
  452. if (s != null) {
  453.     printTabs();
  454.     currentOutput.println(s);
  455. }
  456.     }
  457.     /** Output the current tab indentation.  This outputs the number of tabs 
  458.      * indicated by the "tabs" variable to the currentOutput stream.
  459.      */
  460.     protected void printTabs() {
  461. for (int i=1; i<=tabs; i++) {
  462.     currentOutput.print("t");
  463. }
  464.     }
  465.     /** Lexically process tree-specifiers in the action.
  466.      *  This will replace #id and #(...) with the appropriate
  467.      *  function calls and/or variables.
  468.      * 
  469.      *  This is the default Java action translator, but I have made
  470.      *  it work for C++ also.  
  471.      */
  472.     protected String processActionForTreeSpecifiers(String actionStr, int line, RuleBlock currentRule, ActionTransInfo tInfo) {
  473. if ( actionStr==null ) return null;
  474. // The action trans info tells us (at the moment) whether an
  475. // assignment was done to the rule's tree root.
  476. if (grammar==null) return actionStr;
  477. if ( (grammar.buildAST && actionStr.indexOf('#') != -1) ||
  478.      grammar instanceof TreeWalkerGrammar ||
  479.      (grammar instanceof LexerGrammar && actionStr.indexOf('$') != -1) ) {
  480.     // Create a lexer to read an action and return the translated version
  481.     antlr.actions.java.ActionLexer lexer = new antlr.actions.java.ActionLexer(actionStr, currentRule, this, tInfo);
  482.     lexer.setLineOffset(line);
  483.     lexer.setTool(tool);
  484.     try {
  485. lexer.mACTION(true);
  486. actionStr = lexer.getTokenObject().getText();
  487. // System.out.println("action translated: "+actionStr);
  488. // System.out.println("trans info is "+tInfo);
  489.     }
  490.     catch (RecognitionException ex) {
  491. lexer.reportError(ex);
  492. return actionStr;
  493.     }
  494.     catch (TokenStreamException tex) {
  495. antlr.Tool.panic("Error reading action:"+actionStr);
  496. return actionStr;
  497.     }
  498.     catch (CharStreamException io) {
  499. antlr.Tool.panic("Error reading action:"+actionStr);
  500. return actionStr;
  501.     }
  502. }
  503. return actionStr;
  504.     }
  505.     /**
  506.      * Remove the assignment portion of a declaration, if any.
  507.      * @param d the declaration
  508.      * @return the declaration without any assignment portion
  509.      */
  510.     protected String removeAssignmentFromDeclaration(String d) {
  511. // If d contains an equal sign, then it's a declaration
  512. // with an initialization.  Strip off the initialization part.
  513. if (d.indexOf('=') >= 0) d = d.substring(0, d.indexOf('=')).trim();
  514. return d;
  515.     } 
  516.     /** Set all fields back like one just created */
  517.     private void reset() {
  518. tabs = 0;
  519. // Allocate list of bitsets tagged for code generation
  520. bitsetsUsed = new Vector();
  521. currentOutput = null;
  522. grammar = null;
  523. DEBUG_CODE_GENERATOR = false;
  524. makeSwitchThreshold = DEFAULT_MAKE_SWITCH_THRESHOLD;
  525. bitsetTestThreshold = DEFAULT_BITSET_TEST_THRESHOLD;
  526.     }
  527.     public static String reverseLexerRuleName(String id) {
  528. return id.substring(1,id.length());
  529.     }
  530.     public void setAnalyzer(LLkGrammarAnalyzer analyzer_) {
  531. analyzer = analyzer_;
  532.     }
  533.     public void setBehavior(DefineGrammarSymbols behavior_) { 
  534. behavior = behavior_;
  535.     }
  536.     /** Set a grammar for the code generator to use */
  537.     protected void setGrammar(Grammar g) {
  538. reset();
  539. grammar = g;
  540. // Lookup make-switch threshold in the grammar generic options
  541. if (grammar.hasOption("codeGenMakeSwitchThreshold")) {
  542.     try {
  543. makeSwitchThreshold = grammar.getIntegerOption("codeGenMakeSwitchThreshold");
  544. //System.out.println("setting codeGenMakeSwitchThreshold to " + makeSwitchThreshold);
  545.     } catch (NumberFormatException e) {
  546. tool.error(
  547.    "option 'codeGenMakeSwitchThreshold' must be an integer",
  548.    grammar.getClassName(),
  549.    grammar.getOption("codeGenMakeSwitchThreshold").getLine()
  550.    );
  551.     }
  552. }
  553. // Lookup bitset-test threshold in the grammar generic options
  554. if (grammar.hasOption("codeGenBitsetTestThreshold")) {
  555.     try {
  556. bitsetTestThreshold = grammar.getIntegerOption("codeGenBitsetTestThreshold");
  557. //System.out.println("setting codeGenBitsetTestThreshold to " + bitsetTestThreshold);
  558.     } catch (NumberFormatException e) {
  559. tool.error(
  560.    "option 'codeGenBitsetTestThreshold' must be an integer",
  561.    grammar.getClassName(),
  562.    grammar.getOption("codeGenBitsetTestThreshold").getLine()
  563.    );
  564.     }
  565. }
  566. // Lookup debug code-gen in the grammar generic options
  567. if (grammar.hasOption("codeGenDebug")) {
  568.     Token t = grammar.getOption("codeGenDebug");
  569.     if (t.getText().equals("true")) {
  570. //System.out.println("setting code-generation debug ON");
  571. DEBUG_CODE_GENERATOR = true;
  572.     }
  573.     else if (t.getText().equals("false")) {
  574. //System.out.println("setting code-generation debug OFF");
  575. DEBUG_CODE_GENERATOR = false;
  576.     }
  577.     else {
  578. tool.error("option 'codeGenDebug' must be true or false", grammar.getClassName(), t.getLine());
  579.     }
  580. }
  581.     }
  582.     public void setTool(Tool tool_) {
  583. tool = tool_;
  584.     }
  585. }