/** * From (blk)+ build * * <p>|---------| v | [o-blk-o]->o->o * * <p>We add a decision for loop back node to the existing one at blk start. */ @NotNull public Handle plus(@NotNull GrammarAST plusAST, @NotNull Handle blk) { PlusBlockStartState blkStart = (PlusBlockStartState) blk.left; BlockEndState blkEnd = (BlockEndState) blk.right; PlusLoopbackState loop = newState(PlusLoopbackState.class, plusAST); atn.defineDecisionState(loop); LoopEndState end = newState(LoopEndState.class, plusAST); blkStart.loopBackState = loop; end.loopBackStateNumber = loop.stateNumber; plusAST.atnState = blkStart; epsilon(blkEnd, loop); // blk can see loop back BlockAST blkAST = (BlockAST) plusAST.getChild(0); loop.isGreedy = isGreedy(blkAST); if (!g.isLexer() || loop.isGreedy) { epsilon(loop, blkStart); // loop back to start epsilon(loop, end); // or exit } else { // only lexers flip entry/exit branches for nongreedy // if not greedy, priority to exit branch; make it first epsilon(loop, end); // exit epsilon(loop, blkStart); // loop back to start } return new Handle(blkStart, end); }
/** * From {@code (blk)+} build * * <pre> * |---------| * v | * [o-blk-o]->o->o * </pre> * * We add a decision for loop back node to the existing one at {@code blk} start. */ @NotNull @Override public Handle plus(@NotNull GrammarAST plusAST, @NotNull Handle blk) { PlusBlockStartState blkStart = (PlusBlockStartState) blk.left; BlockEndState blkEnd = (BlockEndState) blk.right; preventEpsilonClosureBlocks.add( new Triple<Rule, ATNState, ATNState>(currentRule, blkStart, blkEnd)); PlusLoopbackState loop = newState(PlusLoopbackState.class, plusAST); loop.nonGreedy = !((QuantifierAST) plusAST).isGreedy(); atn.defineDecisionState(loop); LoopEndState end = newState(LoopEndState.class, plusAST); blkStart.loopBackState = loop; end.loopBackState = loop; plusAST.atnState = blkStart; epsilon(blkEnd, loop); // blk can see loop back BlockAST blkAST = (BlockAST) plusAST.getChild(0); if (((QuantifierAST) plusAST).isGreedy()) { if (expectNonGreedy(blkAST)) { g.tool.errMgr.grammarError( ErrorType.EXPECTED_NON_GREEDY_WILDCARD_BLOCK, g.fileName, plusAST.getToken(), plusAST.getToken().getText()); } epsilon(loop, blkStart); // loop back to start epsilon(loop, end); // or exit } else { // if not greedy, priority to exit branch; make it first epsilon(loop, end); // exit epsilon(loop, blkStart); // loop back to start } return new Handle(blkStart, end); }