From dc445af663508e3df8ecd7e04fc2bfbd29696a87 Mon Sep 17 00:00:00 2001 From: parrt Date: Fri, 5 Jun 2015 16:14:20 -0700 Subject: [PATCH] Improve ParserInterpreter code simplicity --- .../v4/runtime/InterpreterRuleContext.java | 15 +- .../Java/src/org/antlr/v4/runtime/Parser.java | 2 +- .../antlr/v4/runtime/ParserInterpreter.java | 152 +++--- .../antlr/v4/runtime/atn/ATNDeserializer.java | 15 +- .../antlr/v4/runtime/atn/ATNSerializer.java | 2 +- .../antlr/v4/runtime/atn/RuleStartState.java | 2 +- .../v4/runtime/atn/StarLoopEntryState.java | 2 +- .../src/org/antlr/v4/runtime/dfa/DFA.java | 2 +- .../src/org/antlr/v4/runtime/tree/Trees.java | 28 +- .../antlr/v4/automata/ParserATNFactory.java | 2 +- tool/src/org/antlr/v4/tool/DOTGenerator.java | 2 +- .../org/antlr/v4/tool/LeftRecursiveRule.java | 47 ++ .../v4/test/tool/TestATNParserPrediction.java | 497 ++++++++++-------- tool/tool.iml | 1 + 14 files changed, 444 insertions(+), 325 deletions(-) diff --git a/runtime/Java/src/org/antlr/v4/runtime/InterpreterRuleContext.java b/runtime/Java/src/org/antlr/v4/runtime/InterpreterRuleContext.java index 2616ba3c5..8a7001ff2 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/InterpreterRuleContext.java +++ b/runtime/Java/src/org/antlr/v4/runtime/InterpreterRuleContext.java @@ -43,7 +43,7 @@ package org.antlr.v4.runtime; */ public class InterpreterRuleContext extends ParserRuleContext { /** This is the backing field for {@link #getRuleIndex}. */ - private int ruleIndex = -1; + protected int ruleIndex = -1; public InterpreterRuleContext() { } @@ -67,17 +67,4 @@ public class InterpreterRuleContext extends ParserRuleContext { public int getRuleIndex() { return ruleIndex; } - - /** Copy a {@link ParserRuleContext} or {@link InterpreterRuleContext} - * stack to a {@link InterpreterRuleContext} tree. - * Return {@link null} if {@code ctx} is null. - */ - public static InterpreterRuleContext fromParserRuleContext(ParserRuleContext ctx) { - if ( ctx==null ) return null; - InterpreterRuleContext dup = new InterpreterRuleContext(); - dup.copyFrom(ctx); - dup.ruleIndex = ctx.getRuleIndex(); - dup.parent = fromParserRuleContext(ctx.getParent()); - return dup; - } } diff --git a/runtime/Java/src/org/antlr/v4/runtime/Parser.java b/runtime/Java/src/org/antlr/v4/runtime/Parser.java index c6137369c..41ad686b7 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/Parser.java +++ b/runtime/Java/src/org/antlr/v4/runtime/Parser.java @@ -823,7 +823,7 @@ public abstract class Parser extends Recognizer { // Create a new parser interpreter to parse the ambiguous subphrase ParserInterpreter parser; if ( originalParser instanceof ParserInterpreter ) { - parser = new ParserInterpreter((ParserInterpreter) originalParser); + parser = ((ParserInterpreter)originalParser).copyFrom((ParserInterpreter)originalParser); } else { char[] serializedAtn = ATNSerializer.getSerializedAsChars(originalParser.getATN()); diff --git a/runtime/Java/src/org/antlr/v4/runtime/ParserInterpreter.java b/runtime/Java/src/org/antlr/v4/runtime/ParserInterpreter.java index a40c78397..4e52cfcd7 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/ParserInterpreter.java +++ b/runtime/Java/src/org/antlr/v4/runtime/ParserInterpreter.java @@ -48,7 +48,7 @@ import org.antlr.v4.runtime.dfa.DFA; import org.antlr.v4.runtime.misc.Pair; import java.util.ArrayDeque; -import java.util.BitSet; +import java.util.Arrays; import java.util.Collection; import java.util.Deque; @@ -68,14 +68,9 @@ import java.util.Deque; public class ParserInterpreter extends Parser { protected final String grammarFileName; protected final ATN atn; - /** This identifies StarLoopEntryState's that begin the (...)* - * precedence loops of left recursive rules. - */ - protected final BitSet statesNeedingLeftRecursionContext; protected final DFA[] decisionToDFA; // not shared like it is for generated parsers - protected final PredictionContextCache sharedContextCache = - new PredictionContextCache(); + protected final PredictionContextCache sharedContextCache = new PredictionContextCache(); @Deprecated protected final String[] tokenNames; @@ -83,7 +78,19 @@ public class ParserInterpreter extends Parser { private final Vocabulary vocabulary; - /** Tracks LR rules for adjusting the contexts */ + /** This stack corresponds to the _parentctx, _parentState pair of locals + * that would exist on call stack frames with a recursive descent parser; + * in the generated function for a left-recursive rule you'd see: + * + * private EContext e(int _p) throws RecognitionException { + * ParserRuleContext _parentctx = _ctx; // Pair.a + * int _parentState = getState(); // Pair.b + * ... + * } + * + * Those values are used to create new recursive rule invocation contexts + * associated with left operand of an alt like "expr '*' expr". + */ protected final Deque> _parentContextStack = new ArrayDeque>(); @@ -94,27 +101,6 @@ public class ParserInterpreter extends Parser { protected int overrideDecisionInputIndex = -1; protected int overrideDecisionAlt = -1; - /** A copy constructor that creates a new parser interpreter by reusing - * the fields of a previous interpreter. - * - * @since 4.5.1 - * - * @param old The interpreter to copy - */ - public ParserInterpreter(ParserInterpreter old) { - super(old.getTokenStream()); - this.atn = old.atn; - this.grammarFileName = old.grammarFileName; - this.statesNeedingLeftRecursionContext = old.statesNeedingLeftRecursionContext; - this.decisionToDFA = old.decisionToDFA; - this.tokenNames = old.tokenNames; - this.ruleNames = old.ruleNames; - this.vocabulary = old.vocabulary; - setInterpreter(new ParserATNSimulator(this, atn, - decisionToDFA, - sharedContextCache)); - } - /** * @deprecated Use {@link #ParserInterpreter(String, Vocabulary, Collection, ATN, TokenStream)} instead. */ @@ -137,21 +123,13 @@ public class ParserInterpreter extends Parser { this.ruleNames = ruleNames.toArray(new String[ruleNames.size()]); this.vocabulary = vocabulary; - this.decisionToDFA = new DFA[atn.getNumberOfDecisions()]; - for (int i = 0; i < decisionToDFA.length; i++) { - decisionToDFA[i] = new DFA(atn.getDecisionState(i), i); - } - // identify the ATN states where pushNewRecursionContext() must be called - this.statesNeedingLeftRecursionContext = new BitSet(atn.states.size()); - for (ATNState state : atn.states) { - if (!(state instanceof StarLoopEntryState)) { - continue; - } - - if (((StarLoopEntryState)state).precedenceRuleDecision) { - this.statesNeedingLeftRecursionContext.set(state.stateNumber); - } + // init decision DFA + int numberOfDecisions = atn.getNumberOfDecisions(); + this.decisionToDFA = new DFA[numberOfDecisions]; + for (int i = 0; i < numberOfDecisions; i++) { + DecisionState decisionState = atn.getDecisionState(i); + decisionToDFA[i] = new DFA(decisionState, i); } // get atn simulator that knows how to do predictions @@ -160,6 +138,19 @@ public class ParserInterpreter extends Parser { sharedContextCache)); } + /** A factory-like copy constructor that creates a new parser interpreter by reusing + * the fields of a previous interpreter. + * + * @since 4.5.1 + * + * @param old The interpreter to copy + */ + public ParserInterpreter copyFrom(ParserInterpreter old) { + return new ParserInterpreter(old.grammarFileName, old.vocabulary, + Arrays.asList(old.ruleNames), + old.atn, old.getTokenStream()); + } + @Override public ATN getATN() { return atn; @@ -190,8 +181,8 @@ public class ParserInterpreter extends Parser { public ParserRuleContext parse(int startRuleIndex) { RuleStartState startRuleStartState = atn.ruleToStartState[startRuleIndex]; - InterpreterRuleContext rootContext = new InterpreterRuleContext(null, ATNState.INVALID_STATE_NUMBER, startRuleIndex); - if (startRuleStartState.isPrecedenceRule) { + InterpreterRuleContext rootContext = createInterpreterRuleContext(null, ATNState.INVALID_STATE_NUMBER, startRuleIndex); + if (startRuleStartState.isLeftRecursiveRule) { enterRecursionRule(rootContext, startRuleStartState.stateNumber, startRuleIndex, 0); } else { @@ -204,7 +195,7 @@ public class ParserInterpreter extends Parser { case ATNState.RULE_STOP : // pop; return from rule if ( _ctx.isEmpty() ) { - if (startRuleStartState.isPrecedenceRule) { + if (startRuleStartState.isLeftRecursiveRule) { ParserRuleContext result = _ctx; Pair parentContext = _parentContextStack.pop(); unrollRecursionContexts(parentContext.a); @@ -247,31 +238,28 @@ public class ParserInterpreter extends Parser { } protected void visitState(ATNState p) { - int altNum; - if (p.getNumberOfTransitions() > 1) { - getErrorHandler().sync(this); - int decision = ((DecisionState) p).decision; - if ( decision == overrideDecision && _input.index() == overrideDecisionInputIndex ) { - altNum = overrideDecisionAlt; - } - else { - altNum = getInterpreter().adaptivePredict(_input, decision, _ctx); - } - } - else { - altNum = 1; +// System.out.println("visitState "+p.stateNumber); + int edge = 1; + if ( p instanceof DecisionState ) { + edge = visitDecisionsState((DecisionState) p); } - Transition transition = p.transition(altNum - 1); + Transition transition = p.transition(edge - 1); switch (transition.getSerializationType()) { case Transition.EPSILON: - if ( statesNeedingLeftRecursionContext.get(p.stateNumber) && + if ( p.getStateType()==ATNState.STAR_LOOP_ENTRY && + ((StarLoopEntryState)p).isPrecedenceDecision && !(transition.target instanceof LoopEndState)) { // We are at the start of a left recursive rule's (...)* loop - // but it's not the exit branch of loop. - InterpreterRuleContext ctx = new InterpreterRuleContext(_parentContextStack.peek().a, _parentContextStack.peek().b, _ctx.getRuleIndex()); - pushNewRecursionContext(ctx, atn.ruleToStartState[p.ruleIndex].stateNumber, _ctx.getRuleIndex()); + // and we're not taking the exit branch of loop. + InterpreterRuleContext localctx = + createInterpreterRuleContext(_parentContextStack.peek().a, + _parentContextStack.peek().b, + _ctx.getRuleIndex()); + pushNewRecursionContext(localctx, + atn.ruleToStartState[p.ruleIndex].stateNumber, + _ctx.getRuleIndex()); } break; @@ -295,12 +283,12 @@ public class ParserInterpreter extends Parser { case Transition.RULE: RuleStartState ruleStartState = (RuleStartState)transition.target; int ruleIndex = ruleStartState.ruleIndex; - InterpreterRuleContext ctx = new InterpreterRuleContext(_ctx, p.stateNumber, ruleIndex); - if (ruleStartState.isPrecedenceRule) { - enterRecursionRule(ctx, ruleStartState.stateNumber, ruleIndex, ((RuleTransition)transition).precedence); + InterpreterRuleContext newctx = createInterpreterRuleContext(_ctx, p.stateNumber, ruleIndex); + if (ruleStartState.isLeftRecursiveRule) { + enterRecursionRule(newctx, ruleStartState.stateNumber, ruleIndex, ((RuleTransition)transition).precedence); } else { - enterRule(ctx, transition.target.stateNumber, ruleIndex); + enterRule(newctx, transition.target.stateNumber, ruleIndex); } break; @@ -330,9 +318,35 @@ public class ParserInterpreter extends Parser { setState(transition.target.stateNumber); } + protected int visitDecisionsState(DecisionState p) { + int edge = 1; + if ( p.getNumberOfTransitions()>1 ) { + int predictedAlt; + getErrorHandler().sync(this); + int decision = p.decision; + if (decision == overrideDecision && _input.index() == overrideDecisionInputIndex) { + predictedAlt = overrideDecisionAlt; + } + else { + predictedAlt = getInterpreter().adaptivePredict(_input, decision, _ctx); + } + edge = predictedAlt; + } + return edge; + } + + /** Provide simple "factory" for InterpreterRuleContext's. */ + protected InterpreterRuleContext createInterpreterRuleContext( + ParserRuleContext parent, + int invokingStateNumber, + int ruleIndex) + { + return new InterpreterRuleContext(parent, invokingStateNumber, ruleIndex); + } + protected void visitRuleStopState(ATNState p) { RuleStartState ruleStartState = atn.ruleToStartState[p.ruleIndex]; - if (ruleStartState.isPrecedenceRule) { + if (ruleStartState.isLeftRecursiveRule) { Pair parentContext = _parentContextStack.pop(); unrollRecursionContexts(parentContext.a); setState(parentContext.b); diff --git a/runtime/Java/src/org/antlr/v4/runtime/atn/ATNDeserializer.java b/runtime/Java/src/org/antlr/v4/runtime/atn/ATNDeserializer.java index ae0d861f1..d83c449a0 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/atn/ATNDeserializer.java +++ b/runtime/Java/src/org/antlr/v4/runtime/atn/ATNDeserializer.java @@ -210,7 +210,7 @@ public class ATNDeserializer { int numPrecedenceStates = toInt(data[p++]); for (int i = 0; i < numPrecedenceStates; i++) { int stateNumber = toInt(data[p++]); - ((RuleStartState)atn.states.get(stateNumber)).isPrecedenceRule = true; + ((RuleStartState)atn.states.get(stateNumber)).isLeftRecursiveRule = true; } } @@ -239,9 +239,6 @@ public class ATNDeserializer { // this piece of unused metadata was serialized prior to the // addition of LexerAction int actionIndexIgnored = toInt(data[p++]); - if (actionIndexIgnored == 0xFFFF) { - actionIndexIgnored = -1; - } } } } @@ -319,7 +316,7 @@ public class ATNDeserializer { RuleTransition ruleTransition = (RuleTransition)t; int outermostPrecedenceReturn = -1; - if (atn.ruleToStartState[ruleTransition.target.ruleIndex].isPrecedenceRule) { + if (atn.ruleToStartState[ruleTransition.target.ruleIndex].isLeftRecursiveRule) { if (ruleTransition.precedence == 0) { outermostPrecedenceReturn = ruleTransition.target.ruleIndex; } @@ -451,7 +448,7 @@ public class ATNDeserializer { ATNState endState; Transition excludeTransition = null; - if (atn.ruleToStartState[i].isPrecedenceRule) { + if (atn.ruleToStartState[i].isLeftRecursiveRule) { // wrap from the beginning of the rule to the StarLoopEntryState endState = null; for (ATNState state : atn.states) { @@ -524,7 +521,7 @@ public class ATNDeserializer { /** * Analyze the {@link StarLoopEntryState} states in the specified ATN to set - * the {@link StarLoopEntryState#precedenceRuleDecision} field to the + * the {@link StarLoopEntryState#isPrecedenceDecision} field to the * correct value. * * @param atn The ATN. @@ -539,11 +536,11 @@ public class ATNDeserializer { * decision for the closure block that determines whether a * precedence rule should continue or complete. */ - if (atn.ruleToStartState[state.ruleIndex].isPrecedenceRule) { + if (atn.ruleToStartState[state.ruleIndex].isLeftRecursiveRule) { ATNState maybeLoopEndState = state.transition(state.getNumberOfTransitions() - 1).target; if (maybeLoopEndState instanceof LoopEndState) { if (maybeLoopEndState.epsilonOnlyTransitions && maybeLoopEndState.transition(0).target instanceof RuleStopState) { - ((StarLoopEntryState)state).precedenceRuleDecision = true; + ((StarLoopEntryState)state).isPrecedenceDecision = true; } } } diff --git a/runtime/Java/src/org/antlr/v4/runtime/atn/ATNSerializer.java b/runtime/Java/src/org/antlr/v4/runtime/atn/ATNSerializer.java index fd4a36e7e..4c31ac92f 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/atn/ATNSerializer.java +++ b/runtime/Java/src/org/antlr/v4/runtime/atn/ATNSerializer.java @@ -108,7 +108,7 @@ public class ATNSerializer { nonGreedyStates.add(s.stateNumber); } - if (s instanceof RuleStartState && ((RuleStartState)s).isPrecedenceRule) { + if (s instanceof RuleStartState && ((RuleStartState)s).isLeftRecursiveRule) { precedenceStates.add(s.stateNumber); } diff --git a/runtime/Java/src/org/antlr/v4/runtime/atn/RuleStartState.java b/runtime/Java/src/org/antlr/v4/runtime/atn/RuleStartState.java index b33c357b9..b2105d679 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/atn/RuleStartState.java +++ b/runtime/Java/src/org/antlr/v4/runtime/atn/RuleStartState.java @@ -32,7 +32,7 @@ package org.antlr.v4.runtime.atn; public final class RuleStartState extends ATNState { public RuleStopState stopState; - public boolean isPrecedenceRule; //Synonymous with rule being left recursive; consider renaming. + public boolean isLeftRecursiveRule; @Override public int getStateType() { diff --git a/runtime/Java/src/org/antlr/v4/runtime/atn/StarLoopEntryState.java b/runtime/Java/src/org/antlr/v4/runtime/atn/StarLoopEntryState.java index d61b72c67..621f1ec45 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/atn/StarLoopEntryState.java +++ b/runtime/Java/src/org/antlr/v4/runtime/atn/StarLoopEntryState.java @@ -46,7 +46,7 @@ public final class StarLoopEntryState extends DecisionState { * * @see DFA#isPrecedenceDfa() */ - public boolean precedenceRuleDecision; + public boolean isPrecedenceDecision; @Override public int getStateType() { diff --git a/runtime/Java/src/org/antlr/v4/runtime/dfa/DFA.java b/runtime/Java/src/org/antlr/v4/runtime/dfa/DFA.java index 18a0f188e..1f6890de7 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/dfa/DFA.java +++ b/runtime/Java/src/org/antlr/v4/runtime/dfa/DFA.java @@ -76,7 +76,7 @@ public class DFA { boolean precedenceDfa = false; if (atnStartState instanceof StarLoopEntryState) { - if (((StarLoopEntryState)atnStartState).precedenceRuleDecision) { + if (((StarLoopEntryState)atnStartState).isPrecedenceDecision) { precedenceDfa = true; DFAState precedenceState = new DFAState(new ATNConfigSet()); precedenceState.edges = new DFAState[0]; diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/Trees.java b/runtime/Java/src/org/antlr/v4/runtime/tree/Trees.java index 1f5093055..4bce486e8 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/tree/Trees.java +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/Trees.java @@ -35,6 +35,7 @@ import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.misc.Utils; import org.antlr.v4.runtime.tree.gui.TreePostScriptGenerator; +import org.antlr.v4.runtime.tree.gui.TreeTextProvider; import java.io.BufferedWriter; import java.io.FileWriter; @@ -100,26 +101,39 @@ public class Trees { return toStringTree(t, ruleNamesList); } - /** Print out a whole tree in LISP form. {@link #getNodeText} is used on the - * node payloads to get the text for the nodes. Detect - * parse trees and extract data appropriately. + /** Print out a whole tree in LISP form. Arg nodeTextProvider is used on the + * node payloads to get the text for the nodes. + * + * @since 4.5.1 */ - public static String toStringTree(Tree t, List ruleNames) { - String s = Utils.escapeWhitespace(getNodeText(t, ruleNames), false); + public static String toStringTree(Tree t, TreeTextProvider nodeTextProvider) { + String s = Utils.escapeWhitespace(nodeTextProvider.getText(t), false); if ( t.getChildCount()==0 ) return s; StringBuilder buf = new StringBuilder(); buf.append("("); - s = Utils.escapeWhitespace(getNodeText(t, ruleNames), false); + s = Utils.escapeWhitespace(nodeTextProvider.getText(t), false); buf.append(s); buf.append(' '); for (int i = 0; i0 ) buf.append(' '); - buf.append(toStringTree(t.getChild(i), ruleNames)); + buf.append(toStringTree(t.getChild(i), nodeTextProvider)); } buf.append(")"); return buf.toString(); } + /** Print out a whole tree in LISP form. {@link #getNodeText} is used on the + * node payloads to get the text for the nodes. + */ + public static String toStringTree(final Tree t, final List ruleNames) { + return toStringTree(t, new TreeTextProvider() { + @Override + public String getText(Tree node) { + return getNodeText(node, ruleNames); + } + }); + } + public static String getNodeText(Tree t, Parser recog) { String[] ruleNames = recog != null ? recog.getRuleNames() : null; List ruleNamesList = ruleNames != null ? Arrays.asList(ruleNames) : null; diff --git a/tool/src/org/antlr/v4/automata/ParserATNFactory.java b/tool/src/org/antlr/v4/automata/ParserATNFactory.java index 3eb34cb53..366411117 100644 --- a/tool/src/org/antlr/v4/automata/ParserATNFactory.java +++ b/tool/src/org/antlr/v4/automata/ParserATNFactory.java @@ -659,7 +659,7 @@ public class ParserATNFactory implements ATNFactory { RuleStartState start = newState(RuleStartState.class, r.ast); RuleStopState stop = newState(RuleStopState.class, r.ast); start.stopState = stop; - start.isPrecedenceRule = r instanceof LeftRecursiveRule; + start.isLeftRecursiveRule = r instanceof LeftRecursiveRule; start.setRuleIndex(r.index); stop.setRuleIndex(r.index); atn.ruleToStartState[r.index] = start; diff --git a/tool/src/org/antlr/v4/tool/DOTGenerator.java b/tool/src/org/antlr/v4/tool/DOTGenerator.java index a9c3934b1..740bfe459 100644 --- a/tool/src/org/antlr/v4/tool/DOTGenerator.java +++ b/tool/src/org/antlr/v4/tool/DOTGenerator.java @@ -246,7 +246,7 @@ public class DOTGenerator { edgeST = stlib.getInstanceOf("edge"); String label = "<" + ruleNames[rr.ruleIndex]; - if (((RuleStartState)rr.target).isPrecedenceRule) { + if (((RuleStartState)rr.target).isLeftRecursiveRule) { label += "[" + rr.precedence + "]"; } label += ">"; diff --git a/tool/src/org/antlr/v4/tool/LeftRecursiveRule.java b/tool/src/org/antlr/v4/tool/LeftRecursiveRule.java index 07c90dd64..1d3b9902f 100644 --- a/tool/src/org/antlr/v4/tool/LeftRecursiveRule.java +++ b/tool/src/org/antlr/v4/tool/LeftRecursiveRule.java @@ -89,6 +89,53 @@ public class LeftRecursiveRule extends Rule { return alts; } + /** Return an array that maps predicted alt from primary decision + * to original alt of rule. For following rule, return [0, 2, 4] + * + e : e '*' e + | INT + | e '+' e + | ID + ; + + * That maps predicted alt 1 to original alt 2 and predicted 2 to alt 4. + * + * @since 4.5.1 + */ + public int[] getPrimaryAlts() { + if ( recPrimaryAlts.size()==0 ) return null; + int[] alts = new int[recPrimaryAlts.size()+1]; + for (int i = 0; i < recPrimaryAlts.size(); i++) { // recPrimaryAlts is a List not Map like recOpAlts + LeftRecursiveRuleAltInfo altInfo = recPrimaryAlts.get(i); + alts[i+1] = altInfo.altNum; + } + return alts; + } + + /** Return an array that maps predicted alt from recursive op decision + * to original alt of rule. For following rule, return [0, 1, 3] + * + e : e '*' e + | INT + | e '+' e + | ID + ; + + * That maps predicted alt 1 to original alt 1 and predicted 2 to alt 3. + * + * @since 4.5.1 + */ + public int[] getRecursiveOpAlts() { + if ( recOpAlts.size()==0 ) return null; + int[] alts = new int[recOpAlts.size()+1]; + int alt = 1; + for (LeftRecursiveRuleAltInfo altInfo : recOpAlts.values()) { + alts[alt] = altInfo.altNum; + alt++; // recOpAlts has alts possibly with gaps + } + return alts; + } + /** Get -> labels from those alts we deleted for left-recursive rules. */ @Override public Map>> getAltLabels() { diff --git a/tool/test/org/antlr/v4/test/tool/TestATNParserPrediction.java b/tool/test/org/antlr/v4/test/tool/TestATNParserPrediction.java index 56671add1..d82843063 100644 --- a/tool/test/org/antlr/v4/test/tool/TestATNParserPrediction.java +++ b/tool/test/org/antlr/v4/test/tool/TestATNParserPrediction.java @@ -43,153 +43,157 @@ import org.antlr.v4.runtime.dfa.DFA; import org.antlr.v4.runtime.misc.IntegerList; import org.antlr.v4.tool.DOTGenerator; import org.antlr.v4.tool.Grammar; +import org.antlr.v4.tool.LeftRecursiveRule; import org.antlr.v4.tool.LexerGrammar; import org.antlr.v4.tool.Rule; import org.junit.Test; -import static org.junit.Assert.assertEquals; +import java.util.Arrays; - // NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH - // NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH - // NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +// NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH +// NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH +// NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH public class TestATNParserPrediction extends BaseTest { @Test public void testAorB() throws Exception { LexerGrammar lg = new LexerGrammar( - "lexer grammar L;\n" + - "A : 'a' ;\n" + - "B : 'b' ;\n" + - "C : 'c' ;\n"); + "lexer grammar L;\n" + + "A : 'a' ;\n" + + "B : 'b' ;\n" + + "C : 'c' ;\n"); Grammar g = new Grammar( - "parser grammar T;\n"+ - "a : A{;} | B ;"); + "parser grammar T;\n"+ + "a : A{;} | B ;"); int decision = 0; checkPredictedAlt(lg, g, decision, "a", 1); checkPredictedAlt(lg, g, decision, "b", 2); // After matching these inputs for decision, what is DFA after each prediction? String[] inputs = { - "a", - "b", - "a" + "a", + "b", + "a" }; String[] dfa = { - "s0-'a'->:s1=>1\n", + "s0-'a'->:s1=>1\n", - "s0-'a'->:s1=>1\n" + - "s0-'b'->:s2=>2\n", + "s0-'a'->:s1=>1\n" + + "s0-'b'->:s2=>2\n", - "s0-'a'->:s1=>1\n" + // don't change after it works - "s0-'b'->:s2=>2\n", + "s0-'a'->:s1=>1\n" + // don't change after it works + "s0-'b'->:s2=>2\n", }; checkDFAConstruction(lg, g, decision, inputs, dfa); } @Test public void testEmptyInput() throws Exception { LexerGrammar lg = new LexerGrammar( - "lexer grammar L;\n" + - "A : 'a' ;\n" + - "B : 'b' ;\n" + - "C : 'c' ;\n"); + "lexer grammar L;\n" + + "A : 'a' ;\n" + + "B : 'b' ;\n" + + "C : 'c' ;\n"); Grammar g = new Grammar( - "parser grammar T;\n"+ - "a : A | ;"); + "parser grammar T;\n"+ + "a : A | ;"); int decision = 0; checkPredictedAlt(lg, g, decision, "a", 1); checkPredictedAlt(lg, g, decision, "", 2); // After matching these inputs for decision, what is DFA after each prediction? String[] inputs = { - "a", - "", + "a", + "", }; String[] dfa = { - "s0-'a'->:s1=>1\n", + "s0-'a'->:s1=>1\n", - "s0-EOF->:s2=>2\n" + - "s0-'a'->:s1=>1\n", + "s0-EOF->:s2=>2\n" + + "s0-'a'->:s1=>1\n", }; checkDFAConstruction(lg, g, decision, inputs, dfa); } @Test public void testPEGAchillesHeel() throws Exception { LexerGrammar lg = new LexerGrammar( - "lexer grammar L;\n" + - "A : 'a' ;\n" + - "B : 'b' ;\n" + - "C : 'c' ;\n"); + "lexer grammar L;\n" + + "A : 'a' ;\n" + + "B : 'b' ;\n" + + "C : 'c' ;\n"); Grammar g = new Grammar( - "parser grammar T;\n"+ - "a : A | A B ;"); + "parser grammar T;\n"+ + "a : A | A B ;"); checkPredictedAlt(lg, g, 0, "a", 1); checkPredictedAlt(lg, g, 0, "ab", 2); checkPredictedAlt(lg, g, 0, "abc", 2); String[] inputs = { - "a", - "ab", - "abc" + "a", + "ab", + "abc" }; String[] dfa = { - "s0-'a'->s1\n" + - "s1-EOF->:s2=>1\n", + "s0-'a'->s1\n" + + "s1-EOF->:s2=>1\n", - "s0-'a'->s1\n" + - "s1-EOF->:s2=>1\n" + - "s1-'b'->:s3=>2\n", + "s0-'a'->s1\n" + + "s1-EOF->:s2=>1\n" + + "s1-'b'->:s3=>2\n", - "s0-'a'->s1\n" + - "s1-EOF->:s2=>1\n" + - "s1-'b'->:s3=>2\n" + "s0-'a'->s1\n" + + "s1-EOF->:s2=>1\n" + + "s1-'b'->:s3=>2\n" }; checkDFAConstruction(lg, g, 0, inputs, dfa); } @Test public void testRuleRefxory() throws Exception { LexerGrammar lg = new LexerGrammar( - "lexer grammar L;\n" + - "A : 'a' ;\n" + - "B : 'b' ;\n" + - "C : 'c' ;\n"); + "lexer grammar L;\n" + + "A : 'a' ;\n" + + "B : 'b' ;\n" + + "C : 'c' ;\n"); Grammar g = new Grammar( - "parser grammar T;\n"+ - "a : x | y ;\n" + - "x : A ;\n" + - "y : B ;\n"); + "parser grammar T;\n"+ + "a : x | y ;\n" + + "x : A ;\n" + + "y : B ;\n"); int decision = 0; checkPredictedAlt(lg, g, decision, "a", 1); checkPredictedAlt(lg, g, decision, "b", 2); // After matching these inputs for decision, what is DFA after each prediction? String[] inputs = { - "a", - "b", - "a" + "a", + "b", + "a" }; String[] dfa = { - "s0-'a'->:s1=>1\n", + "s0-'a'->:s1=>1\n", - "s0-'a'->:s1=>1\n" + - "s0-'b'->:s2=>2\n", + "s0-'a'->:s1=>1\n" + + "s0-'b'->:s2=>2\n", - "s0-'a'->:s1=>1\n" + // don't change after it works - "s0-'b'->:s2=>2\n", + "s0-'a'->:s1=>1\n" + // don't change after it works + "s0-'b'->:s2=>2\n", }; checkDFAConstruction(lg, g, decision, inputs, dfa); } @Test public void testOptionalRuleChasesGlobalFollow() throws Exception { LexerGrammar lg = new LexerGrammar( - "lexer grammar L;\n" + - "A : 'a' ;\n" + - "B : 'b' ;\n" + - "C : 'c' ;\n"); + "lexer grammar L;\n" + + "A : 'a' ;\n" + + "B : 'b' ;\n" + + "C : 'c' ;\n"); Grammar g = new Grammar( - "parser grammar T;\n"+ - "tokens {A,B,C}\n" + - "a : x B ;\n" + - "b : x C ;\n" + - "x : A | ;\n"); + "parser grammar T;\n"+ + "tokens {A,B,C}\n" + + "a : x B ;\n" + + "b : x C ;\n" + + "x : A | ;\n"); int decision = 0; checkPredictedAlt(lg, g, decision, "a", 1); checkPredictedAlt(lg, g, decision, "b", 2); @@ -197,116 +201,116 @@ public class TestATNParserPrediction extends BaseTest { // After matching these inputs for decision, what is DFA after each prediction? String[] inputs = { - "a", - "b", - "c", - "c", + "a", + "b", + "c", + "c", }; String[] dfa = { - "s0-'a'->:s1=>1\n", + "s0-'a'->:s1=>1\n", - "s0-'a'->:s1=>1\n" + - "s0-'b'->:s2=>2\n", + "s0-'a'->:s1=>1\n" + + "s0-'b'->:s2=>2\n", - "s0-'a'->:s1=>1\n" + - "s0-'b'->:s2=>2\n" + - "s0-'c'->:s3=>2\n", + "s0-'a'->:s1=>1\n" + + "s0-'b'->:s2=>2\n" + + "s0-'c'->:s3=>2\n", - "s0-'a'->:s1=>1\n" + - "s0-'b'->:s2=>2\n" + - "s0-'c'->:s3=>2\n", + "s0-'a'->:s1=>1\n" + + "s0-'b'->:s2=>2\n" + + "s0-'c'->:s3=>2\n", }; checkDFAConstruction(lg, g, decision, inputs, dfa); } @Test public void testLL1Ambig() throws Exception { LexerGrammar lg = new LexerGrammar( - "lexer grammar L;\n" + - "A : 'a' ;\n" + - "B : 'b' ;\n" + - "C : 'c' ;\n"); + "lexer grammar L;\n" + + "A : 'a' ;\n" + + "B : 'b' ;\n" + + "C : 'c' ;\n"); Grammar g = new Grammar( - "parser grammar T;\n"+ - "a : A | A | A B ;"); + "parser grammar T;\n"+ + "a : A | A | A B ;"); int decision = 0; checkPredictedAlt(lg, g, decision, "a", 1); checkPredictedAlt(lg, g, decision, "ab", 3); // After matching these inputs for decision, what is DFA after each prediction? String[] inputs = { - "a", - "ab", - "ab" + "a", + "ab", + "ab" }; String[] dfa = { - "s0-'a'->s1\n" + - "s1-EOF->:s2^=>1\n", + "s0-'a'->s1\n" + + "s1-EOF->:s2^=>1\n", - "s0-'a'->s1\n" + - "s1-EOF->:s2^=>1\n" + - "s1-'b'->:s3=>3\n", + "s0-'a'->s1\n" + + "s1-EOF->:s2^=>1\n" + + "s1-'b'->:s3=>3\n", - "s0-'a'->s1\n" + - "s1-EOF->:s2^=>1\n" + - "s1-'b'->:s3=>3\n", + "s0-'a'->s1\n" + + "s1-EOF->:s2^=>1\n" + + "s1-'b'->:s3=>3\n", }; checkDFAConstruction(lg, g, decision, inputs, dfa); } @Test public void testLL2Ambig() throws Exception { LexerGrammar lg = new LexerGrammar( - "lexer grammar L;\n" + - "A : 'a' ;\n" + - "B : 'b' ;\n" + - "C : 'c' ;\n"); + "lexer grammar L;\n" + + "A : 'a' ;\n" + + "B : 'b' ;\n" + + "C : 'c' ;\n"); Grammar g = new Grammar( - "parser grammar T;\n"+ - "a : A B | A B | A B C ;"); + "parser grammar T;\n"+ + "a : A B | A B | A B C ;"); int decision = 0; checkPredictedAlt(lg, g, decision, "ab", 1); checkPredictedAlt(lg, g, decision, "abc", 3); // After matching these inputs for decision, what is DFA after each prediction? String[] inputs = { - "ab", - "abc", - "ab" + "ab", + "abc", + "ab" }; String[] dfa = { - "s0-'a'->s1\n" + - "s1-'b'->s2\n" + - "s2-EOF->:s3^=>1\n", + "s0-'a'->s1\n" + + "s1-'b'->s2\n" + + "s2-EOF->:s3^=>1\n", - "s0-'a'->s1\n" + - "s1-'b'->s2\n" + - "s2-EOF->:s3^=>1\n" + - "s2-'c'->:s4=>3\n", + "s0-'a'->s1\n" + + "s1-'b'->s2\n" + + "s2-EOF->:s3^=>1\n" + + "s2-'c'->:s4=>3\n", - "s0-'a'->s1\n" + - "s1-'b'->s2\n" + - "s2-EOF->:s3^=>1\n" + - "s2-'c'->:s4=>3\n", + "s0-'a'->s1\n" + + "s1-'b'->s2\n" + + "s2-EOF->:s3^=>1\n" + + "s2-'c'->:s4=>3\n", }; checkDFAConstruction(lg, g, decision, inputs, dfa); } @Test public void testRecursiveLeftPrefix() throws Exception { LexerGrammar lg = new LexerGrammar( - "lexer grammar L;\n" + - "A : 'a' ;\n" + - "B : 'b' ;\n" + - "C : 'c' ;\n" + - "LP : '(' ;\n" + - "RP : ')' ;\n" + - "INT : '0'..'9'+ ;\n" + "lexer grammar L;\n" + + "A : 'a' ;\n" + + "B : 'b' ;\n" + + "C : 'c' ;\n" + + "LP : '(' ;\n" + + "RP : ')' ;\n" + + "INT : '0'..'9'+ ;\n" ); Grammar g = new Grammar( - "parser grammar T;\n"+ - "tokens {A,B,C,LP,RP,INT}\n" + - "a : e B | e C ;\n" + - "e : LP e RP\n" + - " | INT\n" + - " ;"); + "parser grammar T;\n"+ + "tokens {A,B,C,LP,RP,INT}\n" + + "a : e B | e C ;\n" + + "e : LP e RP\n" + + " | INT\n" + + " ;"); int decision = 0; checkPredictedAlt(lg, g, decision, "34b", 1); checkPredictedAlt(lg, g, decision, "34c", 2); @@ -315,57 +319,57 @@ public class TestATNParserPrediction extends BaseTest { // After matching these inputs for decision, what is DFA after each prediction? String[] inputs = { - "34b", - "34c", - "((34))b", - "((34))c" + "34b", + "34c", + "((34))b", + "((34))c" }; String[] dfa = { - "s0-INT->s1\n" + - "s1-'b'->:s2=>1\n", + "s0-INT->s1\n" + + "s1-'b'->:s2=>1\n", - "s0-INT->s1\n" + - "s1-'b'->:s2=>1\n" + - "s1-'c'->:s3=>2\n", + "s0-INT->s1\n" + + "s1-'b'->:s2=>1\n" + + "s1-'c'->:s3=>2\n", - "s0-'('->s4\n" + - "s0-INT->s1\n" + - "s1-'b'->:s2=>1\n" + - "s1-'c'->:s3=>2\n" + - "s4-'('->s5\n" + - "s5-INT->s6\n" + - "s6-')'->s7\n" + - "s7-')'->s1\n", + "s0-'('->s4\n" + + "s0-INT->s1\n" + + "s1-'b'->:s2=>1\n" + + "s1-'c'->:s3=>2\n" + + "s4-'('->s5\n" + + "s5-INT->s6\n" + + "s6-')'->s7\n" + + "s7-')'->s1\n", - "s0-'('->s4\n" + - "s0-INT->s1\n" + - "s1-'b'->:s2=>1\n" + - "s1-'c'->:s3=>2\n" + - "s4-'('->s5\n" + - "s5-INT->s6\n" + - "s6-')'->s7\n" + - "s7-')'->s1\n", + "s0-'('->s4\n" + + "s0-INT->s1\n" + + "s1-'b'->:s2=>1\n" + + "s1-'c'->:s3=>2\n" + + "s4-'('->s5\n" + + "s5-INT->s6\n" + + "s6-')'->s7\n" + + "s7-')'->s1\n", }; checkDFAConstruction(lg, g, decision, inputs, dfa); } @Test public void testRecursiveLeftPrefixWithAorABIssue() throws Exception { LexerGrammar lg = new LexerGrammar( - "lexer grammar L;\n" + - "A : 'a' ;\n" + - "B : 'b' ;\n" + - "C : 'c' ;\n" + - "LP : '(' ;\n" + - "RP : ')' ;\n" + - "INT : '0'..'9'+ ;\n" + "lexer grammar L;\n" + + "A : 'a' ;\n" + + "B : 'b' ;\n" + + "C : 'c' ;\n" + + "LP : '(' ;\n" + + "RP : ')' ;\n" + + "INT : '0'..'9'+ ;\n" ); Grammar g = new Grammar( - "parser grammar T;\n"+ - "tokens {A,B,C,LP,RP,INT}\n" + - "a : e A | e A B ;\n" + - "e : LP e RP\n" + - " | INT\n" + - " ;"); + "parser grammar T;\n"+ + "tokens {A,B,C,LP,RP,INT}\n" + + "a : e A | e A B ;\n" + + "e : LP e RP\n" + + " | INT\n" + + " ;"); int decision = 0; checkPredictedAlt(lg, g, decision, "34a", 1); checkPredictedAlt(lg, g, decision, "34ab", 2); // PEG would miss this one! @@ -374,40 +378,40 @@ public class TestATNParserPrediction extends BaseTest { // After matching these inputs for decision, what is DFA after each prediction? String[] inputs = { - "34a", - "34ab", - "((34))a", - "((34))ab", + "34a", + "34ab", + "((34))a", + "((34))ab", }; String[] dfa = { - "s0-INT->s1\n" + - "s1-'a'->s2\n" + - "s2-EOF->:s3=>1\n", + "s0-INT->s1\n" + + "s1-'a'->s2\n" + + "s2-EOF->:s3=>1\n", - "s0-INT->s1\n" + - "s1-'a'->s2\n" + - "s2-EOF->:s3=>1\n" + - "s2-'b'->:s4=>2\n", + "s0-INT->s1\n" + + "s1-'a'->s2\n" + + "s2-EOF->:s3=>1\n" + + "s2-'b'->:s4=>2\n", - "s0-'('->s5\n" + - "s0-INT->s1\n" + - "s1-'a'->s2\n" + - "s2-EOF->:s3=>1\n" + - "s2-'b'->:s4=>2\n" + - "s5-'('->s6\n" + - "s6-INT->s7\n" + - "s7-')'->s8\n" + - "s8-')'->s1\n", + "s0-'('->s5\n" + + "s0-INT->s1\n" + + "s1-'a'->s2\n" + + "s2-EOF->:s3=>1\n" + + "s2-'b'->:s4=>2\n" + + "s5-'('->s6\n" + + "s6-INT->s7\n" + + "s7-')'->s8\n" + + "s8-')'->s1\n", - "s0-'('->s5\n" + - "s0-INT->s1\n" + - "s1-'a'->s2\n" + - "s2-EOF->:s3=>1\n" + - "s2-'b'->:s4=>2\n" + - "s5-'('->s6\n" + - "s6-INT->s7\n" + - "s7-')'->s8\n" + - "s8-')'->s1\n", + "s0-'('->s5\n" + + "s0-INT->s1\n" + + "s1-'a'->s2\n" + + "s2-EOF->:s3=>1\n" + + "s2-'b'->:s4=>2\n" + + "s5-'('->s6\n" + + "s6-INT->s7\n" + + "s7-')'->s8\n" + + "s8-')'->s1\n", }; checkDFAConstruction(lg, g, decision, inputs, dfa); } @@ -418,15 +422,15 @@ public class TestATNParserPrediction extends BaseTest { // be declared ambig since (12, 2, []) can take us to // unambig state maybe. keep going. LexerGrammar lg = new LexerGrammar( - "lexer grammar L;\n" + - "ID : 'a'..'z' ;\n" + // one char - "SEMI : ';' ;\n"+ - "INT : '0'..'9'+ ;\n" + "lexer grammar L;\n" + + "ID : 'a'..'z' ;\n" + // one char + "SEMI : ';' ;\n"+ + "INT : '0'..'9'+ ;\n" ); Grammar g = new Grammar( - "parser grammar T;\n"+ - "tokens {ID,SEMI,INT}\n" + - "a : (ID | ID ID?) SEMI ;"); + "parser grammar T;\n"+ + "tokens {ID,SEMI,INT}\n" + + "a : (ID | ID ID?) SEMI ;"); int decision = 1; checkPredictedAlt(lg, g, decision, "a;", 1); checkPredictedAlt(lg, g, decision, "ab;", 2); @@ -435,30 +439,85 @@ public class TestATNParserPrediction extends BaseTest { @Test public void testContinuePrediction2() throws Exception { // ID is ambig for first two alts, but ID SEMI lets us move forward with alt 3 LexerGrammar lg = new LexerGrammar( - "lexer grammar L;\n" + - "ID : 'a'..'z' ;\n" + // one char - "SEMI : ';' ;\n"+ - "INT : '0'..'9'+ ;\n" + "lexer grammar L;\n" + + "ID : 'a'..'z' ;\n" + // one char + "SEMI : ';' ;\n"+ + "INT : '0'..'9'+ ;\n" ); Grammar g = new Grammar( - "parser grammar T;\n"+ - "tokens {ID,SEMI,INT}\n" + - "a : ID | ID | ID SEMI ;\n"); + "parser grammar T;\n"+ + "tokens {ID,SEMI,INT}\n" + + "a : ID | ID | ID SEMI ;\n"); int decision = 0; checkPredictedAlt(lg, g, decision, "a", 1); checkPredictedAlt(lg, g, decision, "a;", 3); } + @Test public void testAltsForLRRuleComputation() throws Exception { + Grammar g = new Grammar( + "grammar T;\n" + + "e : e '*' e\n" + + " | INT\n" + + " | e '+' e\n" + + " | ID\n" + + " ;\n" + + "ID : [a-z]+ ;\n" + + "INT : [0-9]+ ;\n" + + "WS : [ \\r\\t\\n]+ ;"); + Rule e = g.getRule("e"); + assertTrue(e instanceof LeftRecursiveRule); + LeftRecursiveRule lr = (LeftRecursiveRule)e; + assertEquals("[0, 2, 4]", Arrays.toString(lr.getPrimaryAlts())); + assertEquals("[0, 1, 3]", Arrays.toString(lr.getRecursiveOpAlts())); + } + + @Test public void testAltsForLRRuleComputation2() throws Exception { + Grammar g = new Grammar( + "grammar T;\n" + + "e : INT\n" + + " | e '*' e\n" + + " | ID\n" + + " ;\n" + + "ID : [a-z]+ ;\n" + + "INT : [0-9]+ ;\n" + + "WS : [ \\r\\t\\n]+ ;"); + Rule e = g.getRule("e"); + assertTrue(e instanceof LeftRecursiveRule); + LeftRecursiveRule lr = (LeftRecursiveRule)e; + assertEquals("[0, 1, 3]", Arrays.toString(lr.getPrimaryAlts())); + assertEquals("[0, 2]", Arrays.toString(lr.getRecursiveOpAlts())); + } + + @Test public void testAltsForLRRuleComputation3() throws Exception { + Grammar g = new Grammar( + "grammar T;\n" + + "random : 'blort';\n" + // should have no effect + "e : '--' e\n" + + " | e '*' e\n" + + " | e '+' e\n" + + " | e '--'\n" + + " | ID\n" + + " ;\n" + + "ID : [a-z]+ ;\n" + + "INT : [0-9]+ ;\n" + + "WS : [ \\r\\t\\n]+ ;"); + Rule e = g.getRule("e"); + assertTrue(e instanceof LeftRecursiveRule); + LeftRecursiveRule lr = (LeftRecursiveRule)e; + assertEquals("[0, 1, 5]", Arrays.toString(lr.getPrimaryAlts())); + assertEquals("[0, 2, 3, 4]", Arrays.toString(lr.getRecursiveOpAlts())); + } + /** first check that the ATN predicts right alt. * Then check adaptive prediction. */ public void checkPredictedAlt(LexerGrammar lg, Grammar g, int decision, - String inputString, int expectedAlt) + String inputString, int expectedAlt) { Tool.internalOption_ShowATNConfigsInDFA = true; ATN lexatn = createATN(lg, true); LexerATNSimulator lexInterp = - new LexerATNSimulator(lexatn,new DFA[] { new DFA(lexatn.modeToStartState.get(Lexer.DEFAULT_MODE)) },new PredictionContextCache()); + new LexerATNSimulator(lexatn,new DFA[] { new DFA(lexatn.modeToStartState.get(Lexer.DEFAULT_MODE)) },new PredictionContextCache()); IntegerList types = getTokenTypesViaATN(inputString, lexInterp); System.out.println(types); @@ -501,12 +560,12 @@ public class TestATNParserPrediction extends BaseTest { } public void checkDFAConstruction(LexerGrammar lg, Grammar g, int decision, - String[] inputString, String[] dfaString) + String[] inputString, String[] dfaString) { // Tool.internalOption_ShowATNConfigsInDFA = true; ATN lexatn = createATN(lg, true); LexerATNSimulator lexInterp = - new LexerATNSimulator(lexatn,new DFA[] { new DFA(lexatn.getDecisionState(Lexer.DEFAULT_MODE)) }, new PredictionContextCache()); + new LexerATNSimulator(lexatn,new DFA[] { new DFA(lexatn.getDecisionState(Lexer.DEFAULT_MODE)) }, new PredictionContextCache()); semanticProcess(lg); g.importVocab(lg); diff --git a/tool/tool.iml b/tool/tool.iml index 40ed50241..437a30f70 100644 --- a/tool/tool.iml +++ b/tool/tool.iml @@ -43,6 +43,7 @@ +