reorg error and add parse tree tests
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9106]
This commit is contained in:
parent
5f9e2f6e05
commit
d56e8c3a18
|
@ -81,6 +81,21 @@ public interface ANTLRErrorStrategy {
|
|||
*/
|
||||
void sync(BaseRecognizer recognizer);
|
||||
|
||||
/** Notify handler that parser has entered an error state. The
|
||||
* parser currently doesn't call this--the handler itself calls this
|
||||
* in report error methods. But, for symmetry with endErrorCondition,
|
||||
* this method is in the interface.
|
||||
*/
|
||||
void beginErrorCondition(BaseRecognizer recognizer);
|
||||
|
||||
/** Is the parser in the process of recovering from an error? Upon
|
||||
* a syntax error, the parser enters recovery mode and stays there until
|
||||
* the next successful match of a token. In this way, we can
|
||||
* avoid sending out spurious error messages. We only want one error
|
||||
* message per syntax error
|
||||
*/
|
||||
boolean inErrorRecoveryMode(BaseRecognizer recognizer);
|
||||
|
||||
/** Reset the error handler. Call this when the parser
|
||||
* matches a valid token (indicating no longer in recovery mode)
|
||||
* and from its own reset method.
|
||||
|
|
|
@ -30,7 +30,9 @@ package org.antlr.v4.runtime;
|
|||
|
||||
import com.sun.istack.internal.Nullable;
|
||||
import org.antlr.v4.runtime.atn.ATNConfig;
|
||||
import org.antlr.v4.runtime.atn.ATNState;
|
||||
import org.antlr.v4.runtime.atn.ParserATNSimulator;
|
||||
import org.antlr.v4.runtime.atn.RuleTransition;
|
||||
import org.antlr.v4.runtime.misc.IntervalSet;
|
||||
import org.antlr.v4.runtime.misc.OrderedHashSet;
|
||||
|
||||
|
@ -58,12 +60,6 @@ public abstract class BaseRecognizer extends Recognizer<ParserATNSimulator> {
|
|||
protected boolean buildParseTrees;
|
||||
protected boolean traceATNStates;
|
||||
|
||||
/** This is true after we see an error and before having successfully
|
||||
* matched a token. Prevents generation of more than one error message
|
||||
* per error.
|
||||
*/
|
||||
protected boolean errorRecoveryMode = false;
|
||||
|
||||
/** Did the recognizer encounter a syntax error? Track how many. */
|
||||
protected int syntaxErrors = 0;
|
||||
|
||||
|
@ -199,7 +195,7 @@ public abstract class BaseRecognizer extends Recognizer<ParserATNSimulator> {
|
|||
getInputStream().consume();
|
||||
if ( buildParseTrees ) {
|
||||
// TODO: tree parsers?
|
||||
if ( errorRecoveryMode ) _ctx.addErrorNode((Token) o);
|
||||
if ( _errHandler.inErrorRecoveryMode(this) ) _ctx.addErrorNode((Token) o);
|
||||
else _ctx.addChild((Token)o);
|
||||
}
|
||||
return o;
|
||||
|
@ -211,6 +207,8 @@ public abstract class BaseRecognizer extends Recognizer<ParserATNSimulator> {
|
|||
}
|
||||
}
|
||||
|
||||
public abstract void enterRule(ParserRuleContext localctx, int ruleIndex);
|
||||
|
||||
public void exitRule(int ruleIndex) {
|
||||
_ctx = (ParserRuleContext)_ctx.parent;
|
||||
}
|
||||
|
@ -233,48 +231,25 @@ public abstract class BaseRecognizer extends Recognizer<ParserATNSimulator> {
|
|||
return _interp.atn.nextTokens(_ctx);
|
||||
}
|
||||
|
||||
/** Return List<String> of the rules in your parser instance
|
||||
* leading up to a call to this method. You could override if
|
||||
/** Return List<String> of the rule names in your parser instance
|
||||
* leading up to a call to the current rule. You could override if
|
||||
* you want more details such as the file/line info of where
|
||||
* in the parser java code a rule is invoked.
|
||||
* in the ATN a rule is invoked.
|
||||
*
|
||||
* This is very useful for error messages and for context-sensitive
|
||||
* error recovery.
|
||||
* This is very useful for error messages.
|
||||
*/
|
||||
public List getRuleInvocationStack() {
|
||||
// TODO: walk ctx chain now; this is legacy
|
||||
String parserClassName = getClass().getName();
|
||||
return getRuleInvocationStack(new Throwable(), parserClassName);
|
||||
}
|
||||
|
||||
/** A more general version of getRuleInvocationStack where you can
|
||||
* pass in, for example, a RecognitionException to get it's rule
|
||||
* stack trace. This routine is shared with all recognizers, hence,
|
||||
* static.
|
||||
*
|
||||
* TODO: move to a utility class or something; weird having lexer call this
|
||||
*/
|
||||
public static List getRuleInvocationStack(Throwable e,
|
||||
String recognizerClassName)
|
||||
{
|
||||
// TODO: walk ctx chain now; this is legacy
|
||||
List rules = new ArrayList();
|
||||
StackTraceElement[] stack = e.getStackTrace();
|
||||
int i = 0;
|
||||
for (i=stack.length-1; i>=0; i--) {
|
||||
StackTraceElement t = stack[i];
|
||||
if ( t.getClassName().startsWith("org.antlr.v4.runtime.") ) {
|
||||
continue; // skip support code such as this method
|
||||
}
|
||||
if ( t.getMethodName().equals(NEXT_TOKEN_RULE_NAME) ) {
|
||||
continue;
|
||||
}
|
||||
if ( !t.getClassName().equals(recognizerClassName) ) {
|
||||
continue; // must not be part of this parser
|
||||
}
|
||||
rules.add(t.getMethodName());
|
||||
public List<String> getRuleInvocationStack() {
|
||||
String[] ruleNames = getRuleNames();
|
||||
List<String> stack = new ArrayList<String>();
|
||||
RuleContext p = _ctx;
|
||||
while ( p!=null && p.invokingState>=0 ) {
|
||||
// compute what follows who invoked us
|
||||
ATNState invokingState = _interp.atn.states.get(p.invokingState);
|
||||
RuleTransition rt = (RuleTransition)invokingState.transition(0);
|
||||
stack.add(ruleNames[rt.ruleIndex]);
|
||||
p = p.parent;
|
||||
}
|
||||
return rules;
|
||||
return stack;
|
||||
}
|
||||
|
||||
/** For debugging and other purposes, might want the grammar name.
|
||||
|
|
|
@ -9,6 +9,12 @@ import org.antlr.v4.runtime.misc.IntervalSet;
|
|||
* and tree parsers.
|
||||
*/
|
||||
public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
|
||||
/** This is true after we see an error and before having successfully
|
||||
* matched a token. Prevents generation of more than one error message
|
||||
* per error.
|
||||
*/
|
||||
protected boolean errorRecoveryMode = false;
|
||||
|
||||
/** The index into the input stream where the last error occurred.
|
||||
* This is used to prevent infinite loops where an error is found
|
||||
* but no token is consumed during recovery...another error is found,
|
||||
|
@ -19,13 +25,19 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
|
|||
|
||||
protected IntervalSet lastErrorStates;
|
||||
|
||||
protected void beginErrorCondition(BaseRecognizer recognizer) {
|
||||
recognizer.errorRecoveryMode = true;
|
||||
@Override
|
||||
public void beginErrorCondition(BaseRecognizer recognizer) {
|
||||
errorRecoveryMode = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inErrorRecoveryMode(BaseRecognizer recognizer) {
|
||||
return errorRecoveryMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endErrorCondition(BaseRecognizer recognizer) {
|
||||
recognizer.errorRecoveryMode = false;
|
||||
errorRecoveryMode = false;
|
||||
lastErrorStates = null;
|
||||
lastErrorIndex = -1;
|
||||
}
|
||||
|
@ -37,7 +49,7 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
|
|||
{
|
||||
// if we've already reported an error and have not matched a token
|
||||
// yet successfully, don't report any errors.
|
||||
if (recognizer.errorRecoveryMode) return; // don't count spurious errors
|
||||
if (errorRecoveryMode) return; // don't count spurious errors
|
||||
recognizer.syntaxErrors++;
|
||||
beginErrorCondition(recognizer);
|
||||
if ( e instanceof NoViableAltException ) {
|
||||
|
@ -128,7 +140,7 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
|
|||
}
|
||||
|
||||
public void reportUnwantedToken(BaseRecognizer recognizer) {
|
||||
if (recognizer.errorRecoveryMode) return;
|
||||
if (errorRecoveryMode) return;
|
||||
recognizer.syntaxErrors++;
|
||||
beginErrorCondition(recognizer);
|
||||
|
||||
|
@ -141,7 +153,7 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
|
|||
}
|
||||
|
||||
public void reportMissingToken(BaseRecognizer recognizer) {
|
||||
if (recognizer.errorRecoveryMode) return;
|
||||
if (errorRecoveryMode) return;
|
||||
recognizer.syntaxErrors++;
|
||||
beginErrorCondition(recognizer);
|
||||
|
||||
|
@ -415,10 +427,4 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
|
|||
ttype = recognizer.getInputStream().LA(1);
|
||||
}
|
||||
}
|
||||
|
||||
// protected void trackError(BaseRecognizer recognizer) {
|
||||
// recognizer.syntaxErrors++;
|
||||
// recognizer.errorRecovery = true;
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@
|
|||
package org.antlr.v4.runtime;
|
||||
|
||||
|
||||
import org.antlr.v4.runtime.tree.*;
|
||||
import org.antlr.v4.runtime.tree.ASTAdaptor;
|
||||
import org.antlr.v4.runtime.tree.CommonASTAdaptor;
|
||||
|
||||
/** A parser for TokenStreams. "parser grammars" result in a subclass
|
||||
* of this.
|
||||
|
@ -57,6 +58,7 @@ public class Parser extends BaseRecognizer {
|
|||
* This is flexible because users do not have to regenerate parsers
|
||||
* to get trace facilities.
|
||||
*/
|
||||
@Override
|
||||
public void enterRule(ParserRuleContext localctx, int ruleIndex) {
|
||||
_ctx = localctx;
|
||||
_ctx.start = _input.LT(1);
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.antlr.v4.runtime;
|
|||
import org.stringtemplate.v4.ST;
|
||||
|
||||
public class TreeParserRuleContext extends ParserRuleContext {
|
||||
// TODO: heh, these are duplicates of the fields above!
|
||||
public Object start, stop;
|
||||
public Object tree;
|
||||
public ST st;
|
||||
|
|
|
@ -78,10 +78,12 @@ public class TreeParser extends BaseRecognizer {
|
|||
* This is flexible because users do not have to regenerate parsers
|
||||
* to get trace facilities.
|
||||
*/
|
||||
public void enterRule(TreeParserRuleContext localctx, int ruleIndex) {
|
||||
_ctx = localctx;
|
||||
localctx.start = _input.LT(1);
|
||||
localctx.ruleIndex = ruleIndex;
|
||||
@Override
|
||||
public void enterRule(ParserRuleContext localctx, int ruleIndex) {
|
||||
TreeParserRuleContext tctx = (TreeParserRuleContext)localctx;
|
||||
_ctx = tctx;
|
||||
tctx.start = _input.LT(1);
|
||||
tctx.ruleIndex = ruleIndex;
|
||||
}
|
||||
|
||||
public String getSourceName() {
|
||||
|
|
|
@ -3,13 +3,29 @@ package org.antlr.v4.test;
|
|||
import org.junit.Test;
|
||||
|
||||
public class TestParseTrees extends BaseTest {
|
||||
@Test public void testTokenMismatch() throws Exception {
|
||||
@Test public void testToken() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a : 'a' 'b' ;";
|
||||
// String found = execParser("T.g", grammar, "TParser", "TLexer", "a", "aa", false);
|
||||
// String expecting = "line 1:1 mismatched input 'a' expecting 'b'\n";
|
||||
// String result = stderrDuringParse;
|
||||
// assertEquals(expecting, result);
|
||||
"a\n" +
|
||||
"@init {setBuildParseTrees(true);}\n" +
|
||||
"@after {System.out.println(_localctx.toStringTree(this));}\n" +
|
||||
" : 'x'\n" +
|
||||
" ;\n";
|
||||
String result = execParser("T.g", grammar, "TParser", "TLexer", "a", "x", false);
|
||||
String expecting = "(a x)\n";
|
||||
assertEquals(expecting, result);
|
||||
}
|
||||
|
||||
@Test public void testToken2() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"a\n" +
|
||||
"@init {setBuildParseTrees(true);}\n" +
|
||||
"@after {System.out.println(_localctx.toStringTree(this));}\n" +
|
||||
" : 'x' 'y'\n" +
|
||||
" ;\n";
|
||||
String result = execParser("T.g", grammar, "TParser", "TLexer", "a", "xy", false);
|
||||
String expecting = "(a x y)\n";
|
||||
assertEquals(expecting, result);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue