protected int execATN(CharStream input, DFAState ds0) {
		//System.out.println("enter exec index "+input.index()+" from "+ds0.configs);
		if ( debug ) {
			System.out.format(Locale.getDefault(), "start state closure=%s\n", ds0.configs);
		}

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

		int t = input.LA(1);

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

		while ( true ) { // while more work
			if ( debug ) {
				System.out.format(Locale.getDefault(), "execATN loop starting closure: %s\n", s.configs);
			}

			// 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.
			DFAState target = getExistingTargetState(s, t);
			if (target == null) {
				target = computeTargetState(input, s, t);
			}

			if (target == 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);
	}
Used during DFA/ATN exec to record the most recent accept configuration info
runtime/Java/src/org/antlr/v4/runtime/atn/LexerATNSimulator.java