/** * From (blk)* build ( blk+ )? with *two* decisions, one for entry and one for choosing alts of * blk. * * <p>|-------------| v | o--[o-blk-o]->o o | ^ -----------------| * * <p>Note that the optional bypass must jump outside the loop as (A|B)* is not the same thing as * (A|B|)+. */ @NotNull public Handle star(@NotNull GrammarAST starAST, @NotNull Handle elem) { StarBlockStartState blkStart = (StarBlockStartState) elem.left; BlockEndState blkEnd = (BlockEndState) elem.right; StarLoopEntryState entry = newState(StarLoopEntryState.class, starAST); atn.defineDecisionState(entry); LoopEndState end = newState(LoopEndState.class, starAST); StarLoopbackState loop = newState(StarLoopbackState.class, starAST); entry.loopBackState = loop; end.loopBackStateNumber = loop.stateNumber; BlockAST blkAST = (BlockAST) starAST.getChild(0); entry.isGreedy = isGreedy(blkAST); if (!g.isLexer() || entry.isGreedy) { epsilon(entry, blkStart); // loop enter edge (alt 1) epsilon(entry, end); // bypass loop edge (alt 2) } else { // only lexers flip entry/exit branches for nongreedy // if not greedy, priority to exit branch; make it first epsilon(entry, end); // bypass loop edge (alt 1) epsilon(entry, blkStart); // loop enter edge (alt 2) } epsilon(blkEnd, loop); // block end hits loop back epsilon(loop, entry); // loop back to entry/exit decision starAST.atnState = entry; // decision is to enter/exit; blk is its own decision return new Handle(entry, end); }
/** * 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); }