protected int ExecATN(ICharStream input, DFAState ds0)
{
//System.out.println("enter exec index "+input.index()+" from "+ds0.configs);
if (debug)
{
Console.WriteLine("start state closure=" + ds0.configSet);
}
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)
{
Console.WriteLine("execATN loop starting closure: " + s.configSet);
}
// 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 != IntStreamConstants.EOF)
{
Consume(input);
}
if (target.isAcceptState)
{
CaptureSimState(prevAccept, input, target);
if (t == IntStreamConstants.EOF)
{
break;
}
}
t = input.LA(1);
s = target; // flip; current DFA target becomes new src/from state
}
return FailOrAccept(prevAccept, input, s.configSet, t);
}