use of org.antlr.v4.tool.Rule in project antlr4 by tunnelvisionlabs.
the class StructDecl method addDispatchMethods.
public void addDispatchMethods(Rule r) {
dispatchMethods = new ArrayList<DispatchMethod>();
if (!r.hasAltSpecificContexts()) {
// no enter/exit for this ruleContext if rule has labels
if (factory.getGrammar().tool.gen_listener) {
dispatchMethods.add(new ListenerDispatchMethod(factory, true));
dispatchMethods.add(new ListenerDispatchMethod(factory, false));
}
if (factory.getGrammar().tool.gen_visitor) {
dispatchMethods.add(new VisitorDispatchMethod(factory));
}
}
}
use of org.antlr.v4.tool.Rule in project antlr4 by tunnelvisionlabs.
the class ParserATNSimulator method execATN.
/**
* Performs ATN simulation to compute a predicted alternative based
* upon the remaining input, but also updates the DFA cache to avoid
* having to traverse the ATN again for the same input sequence.
*
* There are some key conditions we're looking for after computing a new
* set of ATN configs (proposed DFA state):
* if the set is empty, there is no viable alternative for current symbol
* does the state uniquely predict an alternative?
* does the state have a conflict that would prevent us from
* putting it on the work list?
* if in non-greedy decision is there a config at a rule stop state?
*
* We also have some key operations to do:
* add an edge from previous DFA state to potentially new DFA state, D,
* upon current symbol but only if adding to work list, which means in all
* cases except no viable alternative (and possibly non-greedy decisions?)
* collecting predicates and adding semantic context to DFA accept states
* adding rule context to context-sensitive DFA accept states
* consuming an input symbol
* reporting a conflict
* reporting an ambiguity
* reporting a context sensitivity
* reporting insufficient predicates
*
* We should isolate those operations, which are side-effecting, to the
* main work loop. We can isolate lots of code into other functions, but
* they should be side effect free. They can return package that
* indicates whether we should report something, whether we need to add a
* DFA edge, whether we need to augment accept state with semantic
* context or rule invocation context. Actually, it seems like we always
* add predicates if they exist, so that can simply be done in the main
* loop for any accept state creation or modification request.
*
* cover these cases:
* dead end
* single alt
* single alt + preds
* conflict
* conflict + preds
*
* TODO: greedy + those
*/
protected int execATN(@NotNull DFA dfa, @NotNull TokenStream input, int startIndex, @NotNull SimulatorState initialState) {
if (debug)
System.out.println("execATN decision " + dfa.decision + " exec LA(1)==" + getLookaheadName(input));
final ParserRuleContext outerContext = initialState.outerContext;
final boolean useContext = initialState.useContext;
int t = input.LA(1);
SimulatorState previous = initialState;
PredictionContextCache contextCache = new PredictionContextCache();
while (true) {
// while more work
SimulatorState nextState = computeReachSet(dfa, previous, t, contextCache);
if (nextState == null) {
addDFAEdge(previous.s0, input.LA(1), ERROR);
return handleNoViableAlt(input, startIndex, previous);
}
DFAState D = nextState.s0;
// predicted alt => accept state
assert D.isAcceptState() || D.getPrediction() == ATN.INVALID_ALT_NUMBER;
// conflicted => accept state
assert D.isAcceptState() || D.configs.getConflictInfo() == null;
if (isAcceptState(D, useContext)) {
BitSet conflictingAlts = D.configs.getConflictingAlts();
int predictedAlt = conflictingAlts == null ? D.getPrediction() : ATN.INVALID_ALT_NUMBER;
if (predictedAlt != ATN.INVALID_ALT_NUMBER) {
if (optimize_ll1 && input.index() == startIndex && !dfa.isPrecedenceDfa() && nextState.outerContext == nextState.remainingOuterContext && dfa.decision >= 0 && !D.configs.hasSemanticContext()) {
if (t >= 0 && t <= Short.MAX_VALUE) {
int key = (dfa.decision << 16) + t;
atn.LL1Table.put(key, predictedAlt);
}
}
if (useContext && always_try_local_context) {
reportContextSensitivity(dfa, predictedAlt, nextState, startIndex, input.index());
}
}
predictedAlt = D.getPrediction();
// int k = input.index() - startIndex + 1; // how much input we used
// System.out.println("used k="+k);
boolean attemptFullContext = conflictingAlts != null && userWantsCtxSensitive;
if (attemptFullContext) {
// Only exact conflicts are known to be ambiguous when local
// prediction does not step out of the decision rule.
attemptFullContext = !useContext && (D.configs.getDipsIntoOuterContext() || !D.configs.isExactConflict()) && (!treat_sllk1_conflict_as_ambiguity || input.index() != startIndex);
}
if (D.configs.hasSemanticContext()) {
DFAState.PredPrediction[] predPredictions = D.predicates;
if (predPredictions != null) {
int conflictIndex = input.index();
if (conflictIndex != startIndex) {
input.seek(startIndex);
}
// use complete evaluation here if we'll want to retry with full context if still ambiguous
conflictingAlts = evalSemanticContext(predPredictions, outerContext, attemptFullContext || reportAmbiguities);
switch(conflictingAlts.cardinality()) {
case 0:
throw noViableAlt(input, outerContext, D.configs, startIndex);
case 1:
return conflictingAlts.nextSetBit(0);
default:
break;
}
if (conflictIndex != startIndex) {
// restore the index so reporting the fallback to full
// context occurs with the index at the correct spot
input.seek(conflictIndex);
}
}
}
if (!attemptFullContext) {
if (conflictingAlts != null) {
if (reportAmbiguities && conflictingAlts.cardinality() > 1) {
reportAmbiguity(dfa, D, startIndex, input.index(), D.configs.isExactConflict(), conflictingAlts, D.configs);
}
predictedAlt = conflictingAlts.nextSetBit(0);
}
return predictedAlt;
} else {
assert !useContext;
assert isAcceptState(D, false);
if (debug)
System.out.println("RETRY with outerContext=" + outerContext);
SimulatorState fullContextState = computeStartState(dfa, outerContext, true);
if (reportAmbiguities) {
reportAttemptingFullContext(dfa, conflictingAlts, nextState, startIndex, input.index());
}
input.seek(startIndex);
return execATN(dfa, input, startIndex, fullContextState);
}
}
previous = nextState;
if (t != IntStream.EOF) {
input.consume();
t = input.LA(1);
}
}
}
use of org.antlr.v4.tool.Rule in project antlr4 by tunnelvisionlabs.
the class ParserATNSimulator method computeStartState.
@NotNull
protected SimulatorState computeStartState(DFA dfa, ParserRuleContext globalContext, boolean useContext) {
DFAState s0 = dfa.isPrecedenceDfa() ? dfa.getPrecedenceStartState(parser.getPrecedence(), useContext) : useContext ? dfa.s0full.get() : dfa.s0.get();
if (s0 != null) {
if (!useContext) {
return new SimulatorState(globalContext, s0, useContext, globalContext);
}
s0.setContextSensitive(atn);
}
final int decision = dfa.decision;
@NotNull final ATNState p = dfa.atnStartState;
int previousContext = 0;
ParserRuleContext remainingGlobalContext = globalContext;
// always at least the implicit call to start rule
PredictionContext initialContext = useContext ? PredictionContext.EMPTY_FULL : PredictionContext.EMPTY_LOCAL;
PredictionContextCache contextCache = new PredictionContextCache();
if (useContext) {
if (!enable_global_context_dfa) {
while (remainingGlobalContext != null) {
if (remainingGlobalContext.isEmpty()) {
previousContext = PredictionContext.EMPTY_FULL_STATE_KEY;
remainingGlobalContext = null;
} else {
previousContext = getReturnState(remainingGlobalContext);
initialContext = initialContext.appendContext(previousContext, contextCache);
remainingGlobalContext = remainingGlobalContext.getParent();
}
}
}
while (s0 != null && s0.isContextSensitive() && remainingGlobalContext != null) {
DFAState next;
remainingGlobalContext = skipTailCalls(remainingGlobalContext);
if (remainingGlobalContext.isEmpty()) {
next = s0.getContextTarget(PredictionContext.EMPTY_FULL_STATE_KEY);
previousContext = PredictionContext.EMPTY_FULL_STATE_KEY;
remainingGlobalContext = null;
} else {
previousContext = getReturnState(remainingGlobalContext);
next = s0.getContextTarget(previousContext);
initialContext = initialContext.appendContext(previousContext, contextCache);
remainingGlobalContext = remainingGlobalContext.getParent();
}
if (next == null) {
break;
}
s0 = next;
}
}
if (s0 != null && !s0.isContextSensitive()) {
return new SimulatorState(globalContext, s0, useContext, remainingGlobalContext);
}
ATNConfigSet configs = new ATNConfigSet();
while (true) {
ATNConfigSet reachIntermediate = new ATNConfigSet();
int n = p.getNumberOfTransitions();
for (int ti = 0; ti < n; ti++) {
// for each transition
ATNState target = p.transition(ti).target;
reachIntermediate.add(ATNConfig.create(target, ti + 1, initialContext));
}
boolean hasMoreContext = remainingGlobalContext != null;
if (!hasMoreContext) {
configs.setOutermostConfigSet(true);
}
final boolean collectPredicates = true;
closure(reachIntermediate, configs, collectPredicates, hasMoreContext, contextCache, false);
boolean stepIntoGlobal = configs.getDipsIntoOuterContext();
DFAState next;
if (useContext && !enable_global_context_dfa) {
s0 = addDFAState(dfa, configs, contextCache);
break;
} else if (s0 == null) {
if (!dfa.isPrecedenceDfa()) {
AtomicReference<DFAState> reference = useContext ? dfa.s0full : dfa.s0;
next = addDFAState(dfa, configs, contextCache);
if (!reference.compareAndSet(null, next)) {
next = reference.get();
}
} else {
/* If this is a precedence DFA, we use applyPrecedenceFilter
* to convert the computed start state to a precedence start
* state. We then use DFA.setPrecedenceStartState to set the
* appropriate start state for the precedence level rather
* than simply setting DFA.s0.
*/
configs = applyPrecedenceFilter(configs, globalContext, contextCache);
next = addDFAState(dfa, configs, contextCache);
dfa.setPrecedenceStartState(parser.getPrecedence(), useContext, next);
}
} else {
if (dfa.isPrecedenceDfa()) {
configs = applyPrecedenceFilter(configs, globalContext, contextCache);
}
next = addDFAState(dfa, configs, contextCache);
s0.setContextTarget(previousContext, next);
}
s0 = next;
if (!useContext || !stepIntoGlobal) {
break;
}
// TODO: make sure it distinguishes empty stack states
next.setContextSensitive(atn);
configs.clear();
remainingGlobalContext = skipTailCalls(remainingGlobalContext);
int nextContextElement = getReturnState(remainingGlobalContext);
if (remainingGlobalContext.isEmpty()) {
remainingGlobalContext = null;
} else {
remainingGlobalContext = remainingGlobalContext.getParent();
}
if (nextContextElement != PredictionContext.EMPTY_FULL_STATE_KEY) {
initialContext = initialContext.appendContext(nextContextElement, contextCache);
}
previousContext = nextContextElement;
}
return new SimulatorState(globalContext, s0, useContext, remainingGlobalContext);
}
use of org.antlr.v4.tool.Rule in project antlr4 by tunnelvisionlabs.
the class Parser method triggerEnterRuleEvent.
/**
* Notify any parse listeners of an enter rule event.
*
* @see #addParseListener
*/
protected void triggerEnterRuleEvent() {
for (ParseTreeListener listener : _parseListeners) {
listener.enterEveryRule(_ctx);
_ctx.enterRule(listener);
}
}
use of org.antlr.v4.tool.Rule in project antlr4 by tunnelvisionlabs.
the class ParserRuleContext method copyFrom.
/**
* COPY a ctx (I'm deliberately not using copy constructor) to avoid
* confusion with creating node with parent. Does not copy children
* (except error leaves).
*
* <p>This is used in the generated parser code to flip a generic XContext
* node for rule X to a YContext for alt label Y. In that sense, it is not
* really a generic copy function.</p>
*
* <p>If we do an error sync() at start of a rule, we might add error nodes
* to the generic XContext so this function must copy those nodes to the
* YContext as well else they are lost!</p>
*/
public void copyFrom(ParserRuleContext ctx) {
this.parent = ctx.parent;
this.invokingState = ctx.invokingState;
this.start = ctx.start;
this.stop = ctx.stop;
// copy any error nodes to alt label node
if (ctx.children != null) {
this.children = new ArrayList<ParseTree>();
// reset parent pointer for any error nodes
for (ParseTree child : ctx.children) {
if (child instanceof ErrorNodeImpl) {
((ErrorNodeImpl) child).setParent(this);
}
addAnyChild(child);
}
}
}
Aggregations