execATN method

int execATN(
  1. CharStream input,
  2. DFAState ds0
)

Implementation

int execATN(CharStream input, DFAState ds0) {
  //log("enter exec index "+input.index()+" from "+ds0.configs, level: Level.FINE.value);
  if (debug) {
    log('start state closure=${ds0.configs}\n', level: Level.FINE.value);
  }

  if (ds0.isAcceptState) {
    // allow zero-length tokens
    captureSimState(prevAccept, input, ds0);
  }

  var t = input.LA(1)!;

  var s = ds0; // s is current/from DFA state

  while (true) {
    // while more work
    if (debug) {
      log('execATN loop starting closure: ${s.configs}\n',
          level: Level.FINE.value);
    }

    // As we move src->trg, src->trg, we keep track of the previous trg to
    // avoid looking up the DFA state again, which is expensive.
    // If the previous target was already part of the DFA, we might
    // be able to avoid doing a reach operation upon t. If s!=null,
    // it means that semantic predicates didn't prevent us from
    // creating a DFA state. Once we know s!=null, we check to see if
    // the DFA state has an edge already for t. If so, we can just reuse
    // it's configuration set; there's no point in re-computing it.
    // This is kind of like doing DFA simulation within the ATN
    // simulation because DFA simulation is really just a way to avoid
    // computing reach/closure sets. Technically, once we know that
    // we have a previously added DFA state, we could jump over to
    // the DFA simulator. But, that would mean popping back and forth
    // a lot and making things more complicated algorithmically.
    // This optimization makes a lot of sense for loops within DFA.
    // A character will take us back to an existing DFA state
    // that already has lots of edges out of it. e.g., .* in comments.
    var target = getExistingTargetState(s, t);
    target ??= computeTargetState(input, s, t);

    if (target == ATNSimulator.ERROR) {
      break;
    }

    // If this is a consumable input element, make sure to consume before
    // capturing the accept state so the input index, line, and char
    // position accurately reflect the state of the interpreter at the
    // end of the token.
    if (t != IntStream.EOF) {
      consume(input);
    }

    if (target.isAcceptState) {
      captureSimState(prevAccept, input, target);
      if (t == IntStream.EOF) {
        break;
      }
    }

    t = input.LA(1)!;
    s = target; // flip; current DFA target becomes new src/from state
  }

  return failOrAccept(prevAccept, input, s.configs, t);
}