Added lots of little stuff

[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9310]
This commit is contained in:
parrt 2011-11-13 18:04:35 -08:00
parent c8e9e12a74
commit 27cbd249ac
19 changed files with 191 additions and 42 deletions

View File

@ -32,7 +32,9 @@ package org.antlr.v4.runtime;
import org.antlr.v4.runtime.tree.*; import org.antlr.v4.runtime.tree.*;
import org.antlr.v4.runtime.tree.gui.TreeViewer; import org.antlr.v4.runtime.tree.gui.TreeViewer;
public class DefaultANTLRTreeGrammarErrorStrategy extends DefaultANTLRErrorStrategy { import java.util.*;
public class DefaultANTLRTreeGrammarErrorStrategy<T> extends DefaultANTLRErrorStrategy {
@Override @Override
public void beginErrorCondition(BaseRecognizer recognizer) { public void beginErrorCondition(BaseRecognizer recognizer) {
} }
@ -42,23 +44,72 @@ public class DefaultANTLRTreeGrammarErrorStrategy extends DefaultANTLRErrorStrat
throws RecognitionException throws RecognitionException
{ {
super.reportError(recognizer, e); super.reportError(recognizer, e);
ASTNodeStream input = ((TreeParser) recognizer).getInputStream(); TreeParser<T> parser = (TreeParser<T>)recognizer;
ASTNodeStream input = parser.getInputStream();
Object root = input.getTreeSource(); Object root = input.getTreeSource();
if ( root instanceof AST ) { // If instanceof Tree, we can show in TreeViewer
if ( root instanceof Tree ) {
TreeViewer viewer = new TreeViewer(recognizer, (Tree)root); TreeViewer viewer = new TreeViewer(recognizer, (Tree)root);
viewer.open(); viewer.open();
List<T> unmatchedNodes = null;
if ( e instanceof NoViableTreeGrammarAltException ) { if ( e instanceof NoViableTreeGrammarAltException ) {
NoViableTreeGrammarAltException nva = NoViableTreeGrammarAltException nva =
(NoViableTreeGrammarAltException)e; (NoViableTreeGrammarAltException)e;
// ((AST)nva.startNode).get unmatchedNodes = getNodeList(input, nva);
} }
else { else {
unmatchedNodes = new ArrayList<T>();
unmatchedNodes.add((T)e.offendingNode);
}
viewer.setHighlightedBoxColor(TreeViewer.LIGHT_RED);
viewer.addHighlightedNodes((List<Tree>)unmatchedNodes);
}
}
@Override
public void reportNoViableAlternative(BaseRecognizer recognizer,
NoViableAltException e)
throws RecognitionException
{
TreeParser<T> parser = (TreeParser<T>)recognizer;
ASTNodeStream input = parser.getInputStream();
List<T> unmatchedNodes =
getNodeList(input, (NoViableTreeGrammarAltException)e);
StringBuffer buf = new StringBuffer();
ASTAdaptor<T> adap = input.getTreeAdaptor();
for (int i = 0; i < unmatchedNodes.size(); i++) {
if ( i>0 ) buf.append(" ");
T t = unmatchedNodes.get(i);
buf.append(adap.getText(t));
} }
// input.get() String s = buf.toString();
// viewer.addHighlightedNodes(); String msg = "no viable alternative at node(s) "+escapeWSAndQuote(s);
// TODO: highlight error node recognizer.notifyListeners(e.offendingToken, msg, e);
} }
protected List<T> getNodeList(ASTNodeStream input,
NoViableTreeGrammarAltException nva)
{
List<T> unmatchedNodes;
T start = (T)nva.startNode;
T stop = (T)nva.offendingNode;
if ( input instanceof BufferedASTNodeStream) {
BufferedASTNodeStream<T> b =
(BufferedASTNodeStream<T>)input;
unmatchedNodes = b.get(start, stop);
}
else {
// if not buffered then we can't get from start to stop;
// just highlight the start/stop nodes, but not in between
unmatchedNodes = new ArrayList<T>();
if ( nva.startNode!=null ) {
unmatchedNodes.add((T)nva.startNode);
}
if ( nva.startNode==null || nva.offendingNode!=nva.startNode ) {
unmatchedNodes.add((T)nva.offendingNode);
}
}
return unmatchedNodes;
} }
@Override @Override
@ -70,9 +121,7 @@ public class DefaultANTLRTreeGrammarErrorStrategy extends DefaultANTLRErrorStrat
@Override @Override
public void recover(BaseRecognizer recognizer, RecognitionException e) { public void recover(BaseRecognizer recognizer, RecognitionException e) {
throw new RecognitionException(recognizer, throw new RuntimeException(e);
recognizer.getInputStream(),
recognizer._ctx);
} }
@Override @Override

View File

@ -136,7 +136,7 @@ public abstract class Lexer extends Recognizer<LexerATNSimulator>
} }
catch (LexerNoViableAltException e) { catch (LexerNoViableAltException e) {
notifyListeners(e); // report error notifyListeners(e); // report error
recover(); recover(e);
ttype = SKIP; ttype = SKIP;
} }
if ( input.LA(1)==CharStream.EOF ) { if ( input.LA(1)==CharStream.EOF ) {
@ -301,7 +301,7 @@ public abstract class Lexer extends Recognizer<LexerATNSimulator>
return null; return null;
} }
public void recover() { public void recover(LexerNoViableAltException e) {
_interp.consume(input); // skip a char and try again _interp.consume(input); // skip a char and try again
} }

View File

@ -38,16 +38,24 @@ public class NoViableTreeGrammarAltException extends NoViableAltException {
protected Object offendingNode; protected Object offendingNode;
public NoViableTreeGrammarAltException(BaseRecognizer recognizer) { public NoViableTreeGrammarAltException(BaseRecognizer recognizer) {
super(recognizer); this(recognizer,
(ASTNodeStream<Object>)recognizer.getInputStream(),
recognizer.getCurrentInputSymbol(),
recognizer.getCurrentInputSymbol(),
null,
recognizer._ctx);
} }
public NoViableTreeGrammarAltException(BaseRecognizer recognizer, public NoViableTreeGrammarAltException(BaseRecognizer recognizer,
ASTNodeStream input, ASTNodeStream<Object> input,
Object startNode, Object startNode,
Object offendingNode, Object offendingNode,
OrderedHashSet<ATNConfig> deadEndConfigs, OrderedHashSet<ATNConfig> deadEndConfigs,
RuleContext ctx) { RuleContext ctx) {
super(recognizer, input, null, null, deadEndConfigs, ctx); super(recognizer, input,
input.getTreeAdaptor().getToken(startNode),
input.getTreeAdaptor().getToken(offendingNode),
deadEndConfigs, ctx);
this.startNode = startNode; this.startNode = startNode;
this.offendingNode = offendingNode; this.offendingNode = offendingNode;
} }

View File

@ -852,15 +852,20 @@ public class ParserATNSimulator extends ATNSimulator {
public int throwNoViableAlt(ObjectStream input, RuleContext outerContext, public int throwNoViableAlt(ObjectStream input, RuleContext outerContext,
OrderedHashSet<ATNConfig> configs, int startIndex) OrderedHashSet<ATNConfig> configs, int startIndex)
{ {
Object startNode = null;
if ( input instanceof BufferedASTNodeStream ) {
startNode = input.get(startIndex);
}
if ( parser instanceof TreeParser) { if ( parser instanceof TreeParser) {
throw new NoViableTreeGrammarAltException(parser, (ASTNodeStream)input, throw new NoViableTreeGrammarAltException(parser,
input.get(startIndex), (ASTNodeStream<Object>)input,
startNode,
input.LT(1), input.LT(1),
configs, outerContext); configs, outerContext);
} }
else { else {
throw new NoViableAltException(parser, input, throw new NoViableAltException(parser, input,
(Token)input.get(startIndex), (Token) startNode,
(Token)input.LT(1), (Token)input.LT(1),
configs, outerContext); configs, outerContext);
} }

View File

@ -42,17 +42,18 @@ import java.util.List;
public interface ASTAdaptor<T> { public interface ASTAdaptor<T> {
// BEGIN new v4 stuff // BEGIN new v4 stuff
// If not null root, add kids to it
//public void addChildren(Object root, List kids);
//public List getChildren(Object root);
/** Used to track elements to left of -> for use in rewrite. These /** Used to track elements to left of -> for use in rewrite. These
* are some kind of trees, but we generically use Object * are some kind of trees, but we generically use Object
* for tree types in ANTLR. * for tree types in ANTLR.
*/ */
public List<T> createElementList(); public List<T> createElementList();
/** Get the absolute index starting from 0 of this note within
* a node stream. This should w
ork even if the stream is not buffered
*/
// public int getNodeIndex(T t);
// END new v4 stuff // END new v4 stuff
// C o n s t r u c t i o n // C o n s t r u c t i o n

View File

@ -213,6 +213,29 @@ public class BufferedASTNodeStream<T> implements ASTNodeStream<T> {
return nodes.get(i); return nodes.get(i);
} }
public List<T> get(int i, int j) {
if ( p==-1 ) {
fillBuffer();
}
return nodes.subList(i,j+1);
}
public List<T> get(T start, T stop) {
int i=0;
for (; i<nodes.size(); i++) {
T t = nodes.get(i);
if ( t==start ) break;
}
int j=i;
for (; j<nodes.size(); j++) {
T t = nodes.get(j);
if ( t==stop ) break;
}
if ( i>=nodes.size() ) return null;
if ( j>=nodes.size() ) j = nodes.size()-1;
return get(i,j);
}
public T LT(int k) { public T LT(int k) {
if ( p==-1 ) { if ( p==-1 ) {
fillBuffer(); fillBuffer();

View File

@ -130,6 +130,7 @@ public class CommonASTAdaptor extends BaseASTAdaptor<CommonAST> {
* override this in your own adaptor. * override this in your own adaptor.
*/ */
public Token getToken(CommonAST t) { public Token getToken(CommonAST t) {
if ( t==null ) return null;
return t.getToken(); return t.getToken();
} }

View File

@ -41,7 +41,7 @@ public class TreeParser<T> extends BaseRecognizer {
public static final int DOWN = Token.DOWN; public static final int DOWN = Token.DOWN;
public static final int UP = Token.UP; public static final int UP = Token.UP;
public ASTAdaptor _adaptor = new CommonASTAdaptor(); public ASTAdaptor<T> _adaptor = (ASTAdaptor<T>)new CommonASTAdaptor();
// precompiled regex used by inContext // precompiled regex used by inContext
static String dotdot = ".*[^.]\\.\\.[^.].*"; static String dotdot = ".*[^.]\\.\\.[^.].*";
@ -53,7 +53,7 @@ public class TreeParser<T> extends BaseRecognizer {
public TreeParser(ASTNodeStream<T> input) { public TreeParser(ASTNodeStream<T> input) {
super(input); super(input);
_errHandler = new DefaultANTLRTreeGrammarErrorStrategy(); _errHandler = new DefaultANTLRTreeGrammarErrorStrategy<T>();
} }
public void reset() { public void reset() {

View File

@ -232,6 +232,7 @@ public class TreeViewer extends JComponent {
ok.addActionListener( ok.addActionListener(
new ActionListener() { new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
dialog.setVisible(false);
dialog.dispose(); dialog.dispose();
} }
} }

View File

@ -1,5 +1,12 @@
grammar E; grammar E;
@lexer::members {
public void recover(LexerNoViableAltException e) {
super.recover(e);
throw new RuntimeException(e);
}
}
prog: classDef+ ; // match one or more class definitions prog: classDef+ ; // match one or more class definitions
classDef classDef

View File

@ -188,12 +188,10 @@ RuleFunction(currentRule,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAc
<postamble; separator="\n"> <postamble; separator="\n">
<namedActions.after> <namedActions.after>
} }
<if(currentRule.catch_)>
catch (RecognitionException re) { catch (RecognitionException re) {
_errHandler.reportError(this, re); _errHandler.reportError(this, re);
_errHandler.recover(this, re); _errHandler.recover(this, re);
} }
<endif>
finally { finally {
<finallyAction> <finallyAction>
exitRule(RULE_<currentRule.name>); exitRule(RULE_<currentRule.name>);
@ -378,6 +376,14 @@ case <i>:
Sync(s) ::= "sync(<s.expecting.name>);" Sync(s) ::= "sync(<s.expecting.name>);"
ThrowNoViableAlt(t) ::= "throw new NoViableAltException(this);" ThrowNoViableAlt(t) ::= "throw new NoViableAltException(this);"
ThrowNoViableTreeAlt(t) ::= <<
/*
NoViableTreeGrammarAltException e<choice.uniqueID> = new NoViableTreeGrammarAltException(this);
_errHandler.reportError(this, e<choice.uniqueID>);
throw e<choice.uniqueID>;
*/
throw new NoViableTreeGrammarAltException(this);
>>
TestSetInline(s) ::= << TestSetInline(s) ::= <<
<s.ttypes:{ttype | <s.varName>==<ttype>}; separator=" || "> <s.ttypes:{ttype | <s.varName>==<ttype>}; separator=" || ">

View File

@ -30,14 +30,12 @@
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.codegen.model.decl.Decl; import org.antlr.v4.codegen.model.decl.*;
import org.antlr.v4.codegen.model.decl.TokenTypeDecl;
import org.antlr.v4.misc.Utils; import org.antlr.v4.misc.Utils;
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;
/** The class hierarchy underneath SrcOp is pretty deep but makes sense that, /** The class hierarchy underneath SrcOp is pretty deep but makes sense that,
* for example LL1StarBlock is a kind of LL1Loop which is a kind of Choice. * for example LL1StarBlock is a kind of LL1Loop which is a kind of Choice.
@ -89,4 +87,15 @@ public abstract class Choice extends RuleElement {
} }
return expr; return expr;
} }
public ThrowNoViableAlt getThrowNoViableAlt(OutputModelFactory factory,
GrammarAST blkAST,
IntervalSet expecting) {
if ( factory.getGrammar().isTreeGrammar() ) {
return new ThrowNoViableTreeAlt(factory, blkAST, expecting);
}
else {
return new ThrowNoViableAlt(factory, blkAST, expecting);
}
}
} }

View File

@ -48,7 +48,7 @@ public class LL1AltBlock extends LL1Choice {
altLook = getAltLookaheadAsStringLists(altLookSets); altLook = getAltLookaheadAsStringLists(altLookSets);
IntervalSet expecting = IntervalSet.or(altLookSets); // combine alt sets IntervalSet expecting = IntervalSet.or(altLookSets); // combine alt sets
this.error = new ThrowNoViableAlt(factory, blkAST, expecting); this.error = getThrowNoViableAlt(factory, blkAST, expecting);
System.out.println(blkAST.toStringTree()+" LL1AltBlock expecting="+expecting); System.out.println(blkAST.toStringTree()+" LL1AltBlock expecting="+expecting);
} }
} }

View File

@ -56,7 +56,7 @@ public class LL1OptionalBlockSingleAlt extends LL1Choice {
IntervalSet followLook = altLookSets[2]; IntervalSet followLook = altLookSets[2];
IntervalSet expecting = (IntervalSet)look.or(followLook); IntervalSet expecting = (IntervalSet)look.or(followLook);
this.error = new ThrowNoViableAlt(factory, blkAST, expecting); this.error = getThrowNoViableAlt(factory, blkAST, expecting);
System.out.println(blkAST.toStringTree()+" LL1OptionalBlockSingleAlt expecting="+expecting); System.out.println(blkAST.toStringTree()+" LL1OptionalBlockSingleAlt expecting="+expecting);
expr = addCodeForLookaheadTempVar(look); expr = addCodeForLookaheadTempVar(look);

View File

@ -29,8 +29,7 @@
package org.antlr.v4.codegen.model; package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.CodeGenerator; import org.antlr.v4.codegen.*;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.runtime.atn.PlusBlockStartState; import org.antlr.v4.runtime.atn.PlusBlockStartState;
import org.antlr.v4.runtime.misc.IntervalSet; import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.tool.Grammar; import org.antlr.v4.tool.Grammar;
@ -67,7 +66,7 @@ public class LL1PlusBlock extends LL1Loop {
IntervalSet all = new IntervalSet(); IntervalSet all = new IntervalSet();
for (IntervalSet s : altLookSets) all.addAll(s); for (IntervalSet s : altLookSets) all.addAll(s);
this.error = new ThrowNoViableAlt(factory, plusRoot, all); this.error = getThrowNoViableAlt(factory, plusRoot, all);
loopExpr = addCodeForLoopLookaheadTempVar(all); loopExpr = addCodeForLoopLookaheadTempVar(all);

View File

@ -49,7 +49,7 @@ public class PlusBlock extends Loop {
stateNumber = blkStart.loopBackState.stateNumber; stateNumber = blkStart.loopBackState.stateNumber;
blockStartStateNumber = blkStart.stateNumber; blockStartStateNumber = blkStart.stateNumber;
loopBackStateNumber = loop.stateNumber; loopBackStateNumber = loop.stateNumber;
this.error = new ThrowNoViableAlt(factory, plusRoot, null); this.error = getThrowNoViableAlt(factory, plusRoot, null);
decision = loop.decision; decision = loop.decision;
exitAlt = alts.size()+1; exitAlt = alts.size()+1;
} }

View File

@ -52,7 +52,6 @@ public class RuleFunction extends OutputModelObject {
public int index; public int index;
public Collection<Attribute> args = null; public Collection<Attribute> args = null;
public Rule rule; public Rule rule;
public boolean catch_;
@ModelElement public List<SrcOp> code; @ModelElement public List<SrcOp> code;
@ModelElement public OrderedHashSet<Decl> locals; // TODO: move into ctx? @ModelElement public OrderedHashSet<Decl> locals; // TODO: move into ctx?
@ -74,8 +73,6 @@ public class RuleFunction extends OutputModelObject {
index = r.index; index = r.index;
catch_ = !r.g.isTreeGrammar();
ruleCtx = r.g.isTreeGrammar() ? ruleCtx = r.g.isTreeGrammar() ?
new TreeParserStructDecl(factory, r) : new TreeParserStructDecl(factory, r) :
new StructDecl(factory, r); new StructDecl(factory, r);

View File

@ -0,0 +1,43 @@
/*
[The "BSD license"]
Copyright (c) 2011 Terence Parr
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.tool.ast.GrammarAST;
public class ThrowNoViableTreeAlt extends ThrowNoViableAlt {
public ThrowNoViableTreeAlt(OutputModelFactory factory,
GrammarAST blkOrEbnfRootAST,
IntervalSet expecting)
{
super(factory, blkOrEbnfRootAST, expecting);
}
}