/** * From {@code A|B|..|Z} alternative block build * * <pre> * o->o-A->o->o (last ATNState is BlockEndState pointed to by all alts) * | ^ * |->o-B->o--| * | | * ... | * | | * |->o-Z->o--| * </pre> * * So start node points at every alternative with epsilon transition and every alt right side * points at a block end ATNState. * * <p>Special case: only one alternative: don't make a block with alt begin/end. * * <p>Special case: if just a list of tokens/chars/sets, then collapse to a single edged o-set->o * graph. * * <p>TODO: Set alt number (1..n) in the states? */ @NotNull @Override public Handle block( @NotNull BlockAST blkAST, @NotNull GrammarAST ebnfRoot, @NotNull List<Handle> alts) { if (ebnfRoot == null) { if (alts.size() == 1) { Handle h = alts.get(0); blkAST.atnState = h.left; return h; } BlockStartState start = newState(BasicBlockStartState.class, blkAST); if (alts.size() > 1) atn.defineDecisionState(start); return makeBlock(start, blkAST, alts); } switch (ebnfRoot.getType()) { case ANTLRParser.OPTIONAL: BlockStartState start = newState(BasicBlockStartState.class, blkAST); atn.defineDecisionState(start); Handle h = makeBlock(start, blkAST, alts); return optional(ebnfRoot, h); case ANTLRParser.CLOSURE: BlockStartState star = newState(StarBlockStartState.class, ebnfRoot); if (alts.size() > 1) atn.defineDecisionState(star); h = makeBlock(star, blkAST, alts); return star(ebnfRoot, h); case ANTLRParser.POSITIVE_CLOSURE: PlusBlockStartState plus = newState(PlusBlockStartState.class, ebnfRoot); if (alts.size() > 1) atn.defineDecisionState(plus); h = makeBlock(plus, blkAST, alts); return plus(ebnfRoot, h); } return null; }
protected Handle makeBlock(BlockStartState start, BlockAST blkAST, List<Handle> alts) { BlockEndState end = newState(BlockEndState.class, blkAST); start.endState = end; for (Handle alt : alts) { // hook alts up to decision block epsilon(start, alt.left); epsilon(alt.right, end); // no back link in ATN so must walk entire alt to see if we can // strip out the epsilon to 'end' state TailEpsilonRemover opt = new TailEpsilonRemover(atn); opt.visit(alt.left); } Handle h = new Handle(start, end); // FASerializer ser = new FASerializer(g, h.left); // System.out.println(blkAST.toStringTree()+":\n"+ser); blkAST.atnState = start; return h; }