📄 parseengine.java
字号:
/* * Copyright © 2002 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * California 95054, U.S.A. All rights reserved. Sun Microsystems, Inc. has * intellectual property rights relating to technology embodied in the product * that is described in this document. In particular, and without limitation, * these intellectual property rights may include one or more of the U.S. * patents listed at http://www.sun.com/patents and one or more additional * patents or pending patent applications in the U.S. and in other countries. * U.S. Government Rights - Commercial software. Government users are subject * to the Sun Microsystems, Inc. standard license agreement and applicable * provisions of the FAR and its supplements. Use is subject to license terms. * Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered * trademarks of Sun Microsystems, Inc. in the U.S. and other countries. This * product is covered and controlled by U.S. Export Control laws and may be * subject to the export or import laws in other countries. Nuclear, missile, * chemical biological weapons or nuclear maritime end uses or end users, * whether direct or indirect, are strictly prohibited. Export or reexport * to countries subject to U.S. embargo or to entities identified on U.S. * export exclusion lists, including, but not limited to, the denied persons * and specially designated nationals lists is strictly prohibited. */package org.javacc.parser;import java.util.Hashtable;import java.util.*;public class ParseEngine extends JavaCCGlobals { static private java.io.PrintWriter ostr; static private int gensymindex = 0; static private int indentamt; static private boolean jj2LA; /** * These lists are used to maintain expansions for which code generation * in phase 2 and phase 3 is required. Whenever a call is generated to * a phase 2 or phase 3 routine, a corresponding entry is added here if * it has not already been added. * The phase 3 routines have been optimized in version 0.7pre2. Essentially * only those methods (and only those portions of these methods) are * generated that are required. The lookahead amount is used to determine * this. This change requires the use of a hash table because it is now * possible for the same phase 3 routine to be requested multiple times * with different lookaheads. The hash table provides a easily searchable * capability to determine the previous requests. * The phase 3 routines now are performed in a two step process - the first * step gathers the requests (replacing requests with lower lookaheads with * those requiring larger lookaheads). The second step then generates these * methods. * This optimization and the hashtable makes it look like we do not need * the flag "phase3done" any more. But this has not been removed yet. */ static private java.util.Vector phase2list = new java.util.Vector(); static private java.util.Vector phase3list = new java.util.Vector(); static private java.util.Hashtable phase3table = new java.util.Hashtable(); /** * The phase 1 routines generates their output into String's and dumps * these String's once for each method. These String's contain the * special characters '\u0001' to indicate a positive indent, and '\u0002' * to indicate a negative indent. '\n' is used to indicate a line terminator. * The characters '\u0003' and '\u0004' are used to delineate portions of * text where '\n's should not be followed by an indentation. */ /** * Returns true if there is a JAVACODE production that the argument expansion * may directly expand to (without consuming tokens). */ static private boolean javaCodeCheck(Expansion exp) { if (exp instanceof RegularExpression) { return false; } else if (exp instanceof NonTerminal) { NormalProduction prod = ((NonTerminal)exp).prod; if (prod instanceof JavaCodeProduction) { return true; } else { return javaCodeCheck(prod.expansion); } } else if (exp instanceof Choice) { Choice ch = (Choice)exp; for (int i = 0; i < ch.choices.size(); i++) { if (javaCodeCheck((Expansion)(ch.choices.elementAt(i)))) { return true; } } return false; } else if (exp instanceof Sequence) { Sequence seq = (Sequence)exp; for (int i = 0; i < seq.units.size(); i++) { if (javaCodeCheck((Expansion)(seq.units.elementAt(i)))) { return true; } else if (!Semanticize.emptyExpansionExists((Expansion)(seq.units.elementAt(i)))) { return false; } } return false; } else if (exp instanceof OneOrMore) { OneOrMore om = (OneOrMore)exp; return javaCodeCheck(om.expansion); } else if (exp instanceof ZeroOrMore) { ZeroOrMore zm = (ZeroOrMore)exp; return javaCodeCheck(zm.expansion); } else if (exp instanceof ZeroOrOne) { ZeroOrOne zo = (ZeroOrOne)exp; return javaCodeCheck(zo.expansion); } else if (exp instanceof TryBlock) { TryBlock tb = (TryBlock)exp; return javaCodeCheck(tb.exp); } else { return false; } } /** * An array used to store the first sets generated by the following method. * A true entry means that the corresponding token is in the first set. */ static private boolean[] firstSet; /** * Sets up the array "firstSet" above based on the Expansion argument * passed to it. Since this is a recursive function, it assumes that * "firstSet" has been reset before the first call. */ static private void genFirstSet(Expansion exp) { if (exp instanceof RegularExpression) { firstSet[((RegularExpression)exp).ordinal] = true; } else if (exp instanceof NonTerminal) { genFirstSet(((BNFProduction)(((NonTerminal)exp).prod)).expansion); } else if (exp instanceof Choice) { Choice ch = (Choice)exp; for (int i = 0; i < ch.choices.size(); i++) { genFirstSet((Expansion)(ch.choices.elementAt(i))); } } else if (exp instanceof Sequence) { Sequence seq = (Sequence)exp; Object obj = seq.units.elementAt(0); if ((obj instanceof Lookahead) && (((Lookahead)obj).action_tokens.size() != 0)) { jj2LA = true; } for (int i = 0; i < seq.units.size(); i++) { genFirstSet((Expansion)(seq.units.elementAt(i))); if (!Semanticize.emptyExpansionExists((Expansion)(seq.units.elementAt(i)))) { break; } } } else if (exp instanceof OneOrMore) { OneOrMore om = (OneOrMore)exp; genFirstSet(om.expansion); } else if (exp instanceof ZeroOrMore) { ZeroOrMore zm = (ZeroOrMore)exp; genFirstSet(zm.expansion); } else if (exp instanceof ZeroOrOne) { ZeroOrOne zo = (ZeroOrOne)exp; genFirstSet(zo.expansion); } else if (exp instanceof TryBlock) { TryBlock tb = (TryBlock)exp; genFirstSet(tb.exp); } } /** * Constants used in the following method "buildLookaheadChecker". */ static final int NOOPENSTM = 0; static final int OPENIF = 1; static final int OPENSWITCH = 2; /** * This method takes two parameters - an array of Lookahead's * "conds", and an array of String's "actions". "actions" contains * exactly one element more than "conds". "actions" are Java source * code, and "conds" translate to conditions - so lets say * "f(conds[i])" is true if the lookahead required by "conds[i]" is * indeed the case. This method returns a string corresponding to * the Java code for: * * if (f(conds[0]) actions[0] * else if (f(conds[1]) actions[1] * . . . * else actions[action.length-1] * * A particular action entry ("actions[i]") can be null, in which * case, a noop is generated for that action. */ static String buildLookaheadChecker(Lookahead[] conds, String[] actions) { // The state variables. int state = NOOPENSTM; int indentAmt = 0; boolean[] casedValues = new boolean[tokenCount]; String retval = ""; Lookahead la; Token t = null; int tokenMaskSize = (tokenCount-1)/32 + 1; int[] tokenMask = null; // Iterate over all the conditions. int index = 0; while (index < conds.length) { la = conds[index]; jj2LA = false; if ((la.amount == 0) || Semanticize.emptyExpansionExists(la.la_expansion) || javaCodeCheck(la.la_expansion) ) { // This handles the following cases: // . If syntactic lookahead is not wanted (and hence explicitly specified // as 0). // . If it is possible for the lookahead expansion to recognize the empty // string - in which case the lookahead trivially passes. // . If the lookahead expansion has a JAVACODE production that it directly // expands to - in which case the lookahead trivially passes. if (la.action_tokens.size() == 0) { // In addition, if there is no semantic lookahead, then the // lookahead trivially succeeds. So break the main loop and // treat this case as the default last action. break; } else { // This case is when there is only semantic lookahead // (without any preceding syntactic lookahead). In this // case, an "if" statement is generated. switch (state) { case NOOPENSTM: retval += "\n" + "if ("; indentAmt++; break; case OPENIF: retval += "\u0002\n" + "} else if ("; break; case OPENSWITCH: retval += "\u0002\n" + "default:" + "\u0001"; if (Options.B("ERROR_REPORTING")) { retval += "\njj_la1[" + maskindex + "] = jj_gen;"; maskindex++; } maskVals.addElement(tokenMask); retval += "\n" + "if ("; indentAmt++; } printTokenSetup((Token)(la.action_tokens.elementAt(0))); for (java.util.Enumeration enum = la.action_tokens.elements(); enum.hasMoreElements();) { t = (Token)enum.nextElement(); retval += printToken(t); } retval += printTrailingComments(t); retval += ") {\u0001" + actions[index]; state = OPENIF; } } else if (la.amount == 1 && la.action_tokens.size() == 0) { // Special optimal processing when the lookahead is exactly 1, and there // is no semantic lookahead. if (firstSet == null) { firstSet = new boolean[tokenCount]; } for (int i = 0; i < tokenCount; i++) { firstSet[i] = false; } // jj2LA is set to false at the beginning of the containing "if" statement. // It is checked immediately after the end of the same statement to determine // if lookaheads are to be performed using calls to the jj2 methods. genFirstSet(la.la_expansion); // genFirstSet may find that semantic attributes are appropriate for the next // token. In which case, it sets jj2LA to true. if (!jj2LA) { // This case is if there is no applicable semantic lookahead and the lookahead // is one (excluding the earlier cases such as JAVACODE, etc.). switch (state) { case OPENIF: retval += "\u0002\n" + "} else {\u0001"; // Control flows through to next case. case NOOPENSTM: retval += "\n" + "switch ("; if (Options.B("CACHE_TOKENS")) { retval += "jj_nt.kind) {\u0001"; } else { retval += "(jj_ntk==-1)?jj_ntk():jj_ntk) {\u0001"; } for (int i = 0; i < tokenCount; i++) { casedValues[i] = false; } indentAmt++; tokenMask = new int[tokenMaskSize]; for (int i = 0; i < tokenMaskSize; i++) { tokenMask[i] = 0; } // Don't need to do anything if state is OPENSWITCH. } for (int i = 0; i < tokenCount; i++) { if (firstSet[i]) { if (!casedValues[i]) { casedValues[i] = true; retval += "\u0002\ncase "; int j1 = i/32; int j2 = i%32; tokenMask[j1] |= 1 << j2; String s = (String)(names_of_tokens.get(new Integer(i))); if (s == null) { retval += i; } else { retval += s; } retval += ":\u0001"; } } } retval += actions[index]; retval += "\nbreak;"; state = OPENSWITCH; } } else { // This is the case when lookahead is determined through calls to // jj2 methods. The other case is when lookahead is 1, but semantic // attributes need to be evaluated. Hence this crazy control structure. jj2LA = true; } if (jj2LA) { // In this case lookahead is determined by the jj2 methods. switch (state) { case NOOPENSTM: retval += "\n" + "if ("; indentAmt++; break; case OPENIF: retval += "\u0002\n" + "} else if ("; break; case OPENSWITCH: retval += "\u0002\n" + "default:" + "\u0001"; if (Options.B("ERROR_REPORTING")) { retval += "\njj_la1[" + maskindex + "] = jj_gen;"; maskindex++; } maskVals.addElement(tokenMask); retval += "\n" + "if ("; indentAmt++; } jj2index++; // At this point, la.la_expansion.internal_name must be "". la.la_expansion.internal_name = "_" + jj2index; phase2list.addElement(la); retval += "jj_2" + la.la_expansion.internal_name + "(" + la.amount + ")"; if (la.action_tokens.size() != 0) { // In addition, there is also a semantic lookahead. So concatenate // the semantic check with the syntactic one. retval += " && ("; printTokenSetup((Token)(la.action_tokens.elementAt(0))); for (java.util.Enumeration enum = la.action_tokens.elements(); enum.hasMoreElements();) { t = (Token)enum.nextElement(); retval += printToken(t); } retval += printTrailingComments(t); retval += ")"; } retval += ") {\u0001" + actions[index]; state = OPENIF; } index++; } // Generate code for the default case. Note this may not // be the last entry of "actions" if any condition can be // statically determined to be always "true". switch (state) { case NOOPENSTM: retval += actions[index]; break; case OPENIF: retval += "\u0002\n" + "} else {\u0001" + actions[index]; break; case OPENSWITCH: retval += "\u0002\n" + "default:" + "\u0001"; if (Options.B("ERROR_REPORTING")) { retval += "\njj_la1[" + maskindex + "] = jj_gen;"; maskVals.addElement(tokenMask); maskindex++; } retval += actions[index]; } for (int i = 0; i < indentAmt; i++) { retval += "\u0002\n}";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -