forked from jasder/antlr
Merge branch 'main' of github.com:parrt/antlr4 into main
This commit is contained in:
commit
11e6bdaef6
|
@ -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);
|
||||
}
|
|
@ -36,41 +36,53 @@ import org.antlr.v4.runtime.atn.RuleTransition;
|
|||
import org.antlr.v4.runtime.dfa.DFA;
|
||||
import org.antlr.v4.runtime.misc.IntervalSet;
|
||||
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.List;
|
||||
|
||||
/** 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 class TraceListener implements ParseListener<Token> {
|
||||
public class TraceListener implements ParseTreeListener<Token> {
|
||||
@Override
|
||||
public void enterNonLRRule(ParserRuleContext<Token> ctx) {
|
||||
System.out.println("enter " + getRuleNames()[ctx.getRuleIndex()] + ", LT(1)=" + _input.LT(1).getText());
|
||||
public void enterEveryRule(ParserRuleContext<Token> ctx) {
|
||||
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
|
||||
public void exitEveryRule(ParserRuleContext<Token> ctx) {
|
||||
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);
|
||||
System.out.println("exit "+getRuleNames()[ctx.getRuleIndex()]+
|
||||
", LT(1)="+_input.LT(1).getText());
|
||||
}
|
||||
}
|
||||
|
||||
public static class TrimToSizeListener implements ParseListener<Token> {
|
||||
public static class TrimToSizeListener implements ParseTreeListener<Token> {
|
||||
public static final TrimToSizeListener INSTANCE = new TrimToSizeListener();
|
||||
|
||||
@Override
|
||||
public void visitTerminal(ParserRuleContext<Token> parent, Token token) {
|
||||
}
|
||||
public void enterEveryRule(ParserRuleContext<Token> ctx) { }
|
||||
|
||||
@Override
|
||||
public void enterNonLRRule(ParserRuleContext<Token> ctx) {
|
||||
}
|
||||
public void visitTerminal(TerminalNode<Token> node) { }
|
||||
|
||||
@Override
|
||||
public void visitErrorNode(ErrorNode<Token> node) { }
|
||||
|
||||
@Override
|
||||
public void exitEveryRule(ParserRuleContext<Token> ctx) {
|
||||
|
@ -78,7 +90,6 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
|
|||
((ArrayList<?>)ctx.children).trimToSize();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
* parse trees for later visiting. We either trigger events during
|
||||
* 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. */
|
||||
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
|
||||
* 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;
|
||||
// }
|
||||
|
||||
public List<ParseListener<Token>> getParseListeners() {
|
||||
public List<ParseTreeListener<Token>> getParseListeners() {
|
||||
return _parseListeners;
|
||||
}
|
||||
|
||||
// TODO: make comment directing people to ParseTreeListener
|
||||
public void addParseListener(ParseListener<Token> listener) {
|
||||
/** Provide a listener that gets notified about token matches,
|
||||
* 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 ( _parseListeners==null ) {
|
||||
_parseListeners = new ArrayList<ParseListener<Token>>();
|
||||
_parseListeners = new ArrayList<ParseTreeListener<Token>>();
|
||||
}
|
||||
this._parseListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeParseListener(ParseListener<Token> l) {
|
||||
public void removeParseListener(ParseTreeListener<Token> l) {
|
||||
if ( l==null ) return;
|
||||
if ( _parseListeners!=null ) {
|
||||
_parseListeners.remove(l);
|
||||
|
@ -235,17 +255,27 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
|
|||
_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() {
|
||||
for (ParseListener<Token> l : _parseListeners) {
|
||||
l.enterNonLRRule(_ctx);
|
||||
for (ParseTreeListener<Token> l : _parseListeners) {
|
||||
l.enterEveryRule(_ctx);
|
||||
_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() {
|
||||
// reverse order walk of listeners
|
||||
for (int i = _parseListeners.size()-1; i >= 0; i--) {
|
||||
ParseListener<Token> l = _parseListeners.get(i);
|
||||
ParseTreeListener<Token> l = _parseListeners.get(i);
|
||||
_ctx.exitRule(l);
|
||||
l.exitEveryRule(_ctx);
|
||||
}
|
||||
|
@ -336,15 +366,15 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
|
|||
Token o = getCurrentToken();
|
||||
getInputStream().consume();
|
||||
if (_buildParseTrees) {
|
||||
// TODO: tree parsers?
|
||||
if ( _errHandler.inErrorRecoveryMode(this) ) {
|
||||
// System.out.println("consume in error recovery mode for "+o);
|
||||
_ctx.addErrorNode(o);
|
||||
}
|
||||
else _ctx.addChild(o);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -390,10 +420,13 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
|
|||
_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) {
|
||||
_ctx = localctx;
|
||||
_ctx.start = _input.LT(1);
|
||||
if ( _parseListeners != null ) {
|
||||
triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules
|
||||
}
|
||||
}
|
||||
|
||||
public void unrollRecursionContexts(ParserRuleContext<Token> _parentctx) {
|
||||
|
@ -589,7 +622,7 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator<Token>
|
|||
// 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.
|
||||
*/
|
||||
public void setTrace(boolean trace) {
|
||||
|
|
|
@ -138,15 +138,10 @@ public class ParserRuleContext<Symbol extends Token> extends RuleContext {
|
|||
|
||||
// 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 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) {
|
||||
if ( children==null ) children = new ArrayList<ParseTree>();
|
||||
children.add(t);
|
||||
|
|
|
@ -263,11 +263,13 @@ public class RuleContext implements RuleNode {
|
|||
@Override
|
||||
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) {
|
||||
TreeViewer viewer = new TreeViewer(parser, this);
|
||||
viewer.open();
|
||||
}
|
||||
|
||||
/** Save this tree in a postscript file */
|
||||
public void save(Parser parser, String fileName)
|
||||
throws IOException, PrintException
|
||||
{
|
||||
|
@ -276,6 +278,7 @@ public class RuleContext implements RuleNode {
|
|||
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,
|
||||
String fontName, int fontSize)
|
||||
throws IOException
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
grammar T;
|
||||
|
||||
s : A | B ;
|
||||
s : e ';' ;
|
||||
|
||||
e : e '+' e
|
||||
| INT
|
||||
;
|
||||
|
||||
INT : [0-9]+ ;
|
||||
WS : [ \r\n\t]+ -> skip ;
|
||||
|
|
|
@ -26,7 +26,8 @@ public class TestT {
|
|||
|
||||
parser.addErrorListener(new DiagnosticErrorListener());
|
||||
|
||||
parser.getInterpreter().setSLL(true);
|
||||
// parser.getInterpreter().setSLL(true);
|
||||
// parser.setTrace(true);
|
||||
|
||||
ParserRuleContext tree = parser.s();
|
||||
System.out.println(tree.toStringTree(parser));
|
||||
|
|
Loading…
Reference in New Issue