@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); } } } } }
@NotNull public Handle elemList(@NotNull List<Handle> els) { int n = els.size(); for (int i = 0; i < n - 1; i++) { // hook up elements (visit all but last) Handle el = els.get(i); // if el is of form o-x->o for x in {rule, action, pred, token, ...} // and not last in alt Transition tr = null; if (el.left.getNumberOfTransitions() == 1) tr = el.left.transition(0); boolean isRuleTrans = tr instanceof RuleTransition; if (el.left.getClass() == ATNState.class && el.right.getClass() == ATNState.class && tr != null && (isRuleTrans || tr.target == el.right)) { // we can avoid epsilon edge to next el if (isRuleTrans) ((RuleTransition) tr).followState = els.get(i + 1).left; else tr.target = els.get(i + 1).left; atn.removeState(el.right); // we skipped over this state } else { // need epsilon if previous block's right end node is complicated epsilon(el.right, els.get(i + 1).left); } } Handle first = els.get(0); Handle last = els.get(n - 1); if (first == null || last == null) { g.tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, "element list has first|last == null"); } return new Handle(first.left, last.right); }