Merge branch 'main' of github.com:parrt/antlr4 into main

This commit is contained in:
Terence Parr 2012-09-02 14:22:37 -07:00
commit 11e6bdaef6
7 changed files with 76 additions and 163 deletions

View File

@ -1,18 +0,0 @@
package org.antlr.v4.runtime;
/** We must distinguish between listeners triggered during the parse
* from listeners triggered during a subsequent tree walk. During
* the parse, the ctx object arg for enter methods don't have any labels set.
* We can only access the general ParserRuleContext<Symbol> ctx.
* Also, we can only call exit methods for left-recursive rules. Let's
* make the interface clear these semantics up. If you need the ctx,
* use Parser.getRuleContext().
*/
public interface ParseListener<Symbol extends Token> {
void visitTerminal(ParserRuleContext<Symbol> parent, Symbol token);
/** Enter all but left-recursive rules */
void enterNonLRRule(ParserRuleContext<Symbol> ctx);
void exitEveryRule(ParserRuleContext<Symbol> ctx);
}

View File

@ -36,41 +36,53 @@ import org.antlr.v4.runtime.atn.RuleTransition;
import org.antlr.v4.runtime.dfa.DFA; import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.IntervalSet; import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.runtime.misc.Nullable; import org.antlr.v4.runtime.misc.Nullable;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.antlr.v4.runtime.tree.TerminalNodeImpl;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** This is all the parsing support code essentially; most of it is error recovery stuff. */ /** This is all the parsing support code essentially; most of it is error recovery stuff. */
public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>> { public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>> {
public class TraceListener implements ParseListener<Token> { public class TraceListener implements ParseTreeListener<Token> {
@Override @Override
public void enterNonLRRule(ParserRuleContext<Token> ctx) { public void enterEveryRule(ParserRuleContext<Token> ctx) {
System.out.println("enter " + getRuleNames()[ctx.getRuleIndex()] + ", LT(1)=" + _input.LT(1).getText()); System.out.println("enter " + getRuleNames()[ctx.getRuleIndex()] +
", LT(1)=" + _input.LT(1).getText());
}
@Override
public void visitTerminal(TerminalNode<Token> node) {
System.out.println("consume "+node.getSymbol()+" rule "+
getRuleNames()[_ctx.getRuleIndex()]+
" alt="+_ctx.altNum);
}
@Override
public void visitErrorNode(ErrorNode<Token> node) {
} }
@Override @Override
public void exitEveryRule(ParserRuleContext<Token> ctx) { public void exitEveryRule(ParserRuleContext<Token> ctx) {
System.out.println("exit "+getRuleNames()[ctx.getRuleIndex()]+", LT(1)="+_input.LT(1).getText()); System.out.println("exit "+getRuleNames()[ctx.getRuleIndex()]+
} ", LT(1)="+_input.LT(1).getText());
@Override
public void visitTerminal(ParserRuleContext<Token> parent, Token token) {
System.out.println("consume "+token+" rule "+
getRuleNames()[parent.getRuleIndex()]+
" alt="+parent.altNum);
} }
} }
public static class TrimToSizeListener implements ParseListener<Token> { public static class TrimToSizeListener implements ParseTreeListener<Token> {
public static final TrimToSizeListener INSTANCE = new TrimToSizeListener(); public static final TrimToSizeListener INSTANCE = new TrimToSizeListener();
@Override @Override
public void visitTerminal(ParserRuleContext<Token> parent, Token token) { public void enterEveryRule(ParserRuleContext<Token> ctx) { }
}
@Override @Override
public void enterNonLRRule(ParserRuleContext<Token> ctx) { public void visitTerminal(TerminalNode<Token> node) { }
}
@Override
public void visitErrorNode(ErrorNode<Token> node) { }
@Override @Override
public void exitEveryRule(ParserRuleContext<Token> ctx) { public void exitEveryRule(ParserRuleContext<Token> ctx) {
@ -78,7 +90,6 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
((ArrayList<?>)ctx.children).trimToSize(); ((ArrayList<?>)ctx.children).trimToSize();
} }
} }
} }
protected ANTLRErrorStrategy _errHandler = new DefaultErrorStrategy(); protected ANTLRErrorStrategy _errHandler = new DefaultErrorStrategy();
@ -100,9 +111,11 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
* *during* the parse. This is typically done only when not building * *during* the parse. This is typically done only when not building
* parse trees for later visiting. We either trigger events during * parse trees for later visiting. We either trigger events during
* the parse or during tree walks later. Both could be done. * the parse or during tree walks later. Both could be done.
* Not intended for tree parsing but would work. * Not intended for average user!!! Most people should use
* ParseTreeListener with ParseTreeWalker.
* @see ParseTreeWalker
*/ */
protected List<ParseListener<Token>> _parseListeners; protected List<ParseTreeListener<Token>> _parseListeners;
/** Did the recognizer encounter a syntax error? Track how many. */ /** Did the recognizer encounter a syntax error? Track how many. */
protected int _syntaxErrors = 0; protected int _syntaxErrors = 0;
@ -191,7 +204,6 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
} }
/** /**
*
* @return {@code true} if the {@link ParserRuleContext#children} list is trimmed * @return {@code true} if the {@link ParserRuleContext#children} list is trimmed
* using the default {@link Parser.TrimToSizeListener} during the parse process. * using the default {@link Parser.TrimToSizeListener} during the parse process.
*/ */
@ -208,20 +220,28 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
// return traceATNStates; // return traceATNStates;
// } // }
public List<ParseListener<Token>> getParseListeners() { public List<ParseTreeListener<Token>> getParseListeners() {
return _parseListeners; return _parseListeners;
} }
// TODO: make comment directing people to ParseTreeListener /** Provide a listener that gets notified about token matches,
public void addParseListener(ParseListener<Token> listener) { * and rule entry/exit events DURING the parse. It's a little bit
* weird for left recursive rule entry events but it's
* deterministic.
*
* THIS IS ONLY FOR ADVANCED USERS. Please give your
* ParseTreeListener to a ParseTreeWalker instead of giving it to
* the parser!!!!
*/
public void addParseListener(ParseTreeListener<Token> listener) {
if ( listener==null ) return; if ( listener==null ) return;
if ( _parseListeners==null ) { if ( _parseListeners==null ) {
_parseListeners = new ArrayList<ParseListener<Token>>(); _parseListeners = new ArrayList<ParseTreeListener<Token>>();
} }
this._parseListeners.add(listener); this._parseListeners.add(listener);
} }
public void removeParseListener(ParseListener<Token> l) { public void removeParseListener(ParseTreeListener<Token> l) {
if ( l==null ) return; if ( l==null ) return;
if ( _parseListeners!=null ) { if ( _parseListeners!=null ) {
_parseListeners.remove(l); _parseListeners.remove(l);
@ -235,17 +255,27 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
_parseListeners = null; _parseListeners = null;
} }
/** Notify any parse listeners (implemented as ParseTreeListener's)
* of an enter rule event. This is not involved with
* parse tree walking in any way; it's just reusing the
* ParseTreeListener interface. This is not for the average user.
*/
public void triggerEnterRuleEvent() { public void triggerEnterRuleEvent() {
for (ParseListener<Token> l : _parseListeners) { for (ParseTreeListener<Token> l : _parseListeners) {
l.enterNonLRRule(_ctx); l.enterEveryRule(_ctx);
_ctx.enterRule(l); _ctx.enterRule(l);
} }
} }
/** Notify any parse listeners (implemented as ParseTreeListener's)
* of an exit rule event. This is not involved with
* parse tree walking in any way; it's just reusing the
* ParseTreeListener interface. This is not for the average user.
*/
public void triggerExitRuleEvent() { public void triggerExitRuleEvent() {
// reverse order walk of listeners // reverse order walk of listeners
for (int i = _parseListeners.size()-1; i >= 0; i--) { for (int i = _parseListeners.size()-1; i >= 0; i--) {
ParseListener<Token> l = _parseListeners.get(i); ParseTreeListener<Token> l = _parseListeners.get(i);
_ctx.exitRule(l); _ctx.exitRule(l);
l.exitEveryRule(_ctx); l.exitEveryRule(_ctx);
} }
@ -336,15 +366,15 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
Token o = getCurrentToken(); Token o = getCurrentToken();
getInputStream().consume(); getInputStream().consume();
if (_buildParseTrees) { if (_buildParseTrees) {
// TODO: tree parsers?
if ( _errHandler.inErrorRecoveryMode(this) ) { if ( _errHandler.inErrorRecoveryMode(this) ) {
// System.out.println("consume in error recovery mode for "+o);
_ctx.addErrorNode(o); _ctx.addErrorNode(o);
} }
else _ctx.addChild(o); else _ctx.addChild(o);
} }
if ( _parseListeners != null) { if ( _parseListeners != null) {
for (ParseListener<Token> l : _parseListeners) l.visitTerminal(_ctx, o); for (ParseTreeListener<Token> l : _parseListeners) {
l.visitTerminal(new TerminalNodeImpl<Token>(o));
}
} }
return o; return o;
} }
@ -390,10 +420,13 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
_ctx.altNum = altNum; _ctx.altNum = altNum;
} }
/* like enterRule but for recursive rules; no enter events for recursive rules. */ /* like enterRule but for recursive rules */
public void pushNewRecursionContext(ParserRuleContext<Token> localctx, int ruleIndex) { public void pushNewRecursionContext(ParserRuleContext<Token> localctx, int ruleIndex) {
_ctx = localctx; _ctx = localctx;
_ctx.start = _input.LT(1); _ctx.start = _input.LT(1);
if ( _parseListeners != null ) {
triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules
}
} }
public void unrollRecursionContexts(ParserRuleContext<Token> _parentctx) { public void unrollRecursionContexts(ParserRuleContext<Token> _parentctx) {
@ -589,7 +622,7 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
// if ( traceATNStates ) _ctx.trace(atnState); // if ( traceATNStates ) _ctx.trace(atnState);
} }
/** During a parse is extremely useful to listen in on the rule entry and exit /** During a parse is sometimes useful to listen in on the rule entry and exit
* events as well as token matches. This is for quick and dirty debugging. * events as well as token matches. This is for quick and dirty debugging.
*/ */
public void setTrace(boolean trace) { public void setTrace(boolean trace) {

View File

@ -138,15 +138,10 @@ public class ParserRuleContext<Symbol extends Token> extends RuleContext {
// Double dispatch methods for listeners // Double dispatch methods for listeners
// parse listener
public void enterRule(ParseListener<Symbol> listener) { }
public void exitRule(ParseListener<Symbol> listener) { }
// parse tree listener
public void enterRule(ParseTreeListener<Symbol> listener) { } public void enterRule(ParseTreeListener<Symbol> listener) { }
public void exitRule(ParseTreeListener<Symbol> listener) { } public void exitRule(ParseTreeListener<Symbol> listener) { }
/** Does not set parent link; other add methods do */ /** Does not set parent link; other add methods do that */
public void addChild(TerminalNode<Symbol> t) { public void addChild(TerminalNode<Symbol> t) {
if ( children==null ) children = new ArrayList<ParseTree>(); if ( children==null ) children = new ArrayList<ParseTree>();
children.add(t); children.add(t);

View File

@ -263,11 +263,13 @@ public class RuleContext implements RuleNode {
@Override @Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) { return visitor.visitChildren(this); } public <T> T accept(ParseTreeVisitor<? extends T> visitor) { return visitor.visitChildren(this); }
/** Call this method to view a parse tree in a dialog box visually. */
public void inspect(Parser parser) { public void inspect(Parser parser) {
TreeViewer viewer = new TreeViewer(parser, this); TreeViewer viewer = new TreeViewer(parser, this);
viewer.open(); viewer.open();
} }
/** Save this tree in a postscript file */
public void save(Parser parser, String fileName) public void save(Parser parser, String fileName)
throws IOException, PrintException throws IOException, PrintException
{ {
@ -276,6 +278,7 @@ public class RuleContext implements RuleNode {
Trees.writePS(this, parser, fileName); // parrt routine Trees.writePS(this, parser, fileName); // parrt routine
} }
/** Save this tree in a postscript file using a particular font name and size */
public void save(Parser parser, String fileName, public void save(Parser parser, String fileName,
String fontName, int fontSize) String fontName, int fontSize)
throws IOException throws IOException

View File

@ -1,104 +0,0 @@
/*
[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.runtime.tree;
import org.antlr.v4.runtime.atn.ATNState;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class TraceTree implements Tree {
public TraceTree parent;
public List<TraceTree> children;
/** If this node is root, it has list of all leaves of tree after ParserATNPathFinder.trace() */
public List<TraceTree> leaves;
public ATNState state; // payload
public TraceTree(ATNState s) { state = s; }
public void addChild(TraceTree t) {
if ( children==null ) {
children = new ArrayList<TraceTree>();
}
children.add(t);
t.parent = this;
}
public void addChild(ATNState s) { addChild(new TraceTree(s)); }
@Override
public Tree getChild(int i) {
if ( children==null ) {
throw new IndexOutOfBoundsException(i+"<0 or >"+getChildCount());
}
return children.get(i);
}
@Override
public Tree getParent() {
return parent;
}
@Override
public Object getPayload() {
return state;
}
@Override
public int getChildCount() {
if ( children==null ) return 0;
return children.size();
}
public List<ATNState> getPathToNode(TraceTree s) {
List<ATNState> states = new LinkedList<ATNState>();
TraceTree p = s;
while ( p!=null ) {
states.add(0, p.state);
p = p.parent;
}
if ( states.isEmpty() ) return null;
return states;
}
@Override
public String toString() {
if ( state==null ) return "null";
return state.toString();
}
@Override
public String toStringTree() {
return Trees.toStringTree(this, null);
}
}

View File

@ -1,7 +1,10 @@
grammar T; grammar T;
s : A | B ; s : e ';' ;
e : e '+' e e : e '+' e
| INT | INT
; ;
INT : [0-9]+ ;
WS : [ \r\n\t]+ -> skip ;

View File

@ -26,7 +26,8 @@ public class TestT {
parser.addErrorListener(new DiagnosticErrorListener()); parser.addErrorListener(new DiagnosticErrorListener());
parser.getInterpreter().setSLL(true); // parser.getInterpreter().setSLL(true);
// parser.setTrace(true);
ParserRuleContext tree = parser.s(); ParserRuleContext tree = parser.s();
System.out.println(tree.toStringTree(parser)); System.out.println(tree.toStringTree(parser));