Beispiel #1
0
  /**
   * 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);
  }
Beispiel #2
0
 /* start->ruleblock->end */
 public Handle rule(GrammarAST ruleAST, String name, Handle blk) {
   Rule r = g.getRule(name);
   RuleStartState start = atn.ruleToStartState[r.index];
   epsilon(start, blk.left);
   RuleStopState stop = atn.ruleToStopState[r.index];
   epsilon(blk.right, stop);
   Handle h = new Handle(start, stop);
   //		ATNPrinter ser = new ATNPrinter(g, h.left);
   //		System.out.println(ruleAST.toStringTree()+":\n"+ser.asString());
   ruleAST.atnState = start;
   return h;
 }
 @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.getStateType() == ATNState.BASIC
         && el.right.getStateType() == ATNState.BASIC
         && tr != null
         && (isRuleTrans && ((RuleTransition) tr).followState == el.right
             || 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);
 }
Beispiel #4
0
 /** From an empty alternative build o-e->o */
 public Handle epsilon(GrammarAST node) {
   ATNState left = newState(node);
   ATNState right = newState(node);
   epsilon(left, right);
   node.atnState = left;
   return new Handle(left, right);
 }
Beispiel #5
0
 /**
  * From (A)? build either:
  *
  * <p>o--A->o | ^ o---->|
  *
  * <p>or, if A is a block, just add an empty alt to the end of the block
  */
 @NotNull
 public Handle optional(@NotNull GrammarAST optAST, @NotNull Handle blk) {
   // TODO: no such thing as nongreedy ()? so give error
   BlockStartState blkStart = (BlockStartState) blk.left;
   epsilon(blkStart, blk.right);
   optAST.atnState = blk.left;
   return blk;
 }
Beispiel #6
0
 protected Handle makeBlock(BlockStartState start, GrammarAST 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();
     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;
 }
Beispiel #7
0
  /**
   * 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 {@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);
  }
  /**
   * From {@code (A)?} build either:
   *
   * <pre>
   *  o--A-&gt;o
   *  |     ^
   *  o----&gt;|
   * </pre>
   *
   * or, if {@code A} is a block, just add an empty alt to the end of the block
   */
  @Override
  public Handle optional(GrammarAST optAST, Handle blk) {
    BlockStartState blkStart = (BlockStartState) blk.left;
    ATNState blkEnd = blk.right;
    preventEpsilonOptionalBlocks.add(
        new Triple<Rule, ATNState, ATNState>(currentRule, blkStart, blkEnd));

    boolean greedy = ((QuantifierAST) optAST).isGreedy();
    blkStart.nonGreedy = !greedy;
    epsilon(blkStart, blk.right, !greedy);

    optAST.atnState = blk.left;
    return blk;
  }
  /**
   * From {@code (blk)*} build {@code ( blk+ )?} with *two* decisions, one for entry and one for
   * choosing alts of {@code blk}.
   *
   * <pre>
   *   |-------------|
   *   v             |
   *   o--[o-blk-o]->o  o
   *   |                ^
   *   -----------------|
   * </pre>
   *
   * Note that the optional bypass must jump outside the loop as {@code (A|B)*} is not the same
   * thing as {@code (A|B|)+}.
   */
  @NotNull
  @Override
  public Handle star(@NotNull GrammarAST starAST, @NotNull Handle elem) {
    StarBlockStartState blkStart = (StarBlockStartState) elem.left;
    BlockEndState blkEnd = (BlockEndState) elem.right;
    preventEpsilonClosureBlocks.add(
        new Triple<Rule, ATNState, ATNState>(currentRule, blkStart, blkEnd));

    StarLoopEntryState entry = newState(StarLoopEntryState.class, starAST);
    entry.nonGreedy = !((QuantifierAST) starAST).isGreedy();
    atn.defineDecisionState(entry);
    LoopEndState end = newState(LoopEndState.class, starAST);
    StarLoopbackState loop = newState(StarLoopbackState.class, starAST);
    entry.loopBackState = loop;
    end.loopBackState = loop;

    BlockAST blkAST = (BlockAST) starAST.getChild(0);
    if (((QuantifierAST) starAST).isGreedy()) {
      if (expectNonGreedy(blkAST)) {
        g.tool.errMgr.grammarError(
            ErrorType.EXPECTED_NON_GREEDY_WILDCARD_BLOCK,
            g.fileName,
            starAST.getToken(),
            starAST.getToken().getText());
      }

      epsilon(entry, blkStart); // loop enter edge (alt 1)
      epsilon(entry, end); // bypass loop edge (alt 2)
    } else {
      // 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);
  }
 protected void epsilon(ATNState a, @NotNull ATNState b) {
   epsilon(a, b, false);
 }
 public void addFollowLink(int ruleIndex, ATNState right) {
   // add follow edge from end of invoked rule
   RuleStopState stop = atn.ruleToStopState[ruleIndex];
   //        System.out.println("add follow link from "+ruleIndex+" to "+right);
   epsilon(stop, right);
 }
 protected void epsilon(ATNState a, ATNState b) {
   epsilon(a, b, false);
 }