protected void ClosureCheckingStopState(ATNConfig config,
ATNConfigSet configSet,
HashSet<ATNConfig> closureBusy,
bool collectPredicates,
bool fullCtx,
int depth,
bool treatEofAsEpsilon)
{
if (debug)
Console.WriteLine("closure(" + config.ToString(parser, true) + ")");
if (config.state is RuleStopState)
{
// We hit rule end. If we have context info, use it
// run thru all possible stack tops in ctx
if (!config.context.IsEmpty)
{
for (int i = 0; i < config.context.Size; i++)
{
if (config.context.GetReturnState(i) == PredictionContext.EMPTY_RETURN_STATE)
{
if (fullCtx)
{
configSet.Add(new ATNConfig(config, config.state, PredictionContext.EMPTY), mergeCache);
continue;
}
else {
// we have no context info, just chase follow links (if greedy)
if (debug) Console.WriteLine("FALLING off rule " +
GetRuleName(config.state.ruleIndex));
Closure_(config, configSet, closureBusy, collectPredicates,
fullCtx, depth, treatEofAsEpsilon);
}
continue;
}
ATNState returnState = atn.states[config.context.GetReturnState(i)];
PredictionContext newContext = config.context.GetParent(i); // "pop" return state
ATNConfig c = new ATNConfig(returnState, config.alt, newContext, config.semanticContext);
// While we have context to pop back from, we may have
// gotten that context AFTER having falling off a rule.
// Make sure we track that we are now out of context.
//
// This assignment also propagates the
// isPrecedenceFilterSuppressed() value to the new
// configuration.
c.reachesIntoOuterContext = config.OuterContextDepth;
ClosureCheckingStopState(c, configSet, closureBusy, collectPredicates,
fullCtx, depth - 1, treatEofAsEpsilon);
}
return;
}
else if (fullCtx)
{
// reached end of start rule
configSet.Add(config, mergeCache);
return;
}
else {
// else if we have no context info, just chase follow links (if greedy)
if (debug) Console.WriteLine("FALLING off rule " +
GetRuleName(config.state.ruleIndex));
}
}
Closure_(config, configSet, closureBusy, collectPredicates,
fullCtx, depth, treatEofAsEpsilon);
}