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.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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
grammar T;
|
||||||
|
|
||||||
s : A | B ;
|
s : e ';' ;
|
||||||
|
|
||||||
e : e '+' e
|
e : e '+' e
|
||||||
| INT
|
| INT
|
||||||
;
|
;
|
||||||
|
|
||||||
|
INT : [0-9]+ ;
|
||||||
|
WS : [ \r\n\t]+ -> skip ;
|
||||||
|
|
|
@ -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));
|
||||||
|
|
Loading…
Reference in New Issue