forked from jasder/antlr
refactored sync/recoverInLine. figured out exactly what sync does at start of alt. setState goes to loopBack now in loops
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9177]
This commit is contained in:
parent
4920bb2c9e
commit
11b61d979d
|
@ -190,7 +190,7 @@ public abstract class BaseRecognizer extends Recognizer<ParserATNSimulator> {
|
||||||
* If the parser is creating parse trees, the current symbol
|
* If the parser is creating parse trees, the current symbol
|
||||||
* would also be added as a child to the current context (node).
|
* would also be added as a child to the current context (node).
|
||||||
*/
|
*/
|
||||||
protected Object consume() {
|
public Object consume() {
|
||||||
Object o = getCurrentInputSymbol();
|
Object o = getCurrentInputSymbol();
|
||||||
getInputStream().consume();
|
getInputStream().consume();
|
||||||
if ( buildParseTrees ) {
|
if ( buildParseTrees ) {
|
||||||
|
@ -227,6 +227,10 @@ public abstract class BaseRecognizer extends Recognizer<ParserATNSimulator> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ParserRuleContext getContext() {
|
||||||
|
return _ctx;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean inContext(String context) {
|
public boolean inContext(String context) {
|
||||||
// TODO: useful in parser?
|
// TODO: useful in parser?
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -129,28 +129,53 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
|
||||||
|
|
||||||
/** Make sure that the current lookahead symbol is consistent with
|
/** Make sure that the current lookahead symbol is consistent with
|
||||||
* what were expecting at this point in the ATN.
|
* what were expecting at this point in the ATN.
|
||||||
* sync() differs fundamentally from the recoverInline() method.
|
*
|
||||||
* In this case, we throw out a token that's not in the set of what
|
* At the start of a sub rule upon error, sync() performs single
|
||||||
* were expecting at this point. recoverInline() only deletes this
|
* token deletion, if possible. If it can't do that, it bails
|
||||||
* token if LT(2) (token after the current token) is what were expecting;
|
* on the current rule and uses the default error recovery,
|
||||||
* i.e., we have an extra token sitting on the input stream. sync()
|
* which consumes until the resynchronization set of the current rule.
|
||||||
* simply consumes until it finds something that can start whatever
|
*
|
||||||
* follows the call to sync().
|
* If the sub rule is optional, ()? or ()* or optional alternative,
|
||||||
|
* then the expected set includes what follows the subrule.
|
||||||
|
*
|
||||||
|
* During loop iteration, it consumes until it sees a token that can
|
||||||
|
* start a sub rule or what follows loop. Yes, that is pretty aggressive.
|
||||||
|
* We opt to stay in the loop as long as possible.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void sync(BaseRecognizer recognizer) {
|
public void sync(BaseRecognizer recognizer) {
|
||||||
|
ATNState s = recognizer._interp.atn.states.get(recognizer._ctx.s);
|
||||||
|
// System.err.println("sync @ "+s.stateNumber+"="+s.getClass().getSimpleName());
|
||||||
// If already recovering, don't try to sync
|
// If already recovering, don't try to sync
|
||||||
if ( errorRecoveryMode ) return;
|
if ( errorRecoveryMode ) return;
|
||||||
|
|
||||||
// TODO: CACHE THESE RESULTS!!
|
// TODO: CACHE THESE RESULTS!!
|
||||||
IntervalSet expecting = getExpectedTokens(recognizer);
|
IntervalSet expecting = getExpectedTokens(recognizer);
|
||||||
|
// System.err.println("sync expecting: "+expecting);
|
||||||
|
|
||||||
// TODO: subclass this class for treeparsers
|
// TODO: subclass this class for treeparsers
|
||||||
TokenStream tokens = (TokenStream)recognizer.getInputStream();
|
TokenStream tokens = (TokenStream)recognizer.getInputStream();
|
||||||
Token la = tokens.LT(1);
|
Token la = tokens.LT(1);
|
||||||
// Return but don't end recovery. only do that upon valid token match
|
// Return but don't end recovery. only do that upon valid token match
|
||||||
if ( la.getType()==Token.EOF || expecting.contains(la.getType()) ) return;
|
if ( la.getType()==Token.EOF || expecting.contains(la.getType()) ) return;
|
||||||
|
|
||||||
|
if ( s instanceof PlusBlockStartState ||
|
||||||
|
s instanceof StarLoopEntryState ||
|
||||||
|
s instanceof BlockStartState )
|
||||||
|
{
|
||||||
|
// report error and recover if possible
|
||||||
|
if ( singleTokenDeletion(recognizer)!=null ) return;
|
||||||
|
throw new InputMismatchException(recognizer);
|
||||||
|
}
|
||||||
|
if ( s instanceof PlusLoopbackState ||
|
||||||
|
s instanceof StarLoopbackState )
|
||||||
|
{
|
||||||
|
// System.err.println("at loop back: "+s.getClass().getSimpleName());
|
||||||
reportUnwantedToken(recognizer);
|
reportUnwantedToken(recognizer);
|
||||||
consumeUntil(recognizer, expecting);
|
consumeUntil(recognizer, expecting);
|
||||||
}
|
}
|
||||||
|
// do nothing if we can identify the exact kind of ATN state
|
||||||
|
}
|
||||||
|
|
||||||
public void reportNoViableAlternative(BaseRecognizer recognizer,
|
public void reportNoViableAlternative(BaseRecognizer recognizer,
|
||||||
NoViableAltException e)
|
NoViableAltException e)
|
||||||
|
@ -241,10 +266,55 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
|
||||||
public Object recoverInline(BaseRecognizer recognizer)
|
public Object recoverInline(BaseRecognizer recognizer)
|
||||||
throws RecognitionException
|
throws RecognitionException
|
||||||
{
|
{
|
||||||
Object currentSymbol = recognizer.getCurrentInputSymbol();
|
|
||||||
|
|
||||||
// SINGLE TOKEN DELETION
|
|
||||||
// if next token is what we are looking for then "delete" this token
|
// if next token is what we are looking for then "delete" this token
|
||||||
|
// int nextTokenType = recognizer.getInputStream().LA(2);
|
||||||
|
// IntervalSet expecting = getExpectedTokens(recognizer);
|
||||||
|
// if ( expecting.contains(nextTokenType) ) {
|
||||||
|
// reportUnwantedToken(recognizer);
|
||||||
|
// /*
|
||||||
|
// System.err.println("recoverFromMismatchedToken deleting "+
|
||||||
|
// ((TokenStream)recognizer.getInputStream()).LT(1)+
|
||||||
|
// " since "+((TokenStream)recognizer.getInputStream()).LT(2)+
|
||||||
|
// " is what we want");
|
||||||
|
// */
|
||||||
|
// recognizer.consume(); // simply delete extra token
|
||||||
|
// // we want to return the token we're actually matching
|
||||||
|
// Object matchedSymbol = recognizer.getCurrentInputSymbol();
|
||||||
|
// endErrorCondition(recognizer); // we know next token is correct
|
||||||
|
// recognizer.consume(); // move past ttype token as if all were ok
|
||||||
|
// return matchedSymbol;
|
||||||
|
// }
|
||||||
|
// SINGLE TOKEN DELETION
|
||||||
|
Object matchedSymbol = singleTokenDeletion(recognizer);
|
||||||
|
if ( matchedSymbol!=null ) return matchedSymbol;
|
||||||
|
|
||||||
|
// SINGLE TOKEN INSERTION
|
||||||
|
if ( singleTokenInsertion(recognizer) ) {
|
||||||
|
return getMissingSymbol(recognizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// even that didn't work; must throw the exception
|
||||||
|
throw new InputMismatchException(recognizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if next token is what we are looking for then "delete" this token
|
||||||
|
public boolean singleTokenInsertion(BaseRecognizer recognizer) {
|
||||||
|
Object currentSymbol = recognizer.getCurrentInputSymbol();
|
||||||
|
// if current token is consistent with what could come after current
|
||||||
|
// ATN state, then we know we're missing a token; error recovery
|
||||||
|
// is free to conjure up and insert the missing token
|
||||||
|
ATNState currentState = recognizer._interp.atn.states.get(recognizer._ctx.s);
|
||||||
|
ATNState next = currentState.transition(0).target;
|
||||||
|
IntervalSet expectingAtLL2 = recognizer._interp.atn.nextTokens(next, recognizer._ctx);
|
||||||
|
// System.out.println("LT(2) set="+expectingAtLL2.toString(recognizer.getTokenNames()));
|
||||||
|
if ( expectingAtLL2.contains(((Token)currentSymbol).getType()) ) {
|
||||||
|
reportMissingToken(recognizer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object singleTokenDeletion(BaseRecognizer recognizer) {
|
||||||
int nextTokenType = recognizer.getInputStream().LA(2);
|
int nextTokenType = recognizer.getInputStream().LA(2);
|
||||||
IntervalSet expecting = getExpectedTokens(recognizer);
|
IntervalSet expecting = getExpectedTokens(recognizer);
|
||||||
if ( expecting.contains(nextTokenType) ) {
|
if ( expecting.contains(nextTokenType) ) {
|
||||||
|
@ -256,29 +326,13 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
|
||||||
" is what we want");
|
" is what we want");
|
||||||
*/
|
*/
|
||||||
recognizer.consume(); // simply delete extra token
|
recognizer.consume(); // simply delete extra token
|
||||||
// recognizer.getInputStream().consume(); // simply delete extra token
|
|
||||||
// we want to return the token we're actually matching
|
// we want to return the token we're actually matching
|
||||||
Object matchedSymbol = recognizer.getCurrentInputSymbol();
|
Object matchedSymbol = recognizer.getCurrentInputSymbol();
|
||||||
endErrorCondition(recognizer); // we know next token is correct
|
endErrorCondition(recognizer); // we know next token is correct
|
||||||
recognizer.consume(); // move past ttype token as if all were ok
|
recognizer.consume(); // move past ttype token as if all were ok
|
||||||
// recognizer.getInputStream().consume(); // move past ttype token as if all were ok
|
|
||||||
return matchedSymbol;
|
return matchedSymbol;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
// SINGLE TOKEN INSERTION
|
|
||||||
// if current token is consistent with what could come after current
|
|
||||||
// ATN state, then we know we're missing a token; error recovery
|
|
||||||
// is free to conjure up and insert the missing token
|
|
||||||
ATNState currentState = recognizer._interp.atn.states.get(recognizer._ctx.s);
|
|
||||||
ATNState next = currentState.transition(0).target;
|
|
||||||
IntervalSet expectingAtLL2 = recognizer._interp.atn.nextTokens(next, recognizer._ctx);
|
|
||||||
// System.out.println("LT(2) set="+expectingAtLL2.toString(recognizer.getTokenNames()));
|
|
||||||
if ( expectingAtLL2.contains(((Token)currentSymbol).getType()) ) {
|
|
||||||
reportMissingToken(recognizer);
|
|
||||||
return getMissingSymbol(recognizer);
|
|
||||||
}
|
|
||||||
// even that didn't work; must throw the exception
|
|
||||||
throw new InputMismatchException(recognizer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Conjure up a missing token during error recovery.
|
/** Conjure up a missing token during error recovery.
|
||||||
|
@ -461,7 +515,7 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
|
||||||
|
|
||||||
/** Consume tokens until one matches the given token set */
|
/** Consume tokens until one matches the given token set */
|
||||||
public void consumeUntil(BaseRecognizer recognizer, IntervalSet set) {
|
public void consumeUntil(BaseRecognizer recognizer, IntervalSet set) {
|
||||||
// System.out.println("consumeUntil("+set.toString(recognizer.getTokenNames())+")");
|
// System.err.println("consumeUntil("+set.toString(recognizer.getTokenNames())+")");
|
||||||
int ttype = recognizer.getInputStream().LA(1);
|
int ttype = recognizer.getInputStream().LA(1);
|
||||||
while (ttype != Token.EOF && !set.contains(ttype) ) {
|
while (ttype != Token.EOF && !set.contains(ttype) ) {
|
||||||
//System.out.println("consume during recover LA(1)="+getTokenNames()[input.LA(1)]);
|
//System.out.println("consume during recover LA(1)="+getTokenNames()[input.LA(1)]);
|
||||||
|
|
|
@ -35,6 +35,14 @@ public class ATNState {
|
||||||
public static final int INITIAL_NUM_TRANSITIONS = 4;
|
public static final int INITIAL_NUM_TRANSITIONS = 4;
|
||||||
|
|
||||||
// constants for serialization
|
// constants for serialization
|
||||||
|
// public static enum ATNStateType {
|
||||||
|
// BASIC(1), RULE_START(2), BLOCK_START(3), PLUS_BLOCK_START(4),
|
||||||
|
// STAR_BLOCK_START(5), TOKEN_START(6), RULE_STOP(7), BLOCK_END(8),
|
||||||
|
// STAR_LOOP_BACK(9), STAR_LOOP_ENTRY(10), PLUS_LOOP_BACK(11);
|
||||||
|
// public int type;
|
||||||
|
// ATNStateType(int type) { this.type = type; }
|
||||||
|
// public int intValue() { return type; }
|
||||||
|
// }
|
||||||
public static final int BASIC = 1;
|
public static final int BASIC = 1;
|
||||||
public static final int RULE_START = 2;
|
public static final int RULE_START = 2;
|
||||||
public static final int BLOCK_START = 3;
|
public static final int BLOCK_START = 3;
|
||||||
|
@ -83,6 +91,8 @@ public class ATNState {
|
||||||
|
|
||||||
public int ruleIndex; // at runtime, we don't have Rule objects
|
public int ruleIndex; // at runtime, we don't have Rule objects
|
||||||
|
|
||||||
|
public int epsilonOnlyTransitions = -1;
|
||||||
|
|
||||||
/** Which ATN are we in? */
|
/** Which ATN are we in? */
|
||||||
public ATN atn = null;
|
public ATN atn = null;
|
||||||
|
|
||||||
|
@ -123,7 +133,9 @@ public class ATNState {
|
||||||
transitions.set(i, e);
|
transitions.set(i, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int epsilonOnlyTransitions = -1;
|
public int getStateType() {
|
||||||
|
return serializationTypes.get(this.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
//lexer atn sim: getEpTar: 13.2%
|
//lexer atn sim: getEpTar: 13.2%
|
||||||
// ruleCtx.equals 10%
|
// ruleCtx.equals 10%
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
package org.antlr.v4.runtime.atn;
|
package org.antlr.v4.runtime.atn;
|
||||||
|
|
||||||
public class StarLoopEntryState extends DecisionState {
|
public class StarLoopEntryState extends DecisionState {
|
||||||
|
public StarLoopbackState loopBackState;
|
||||||
@Override
|
@Override
|
||||||
public boolean onlyHasEpsilonTransitions() { return true; }
|
public boolean onlyHasEpsilonTransitions() { return true; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,26 +70,26 @@ public class PostScriptDocument {
|
||||||
ps.append("%!PS-Adobe-3.0 EPSF-3.0\n");
|
ps.append("%!PS-Adobe-3.0 EPSF-3.0\n");
|
||||||
ps.append("%%BoundingBox: (atend)\n");
|
ps.append("%%BoundingBox: (atend)\n");
|
||||||
lineWidth(0.3);
|
lineWidth(0.3);
|
||||||
ps.append("%\n");
|
// ps.append("%\n");
|
||||||
ps.append("% x y rarrow\n");
|
// ps.append("% x y rarrow\n");
|
||||||
ps.append("%\n");
|
// ps.append("%\n");
|
||||||
ps.append("/rarrow {\n");
|
// ps.append("/rarrow {\n");
|
||||||
ps.append(" moveto\n");
|
// ps.append(" moveto\n");
|
||||||
ps.append(" -3 +2 rlineto\n");
|
// ps.append(" -3 +2 rlineto\n");
|
||||||
ps.append(" 0 -4 rlineto\n");
|
// ps.append(" 0 -4 rlineto\n");
|
||||||
ps.append(" 3 +2 rlineto\n");
|
// ps.append(" 3 +2 rlineto\n");
|
||||||
ps.append(" fill\n");
|
// ps.append(" fill\n");
|
||||||
ps.append("} def\n");
|
// ps.append("} def\n");
|
||||||
ps.append("%\n");
|
// ps.append("%\n");
|
||||||
ps.append("% x y darrow\n");
|
// ps.append("% x y darrow\n");
|
||||||
ps.append("%\n");
|
// ps.append("%\n");
|
||||||
ps.append("/darrow {\n");
|
// ps.append("/darrow {\n");
|
||||||
ps.append(" moveto\n");
|
// ps.append(" moveto\n");
|
||||||
ps.append(" -2 +3 rlineto\n");
|
// ps.append(" -2 +3 rlineto\n");
|
||||||
ps.append(" 4 0 rlineto\n");
|
// ps.append(" 4 0 rlineto\n");
|
||||||
ps.append(" -2 -3 rlineto\n");
|
// ps.append(" -2 -3 rlineto\n");
|
||||||
ps.append(" fill\n");
|
// ps.append(" fill\n");
|
||||||
ps.append("} def\n");
|
// ps.append("} def\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Courier, Helvetica, Times, ... should be available
|
// Courier, Helvetica, Times, ... should be available
|
||||||
|
@ -144,6 +144,22 @@ public class PostScriptDocument {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void text(String s, double x, double y) {
|
public void text(String s, double x, double y) {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
// escape \, (, ): \\, \(, \)
|
||||||
|
for (char c : s.toCharArray()) {
|
||||||
|
switch ( c ) {
|
||||||
|
case '\\' :
|
||||||
|
case '(' :
|
||||||
|
case ')' :
|
||||||
|
buf.append('\\');
|
||||||
|
buf.append(c);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
buf.append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s = buf.toString();
|
||||||
move(x,y);
|
move(x,y);
|
||||||
ps.append(String.format("(%s) show\n", s));
|
ps.append(String.format("(%s) show\n", s));
|
||||||
stroke();
|
stroke();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
[The "BSD license"]
|
[The "BSD license"]
|
||||||
Copyright (c) 2011 Terence Parr
|
Copyright (c) 2011 T2rence Parr
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -36,6 +36,7 @@ import org.antlr.v4.runtime.tree.*;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public class TreePostScriptGenerator {
|
public class TreePostScriptGenerator {
|
||||||
public class VariableExtentProvide implements NodeExtentProvider<Tree> {
|
public class VariableExtentProvide implements NodeExtentProvider<Tree> {
|
||||||
|
@ -48,16 +49,18 @@ public class TreePostScriptGenerator {
|
||||||
@Override
|
@Override
|
||||||
public double getHeight(Tree tree) {
|
public double getHeight(Tree tree) {
|
||||||
String s = getText(tree);
|
String s = getText(tree);
|
||||||
double h = doc.getLineHeight() + nodeHeightPadding*2;
|
double h =
|
||||||
|
doc.getLineHeight() + nodeHeightPaddingAbove + nodeHeightPaddingBelow;
|
||||||
String[] lines = s.split("\n");
|
String[] lines = s.split("\n");
|
||||||
return h * lines.length;
|
return h * lines.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected double gapBetweenLevels = 30;
|
protected double gapBetweenLevels = 10;
|
||||||
protected double gapBetweenNodes = 10;
|
protected double gapBetweenNodes = 7;
|
||||||
protected int nodeWidthPadding = 1; // added to left/right
|
protected int nodeWidthPadding = 1; // added to left/right
|
||||||
protected int nodeHeightPadding = 1; // added above/below
|
protected int nodeHeightPaddingAbove = 2;
|
||||||
|
protected int nodeHeightPaddingBelow = 5;
|
||||||
|
|
||||||
protected Tree root;
|
protected Tree root;
|
||||||
protected TreeTextProvider treeTextProvider;
|
protected TreeTextProvider treeTextProvider;
|
||||||
|
@ -99,12 +102,12 @@ public class TreePostScriptGenerator {
|
||||||
protected void generateEdges(Tree parent) {
|
protected void generateEdges(Tree parent) {
|
||||||
if (!getTree().isLeaf(parent)) {
|
if (!getTree().isLeaf(parent)) {
|
||||||
Rectangle2D.Double parentBounds = getBoundsOfNode(parent);
|
Rectangle2D.Double parentBounds = getBoundsOfNode(parent);
|
||||||
System.out.println("%% parent("+getText(parent)+")="+parentBounds);
|
// System.out.println("%% parent("+getText(parent)+")="+parentBounds);
|
||||||
double x1 = parentBounds.getCenterX();
|
double x1 = parentBounds.getCenterX();
|
||||||
double y1 = parentBounds.y;
|
double y1 = parentBounds.y;
|
||||||
for (Tree child : getChildren(parent)) {
|
for (Tree child : getChildren(parent)) {
|
||||||
Rectangle2D.Double childBounds = getBoundsOfNode(child);
|
Rectangle2D.Double childBounds = getBoundsOfNode(child);
|
||||||
System.out.println("%% child("+getText(child)+")="+childBounds);
|
// System.out.println("%% child("+getText(child)+")="+childBounds);
|
||||||
double x2 = childBounds.getCenterX();
|
double x2 = childBounds.getCenterX();
|
||||||
double y2 = childBounds.getMaxY();
|
double y2 = childBounds.getMaxY();
|
||||||
doc.line(x1, y1, x2, y2);
|
doc.line(x1, y1, x2, y2);
|
||||||
|
@ -120,7 +123,7 @@ public class TreePostScriptGenerator {
|
||||||
// for debugging, turn this on to see boundingbox of nodes
|
// for debugging, turn this on to see boundingbox of nodes
|
||||||
// doc.rect(box.x, box.y, box.width, box.height);
|
// doc.rect(box.x, box.y, box.width, box.height);
|
||||||
double x = box.x+nodeWidthPadding;
|
double x = box.x+nodeWidthPadding;
|
||||||
double y = box.y+nodeHeightPadding;
|
double y = box.y+nodeHeightPaddingBelow;
|
||||||
for (int i = 0; i < lines.length; i++) {
|
for (int i = 0; i < lines.length; i++) {
|
||||||
doc.text(lines[i], x, y);
|
doc.text(lines[i], x, y);
|
||||||
y += doc.getFontSize();
|
y += doc.getFontSize();
|
||||||
|
@ -151,19 +154,36 @@ public class TreePostScriptGenerator {
|
||||||
this.treeTextProvider = treeTextProvider;
|
this.treeTextProvider = treeTextProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) throws IOException {
|
||||||
CommonAST t = new CommonAST(new CommonToken(1, "+"));
|
CommonAST t = new CommonAST(new CommonToken(1, "s"));
|
||||||
CommonAST a = new CommonAST(new CommonToken(1, "expression"));
|
CommonAST ifstat = new CommonAST(new CommonToken(1, "ifstat"));
|
||||||
CommonAST f = new CommonAST(new CommonToken(1, "3000"));
|
CommonAST iff = new CommonAST(new CommonToken(1, "if"));
|
||||||
CommonAST b = new CommonAST(new CommonToken(1, "*"));
|
CommonAST b = new CommonAST(new CommonToken(1, "("));
|
||||||
CommonAST c = new CommonAST(new CommonToken(1, "42"));
|
CommonAST c = new CommonAST(new CommonToken(1, "expr"));
|
||||||
CommonAST d = new CommonAST(new CommonToken(1, "105"));
|
CommonAST d = new CommonAST(new CommonToken(1, ")"));
|
||||||
t.addChild(a);
|
CommonAST e = new CommonAST(new CommonToken(1, "assign"));
|
||||||
a.addChild(f);
|
CommonAST f = new CommonAST(new CommonToken(1, "34"));
|
||||||
t.addChild(b);
|
CommonAST g = new CommonAST(new CommonToken(1, "a"));
|
||||||
b.addChild(c);
|
CommonAST h = new CommonAST(new CommonToken(1, "="));
|
||||||
b.addChild(d);
|
CommonAST i = new CommonAST(new CommonToken(1, "expr"));
|
||||||
TreePostScriptGenerator psgen = new TreePostScriptGenerator(null, t, "CourierNew", 11);
|
CommonAST j = new CommonAST(new CommonToken(1, ";"));
|
||||||
System.out.println(psgen.getPS());
|
CommonAST k = new CommonAST(new CommonToken(1, "b"));
|
||||||
|
t.addChild(ifstat);
|
||||||
|
ifstat.addChild(iff);
|
||||||
|
ifstat.addChild(b);
|
||||||
|
ifstat.addChild(c);
|
||||||
|
ifstat.addChild(d);
|
||||||
|
ifstat.addChild(e);
|
||||||
|
c.addChild(f);
|
||||||
|
e.addChild(g);
|
||||||
|
e.addChild(h);
|
||||||
|
e.addChild(i);
|
||||||
|
e.addChild(j);
|
||||||
|
i.addChild(k);
|
||||||
|
Trees.writePS(t, null,
|
||||||
|
"/Users/parrt/antlr/code/antlr4/main/tool/playground/t.eps",
|
||||||
|
"Arial", 11);
|
||||||
|
// TreePostScriptGenerator psgen = new TreePostScriptGenerator(null, t, "CourierNew", 11);
|
||||||
|
// System.out.println(psgen.getPS());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,10 +82,10 @@ public class TreeViewer extends JComponent {
|
||||||
protected int fontSize = 12;
|
protected int fontSize = 12;
|
||||||
protected Font font = new Font(fontName, fontStyle, fontSize);
|
protected Font font = new Font(fontName, fontStyle, fontSize);
|
||||||
|
|
||||||
protected double gapBetweenLevels = 30;
|
protected double gapBetweenLevels = 12;
|
||||||
protected double gapBetweenNodes = 10;
|
protected double gapBetweenNodes = 7;
|
||||||
protected int nodeWidthPadding = 2; // added to left/right
|
protected int nodeWidthPadding = 2; // added to left/right
|
||||||
protected int nodeHeightPadding = 1; // added above/below
|
protected int nodeHeightPadding = 4; // added above/below
|
||||||
protected int arcSize = 0; // make an arc in node outline?
|
protected int arcSize = 0; // make an arc in node outline?
|
||||||
|
|
||||||
protected Color boxColor = Color.white;
|
protected Color boxColor = Color.white;
|
||||||
|
|
|
@ -265,7 +265,7 @@ while (true) {
|
||||||
<cases(choice.exitLook)>
|
<cases(choice.exitLook)>
|
||||||
break <choice.loopLabel>;
|
break <choice.loopLabel>;
|
||||||
}
|
}
|
||||||
setState(<choice.stateNumber>);
|
setState(<choice.loopBackStateNumber>);
|
||||||
_errHandler.sync(this);
|
_errHandler.sync(this);
|
||||||
}
|
}
|
||||||
>>
|
>>
|
||||||
|
@ -276,7 +276,7 @@ _errHandler.sync(this);
|
||||||
<preamble; separator="\n">
|
<preamble; separator="\n">
|
||||||
while ( <loopExpr> ) {
|
while ( <loopExpr> ) {
|
||||||
<alts; separator="\n">
|
<alts; separator="\n">
|
||||||
setState(<choice.stateNumber>);
|
setState(<choice.loopBackStateNumber>);
|
||||||
_errHandler.sync(this);
|
_errHandler.sync(this);
|
||||||
<iteration>
|
<iteration>
|
||||||
}
|
}
|
||||||
|
@ -350,7 +350,7 @@ case <i>:
|
||||||
<alt>
|
<alt>
|
||||||
break;}; separator="\n">
|
break;}; separator="\n">
|
||||||
}
|
}
|
||||||
setState(<choice.stateNumber>);
|
setState(<choice.loopBackStateNumber>);
|
||||||
_errHandler.sync(this);
|
_errHandler.sync(this);
|
||||||
_alt<choice.uniqueID> = _interp.adaptivePredict(_input,<choice.decision>,_ctx);
|
_alt<choice.uniqueID> = _interp.adaptivePredict(_input,<choice.decision>,_ctx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ public class ATNSerializer {
|
||||||
int nedges = 0;
|
int nedges = 0;
|
||||||
// dump states, count edges and collect sets while doing so
|
// dump states, count edges and collect sets while doing so
|
||||||
for (ATNState s : atn.states) {
|
for (ATNState s : atn.states) {
|
||||||
data.add(ATNState.serializationTypes.get(s.getClass()));
|
data.add(s.getStateType());
|
||||||
data.add(s.ruleIndex);
|
data.add(s.ruleIndex);
|
||||||
nedges += s.getNumberOfTransitions();
|
nedges += s.getNumberOfTransitions();
|
||||||
for (int i=0; i<s.getNumberOfTransitions(); i++) {
|
for (int i=0; i<s.getNumberOfTransitions(); i++) {
|
||||||
|
|
|
@ -30,26 +30,18 @@
|
||||||
package org.antlr.v4.automata;
|
package org.antlr.v4.automata;
|
||||||
|
|
||||||
|
|
||||||
import org.antlr.runtime.RecognitionException;
|
import org.antlr.runtime.*;
|
||||||
import org.antlr.runtime.Token;
|
import org.antlr.runtime.tree.*;
|
||||||
import org.antlr.runtime.tree.CommonTreeNodeStream;
|
|
||||||
import org.antlr.runtime.tree.Tree;
|
|
||||||
import org.antlr.v4.misc.CharSupport;
|
import org.antlr.v4.misc.CharSupport;
|
||||||
import org.antlr.v4.parse.ANTLRParser;
|
import org.antlr.v4.parse.*;
|
||||||
import org.antlr.v4.parse.ATNBuilder;
|
|
||||||
import org.antlr.v4.parse.GrammarASTAdaptor;
|
|
||||||
import org.antlr.v4.runtime.atn.*;
|
import org.antlr.v4.runtime.atn.*;
|
||||||
import org.antlr.v4.runtime.misc.IntervalSet;
|
import org.antlr.v4.runtime.misc.IntervalSet;
|
||||||
import org.antlr.v4.semantics.UseDefAnalyzer;
|
import org.antlr.v4.semantics.UseDefAnalyzer;
|
||||||
import org.antlr.v4.tool.ErrorManager;
|
import org.antlr.v4.tool.*;
|
||||||
import org.antlr.v4.tool.ErrorType;
|
|
||||||
import org.antlr.v4.tool.Grammar;
|
|
||||||
import org.antlr.v4.tool.Rule;
|
|
||||||
import org.antlr.v4.tool.ast.*;
|
import org.antlr.v4.tool.ast.*;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/** ATN construction routines triggered by ATNBuilder.g.
|
/** ATN construction routines triggered by ATNBuilder.g.
|
||||||
*
|
*
|
||||||
|
@ -364,9 +356,9 @@ public class ParserATNFactory implements ATNFactory {
|
||||||
PlusLoopbackState loop = (PlusLoopbackState)newState(PlusLoopbackState.class, plusAST);
|
PlusLoopbackState loop = (PlusLoopbackState)newState(PlusLoopbackState.class, plusAST);
|
||||||
atn.defineDecisionState(loop);
|
atn.defineDecisionState(loop);
|
||||||
ATNState end = newState(ATNState.class, plusAST);
|
ATNState end = newState(ATNState.class, plusAST);
|
||||||
|
blkStart.loopBackState = loop;
|
||||||
|
|
||||||
plusAST.atnState = blkStart;
|
plusAST.atnState = blkStart;
|
||||||
blkStart.loopBackState = loop;
|
|
||||||
epsilon(blkEnd, loop); // blk can see loop back
|
epsilon(blkEnd, loop); // blk can see loop back
|
||||||
|
|
||||||
BlockAST blkAST = (BlockAST)plusAST.getChild(0);
|
BlockAST blkAST = (BlockAST)plusAST.getChild(0);
|
||||||
|
@ -404,6 +396,7 @@ public class ParserATNFactory implements ATNFactory {
|
||||||
atn.defineDecisionState(entry);
|
atn.defineDecisionState(entry);
|
||||||
ATNState end = newState(ATNState.class, starAST);
|
ATNState end = newState(ATNState.class, starAST);
|
||||||
StarLoopbackState loop = (StarLoopbackState)newState(StarLoopbackState.class, starAST);
|
StarLoopbackState loop = (StarLoopbackState)newState(StarLoopbackState.class, starAST);
|
||||||
|
entry.loopBackState = loop;
|
||||||
|
|
||||||
BlockAST blkAST = (BlockAST)starAST.getChild(0);
|
BlockAST blkAST = (BlockAST)starAST.getChild(0);
|
||||||
entry.isGreedy = isGreedy(blkAST);
|
entry.isGreedy = isGreedy(blkAST);
|
||||||
|
|
|
@ -33,8 +33,7 @@ import org.antlr.v4.codegen.OutputModelFactory;
|
||||||
import org.antlr.v4.runtime.misc.IntervalSet;
|
import org.antlr.v4.runtime.misc.IntervalSet;
|
||||||
import org.antlr.v4.tool.ast.GrammarAST;
|
import org.antlr.v4.tool.ast.GrammarAST;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
public abstract class LL1Loop extends Choice {
|
public abstract class LL1Loop extends Choice {
|
||||||
|
@ -42,6 +41,7 @@ public abstract class LL1Loop extends Choice {
|
||||||
* is super.stateNumber
|
* is super.stateNumber
|
||||||
*/
|
*/
|
||||||
public int blockStartStateNumber;
|
public int blockStartStateNumber;
|
||||||
|
public int loopBackStateNumber;
|
||||||
|
|
||||||
@ModelElement public OutputModelObject loopExpr;
|
@ModelElement public OutputModelObject loopExpr;
|
||||||
@ModelElement public List<SrcOp> iteration;
|
@ModelElement public List<SrcOp> iteration;
|
||||||
|
|
|
@ -50,6 +50,8 @@ public class LL1StarBlock extends LL1Loop {
|
||||||
blockStartStateNumber =
|
blockStartStateNumber =
|
||||||
starRootAST.atnState.transition(0).target.stateNumber;
|
starRootAST.atnState.transition(0).target.stateNumber;
|
||||||
|
|
||||||
|
loopBackStateNumber = star.loopBackState.stateNumber;
|
||||||
|
|
||||||
this.decision = star.decision;
|
this.decision = star.decision;
|
||||||
|
|
||||||
/** Lookahead for each alt 1..n */
|
/** Lookahead for each alt 1..n */
|
||||||
|
|
|
@ -41,8 +41,8 @@ public class LL1StarBlockSingleAlt extends LL1Loop {
|
||||||
public LL1StarBlockSingleAlt(OutputModelFactory factory, GrammarAST starRoot, List<CodeBlockForAlt> alts) {
|
public LL1StarBlockSingleAlt(OutputModelFactory factory, GrammarAST starRoot, List<CodeBlockForAlt> alts) {
|
||||||
super(factory, starRoot, alts);
|
super(factory, starRoot, alts);
|
||||||
|
|
||||||
// StarBlockStartState star = (StarBlockStartState)starRoot.atnState;
|
|
||||||
StarLoopEntryState star = (StarLoopEntryState)starRoot.atnState;
|
StarLoopEntryState star = (StarLoopEntryState)starRoot.atnState;
|
||||||
|
loopBackStateNumber = star.loopBackState.stateNumber;
|
||||||
this.decision = star.decision;
|
this.decision = star.decision;
|
||||||
IntervalSet[] altLookSets = factory.getGrammar().decisionLOOK.get(decision);
|
IntervalSet[] altLookSets = factory.getGrammar().decisionLOOK.get(decision);
|
||||||
IntervalSet enterLook = altLookSets[1];
|
IntervalSet enterLook = altLookSets[1];
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.antlr.v4.tool.ast.GrammarAST;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Loop extends Choice {
|
public class Loop extends Choice {
|
||||||
|
public int loopBackStateNumber;
|
||||||
public int exitAlt;
|
public int exitAlt;
|
||||||
public Loop(OutputModelFactory factory,
|
public Loop(OutputModelFactory factory,
|
||||||
GrammarAST blkOrEbnfRootAST,
|
GrammarAST blkOrEbnfRootAST,
|
||||||
|
|
|
@ -30,8 +30,7 @@
|
||||||
package org.antlr.v4.codegen.model;
|
package org.antlr.v4.codegen.model;
|
||||||
|
|
||||||
import org.antlr.v4.codegen.OutputModelFactory;
|
import org.antlr.v4.codegen.OutputModelFactory;
|
||||||
import org.antlr.v4.runtime.atn.PlusBlockStartState;
|
import org.antlr.v4.runtime.atn.*;
|
||||||
import org.antlr.v4.runtime.atn.PlusLoopbackState;
|
|
||||||
import org.antlr.v4.tool.ast.GrammarAST;
|
import org.antlr.v4.tool.ast.GrammarAST;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -45,6 +44,7 @@ public class PlusBlock extends Loop {
|
||||||
{
|
{
|
||||||
super(factory, ebnfRootAST, alts);
|
super(factory, ebnfRootAST, alts);
|
||||||
PlusLoopbackState loop = ((PlusBlockStartState)ebnfRootAST.atnState).loopBackState;
|
PlusLoopbackState loop = ((PlusBlockStartState)ebnfRootAST.atnState).loopBackState;
|
||||||
|
loopBackStateNumber = loop.stateNumber;
|
||||||
stateNumber = loop.stateNumber;
|
stateNumber = loop.stateNumber;
|
||||||
this.error = new ThrowNoViableAlt(factory, ebnfRootAST, null);
|
this.error = new ThrowNoViableAlt(factory, ebnfRootAST, null);
|
||||||
decision = loop.decision;
|
decision = loop.decision;
|
||||||
|
|
|
@ -45,6 +45,7 @@ public class StarBlock extends Loop {
|
||||||
super(factory, blkOrEbnfRootAST, alts);
|
super(factory, blkOrEbnfRootAST, alts);
|
||||||
loopLabel = factory.getGenerator().target.getLoopLabel(blkOrEbnfRootAST);
|
loopLabel = factory.getGenerator().target.getLoopLabel(blkOrEbnfRootAST);
|
||||||
StarLoopEntryState star = (StarLoopEntryState)blkOrEbnfRootAST.atnState;
|
StarLoopEntryState star = (StarLoopEntryState)blkOrEbnfRootAST.atnState;
|
||||||
|
loopBackStateNumber = star.loopBackState.stateNumber;
|
||||||
decision = star.decision;
|
decision = star.decision;
|
||||||
exitAlt = alts.size()+1;
|
exitAlt = alts.size()+1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,11 +151,14 @@ public class TestParseErrors extends BaseTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test public void testMultiTokenDeletionBeforeLoop() throws Exception {
|
@Test public void testMultiTokenDeletionBeforeLoop() throws Exception {
|
||||||
|
// can only delete 1 before loop
|
||||||
String grammar =
|
String grammar =
|
||||||
"grammar T;\n" +
|
"grammar T;\n" +
|
||||||
"a : 'a' 'b'* 'c';";
|
"a : 'a' 'b'* 'c';";
|
||||||
String found = execParser("T.g", grammar, "TParser", "TLexer", "a", "aacabc", false);
|
String found = execParser("T.g", grammar, "TParser", "TLexer", "a", "aacabc", false);
|
||||||
String expecting = "line 1:1 extraneous input 'a' expecting {'b', 'c'}\n";
|
String expecting =
|
||||||
|
"line 1:1 extraneous input 'a' expecting {'b', 'c'}\n" +
|
||||||
|
"line 1:3 mismatched input 'a' expecting 'c'\n";
|
||||||
String result = stderrDuringParse;
|
String result = stderrDuringParse;
|
||||||
assertEquals(expecting, result);
|
assertEquals(expecting, result);
|
||||||
}
|
}
|
||||||
|
@ -182,6 +185,53 @@ public class TestParseErrors extends BaseTest {
|
||||||
assertEquals(expecting, result);
|
assertEquals(expecting, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------
|
||||||
|
|
||||||
|
@Test public void testSingleTokenDeletionBeforeLoop2() throws Exception {
|
||||||
|
String grammar =
|
||||||
|
"grammar T;\n" +
|
||||||
|
"a : 'a' ('b'|'z'{;})*;";
|
||||||
|
String found = execParser("T.g", grammar, "TParser", "TLexer", "a", "aabc", false);
|
||||||
|
String expecting = "line 1:1 extraneous input 'a' expecting {<EOF>, 'b', 'z'}\n";
|
||||||
|
String result = stderrDuringParse;
|
||||||
|
assertEquals(expecting, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testMultiTokenDeletionBeforeLoop2() throws Exception {
|
||||||
|
// can only delete 1 before loop
|
||||||
|
String grammar =
|
||||||
|
"grammar T;\n" +
|
||||||
|
"a : 'a' ('b'|'z'{;})* 'c';";
|
||||||
|
String found = execParser("T.g", grammar, "TParser", "TLexer", "a", "aacabc", false);
|
||||||
|
String expecting =
|
||||||
|
"line 1:1 extraneous input 'a' expecting {'b', 'z', 'c'}\n" +
|
||||||
|
"line 1:3 mismatched input 'a' expecting 'c'\n";
|
||||||
|
String result = stderrDuringParse;
|
||||||
|
assertEquals(expecting, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testSingleTokenDeletionDuringLoop2() throws Exception {
|
||||||
|
String grammar =
|
||||||
|
"grammar T;\n" +
|
||||||
|
"a : 'a' ('b'|'z'{;})* 'c' ;";
|
||||||
|
String found = execParser("T.g", grammar, "TParser", "TLexer", "a", "ababbc", false);
|
||||||
|
String expecting = "line 1:2 extraneous input 'a' expecting {'b', 'z', 'c'}\n";
|
||||||
|
String result = stderrDuringParse;
|
||||||
|
assertEquals(expecting, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testMultiTokenDeletionDuringLoop2() throws Exception {
|
||||||
|
String grammar =
|
||||||
|
"grammar T;\n" +
|
||||||
|
"a : 'a' ('b'|'z'{;})* 'c' ;";
|
||||||
|
String found = execParser("T.g", grammar, "TParser", "TLexer", "a", "abaaababc", false);
|
||||||
|
String expecting =
|
||||||
|
"line 1:2 extraneous input 'a' expecting {'b', 'z', 'c'}\n" +
|
||||||
|
"line 1:6 extraneous input 'a' expecting {'b', 'z', 'c'}\n";
|
||||||
|
String result = stderrDuringParse;
|
||||||
|
assertEquals(expecting, result);
|
||||||
|
}
|
||||||
|
|
||||||
@Test public void testLL1ErrorInfo() throws Exception {
|
@Test public void testLL1ErrorInfo() throws Exception {
|
||||||
String grammar =
|
String grammar =
|
||||||
"grammar T;\n" +
|
"grammar T;\n" +
|
||||||
|
|
Loading…
Reference in New Issue