reorg error and add parse tree tests

[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9106]
This commit is contained in:
parrt 2011-10-04 10:19:04 -08:00
parent 5f9e2f6e05
commit d56e8c3a18
7 changed files with 85 additions and 68 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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;
// }
}

View File

@ -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);

View File

@ -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;

View File

@ -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() {

View File

@ -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);
}
}