1225 lines
48 KiB
Java
1225 lines
48 KiB
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 csjavacc.parser;
|
|
|
|
import java.util.Hashtable;
|
|
|
|
import csjavacc.struct.Action;
|
|
import csjavacc.struct.BNFProduction;
|
|
import csjavacc.struct.Choice;
|
|
import csjavacc.struct.Expansion;
|
|
import csjavacc.struct.CSCodeProduction;
|
|
import csjavacc.struct.Lookahead;
|
|
import csjavacc.struct.NonTerminal;
|
|
import csjavacc.struct.RegularExpression;
|
|
import csjavacc.struct.TryBlock;
|
|
import csjavacc.struct.ZeroOrMore;
|
|
import csjavacc.struct.ZeroOrOne;
|
|
|
|
|
|
public class ParseEngine extends CSJavaCCGlobals {
|
|
|
|
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 CSCODE production that the argument expansion
|
|
* may directly expand to (without consuming tokens).
|
|
*/
|
|
static private boolean csCodeCheck(Expansion exp) {
|
|
if (exp instanceof RegularExpression) {
|
|
return false;
|
|
} else if (exp instanceof NonTerminal) {
|
|
NormalProduction prod = ((NonTerminal)exp).prod;
|
|
if (prod instanceof CSCodeProduction) {
|
|
return true;
|
|
} else {
|
|
return csCodeCheck(prod.expansion);
|
|
}
|
|
} else if (exp instanceof Choice) {
|
|
Choice ch = (Choice)exp;
|
|
for (int i = 0; i < ch.choices.size(); i++) {
|
|
if (csCodeCheck((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 (csCodeCheck((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 csCodeCheck(om.expansion);
|
|
} else if (exp instanceof ZeroOrMore) {
|
|
ZeroOrMore zm = (ZeroOrMore)exp;
|
|
return csCodeCheck(zm.expansion);
|
|
} else if (exp instanceof ZeroOrOne) {
|
|
ZeroOrOne zo = (ZeroOrOne)exp;
|
|
return csCodeCheck(zo.expansion);
|
|
} else if (exp instanceof TryBlock) {
|
|
TryBlock tb = (TryBlock)exp;
|
|
return csCodeCheck(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;
|
|
java.util.List<Integer> needsBreak = new java.util.ArrayList<Integer>();
|
|
while (index < conds.length) {
|
|
|
|
la = conds[index];
|
|
jj2LA = false;
|
|
|
|
if ((la.amount == 0) ||
|
|
Semanticize.emptyExpansionExists(la.la_expansion) ||
|
|
csCodeCheck(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.getErrorReporting()) {
|
|
retval += "\njj_la1[" + maskindex + "] = jj_gen;";
|
|
maskindex++;
|
|
}
|
|
needsBreak.add(indentAmt);
|
|
maskVals.addElement(tokenMask);
|
|
|
|
retval += "\n" + "if (";
|
|
indentAmt++;
|
|
}
|
|
printTokenSetup((Token)(la.action_tokens.elementAt(0)));
|
|
for (java.util.Enumeration anEnum = la.action_tokens.elements(); anEnum.hasMoreElements();) {
|
|
t = (Token)anEnum.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.getCacheTokens()) {
|
|
retval += "jj_nt.kind) {\u0001";
|
|
} else {
|
|
retval += "(jj_ntk==-1)?jj_init_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.getErrorReporting()) {
|
|
retval += "\njj_la1[" + maskindex + "] = jj_gen;";
|
|
maskindex++;
|
|
}
|
|
needsBreak.add(indentAmt);
|
|
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 anEnum = la.action_tokens.elements(); anEnum.hasMoreElements();) {
|
|
t = (Token)anEnum.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.getErrorReporting()) {
|
|
retval += "\njj_la1[" + maskindex + "] = jj_gen;";
|
|
maskVals.addElement(tokenMask);
|
|
maskindex++;
|
|
}
|
|
retval += actions[index];
|
|
// New for CS... need to break empty default cases
|
|
retval += "break;\n";
|
|
}
|
|
for (int i = 0; i < indentAmt; i++){
|
|
retval += "\u0002\n}";
|
|
if(needsBreak.contains(indentAmt-i-1)){
|
|
needsBreak.remove((Object)(indentAmt-i-1));
|
|
retval += "break;";
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static void dumpFormattedString(String str) {
|
|
char ch = ' ';
|
|
char prevChar;
|
|
boolean indentOn = true;
|
|
for (int i = 0; i < str.length(); i++) {
|
|
prevChar = ch;
|
|
ch = str.charAt(i);
|
|
if (ch == '\n' && prevChar == '\r') {
|
|
// do nothing - we've already printed a new line for the '\r'
|
|
// during the previous iteration.
|
|
} else if (ch == '\n' || ch == '\r') {
|
|
if (indentOn) {
|
|
phase1NewLine();
|
|
} else {
|
|
ostr.println("");
|
|
}
|
|
} else if (ch == '\u0001') {
|
|
indentamt += 2;
|
|
} else if (ch == '\u0002') {
|
|
indentamt -= 2;
|
|
} else if (ch == '\u0003') {
|
|
indentOn = false;
|
|
} else if (ch == '\u0004') {
|
|
indentOn = true;
|
|
} else {
|
|
ostr.print(ch);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void buildPhase1Routine(BNFProduction p) {
|
|
Token t;
|
|
t = (Token)(p.return_type_tokens.elementAt(0));
|
|
boolean voidReturn = false;
|
|
if (t.kind == CSJavaCCParserConstants.VOID) {
|
|
voidReturn = true;
|
|
}
|
|
printTokenSetup(t); ccol = 1;
|
|
printLeadingComments(t, ostr);
|
|
ostr.print(" " + staticOpt() +(p.accessMod != null ? p.accessMod : "public")+ " ");
|
|
cline = t.beginLine; ccol = t.beginColumn;
|
|
printTokenOnly(t, ostr);
|
|
for (int i = 1; i < p.return_type_tokens.size(); i++) {
|
|
t = (Token)(p.return_type_tokens.elementAt(i));
|
|
printToken(t, ostr);
|
|
}
|
|
printTrailingComments(t, ostr);
|
|
ostr.print(" " + p.lhs + "(");
|
|
if (p.parameter_list_tokens.size() != 0) {
|
|
printTokenSetup((Token)(p.parameter_list_tokens.elementAt(0)));
|
|
for (java.util.Enumeration anEnum = p.parameter_list_tokens.elements(); anEnum.hasMoreElements();) {
|
|
t = (Token)anEnum.nextElement();
|
|
printToken(t, ostr);
|
|
}
|
|
printTrailingComments(t, ostr);
|
|
}
|
|
ostr.print(")");
|
|
for (java.util.Enumeration anEnum = p.throws_list.elements(); anEnum.hasMoreElements();) {
|
|
ostr.print(", ");
|
|
java.util.Vector name = (java.util.Vector)anEnum.nextElement();
|
|
for (java.util.Enumeration enum1 = name.elements(); enum1.hasMoreElements();) {
|
|
t = (Token)enum1.nextElement();
|
|
ostr.print(t.image);
|
|
}
|
|
}
|
|
ostr.print(" {");
|
|
indentamt = 4;
|
|
if (Options.getDebugParser()) {
|
|
ostr.println("");
|
|
ostr.println(" trace_call(\"" + p.lhs + "\");");
|
|
ostr.print(" try {");
|
|
indentamt = 6;
|
|
}
|
|
if (p.declaration_tokens.size() != 0) {
|
|
printTokenSetup((Token)(p.declaration_tokens.elementAt(0))); cline--;
|
|
for (java.util.Enumeration anEnum = p.declaration_tokens.elements(); anEnum.hasMoreElements();) {
|
|
t = (Token)anEnum.nextElement();
|
|
printToken(t, ostr);
|
|
}
|
|
printTrailingComments(t, ostr);
|
|
}
|
|
String code = phase1ExpansionGen(p.expansion);
|
|
dumpFormattedString(code);
|
|
ostr.println("");
|
|
if (p.jumpPatched && !voidReturn) {
|
|
ostr.println(" throw new System.Exception(\"Missing return statement in function\");");
|
|
}
|
|
if (Options.getDebugParser()) {
|
|
ostr.println(" } finally {");
|
|
ostr.println(" trace_return(\"" + p.lhs + "\");");
|
|
ostr.println(" }");
|
|
}
|
|
ostr.println(" }");
|
|
ostr.println("");
|
|
}
|
|
|
|
static void phase1NewLine() {
|
|
ostr.println("");
|
|
for (int i = 0; i < indentamt; i++) {
|
|
ostr.print(" ");
|
|
}
|
|
}
|
|
|
|
static String phase1ExpansionGen(Expansion e) {
|
|
String retval = "";
|
|
Token t = null;
|
|
Lookahead[] conds;
|
|
String[] actions;
|
|
if (e instanceof RegularExpression) {
|
|
RegularExpression e_nrw = (RegularExpression)e;
|
|
retval += "\n";
|
|
if (e_nrw.lhsTokens.size() != 0) {
|
|
printTokenSetup((Token)(e_nrw.lhsTokens.elementAt(0)));
|
|
for (java.util.Enumeration anEnum = e_nrw.lhsTokens.elements(); anEnum.hasMoreElements();) {
|
|
t = (Token)anEnum.nextElement();
|
|
retval += printToken(t);
|
|
}
|
|
retval += printTrailingComments(t);
|
|
retval += " = ";
|
|
}
|
|
String tail = e_nrw.rhsToken == null ? ");" : ")." + e_nrw.rhsToken.image + ";";
|
|
if (e_nrw.label.equals("")) {
|
|
Object label = names_of_tokens.get(new Integer(e_nrw.ordinal));
|
|
if (label != null) {
|
|
retval += "jj_consume_token(" + (String)label + tail;
|
|
} else {
|
|
retval += "jj_consume_token(" + e_nrw.ordinal + tail;
|
|
}
|
|
} else {
|
|
retval += "jj_consume_token(" + e_nrw.label + tail;
|
|
}
|
|
} else if (e instanceof NonTerminal) {
|
|
NonTerminal e_nrw = (NonTerminal)e;
|
|
retval += "\n";
|
|
if (e_nrw.lhsTokens.size() != 0) {
|
|
printTokenSetup((Token)(e_nrw.lhsTokens.elementAt(0)));
|
|
for (java.util.Enumeration anEnum = e_nrw.lhsTokens.elements(); anEnum.hasMoreElements();) {
|
|
t = (Token)anEnum.nextElement();
|
|
retval += printToken(t);
|
|
}
|
|
retval += printTrailingComments(t);
|
|
retval += " = ";
|
|
}
|
|
retval += e_nrw.name + "(";
|
|
if (e_nrw.argument_tokens.size() != 0) {
|
|
printTokenSetup((Token)(e_nrw.argument_tokens.elementAt(0)));
|
|
for (java.util.Enumeration anEnum = e_nrw.argument_tokens.elements(); anEnum.hasMoreElements();) {
|
|
t = (Token)anEnum.nextElement();
|
|
retval += printToken(t);
|
|
}
|
|
retval += printTrailingComments(t);
|
|
}
|
|
retval += ");";
|
|
} else if (e instanceof Action) {
|
|
Action e_nrw = (Action)e;
|
|
retval += "\u0003\n";
|
|
if (e_nrw.action_tokens.size() != 0) {
|
|
printTokenSetup((Token)(e_nrw.action_tokens.elementAt(0))); ccol = 1;
|
|
for (java.util.Enumeration anEnum = e_nrw.action_tokens.elements(); anEnum.hasMoreElements();) {
|
|
t = (Token)anEnum.nextElement();
|
|
retval += printToken(t);
|
|
}
|
|
retval += printTrailingComments(t);
|
|
}
|
|
retval += "\u0004";
|
|
} else if (e instanceof Choice) {
|
|
Choice e_nrw = (Choice)e;
|
|
conds = new Lookahead[e_nrw.choices.size()];
|
|
actions = new String[e_nrw.choices.size() + 1];
|
|
actions[e_nrw.choices.size()] = "\n" + "jj_consume_token(-1);\n" + "throw new ParseException();";
|
|
// In previous line, the "throw" never throws an exception since the
|
|
// evaluation of jj_consume_token(-1) causes ParseException to be
|
|
// thrown first.
|
|
Sequence nestedSeq;
|
|
for (int i = 0; i < e_nrw.choices.size(); i++) {
|
|
nestedSeq = (Sequence)(e_nrw.choices.elementAt(i));
|
|
actions[i] = phase1ExpansionGen(nestedSeq);
|
|
conds[i] = (Lookahead)(nestedSeq.units.elementAt(0));
|
|
}
|
|
retval = buildLookaheadChecker(conds, actions);
|
|
} else if (e instanceof Sequence) {
|
|
Sequence e_nrw = (Sequence)e;
|
|
// We skip the first element in the following iteration since it is the
|
|
// Lookahead object.
|
|
for (int i = 1; i < e_nrw.units.size(); i++) {
|
|
retval += phase1ExpansionGen((Expansion)(e_nrw.units.elementAt(i)));
|
|
}
|
|
} else if (e instanceof OneOrMore) {
|
|
OneOrMore e_nrw = (OneOrMore)e;
|
|
Expansion nested_e = e_nrw.expansion;
|
|
Lookahead la;
|
|
if (nested_e instanceof Sequence) {
|
|
la = (Lookahead)(((Sequence)nested_e).units.elementAt(0));
|
|
} else {
|
|
la = new Lookahead();
|
|
la.amount = Options.getLookahead();
|
|
la.la_expansion = nested_e;
|
|
}
|
|
retval += "\n";
|
|
int labelIndex = ++gensymindex;
|
|
// Removed for CS fix...
|
|
//retval += "label_" + labelIndex + ":\n";
|
|
retval += "while (true) {\u0001";
|
|
retval += phase1ExpansionGen(nested_e);
|
|
conds = new Lookahead[1];
|
|
conds[0] = la;
|
|
actions = new String[2];
|
|
actions[0] = "\n;";
|
|
//actions[1] = "\nbreak label_" + labelIndex + ";";
|
|
// New for CS fix...
|
|
actions[1] = "\ngoto label_" + labelIndex + ";";
|
|
retval += buildLookaheadChecker(conds, actions);
|
|
retval += "\u0002\n" + "}\n";
|
|
// New for CS fix... also needs an empty statement, in case it comes
|
|
// at the end of a block/method
|
|
retval += "label_" + labelIndex + ": ;\n";
|
|
} else if (e instanceof ZeroOrMore) {
|
|
ZeroOrMore e_nrw = (ZeroOrMore)e;
|
|
Expansion nested_e = e_nrw.expansion;
|
|
Lookahead la;
|
|
if (nested_e instanceof Sequence) {
|
|
la = (Lookahead)(((Sequence)nested_e).units.elementAt(0));
|
|
} else {
|
|
la = new Lookahead();
|
|
la.amount = Options.getLookahead();
|
|
la.la_expansion = nested_e;
|
|
}
|
|
retval += "\n";
|
|
int labelIndex = ++gensymindex;
|
|
// Removed for CS fix...
|
|
//retval += "label_" + labelIndex + ":\n";
|
|
retval += "while (true) {\u0001";
|
|
conds = new Lookahead[1];
|
|
conds[0] = la;
|
|
actions = new String[2];
|
|
actions[0] = "\n;";
|
|
//actions[1] = "\nbreak label_" + labelIndex + ";";
|
|
// New for CS fix...
|
|
actions[1] = "\ngoto label_" + labelIndex + ";";
|
|
retval += buildLookaheadChecker(conds, actions);
|
|
retval += phase1ExpansionGen(nested_e);
|
|
retval += "\u0002\n" + "}\n";
|
|
// New for CS fix...
|
|
retval += "label_" + labelIndex + ": ;\n";
|
|
} else if (e instanceof ZeroOrOne) {
|
|
ZeroOrOne e_nrw = (ZeroOrOne)e;
|
|
Expansion nested_e = e_nrw.expansion;
|
|
Lookahead la;
|
|
if (nested_e instanceof Sequence) {
|
|
la = (Lookahead)(((Sequence)nested_e).units.elementAt(0));
|
|
} else {
|
|
la = new Lookahead();
|
|
la.amount = Options.getLookahead();
|
|
la.la_expansion = nested_e;
|
|
}
|
|
conds = new Lookahead[1];
|
|
conds[0] = la;
|
|
actions = new String[2];
|
|
actions[0] = phase1ExpansionGen(nested_e);
|
|
actions[1] = "\n;";
|
|
retval += buildLookaheadChecker(conds, actions);
|
|
} else if (e instanceof TryBlock) {
|
|
TryBlock e_nrw = (TryBlock)e;
|
|
Expansion nested_e = e_nrw.exp;
|
|
java.util.Vector v;
|
|
retval += "\n";
|
|
retval += "try {\u0001";
|
|
retval += phase1ExpansionGen(nested_e);
|
|
retval += "\u0002\n" + "}";
|
|
for (int i = 0; i < e_nrw.catchblks.size(); i++) {
|
|
retval += " catch (";
|
|
v = (java.util.Vector)(e_nrw.types.elementAt(i));
|
|
if (v.size() != 0) {
|
|
printTokenSetup((Token)(v.elementAt(0)));
|
|
for (java.util.Enumeration anEnum = v.elements(); anEnum.hasMoreElements();) {
|
|
t = (Token)anEnum.nextElement();
|
|
retval += printToken(t);
|
|
}
|
|
retval += printTrailingComments(t);
|
|
}
|
|
retval += " ";
|
|
t = (Token)(e_nrw.ids.elementAt(i));
|
|
printTokenSetup(t);
|
|
retval += printToken(t);
|
|
retval += printTrailingComments(t);
|
|
retval += ") {\u0003\n";
|
|
v = (java.util.Vector)(e_nrw.catchblks.elementAt(i));
|
|
if (v.size() != 0) {
|
|
printTokenSetup((Token)(v.elementAt(0))); ccol = 1;
|
|
for (java.util.Enumeration anEnum = v.elements(); anEnum.hasMoreElements();) {
|
|
t = (Token)anEnum.nextElement();
|
|
retval += printToken(t);
|
|
}
|
|
retval += printTrailingComments(t);
|
|
}
|
|
retval += "\u0004\n" + "}";
|
|
}
|
|
if (e_nrw.finallyblk != null) {
|
|
retval += " finally {\u0003\n";
|
|
if (e_nrw.finallyblk.size() != 0) {
|
|
printTokenSetup((Token)(e_nrw.finallyblk.elementAt(0))); ccol = 1;
|
|
for (java.util.Enumeration anEnum = e_nrw.finallyblk.elements(); anEnum.hasMoreElements();) {
|
|
t = (Token)anEnum.nextElement();
|
|
retval += printToken(t);
|
|
}
|
|
retval += printTrailingComments(t);
|
|
}
|
|
retval += "\u0004\n" + "}";
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
static void buildPhase2Routine(Lookahead la) {
|
|
Expansion e = la.la_expansion;
|
|
ostr.println(" " + staticOpt() + "private bool jj_2" + e.internal_name + "(int xla) {");
|
|
ostr.println(" jj_la = xla; jj_lastpos = jj_scanpos = token;");
|
|
ostr.println(" try { return !jj_3" + e.internal_name + "(); }");
|
|
ostr.println(" catch(LookaheadSuccess ls) { return true; }");
|
|
if (Options.getErrorReporting())
|
|
ostr.println(" finally { jj_save(" + (Integer.parseInt(e.internal_name.substring(1))-1) + ", xla); }");
|
|
ostr.println(" }");
|
|
ostr.println("");
|
|
Phase3Data p3d = new Phase3Data(e, la.amount);
|
|
phase3list.addElement(p3d);
|
|
phase3table.put(e, p3d);
|
|
}
|
|
|
|
static private boolean xsp_declared;
|
|
|
|
static Expansion jj3_expansion;
|
|
|
|
static String genReturn(boolean value) {
|
|
String retval = (value ? "true" : "false");
|
|
if (Options.getDebugLookahead() && jj3_expansion != null) {
|
|
String tracecode = "trace_return(\"" + ((NormalProduction)jj3_expansion.parent).lhs +
|
|
"(LOOKAHEAD " + (value ? "FAILED" : "SUCCEEDED") + ")\");";
|
|
if (Options.getErrorReporting()) {
|
|
tracecode = "if (!jj_rescan) " + tracecode;
|
|
}
|
|
return "{ " + tracecode + " return " + retval + "; }";
|
|
} else {
|
|
return "return " + retval + ";";
|
|
}
|
|
}
|
|
|
|
private static void generate3R(Expansion e, Phase3Data inf)
|
|
{
|
|
Expansion seq = e;
|
|
if (e.internal_name.equals(""))
|
|
{
|
|
while (true)
|
|
{
|
|
if (seq instanceof Sequence && ((Sequence)seq).units.size() == 2)
|
|
{
|
|
seq = (Expansion)((Sequence)seq).units.elementAt(1);
|
|
}
|
|
else if (seq instanceof NonTerminal)
|
|
{
|
|
NonTerminal e_nrw = (NonTerminal)seq;
|
|
NormalProduction ntprod = (NormalProduction)(production_table.get(e_nrw.name));
|
|
if (ntprod instanceof CSCodeProduction)
|
|
{
|
|
break; // nothing to do here
|
|
}
|
|
else
|
|
{
|
|
seq = ntprod.expansion;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (seq instanceof RegularExpression)
|
|
{
|
|
e.internal_name = "jj_scan_token(" + ((RegularExpression)seq).ordinal + ")";
|
|
return;
|
|
}
|
|
|
|
gensymindex++;
|
|
//if (gensymindex == 100)
|
|
//{
|
|
//new Error().printStackTrace();
|
|
//System.err.println(" ***** seq: " + seq.internal_name + "; size: " + ((Sequence)seq).units.size());
|
|
//}
|
|
e.internal_name = "R_" + gensymindex;
|
|
}
|
|
Phase3Data p3d = (Phase3Data)(phase3table.get(e));
|
|
if (p3d == null || p3d.count < inf.count) {
|
|
p3d = new Phase3Data(e, inf.count);
|
|
phase3list.addElement(p3d);
|
|
phase3table.put(e, p3d);
|
|
}
|
|
}
|
|
|
|
static void setupPhase3Builds(Phase3Data inf) {
|
|
Expansion e = inf.exp;
|
|
if (e instanceof RegularExpression) {
|
|
; // nothing to here
|
|
} else if (e instanceof NonTerminal) {
|
|
// All expansions of non-terminals have the "name" fields set. So
|
|
// there's no need to check it below for "e_nrw" and "ntexp". In
|
|
// fact, we rely here on the fact that the "name" fields of both these
|
|
// variables are the same.
|
|
NonTerminal e_nrw = (NonTerminal)e;
|
|
NormalProduction ntprod = (NormalProduction)(production_table.get(e_nrw.name));
|
|
if (ntprod instanceof CSCodeProduction) {
|
|
; // nothing to do here
|
|
} else {
|
|
generate3R(ntprod.expansion, inf);
|
|
}
|
|
} else if (e instanceof Choice) {
|
|
Choice e_nrw = (Choice)e;
|
|
for (int i = 0; i < e_nrw.choices.size(); i++) {
|
|
generate3R((Expansion)(e_nrw.choices.elementAt(i)), inf);
|
|
}
|
|
} else if (e instanceof Sequence) {
|
|
Sequence e_nrw = (Sequence)e;
|
|
// We skip the first element in the following iteration since it is the
|
|
// Lookahead object.
|
|
int cnt = inf.count;
|
|
for (int i = 1; i < e_nrw.units.size(); i++) {
|
|
Expansion eseq = (Expansion)(e_nrw.units.elementAt(i));
|
|
setupPhase3Builds(new Phase3Data(eseq, cnt));
|
|
cnt -= minimumSize(eseq);
|
|
if (cnt <= 0) break;
|
|
}
|
|
} else if (e instanceof TryBlock) {
|
|
TryBlock e_nrw = (TryBlock)e;
|
|
setupPhase3Builds(new Phase3Data(e_nrw.exp, inf.count));
|
|
} else if (e instanceof OneOrMore) {
|
|
OneOrMore e_nrw = (OneOrMore)e;
|
|
generate3R(e_nrw.expansion, inf);
|
|
} else if (e instanceof ZeroOrMore) {
|
|
ZeroOrMore e_nrw = (ZeroOrMore)e;
|
|
generate3R(e_nrw.expansion, inf);
|
|
} else if (e instanceof ZeroOrOne) {
|
|
ZeroOrOne e_nrw = (ZeroOrOne)e;
|
|
generate3R(e_nrw.expansion, inf);
|
|
}
|
|
}
|
|
|
|
private static String genjj_3Call(Expansion e)
|
|
{
|
|
if (e.internal_name.startsWith("jj_scan_token"))
|
|
return e.internal_name;
|
|
else
|
|
return "jj_3" + e.internal_name + "()";
|
|
}
|
|
|
|
static Hashtable generated = new Hashtable();
|
|
static void buildPhase3Routine(Phase3Data inf, boolean recursive_call) {
|
|
Expansion e = inf.exp;
|
|
Token t = null;
|
|
if (e.internal_name.startsWith("jj_scan_token"))
|
|
return;
|
|
|
|
if (!recursive_call) {
|
|
ostr.println(" " + staticOpt() + "private bool jj_3" + e.internal_name + "() {");
|
|
xsp_declared = false;
|
|
if (Options.getDebugLookahead() && e.parent instanceof NormalProduction) {
|
|
ostr.print(" ");
|
|
if (Options.getErrorReporting()) {
|
|
ostr.print("if (!jj_rescan) ");
|
|
}
|
|
ostr.println("trace_call(\"" + ((NormalProduction)e.parent).lhs + "(LOOKING AHEAD...)\");");
|
|
jj3_expansion = e;
|
|
} else {
|
|
jj3_expansion = null;
|
|
}
|
|
}
|
|
if (e instanceof RegularExpression) {
|
|
RegularExpression e_nrw = (RegularExpression)e;
|
|
if (e_nrw.label.equals("")) {
|
|
Object label = names_of_tokens.get(new Integer(e_nrw.ordinal));
|
|
if (label != null) {
|
|
ostr.println(" if (jj_scan_token(" + (String)label + ")) " + genReturn(true));
|
|
} else {
|
|
ostr.println(" if (jj_scan_token(" + e_nrw.ordinal + ")) " + genReturn(true));
|
|
}
|
|
} else {
|
|
ostr.println(" if (jj_scan_token(" + e_nrw.label + ")) " + genReturn(true));
|
|
}
|
|
//ostr.println(" if (jj_la == 0 && jj_scanpos == jj_lastpos) " + genReturn(false));
|
|
} else if (e instanceof NonTerminal) {
|
|
// All expansions of non-terminals have the "name" fields set. So
|
|
// there's no need to check it below for "e_nrw" and "ntexp". In
|
|
// fact, we rely here on the fact that the "name" fields of both these
|
|
// variables are the same.
|
|
NonTerminal e_nrw = (NonTerminal)e;
|
|
NormalProduction ntprod = (NormalProduction)(production_table.get(e_nrw.name));
|
|
if (ntprod instanceof CSCodeProduction) {
|
|
ostr.println(" if (true) { jj_la = 0; jj_scanpos = jj_lastpos; " + genReturn(false) + "}");
|
|
} else {
|
|
Expansion ntexp = ntprod.expansion;
|
|
//ostr.println(" if (jj_3" + ntexp.internal_name + "()) " + genReturn(true));
|
|
ostr.println(" if (" + genjj_3Call(ntexp)+ ") " + genReturn(true));
|
|
//ostr.println(" if (jj_la == 0 && jj_scanpos == jj_lastpos) " + genReturn(false));
|
|
}
|
|
} else if (e instanceof Choice) {
|
|
if (!xsp_declared) {
|
|
xsp_declared = true;
|
|
ostr.println(" Token xsp;");
|
|
}
|
|
ostr.println(" xsp = jj_scanpos;");
|
|
Sequence nested_seq;
|
|
Choice e_nrw = (Choice)e;
|
|
for (int i = 0; i < e_nrw.choices.size(); i++) {
|
|
nested_seq = (Sequence)(e_nrw.choices.elementAt(i));
|
|
Lookahead la = (Lookahead)(nested_seq.units.elementAt(0));
|
|
if (la.action_tokens.size() != 0) {
|
|
// We have semantic lookahead that must be evaluated.
|
|
ostr.println(" lookingAhead = true;");
|
|
ostr.print(" jj_semLA = ");
|
|
printTokenSetup((Token)(la.action_tokens.elementAt(0)));
|
|
for (java.util.Enumeration anEnum = la.action_tokens.elements(); anEnum.hasMoreElements();) {
|
|
t = (Token)anEnum.nextElement();
|
|
printToken(t, ostr);
|
|
}
|
|
printTrailingComments(t, ostr);
|
|
ostr.println(";");
|
|
ostr.println(" lookingAhead = false;");
|
|
}
|
|
ostr.print(" if (");
|
|
if (la.action_tokens.size() != 0) {
|
|
ostr.print("!jj_semLA || ");
|
|
}
|
|
if (i != e_nrw.choices.size() - 1) {
|
|
//ostr.println("jj_3" + nested_seq.internal_name + "()) {");
|
|
ostr.println(genjj_3Call(nested_seq) + ") {");
|
|
ostr.println(" jj_scanpos = xsp;");
|
|
} else {
|
|
//ostr.println("jj_3" + nested_seq.internal_name + "()) " + genReturn(true));
|
|
ostr.println(genjj_3Call(nested_seq) + ") " + genReturn(true));
|
|
//ostr.println(" if (jj_la == 0 && jj_scanpos == jj_lastpos) " + genReturn(false));
|
|
}
|
|
}
|
|
for (int i = 1; i < e_nrw.choices.size(); i++) {
|
|
//ostr.println(" } else if (jj_la == 0 && jj_scanpos == jj_lastpos) " + genReturn(false));
|
|
ostr.println(" }");
|
|
}
|
|
} else if (e instanceof Sequence) {
|
|
Sequence e_nrw = (Sequence)e;
|
|
// We skip the first element in the following iteration since it is the
|
|
// Lookahead object.
|
|
int cnt = inf.count;
|
|
for (int i = 1; i < e_nrw.units.size(); i++) {
|
|
Expansion eseq = (Expansion)(e_nrw.units.elementAt(i));
|
|
buildPhase3Routine(new Phase3Data(eseq, cnt), true);
|
|
|
|
//System.err.println("minimumSize: line: " + eseq.line + ", column: " + eseq.column + ": " + minimumSize(eseq));//Test Code
|
|
|
|
cnt -= minimumSize(eseq);
|
|
if (cnt <= 0) break;
|
|
}
|
|
} else if (e instanceof TryBlock) {
|
|
TryBlock e_nrw = (TryBlock)e;
|
|
buildPhase3Routine(new Phase3Data(e_nrw.exp, inf.count), true);
|
|
} else if (e instanceof OneOrMore) {
|
|
if (!xsp_declared) {
|
|
xsp_declared = true;
|
|
ostr.println(" Token xsp;");
|
|
}
|
|
OneOrMore e_nrw = (OneOrMore)e;
|
|
Expansion nested_e = e_nrw.expansion;
|
|
//ostr.println(" if (jj_3" + nested_e.internal_name + "()) " + genReturn(true));
|
|
ostr.println(" if (" + genjj_3Call(nested_e) + ") " + genReturn(true));
|
|
//ostr.println(" if (jj_la == 0 && jj_scanpos == jj_lastpos) " + genReturn(false));
|
|
ostr.println(" while (true) {");
|
|
ostr.println(" xsp = jj_scanpos;");
|
|
//ostr.println(" if (jj_3" + nested_e.internal_name + "()) { jj_scanpos = xsp; break; }");
|
|
ostr.println(" if (" + genjj_3Call(nested_e) + ") { jj_scanpos = xsp; break; }");
|
|
//ostr.println(" if (jj_la == 0 && jj_scanpos == jj_lastpos) " + genReturn(false));
|
|
ostr.println(" }");
|
|
} else if (e instanceof ZeroOrMore) {
|
|
if (!xsp_declared) {
|
|
xsp_declared = true;
|
|
ostr.println(" Token xsp;");
|
|
}
|
|
ZeroOrMore e_nrw = (ZeroOrMore)e;
|
|
Expansion nested_e = e_nrw.expansion;
|
|
ostr.println(" while (true) {");
|
|
ostr.println(" xsp = jj_scanpos;");
|
|
//ostr.println(" if (jj_3" + nested_e.internal_name + "()) { jj_scanpos = xsp; break; }");
|
|
ostr.println(" if (" + genjj_3Call(nested_e) + ") { jj_scanpos = xsp; break; }");
|
|
//ostr.println(" if (jj_la == 0 && jj_scanpos == jj_lastpos) " + genReturn(false));
|
|
ostr.println(" }");
|
|
} else if (e instanceof ZeroOrOne) {
|
|
if (!xsp_declared) {
|
|
xsp_declared = true;
|
|
ostr.println(" Token xsp;");
|
|
}
|
|
ZeroOrOne e_nrw = (ZeroOrOne)e;
|
|
Expansion nested_e = e_nrw.expansion;
|
|
ostr.println(" xsp = jj_scanpos;");
|
|
//ostr.println(" if (jj_3" + nested_e.internal_name + "()) jj_scanpos = xsp;");
|
|
ostr.println(" if (" + genjj_3Call(nested_e) + ") jj_scanpos = xsp;");
|
|
//ostr.println(" else if (jj_la == 0 && jj_scanpos == jj_lastpos) " + genReturn(false));
|
|
}
|
|
if (!recursive_call) {
|
|
ostr.println(" " + genReturn(false));
|
|
ostr.println(" }");
|
|
ostr.println("");
|
|
}
|
|
}
|
|
|
|
static int minimumSize(Expansion e) {
|
|
return minimumSize(e, Integer.MAX_VALUE);
|
|
}
|
|
|
|
/*
|
|
* Returns the minimum number of tokens that can parse to this expansion.
|
|
*/
|
|
static int minimumSize(Expansion e, int oldMin) {
|
|
int retval = 0; // should never be used. Will be bad if it is.
|
|
if (e.inMinimumSize) {
|
|
// recursive search for minimum size unnecessary.
|
|
return Integer.MAX_VALUE;
|
|
}
|
|
e.inMinimumSize = true;
|
|
if (e instanceof RegularExpression) {
|
|
retval = 1;
|
|
} else if (e instanceof NonTerminal) {
|
|
NonTerminal e_nrw = (NonTerminal)e;
|
|
NormalProduction ntprod = (NormalProduction)(production_table.get(e_nrw.name));
|
|
if (ntprod instanceof CSCodeProduction) {
|
|
retval = Integer.MAX_VALUE;
|
|
// Make caller think this is unending (for we do not go beyond JAVACODE during
|
|
// phase3 execution).
|
|
} else {
|
|
Expansion ntexp = ntprod.expansion;
|
|
retval = minimumSize(ntexp);
|
|
}
|
|
} else if (e instanceof Choice) {
|
|
int min = oldMin;
|
|
Expansion nested_e;
|
|
Choice e_nrw = (Choice)e;
|
|
for (int i = 0; min > 1 && i < e_nrw.choices.size(); i++) {
|
|
nested_e = (Expansion)(e_nrw.choices.elementAt(i));
|
|
int min1 = minimumSize(nested_e, min);
|
|
if (min > min1) min = min1;
|
|
}
|
|
retval = min;
|
|
} else if (e instanceof Sequence) {
|
|
int min = 0;
|
|
Sequence e_nrw = (Sequence)e;
|
|
// We skip the first element in the following iteration since it is the
|
|
// Lookahead object.
|
|
for (int i = 1; i < e_nrw.units.size(); i++) {
|
|
Expansion eseq = (Expansion)(e_nrw.units.elementAt(i));
|
|
int mineseq = minimumSize(eseq);
|
|
if (min == Integer.MAX_VALUE || mineseq == Integer.MAX_VALUE) {
|
|
min = Integer.MAX_VALUE; // Adding infinity to something results in infinity.
|
|
} else {
|
|
min += mineseq;
|
|
if (min > oldMin)
|
|
break;
|
|
}
|
|
}
|
|
retval = min;
|
|
} else if (e instanceof TryBlock) {
|
|
TryBlock e_nrw = (TryBlock)e;
|
|
retval = minimumSize(e_nrw.exp);
|
|
} else if (e instanceof OneOrMore) {
|
|
OneOrMore e_nrw = (OneOrMore)e;
|
|
retval = minimumSize(e_nrw.expansion);
|
|
} else if (e instanceof ZeroOrMore) {
|
|
retval = 0;
|
|
} else if (e instanceof ZeroOrOne) {
|
|
retval = 0;
|
|
} else if (e instanceof Lookahead) {
|
|
retval = 0;
|
|
} else if (e instanceof Action) {
|
|
retval = 0;
|
|
}
|
|
e.inMinimumSize = false;
|
|
return retval;
|
|
}
|
|
|
|
static void build(java.io.PrintWriter ps) {
|
|
NormalProduction p;
|
|
CSCodeProduction jp;
|
|
Token t = null;
|
|
|
|
ostr = ps;
|
|
|
|
for (java.util.Enumeration anEnum = bnfproductions.elements(); anEnum.hasMoreElements();) {
|
|
p = (NormalProduction)anEnum.nextElement();
|
|
if (p instanceof CSCodeProduction) {
|
|
jp = (CSCodeProduction)p;
|
|
t = (Token)(jp.return_type_tokens.elementAt(0));
|
|
printTokenSetup(t); ccol = 1;
|
|
printLeadingComments(t, ostr);
|
|
ostr.print(" " + staticOpt() + (p.accessMod != null ? p.accessMod + " " : ""));
|
|
cline = t.beginLine; ccol = t.beginColumn;
|
|
printTokenOnly(t, ostr);
|
|
for (int i = 1; i < jp.return_type_tokens.size(); i++) {
|
|
t = (Token)(jp.return_type_tokens.elementAt(i));
|
|
printToken(t, ostr);
|
|
}
|
|
printTrailingComments(t, ostr);
|
|
ostr.print(" " + jp.lhs + "(");
|
|
if (jp.parameter_list_tokens.size() != 0) {
|
|
printTokenSetup((Token)(jp.parameter_list_tokens.elementAt(0)));
|
|
for (java.util.Enumeration enum1 = jp.parameter_list_tokens.elements(); enum1.hasMoreElements();) {
|
|
t = (Token)enum1.nextElement();
|
|
printToken(t, ostr);
|
|
}
|
|
printTrailingComments(t, ostr);
|
|
}
|
|
ostr.print(") throws ParseException");
|
|
for (java.util.Enumeration enum1 = jp.throws_list.elements(); enum1.hasMoreElements();) {
|
|
ostr.print(", ");
|
|
java.util.Vector name = (java.util.Vector)enum1.nextElement();
|
|
for (java.util.Enumeration enum2 = name.elements(); enum2.hasMoreElements();) {
|
|
t = (Token)enum2.nextElement();
|
|
ostr.print(t.image);
|
|
}
|
|
}
|
|
ostr.print(" {");
|
|
if (Options.getDebugParser()) {
|
|
ostr.println("");
|
|
ostr.println(" trace_call(\"" + jp.lhs + "\");");
|
|
ostr.print(" try {");
|
|
}
|
|
if (jp.code_tokens.size() != 0) {
|
|
printTokenSetup((Token)(jp.code_tokens.elementAt(0))); cline--;
|
|
for (java.util.Enumeration enum1 = jp.code_tokens.elements(); enum1.hasMoreElements();) {
|
|
t = (Token)enum1.nextElement();
|
|
printToken(t, ostr);
|
|
}
|
|
printTrailingComments(t, ostr);
|
|
}
|
|
ostr.println("");
|
|
if (Options.getDebugParser()) {
|
|
ostr.println(" } finally {");
|
|
ostr.println(" trace_return(\"" + jp.lhs + "\");");
|
|
ostr.println(" }");
|
|
}
|
|
ostr.println(" }");
|
|
ostr.println("");
|
|
} else {
|
|
buildPhase1Routine((BNFProduction)p);
|
|
}
|
|
}
|
|
|
|
for (int phase2index = 0; phase2index < phase2list.size(); phase2index++) {
|
|
buildPhase2Routine((Lookahead)(phase2list.elementAt(phase2index)));
|
|
}
|
|
|
|
int phase3index = 0;
|
|
|
|
while (phase3index < phase3list.size()) {
|
|
for (; phase3index < phase3list.size(); phase3index++) {
|
|
setupPhase3Builds((Phase3Data)(phase3list.elementAt(phase3index)));
|
|
}
|
|
}
|
|
|
|
for (java.util.Enumeration anEnum = phase3table.elements(); anEnum.hasMoreElements();) {
|
|
buildPhase3Routine((Phase3Data)(anEnum.nextElement()), false);
|
|
}
|
|
|
|
}
|
|
|
|
public static void reInit()
|
|
{
|
|
ostr = null;
|
|
gensymindex = 0;
|
|
indentamt = 0;
|
|
jj2LA = false;
|
|
phase2list = new java.util.Vector();
|
|
phase3list = new java.util.Vector();
|
|
phase3table = new java.util.Hashtable();
|
|
firstSet = null;
|
|
xsp_declared = false;
|
|
jj3_expansion = null;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* This class stored information to pass from phase 2 to phase 3.
|
|
*/
|
|
class Phase3Data {
|
|
|
|
/*
|
|
* This is the expansion to generate the jj3 method for.
|
|
*/
|
|
Expansion exp;
|
|
|
|
/*
|
|
* This is the number of tokens that can still be consumed. This
|
|
* number is used to limit the number of jj3 methods generated.
|
|
*/
|
|
int count;
|
|
|
|
Phase3Data(Expansion e, int c) {
|
|
exp = e;
|
|
count = c;
|
|
}
|
|
|
|
}
|