@NotNull public ATNState newState(@Nullable GrammarAST node) { ATNState n = new BasicState(); n.setRuleIndex(currentRule.index); atn.addState(n); return n; }
@NotNull public Handle _ruleRef(@NotNull GrammarAST node) { Rule r = g.getRule(node.getText()); if (r == null) { g.tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, "Rule " + node.getText() + " undefined"); return null; } RuleStartState start = atn.ruleToStartState[r.index]; ATNState left = newState(node); ATNState right = newState(node); int precedence = 0; if (((GrammarASTWithOptions) node) .getOptionString(LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME) != null) { precedence = Integer.parseInt( ((GrammarASTWithOptions) node) .getOptionString(LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME)); } RuleTransition call = new RuleTransition(start, r.index, precedence, right); left.addTransition(call); node.atnState = left; return new Handle(left, right); }
/** * Checks whether or not {@code symbol} can follow the current state in the ATN. The behavior of * this method is equivalent to the following, but is implemented such that the complete * context-sensitive follow set does not need to be explicitly constructed. * * <pre> * return getExpectedTokens().contains(symbol); * </pre> * * @param symbol the symbol type to check * @return {@code true} if {@code symbol} can follow the current state in the ATN, otherwise * {@code false}. */ public boolean isExpectedToken(int symbol) { // return getInterpreter().atn.nextTokens(_ctx); ATN atn = getInterpreter().atn; ParserRuleContext ctx = _ctx; ATNState s = atn.states.get(getState()); IntervalSet following = atn.nextTokens(s); if (following.contains(symbol)) { return true; } // System.out.println("following "+s+"="+following); if (!following.contains(Token.EPSILON)) return false; while (ctx != null && ctx.invokingState >= 0 && following.contains(Token.EPSILON)) { ATNState invokingState = atn.states.get(ctx.invokingState); RuleTransition rt = (RuleTransition) invokingState.transition(0); following = atn.nextTokens(rt.followState); if (following.contains(symbol)) { return true; } ctx = (ParserRuleContext) ctx.parent; } if (following.contains(Token.EPSILON) && symbol == Token.EOF) { return true; } return false; }
/** Build an atom with all possible values in its label */ @NotNull public Handle wildcard(GrammarAST node) { ATNState left = newState(node); ATNState right = newState(node); left.addTransition(new WildcardTransition(right)); node.atnState = left; return new Handle(left, right); }
/** From label A build Graph o-A->o */ public Handle tokenRef(TerminalAST node) { ATNState left = newState(node); ATNState right = newState(node); int ttype = g.getTokenType(node.getText()); left.addTransition(new AtomTransition(right, ttype)); node.atnState = left; return new Handle(left, right); }
/** [Aa\t \u1234a-z\]\-] char sets */ @Override public Handle charSetLiteral(GrammarAST charSetAST) { ATNState left = newState(charSetAST); ATNState right = newState(charSetAST); IntervalSet set = getSetFromCharSetLiteral(charSetAST); left.addTransition(new SetTransition(right, set)); charSetAST.atnState = left; return new Handle(left, right); }
/** * Build what amounts to an epsilon transition with an action. The action goes into ATN though it * is ignored during prediction if actionIndex < 0. Only forced are executed during prediction. */ public Handle action(ActionAST action) { // System.out.println("action: "+action); ATNState left = newState(action); ATNState right = newState(action); ActionTransition a = new ActionTransition(right, currentRule.index); left.addTransition(a); action.atnState = left; return new Handle(left, right); }
public void addRuleFollowLinks() { for (ATNState p : atn.states) { if (p != null && p.getStateType() == ATNState.BASIC && p.getNumberOfTransitions() == 1 && p.transition(0) instanceof RuleTransition) { RuleTransition rt = (RuleTransition) p.transition(0); addFollowLink(rt.ruleIndex, rt.followState); } } }
/** * Build what amounts to an epsilon transition with a semantic predicate action. The pred is a * pointer into the AST of the SEMPRED token. */ public Handle sempred(PredAST pred) { // System.out.println("sempred: "+ pred); ATNState left = newState(pred); ATNState right = newState(pred); boolean isCtxDependent = UseDefAnalyzer.actionIsContextDependent(pred); PredicateTransition p = new PredicateTransition(right, currentRule.index, g.sempreds.get(pred), isCtxDependent); left.addTransition(p); pred.atnState = left; return new Handle(left, right); }
@Override public Handle tokenRef(TerminalAST node) { // Ref to EOF in lexer yields char transition on -1 if (node.getText().equals("EOF")) { ATNState left = newState(node); ATNState right = newState(node); left.addTransition(new AtomTransition(right, IntStream.EOF)); return new Handle(left, right); } return _ruleRef(node); }
@Override public Handle range(GrammarAST a, GrammarAST b) { ATNState left = newState(a); ATNState right = newState(b); int t1 = CharSupport.getCharValueFromGrammarCharLiteral(a.getText()); int t2 = CharSupport.getCharValueFromGrammarCharLiteral(b.getText()); left.addTransition(new RangeTransition(right, t1, t2)); a.atnState = left; b.atnState = left; return new Handle(left, right); }
/** * Add an EOF transition to any rule end ATNState that points to nothing (i.e., for all those * rules not invoked by another rule). These are start symbols then. * * <p>Return the number of grammar entry points; i.e., how many rules are not invoked by another * rule (they can only be invoked from outside). These are the start rules. */ public int addEOFTransitionToStartRules() { int n = 0; ATNState eofTarget = newState(null); // one unique EOF target for all rules for (Rule r : g.rules.values()) { ATNState stop = atn.ruleToStopState[r.index]; if (stop.getNumberOfTransitions() > 0) continue; n++; Transition t = new AtomTransition(eofTarget, Token.EOF); stop.addTransition(t); } return n; }
protected Handle action(GrammarAST node, LexerAction lexerAction) { ATNState left = newState(node); ATNState right = newState(node); boolean isCtxDependent = false; int lexerActionIndex = getLexerActionIndex(lexerAction); ActionTransition a = new ActionTransition(right, currentRule.index, lexerActionIndex, isCtxDependent); left.addTransition(a); node.atnState = left; Handle h = new Handle(left, right); return h; }
public Handle _ruleRef(GrammarAST node) { Rule r = g.getRule(node.getText()); if (r == null) { g.tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, "Rule " + node.getText() + " undefined"); return null; } RuleStartState start = atn.ruleToStartState[r.index]; ATNState left = newState(node); ATNState right = newState(node); RuleTransition call = new RuleTransition(start, r.index, right); left.addTransition(call); node.atnState = left; return new Handle(left, right); }
/** * For a lexer, a string is a sequence of char to match. That is, "fog" is treated as 'f' 'o' 'g' * not as a single transition in the DFA. Machine== o-'f'->o-'o'->o-'g'->o and has n+1 * states for n characters. */ @Override public Handle stringLiteral(TerminalAST stringLiteralAST) { String chars = stringLiteralAST.getText(); chars = CharSupport.getStringFromGrammarStringLiteral(chars); int n = chars.length(); ATNState left = newState(stringLiteralAST); ATNState prev = left; ATNState right = null; for (int i = 0; i < n; i++) { right = newState(stringLiteralAST); prev.addTransition(new AtomTransition(right, chars.charAt(i))); prev = right; } stringLiteralAST.atnState = left; return new Handle(left, right); }
/** * From set build single edge graph o->o-set->o. To conform to what an alt block looks like, must * have extra state on left. This handles ~A also, converted to ~{A} set. */ public Handle set(GrammarAST associatedAST, List<GrammarAST> terminals, boolean invert) { ATNState left = newState(associatedAST); ATNState right = newState(associatedAST); IntervalSet set = new IntervalSet(); for (GrammarAST t : terminals) { int ttype = g.getTokenType(t.getText()); set.add(ttype); } if (invert) { IntervalSet notSet = set.complement(Token.MIN_TOKEN_TYPE, g.getMaxTokenType()); left.addTransition(new NotSetTransition(right, set, notSet)); } else { left.addTransition(new SetTransition(right, set)); } associatedAST.atnState = left; return new Handle(left, right); }
/** * From set build single edge graph {@code o->o-set->o}. To conform to what an alt block looks * like, must have extra state on left. This also handles {@code ~A}, converted to {@code ~{A}} * set. */ @NotNull @Override public Handle set( @NotNull GrammarAST associatedAST, @NotNull List<GrammarAST> terminals, boolean invert) { ATNState left = newState(associatedAST); ATNState right = newState(associatedAST); IntervalSet set = new IntervalSet(); for (GrammarAST t : terminals) { int ttype = g.getTokenType(t.getText()); set.add(ttype); } if (invert) { left.addTransition(new NotSetTransition(right, set)); } else { left.addTransition(new SetTransition(right, set)); } associatedAST.atnState = left; return new Handle(left, right); }
List<ANTLRMessage> checkRuleDFA(String gtext, String ruleName, String expecting) throws Exception { ErrorQueue equeue = new ErrorQueue(); Grammar g = new Grammar(gtext, equeue); ATN atn = createATN(g); ATNState s = atn.ruleToStartState[g.getRule(ruleName).index]; if (s == null) { System.err.println("no such rule: " + ruleName); return null; } ATNState t = s.transition(0).target; if (!(t instanceof DecisionState)) { System.out.println(ruleName + " has no decision"); return null; } DecisionState blk = (DecisionState) t; checkRuleDFA(g, blk, expecting); return equeue.all; }
@Override public Handle set(GrammarAST associatedAST, List<GrammarAST> alts, boolean invert) { ATNState left = newState(associatedAST); ATNState right = newState(associatedAST); IntervalSet set = new IntervalSet(); for (GrammarAST t : alts) { if (t.getType() == ANTLRParser.RANGE) { int a = CharSupport.getCharValueFromGrammarCharLiteral(t.getChild(0).getText()); int b = CharSupport.getCharValueFromGrammarCharLiteral(t.getChild(1).getText()); set.add(a, b); } else if (t.getType() == ANTLRParser.LEXER_CHAR_SET) { set.addAll(getSetFromCharSetLiteral(t)); } else if (t.getType() == ANTLRParser.STRING_LITERAL) { int c = CharSupport.getCharValueFromGrammarCharLiteral(t.getText()); if (c != -1) { set.add(c); } else { g.tool.errMgr.grammarError( ErrorType.INVALID_LITERAL_IN_LEXER_SET, g.fileName, t.getToken(), t.getText()); } } else if (t.getType() == ANTLRParser.TOKEN_REF) { g.tool.errMgr.grammarError( ErrorType.UNSUPPORTED_REFERENCE_IN_LEXER_SET, g.fileName, t.getToken(), t.getText()); } } if (invert) { left.addTransition(new NotSetTransition(right, set)); } else { Transition transition; if (set.getIntervals().size() == 1) { Interval interval = set.getIntervals().get(0); transition = new RangeTransition(right, interval.a, interval.b); } else { transition = new SetTransition(right, set); } left.addTransition(transition); } associatedAST.atnState = left; return new Handle(left, right); }
/** * Build what amounts to an epsilon transition with a semantic predicate action. The {@code pred} * is a pointer into the AST of the {@link ANTLRParser#SEMPRED} token. */ @Override public Handle sempred(PredAST pred) { // System.out.println("sempred: "+ pred); ATNState left = newState(pred); ATNState right = newState(pred); AbstractPredicateTransition p; if (pred.getOptionString(LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME) != null) { int precedence = Integer.parseInt( pred.getOptionString(LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME)); p = new PrecedencePredicateTransition(right, precedence); } else { boolean isCtxDependent = UseDefAnalyzer.actionIsContextDependent(pred); p = new PredicateTransition(right, currentRule.index, g.sempreds.get(pred), isCtxDependent); } left.addTransition(p); pred.atnState = left; return new Handle(left, right); }
@Override public void visitState(ATNState p) { if (p.getClass() == ATNState.class && p.getNumberOfTransitions() == 1) { ATNState q = p.transition(0).target; if (p.transition(0) instanceof RuleTransition) { q = ((RuleTransition) p.transition(0)).followState; } if (q.getClass() == ATNState.class) { // we have p-x->q for x in {rule, action, pred, token, ...} // if edge out of q is single epsilon to block end // we can strip epsilon p-x->q-eps->r Transition trans = q.transition(0); if (q.getNumberOfTransitions() == 1 && trans.isEpsilon() && !(trans instanceof ActionTransition)) { ATNState r = trans.target; if (r instanceof BlockEndState || r instanceof PlusLoopbackState || r instanceof StarLoopbackState) { // skip over q if (p.transition(0) instanceof RuleTransition) { ((RuleTransition) p.transition(0)).followState = r; } else { p.transition(0).target = r; } atn.removeState(q); } } } } }
void epsilon(ATNState a, @NotNull ATNState b) { if (a != null) a.addTransition(new EpsilonTransition(b)); }
protected void epsilon(ATNState a, @NotNull ATNState b, boolean prepend) { if (a != null) { int index = prepend ? 0 : a.getNumberOfTransitions(); a.addTransition(index, new EpsilonTransition(b)); } }