From 780b7ac4ce934cbb1aea602f82d295a52f9717eb Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Sat, 1 Jun 2013 21:54:24 -0500 Subject: [PATCH] Document ANTLRErrorListener and DiagnosticErrorListener (fixes #265) --- .../antlr/v4/runtime/ANTLRErrorListener.java | 112 ++++++++++++++---- .../v4/runtime/DiagnosticErrorListener.java | 63 ++++++++-- .../antlr/v4/runtime/ProxyErrorListener.java | 8 ++ 3 files changed, 154 insertions(+), 29 deletions(-) diff --git a/runtime/Java/src/org/antlr/v4/runtime/ANTLRErrorListener.java b/runtime/Java/src/org/antlr/v4/runtime/ANTLRErrorListener.java index 564b2f328..c38d9dc97 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/ANTLRErrorListener.java +++ b/runtime/Java/src/org/antlr/v4/runtime/ANTLRErrorListener.java @@ -31,6 +31,8 @@ package org.antlr.v4.runtime; import org.antlr.v4.runtime.atn.ATNConfigSet; +import org.antlr.v4.runtime.atn.ParserATNSimulator; +import org.antlr.v4.runtime.atn.PredictionMode; import org.antlr.v4.runtime.dfa.DFA; import org.antlr.v4.runtime.misc.NotNull; import org.antlr.v4.runtime.misc.Nullable; @@ -80,36 +82,102 @@ public interface ANTLRErrorListener { String msg, @Nullable RecognitionException e); - /** Called when the parser detects a true ambiguity: an input - * sequence can be matched literally by two or more pass through - * the grammar. ANTLR resolves the ambiguity in favor of the - * alternative appearing first in the grammar. The start and stop - * index are zero-based absolute indices into the token - * stream. ambigAlts is a set of alternative numbers that can - * match the input sequence. This method is only called when we - * are parsing with full context. - */ - void reportAmbiguity(@NotNull Parser recognizer, - DFA dfa, int startIndex, int stopIndex, + /** + * This method is called by the parser when a full-context prediction + * results in an ambiguity. + *

+ * When {@code exact} is {@code true}, all of the alternatives in + * {@code ambigAlts} are viable, i.e. this is reporting an exact ambiguity. + * When {@code exact} is {@code false}, at least two of the + * alternatives in {@code ambigAlts} are viable for the current input, but + * the prediction algorithm terminated as soon as it determined that at + * least the minimum alternative in {@code ambigAlts} is viable. + *

+ * When the {@link PredictionMode#LL_EXACT_AMBIG_DETECTION} prediction mode + * is used, the parser is required to identify exact ambiguities so + * {@code exact} will always be {@code true}. + *

+ * This method is not used by lexers. + * + * @param recognizer the parser instance + * @param dfa the DFA for the current decision + * @param startIndex the input index where the decision started + * @param stopIndex the input input where the ambiguity is reported + * @param exact {@code true} if the ambiguity is exactly known, otherwise + * {@code false}. This is always {@code true} when + * {@link PredictionMode#LL_EXACT_AMBIG_DETECTION} is used. + * @param ambigAlts the potentially ambiguous alternatives + * @param configs the ATN configuration set where the ambiguity was + * determined + */ + void reportAmbiguity(@NotNull Parser recognizer, + @NotNull DFA dfa, + int startIndex, + int stopIndex, boolean exact, @NotNull BitSet ambigAlts, @NotNull ATNConfigSet configs); + /** + * This method is called when an SLL conflict occurs and the parser is about + * to use the full context information to make an LL decision. + *

+ * If one or more configurations in {@code configs} contains a semantic + * predicate, the predicates are evaluated before this method is called. The + * subset of alternatives which are still viable after predicates are + * evaluated is reported in {@code conflictingAlts}. + *

+ * This method is not used by lexers. + * + * @param recognizer the parser instance + * @param dfa the DFA for the current decision + * @param startIndex the input index where the decision started + * @param stopIndex the input index where the SLL conflict occurred + * @param conflictingAlts The specific conflicting alternatives. If this is + * {@code null}, the conflicting alternatives are all alternatives + * represented in {@code configs}. + * @param configs the ATN configuration set where the SLL conflict was + * detected + */ void reportAttemptingFullContext(@NotNull Parser recognizer, @NotNull DFA dfa, - int startIndex, int stopIndex, + int startIndex, + int stopIndex, @Nullable BitSet conflictingAlts, @NotNull ATNConfigSet configs); - /** Called by the parser when it find a conflict that is resolved - * by retrying the parse with full context. This is not a - * warning; it simply notifies you that your grammar is more - * complicated than Strong LL can handle. The parser moved up to - * full context parsing for that input sequence. - */ - void reportContextSensitivity(@NotNull Parser recognizer, - @NotNull DFA dfa, - int startIndex, int stopIndex, + /** + * This method is called by the parser when a full-context prediction has a + * unique result. + *

+ * For prediction implementations that only evaluate full-context + * predictions when an SLL conflict is found (including the default + * {@link ParserATNSimulator} implementation), this method reports cases + * where SLL conflicts were resolved to unique full-context predictions, + * i.e. the decision was context-sensitive. This report does not necessarily + * indicate a problem, and it may appear even in completely unambiguous + * grammars. + *

+ * {@code configs} may have more than one represented alternative if the + * full-context prediction algorithm does not evaluate predicates before + * beginning the full-context prediction. In all cases, the final prediction + * is passed as the {@code prediction} argument. + *

+ * This method is not used by lexers. + * + * @param recognizer the parser instance + * @param dfa the DFA for the current decision + * @param startIndex the input index where the decision started + * @param stopIndex the input index where the context sensitivity was + * finally determined + * @param prediction the unambiguous result of the full-context prediction + * @param configs the ATN configuration set where the unambiguous prediction + * was determined + */ + void reportContextSensitivity(@NotNull Parser recognizer, + @NotNull DFA dfa, + int startIndex, + int stopIndex, int prediction, - @NotNull ATNConfigSet configs); + @NotNull ATNConfigSet configs); } diff --git a/runtime/Java/src/org/antlr/v4/runtime/DiagnosticErrorListener.java b/runtime/Java/src/org/antlr/v4/runtime/DiagnosticErrorListener.java index 3cfa81baf..79c84549f 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/DiagnosticErrorListener.java +++ b/runtime/Java/src/org/antlr/v4/runtime/DiagnosticErrorListener.java @@ -39,15 +39,62 @@ import org.antlr.v4.runtime.misc.Nullable; import java.util.BitSet; +/** + * This implementation of {@link ANTLRErrorListener} can be used to identify + * certain potential correctness and performance problems in grammars. "Reports" + * are made by calling {@link Parser#notifyErrorListeners} with the appropriate + * message. + * + *

+ * + * @author Sam Harwell + */ public class DiagnosticErrorListener extends BaseErrorListener { - @Override - public void reportAmbiguity(@NotNull Parser recognizer, - DFA dfa, int startIndex, int stopIndex, + /** + * When {@code true}, only exactly known ambiguities are reported. + */ + protected final boolean exactOnly; + + /** + * Initializes a new instance of {@link DiagnosticErrorListener} which only + * reports exact ambiguities. + */ + public DiagnosticErrorListener() { + this(true); + } + + /** + * Initializes a new instance of {@link DiagnosticErrorListener}, specifying + * whether all ambiguities or only exact ambiguities are reported. + * + * @param exactOnly {@code true} to report only exact ambiguities, otherwise + * {@code false} to report all ambiguities. + */ + public DiagnosticErrorListener(boolean exactOnly) { + this.exactOnly = exactOnly; + } + + @Override + public void reportAmbiguity(@NotNull Parser recognizer, + DFA dfa, + int startIndex, + int stopIndex, boolean exact, @Nullable BitSet ambigAlts, @NotNull ATNConfigSet configs) - { - if (!exact) { + { + if (exactOnly && !exact) { return; } @@ -62,7 +109,8 @@ public class DiagnosticErrorListener extends BaseErrorListener { @Override public void reportAttemptingFullContext(@NotNull Parser recognizer, @NotNull DFA dfa, - int startIndex, int stopIndex, + int startIndex, + int stopIndex, @Nullable BitSet conflictingAlts, @NotNull ATNConfigSet configs) { @@ -76,7 +124,8 @@ public class DiagnosticErrorListener extends BaseErrorListener { @Override public void reportContextSensitivity(@NotNull Parser recognizer, @NotNull DFA dfa, - int startIndex, int stopIndex, + int startIndex, + int stopIndex, int prediction, @NotNull ATNConfigSet configs) { diff --git a/runtime/Java/src/org/antlr/v4/runtime/ProxyErrorListener.java b/runtime/Java/src/org/antlr/v4/runtime/ProxyErrorListener.java index f6d47bcb1..2eebcbd15 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/ProxyErrorListener.java +++ b/runtime/Java/src/org/antlr/v4/runtime/ProxyErrorListener.java @@ -36,12 +36,20 @@ import java.util.BitSet; import java.util.Collection; /** + * This implementation of {@link ANTLRErrorListener} dispatches all calls to a + * collection of delegate listeners. This reduces the effort required to support multiple + * listeners. + * * @author Sam Harwell */ public class ProxyErrorListener implements ANTLRErrorListener { private final Collection delegates; public ProxyErrorListener(Collection delegates) { + if (delegates == null) { + throw new NullPointerException("delegates"); + } + this.delegates = delegates; }