/* * 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.Vector; import csjavacc.struct.Choice; import csjavacc.struct.Expansion; import csjavacc.struct.Lookahead; import csjavacc.struct.MatchInfo; import csjavacc.struct.RegularExpression; import csjavacc.struct.ZeroOrMore; public class LookaheadCalc extends CSJavaCCGlobals { static MatchInfo overlap(Vector v1, Vector v2) { MatchInfo m1, m2, m3; int size; boolean diff; for (int i = 0; i < v1.size(); i++) { m1 = (MatchInfo)v1.elementAt(i); for (int j = 0; j < v2.size(); j++) { m2 = (MatchInfo)v2.elementAt(j); size = m1.firstFreeLoc; m3 = m1; if (size > m2.firstFreeLoc) { size = m2.firstFreeLoc; m3 = m2; } if (size == 0) return null; // we wish to ignore empty expansions and the CSCODE stuff here. diff = false; for (int k = 0; k < size; k++) { if (m1.match[k] != m2.match[k]) { diff = true; break; } } if (!diff) return m3; } } return null; } static boolean csCodeCheck(Vector v) { for (int i = 0; i < v.size(); i++) { if (((MatchInfo)v.elementAt(i)).firstFreeLoc == 0) { return true; } } return false; } static String image(MatchInfo m) { String ret = ""; for (int i = 0; i < m.firstFreeLoc; i++) { if (m.match[i] == 0) { ret += " "; } else { RegularExpression re = (RegularExpression)rexps_of_tokens.get(new Integer(m.match[i])); if (re instanceof RStringLiteral) { ret += " \"" + add_escapes(((RStringLiteral)re).image) + "\""; } else if (re.label != null && !re.label.equals("")) { ret += " <" + re.label + ">"; } else { ret += " "; } } } if (m.firstFreeLoc == 0) { return ""; } else { return ret.substring(1); } } public static void choiceCalc(Choice ch) { int first = firstChoice(ch); // dbl[i] and dbr[i] are vectors of size limited matches for choice i // of ch. dbl ignores matches with semantic lookaheads (when force_la_check // is false), while dbr ignores semantic lookahead. Vector[] dbl = new Vector[ch.choices.size()]; Vector[] dbr = new Vector[ch.choices.size()]; int[] minLA = new int[ch.choices.size()-1]; MatchInfo[] overlapInfo = new MatchInfo[ch.choices.size()-1]; int[] other = new int[ch.choices.size()-1]; MatchInfo m; Vector v; boolean overlapDetected; for (int la = 1; la <= Options.getChoiceAmbiguityCheck(); la++) { MatchInfo.laLimit = la; LookaheadWalk.considerSemanticLA = !Options.getForceLaCheck(); for (int i = first; i < ch.choices.size()-1; i++) { LookaheadWalk.sizeLimitedMatches = new java.util.Vector(); m = new MatchInfo(); m.firstFreeLoc = 0; v = new java.util.Vector(); v.addElement(m); LookaheadWalk.genFirstSet(v, (Expansion)ch.choices.elementAt(i)); dbl[i] = LookaheadWalk.sizeLimitedMatches; } LookaheadWalk.considerSemanticLA = false; for (int i = first+1; i < ch.choices.size(); i++) { LookaheadWalk.sizeLimitedMatches = new java.util.Vector(); m = new MatchInfo(); m.firstFreeLoc = 0; v = new java.util.Vector(); v.addElement(m); LookaheadWalk.genFirstSet(v, (Expansion)ch.choices.elementAt(i)); dbr[i] = LookaheadWalk.sizeLimitedMatches; } if (la == 1) { for (int i = first; i < ch.choices.size()-1; i++) { Expansion exp = (Expansion)ch.choices.elementAt(i); if (Semanticize.emptyExpansionExists(exp)) { CSJavaCCErrors.warning(exp, "This choice can expand to the empty token sequence and will therefore always be taken in favor of the choices appearing later."); break; } else if (csCodeCheck(dbl[i])) { CSJavaCCErrors.warning(exp, "CSCODE non-terminal will force this choice to be taken in favor of the choices appearing later."); break; } } } overlapDetected = false; for (int i = first; i < ch.choices.size()-1; i++) { for (int j = i+1; j < ch.choices.size(); j++) { if ((m = overlap(dbl[i], dbr[j])) != null) { minLA[i] = la+1; overlapInfo[i] = m; other[i] = j; overlapDetected = true; break; } } } if (!overlapDetected) { break; } } for (int i = first; i < ch.choices.size()-1; i++) { if (explicitLA((Expansion)ch.choices.elementAt(i)) && !Options.getForceLaCheck()) { continue; } if (minLA[i] > Options.getChoiceAmbiguityCheck()) { CSJavaCCErrors.warning("Choice conflict involving two expansions at"); System.err.print(" line " + ((Expansion)ch.choices.elementAt(i)).line); System.err.print(", column " + ((Expansion)ch.choices.elementAt(i)).column); System.err.print(" and line " + ((Expansion)ch.choices.elementAt(other[i])).line); System.err.print(", column " + ((Expansion)ch.choices.elementAt(other[i])).column); System.err.println(" respectively."); System.err.println(" A common prefix is: " + image(overlapInfo[i])); System.err.println(" Consider using a lookahead of " + minLA[i] + " or more for earlier expansion."); } else if (minLA[i] > 1) { CSJavaCCErrors.warning("Choice conflict involving two expansions at"); System.err.print(" line " + ((Expansion)ch.choices.elementAt(i)).line); System.err.print(", column " + ((Expansion)ch.choices.elementAt(i)).column); System.err.print(" and line " + ((Expansion)ch.choices.elementAt(other[i])).line); System.err.print(", column " + ((Expansion)ch.choices.elementAt(other[i])).column); System.err.println(" respectively."); System.err.println(" A common prefix is: " + image(overlapInfo[i])); System.err.println(" Consider using a lookahead of " + minLA[i] + " for earlier expansion."); } } } static boolean explicitLA(Expansion exp) { if (!(exp instanceof Sequence)) { return false; } Sequence seq = (Sequence)exp; Object obj = seq.units.elementAt(0); if (!(obj instanceof Lookahead)) { return false; } Lookahead la = (Lookahead)obj; return la.isExplicit; } static int firstChoice(Choice ch) { if (Options.getForceLaCheck()) { return 0; } for (int i = 0; i < ch.choices.size(); i++) { if (!explicitLA((Expansion)ch.choices.elementAt(i))) { return i; } } return ch.choices.size(); } private static String image(Expansion exp) { if (exp instanceof OneOrMore) { return "(...)+"; } else if (exp instanceof ZeroOrMore) { return "(...)*"; } else /* if (exp instanceof ZeroOrOne) */ { return "[...]"; } } public static void ebnfCalc(Expansion exp, Expansion nested) { // exp is one of OneOrMore, ZeroOrMore, ZeroOrOne MatchInfo m, m1 = null; Vector v, first, follow; int la; for (la = 1; la <= Options.getOtherAmbiguityCheck(); la++) { MatchInfo.laLimit = la; LookaheadWalk.sizeLimitedMatches = new java.util.Vector(); m = new MatchInfo(); m.firstFreeLoc = 0; v = new java.util.Vector(); v.addElement(m); LookaheadWalk.considerSemanticLA = !Options.getForceLaCheck(); LookaheadWalk.genFirstSet(v, nested); first = LookaheadWalk.sizeLimitedMatches; LookaheadWalk.sizeLimitedMatches = new java.util.Vector(); LookaheadWalk.considerSemanticLA = false; LookaheadWalk.genFollowSet(v, exp, Expansion.nextGenerationIndex++); follow = LookaheadWalk.sizeLimitedMatches; if (la == 1) { if (csCodeCheck(first)) { CSJavaCCErrors.warning(nested, "CSCODE non-terminal within " + image(exp) + " construct will force this construct to be entered in favor of expansions occurring after construct."); } } if ((m = overlap(first, follow)) == null) { break; } m1 = m; } if (la > Options.getOtherAmbiguityCheck()) { CSJavaCCErrors.warning("Choice conflict in " + image(exp) + " construct at line " + exp.line + ", column " + exp.column + "."); System.err.println(" Expansion nested within construct and expansion following construct"); System.err.println(" have common prefixes, one of which is: " + image(m1)); System.err.println(" Consider using a lookahead of " + la + " or more for nested expansion."); } else if (la > 1) { CSJavaCCErrors.warning("Choice conflict in " + image(exp) + " construct at line " + exp.line + ", column " + exp.column + "."); System.err.println(" Expansion nested within construct and expansion following construct"); System.err.println(" have common prefixes, one of which is: " + image(m1)); System.err.println(" Consider using a lookahead of " + la + " for nested expansion."); } } }