forked from jasder/antlr
add dbg classes. add mark/rewind
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9034]
This commit is contained in:
parent
085dd05bf1
commit
62549b65bf
|
@ -46,14 +46,14 @@ public interface IntStream {
|
|||
int LA(int i);
|
||||
|
||||
/** Tell the stream to start buffering if it hasn't already. Return
|
||||
* current input position, index(), or some other marker so that
|
||||
* when passed to rewind() you get back to the same spot.
|
||||
* rewind(mark()) should not affect the input cursor. The Lexer
|
||||
* track line/col info as well as input index so its markers are
|
||||
* not pure input indexes. Same for tree node streams.
|
||||
* current input position, index(). seek(mark()) should not
|
||||
* affect the input cursor.
|
||||
*/
|
||||
int mark();
|
||||
|
||||
/** Reset the stream so that next call to index() would return index arg. */
|
||||
void rewind(int index);
|
||||
|
||||
/** Return the current input symbol index 0..n where n indicates the
|
||||
* last symbol has been read. The index is the symbol about to be
|
||||
* read not the most recently read symbol.
|
||||
|
|
|
@ -29,7 +29,8 @@
|
|||
package org.antlr.v4.runtime;
|
||||
|
||||
|
||||
import org.antlr.v4.runtime.tree.*;
|
||||
import org.antlr.v4.runtime.tree.CommonTreeAdaptor;
|
||||
import org.antlr.v4.runtime.tree.TreeAdaptor;
|
||||
|
||||
/** A parser for TokenStreams. "parser grammars" result in a subclass
|
||||
* of this.
|
||||
|
@ -86,11 +87,11 @@ public class Parser extends BaseRecognizer {
|
|||
return input.getSourceName();
|
||||
}
|
||||
|
||||
public void traceIn(String ruleName, int ruleIndex) {
|
||||
super.traceIn(ruleName, ruleIndex, input.LT(1));
|
||||
public void traceIn(int ruleIndex, ParserRuleContext ctx) {
|
||||
super.traceIn(getRuleNames()[ruleIndex], ruleIndex, input.LT(1));
|
||||
}
|
||||
|
||||
public void traceOut(String ruleName, int ruleIndex) {
|
||||
super.traceOut(ruleName, ruleIndex, input.LT(1));
|
||||
public void traceOut(int ruleIndex, ParserRuleContext ctx) {
|
||||
super.traceOut(getRuleNames()[ruleIndex], ruleIndex, input.LT(1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +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;
|
||||
|
||||
public class RecognizerSharedState<StreamType> {
|
||||
public StreamType input;
|
||||
public RuleContext getContext() { return null; };
|
||||
}
|
|
@ -30,7 +30,8 @@
|
|||
package org.antlr.v4.runtime.atn;
|
||||
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.dfa.*;
|
||||
import org.antlr.v4.runtime.dfa.DFA;
|
||||
import org.antlr.v4.runtime.dfa.DFAState;
|
||||
import org.antlr.v4.runtime.misc.OrderedHashSet;
|
||||
import org.stringtemplate.v4.misc.MultiMap;
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
/** A blank listener that does nothing; useful for real classes so
|
||||
* they don't have to have lots of blank methods and are less
|
||||
* sensitive to updates to debug interface.
|
||||
*/
|
||||
public class BlankDebugEventListener implements DebugEventListener {
|
||||
public void enterRule(String grammarFileName, String ruleName) {}
|
||||
public void exitRule(String grammarFileName, String ruleName) {}
|
||||
public void enterAlt(int alt) {}
|
||||
public void enterSubRule(int decisionNumber) {}
|
||||
public void exitSubRule(int decisionNumber) {}
|
||||
public void enterDecision(int decisionNumber, boolean couldBacktrack) {}
|
||||
public void exitDecision(int decisionNumber) {}
|
||||
public void location(int line, int pos) {}
|
||||
public void consumeToken(Token token) {}
|
||||
public void consumeHiddenToken(Token token) {}
|
||||
public void LT(int i, Token t) {}
|
||||
public void mark(int i) {}
|
||||
public void rewind(int i) {}
|
||||
public void seek(int i) {}
|
||||
public void recognitionException(RecognitionException e) {}
|
||||
public void beginResync() {}
|
||||
public void endResync() {}
|
||||
public void semanticPredicate(boolean result, String predicate) {}
|
||||
public void commence() {}
|
||||
public void terminate() {}
|
||||
|
||||
// Tree parsing stuff
|
||||
|
||||
public void consumeNode(Object t) {}
|
||||
public void LT(int i, Object t) {}
|
||||
|
||||
// AST Stuff
|
||||
|
||||
public void nilNode(Object t) {}
|
||||
public void errorNode(Object t) {}
|
||||
public void createNode(Object t) {}
|
||||
public void createNode(Object node, Token token) {}
|
||||
public void becomeRoot(Object newRoot, Object oldRoot) {}
|
||||
public void addChild(Object root, Object child) {}
|
||||
public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex) {}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Broadcast debug events to multiple listeners. Lets you debug and still
|
||||
* use the event mechanism to build parse trees etc... Not thread-safe.
|
||||
* Don't add events in one thread while parser fires events in another.
|
||||
*
|
||||
* @see DebugEventRepeater
|
||||
*/
|
||||
public class DebugEventHub implements DebugEventListener {
|
||||
protected List listeners = new ArrayList();
|
||||
|
||||
public DebugEventHub(DebugEventListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public DebugEventHub(DebugEventListener a, DebugEventListener b) {
|
||||
listeners.add(a);
|
||||
listeners.add(b);
|
||||
}
|
||||
|
||||
/** Add another listener to broadcast events too. Not thread-safe.
|
||||
* Don't add events in one thread while parser fires events in another.
|
||||
*/
|
||||
public void addListener(DebugEventListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
/* To avoid a mess like this:
|
||||
public void enterRule(final String ruleName) {
|
||||
broadcast(new Code(){
|
||||
public void exec(DebugEventListener listener) {listener.enterRule(ruleName);}}
|
||||
);
|
||||
}
|
||||
I am dup'ing the for-loop in each. Where are Java closures!? blech!
|
||||
*/
|
||||
|
||||
public void enterRule(String grammarFileName, String ruleName) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.enterRule(grammarFileName, ruleName);
|
||||
}
|
||||
}
|
||||
|
||||
public void exitRule(String grammarFileName, String ruleName) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.exitRule(grammarFileName, ruleName);
|
||||
}
|
||||
}
|
||||
|
||||
public void enterAlt(int alt) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.enterAlt(alt);
|
||||
}
|
||||
}
|
||||
|
||||
public void enterSubRule(int decisionNumber) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.enterSubRule(decisionNumber);
|
||||
}
|
||||
}
|
||||
|
||||
public void exitSubRule(int decisionNumber) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.exitSubRule(decisionNumber);
|
||||
}
|
||||
}
|
||||
|
||||
public void enterDecision(int decisionNumber, boolean couldBacktrack) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.enterDecision(decisionNumber, couldBacktrack);
|
||||
}
|
||||
}
|
||||
|
||||
public void exitDecision(int decisionNumber) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.exitDecision(decisionNumber);
|
||||
}
|
||||
}
|
||||
|
||||
public void location(int line, int pos) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.location(line, pos);
|
||||
}
|
||||
}
|
||||
|
||||
public void consumeToken(Token token) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.consumeToken(token);
|
||||
}
|
||||
}
|
||||
|
||||
public void consumeHiddenToken(Token token) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.consumeHiddenToken(token);
|
||||
}
|
||||
}
|
||||
|
||||
public void LT(int index, Token t) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.LT(index, t);
|
||||
}
|
||||
}
|
||||
|
||||
public void mark(int index) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.mark(index);
|
||||
}
|
||||
}
|
||||
|
||||
public void seek(int index) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.seek(index);
|
||||
}
|
||||
}
|
||||
|
||||
public void rewind(int index) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.rewind(index);
|
||||
}
|
||||
}
|
||||
|
||||
public void recognitionException(RecognitionException e) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.recognitionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void beginResync() {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.beginResync();
|
||||
}
|
||||
}
|
||||
|
||||
public void endResync() {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.endResync();
|
||||
}
|
||||
}
|
||||
|
||||
public void semanticPredicate(boolean result, String predicate) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.semanticPredicate(result, predicate);
|
||||
}
|
||||
}
|
||||
|
||||
public void commence() {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.commence();
|
||||
}
|
||||
}
|
||||
|
||||
public void terminate() {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Tree parsing stuff
|
||||
|
||||
public void consumeNode(Object t) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.consumeNode(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void LT(int index, Object t) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.LT(index, t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// AST Stuff
|
||||
|
||||
public void nilNode(Object t) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.nilNode(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void errorNode(Object t) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.errorNode(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void createNode(Object t) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.createNode(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void createNode(Object node, Token token) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.createNode(node, token);
|
||||
}
|
||||
}
|
||||
|
||||
public void becomeRoot(Object newRoot, Object oldRoot) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.becomeRoot(newRoot, oldRoot);
|
||||
}
|
||||
}
|
||||
|
||||
public void addChild(Object root, Object child) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.addChild(root, child);
|
||||
}
|
||||
}
|
||||
|
||||
public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex) {
|
||||
for (int i = 0; i < listeners.size(); i++) {
|
||||
DebugEventListener listener = (DebugEventListener)listeners.get(i);
|
||||
listener.setTokenBoundaries(t, tokenStartIndex, tokenStopIndex);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
/** All debugging events that a recognizer can trigger.
|
||||
*
|
||||
* I did not create a separate AST debugging interface as it would create
|
||||
* lots of extra classes and DebugParser has a dbg var defined, which makes
|
||||
* it hard to change to ASTDebugEventListener. I looked hard at this issue
|
||||
* and it is easier to understand as one monolithic event interface for all
|
||||
* possible events. Hopefully, adding ST debugging stuff won't be bad. Leave
|
||||
* for future. 4/26/2006.
|
||||
*/
|
||||
public interface DebugEventListener {
|
||||
/** Moved to version 2 for v3.1: added grammar name to enter/exit Rule */
|
||||
public static final String PROTOCOL_VERSION = "2";
|
||||
|
||||
/** serialized version of true */
|
||||
public static final int TRUE = 1;
|
||||
public static final int FALSE = 0;
|
||||
|
||||
/** The parser has just entered a rule. No decision has been made about
|
||||
* which alt is predicted. This is fired AFTER init actions have been
|
||||
* executed. Attributes are defined and available etc...
|
||||
* The grammarFileName allows composite grammars to jump around among
|
||||
* multiple grammar files.
|
||||
*/
|
||||
public void enterRule(String grammarFileName, String ruleName);
|
||||
|
||||
/** Because rules can have lots of alternatives, it is very useful to
|
||||
* know which alt you are entering. This is 1..n for n alts.
|
||||
*/
|
||||
public void enterAlt(int alt);
|
||||
|
||||
/** This is the last thing executed before leaving a rule. It is
|
||||
* executed even if an exception is thrown. This is triggered after
|
||||
* error reporting and recovery have occurred (unless the exception is
|
||||
* not caught in this rule). This implies an "exitAlt" event.
|
||||
* The grammarFileName allows composite grammars to jump around among
|
||||
* multiple grammar files.
|
||||
*/
|
||||
public void exitRule(String grammarFileName, String ruleName);
|
||||
|
||||
/** Track entry into any (...) subrule other EBNF construct */
|
||||
public void enterSubRule(int decisionNumber);
|
||||
|
||||
public void exitSubRule(int decisionNumber);
|
||||
|
||||
/** Every decision, fixed k or arbitrary, has an enter/exit event
|
||||
* so that a GUI can easily track what LT/consume events are
|
||||
* associated with prediction. You will see a single enter/exit
|
||||
* subrule but multiple enter/exit decision events, one for each
|
||||
* loop iteration.
|
||||
*/
|
||||
public void enterDecision(int decisionNumber, boolean couldBacktrack);
|
||||
|
||||
public void exitDecision(int decisionNumber);
|
||||
|
||||
/** The parser is going to look arbitrarily ahead; mark this location. */
|
||||
public void mark(int index);
|
||||
|
||||
/** After an arbitrarily long lookahead, this informs the
|
||||
* debugger that stream should be rewound to the position index.
|
||||
*/
|
||||
public void rewind(int index);
|
||||
|
||||
/** Set the input cursor to the position indicated by index. */
|
||||
public void seek(int index);
|
||||
|
||||
/** An input token was consumed; matched by any kind of element.
|
||||
* Trigger after the token was matched by things like match(), matchAny().
|
||||
*/
|
||||
public void consumeToken(Token t);
|
||||
|
||||
/** An off-channel input token was consumed.
|
||||
* Trigger after the token was matched by things like match(), matchAny().
|
||||
* (unless of course the hidden token is first stuff in the input stream).
|
||||
*/
|
||||
public void consumeHiddenToken(Token t);
|
||||
|
||||
/** Somebody (anybody) looked ahead. Note that this actually gets
|
||||
* triggered by both LA and LT calls. The debugger will want to know
|
||||
* which Token object was examined. Like consumeToken, this indicates
|
||||
* what token was seen at that depth. A remote debugger cannot look
|
||||
* ahead into a file it doesn't have so LT events must pass the token
|
||||
* even if the info is redundant.
|
||||
*/
|
||||
public void LT(int i, Token t);
|
||||
|
||||
/** To watch a parser move through the grammar, the parser needs to
|
||||
* inform the debugger what line/charPos it is passing in the grammar.
|
||||
* For now, this does not know how to switch from one grammar to the
|
||||
* other and back for island grammars etc...
|
||||
*
|
||||
* This should also allow breakpoints because the debugger can stop
|
||||
* the parser whenever it hits this line/pos.
|
||||
*/
|
||||
public void location(int line, int pos);
|
||||
|
||||
/** A recognition exception occurred such as NoViableAltException. I made
|
||||
* this a generic event so that I can alter the exception hierachy later
|
||||
* without having to alter all the debug objects.
|
||||
*
|
||||
* Upon error, the stack of enter rule/subrule must be properly unwound.
|
||||
* If no viable alt occurs it is within an enter/exit decision, which
|
||||
* also must be rewound. Even the rewind for each mark must be unwount.
|
||||
* In the Java target this is pretty easy using try/finally, if a bit
|
||||
* ugly in the generated code. The rewind is generated in DFA.predict()
|
||||
* actually so no code needs to be generated for that. For languages
|
||||
* w/o this "finally" feature (C++?), the target implementor will have
|
||||
* to build an event stack or something.
|
||||
*
|
||||
* Across a socket for remote debugging, only the RecognitionException
|
||||
* data fields are transmitted. The token object or whatever that
|
||||
* caused the problem was the last object referenced by LT. The
|
||||
* immediately preceding LT event should hold the unexpected Token or
|
||||
* char.
|
||||
*
|
||||
* Here is a sample event trace for grammar:
|
||||
*
|
||||
* b : C ({;}A|B) // {;} is there to prevent A|B becoming a set
|
||||
* | D
|
||||
* ;
|
||||
*
|
||||
* The sequence for this rule (with no viable alt in the subrule) for
|
||||
* input 'c c' (there are 3 tokens) is:
|
||||
*
|
||||
* commence
|
||||
* LT(1)
|
||||
* enterRule b
|
||||
* location 7 1
|
||||
* enter decision 3
|
||||
* LT(1)
|
||||
* exit decision 3
|
||||
* enterAlt1
|
||||
* location 7 5
|
||||
* LT(1)
|
||||
* consumeToken [c/<4>,1:0]
|
||||
* location 7 7
|
||||
* enterSubRule 2
|
||||
* enter decision 2
|
||||
* LT(1)
|
||||
* LT(1)
|
||||
* recognitionException NoViableAltException 2 1 2
|
||||
* exit decision 2
|
||||
* exitSubRule 2
|
||||
* beginResync
|
||||
* LT(1)
|
||||
* consumeToken [c/<4>,1:1]
|
||||
* LT(1)
|
||||
* endResync
|
||||
* LT(-1)
|
||||
* exitRule b
|
||||
* terminate
|
||||
*/
|
||||
public void recognitionException(RecognitionException e);
|
||||
|
||||
/** Indicates the recognizer is about to consume tokens to resynchronize
|
||||
* the parser. Any consume events from here until the recovered event
|
||||
* are not part of the parse--they are dead tokens.
|
||||
*/
|
||||
public void beginResync();
|
||||
|
||||
/** Indicates that the recognizer has finished consuming tokens in order
|
||||
* to resychronize. There may be multiple beginResync/endResync pairs
|
||||
* before the recognizer comes out of errorRecovery mode (in which
|
||||
* multiple errors are suppressed). This will be useful
|
||||
* in a gui where you want to probably grey out tokens that are consumed
|
||||
* but not matched to anything in grammar. Anything between
|
||||
* a beginResync/endResync pair was tossed out by the parser.
|
||||
*/
|
||||
public void endResync();
|
||||
|
||||
/** A semantic predicate was evaluate with this result and action text */
|
||||
public void semanticPredicate(boolean result, String predicate);
|
||||
|
||||
/** Announce that parsing has begun. Not technically useful except for
|
||||
* sending events over a socket. A GUI for example will launch a thread
|
||||
* to connect and communicate with a remote parser. The thread will want
|
||||
* to notify the GUI when a connection is made. ANTLR parsers
|
||||
* trigger this upon entry to the first rule (the ruleLevel is used to
|
||||
* figure this out).
|
||||
*/
|
||||
public void commence();
|
||||
|
||||
/** Parsing is over; successfully or not. Mostly useful for telling
|
||||
* remote debugging listeners that it's time to quit. When the rule
|
||||
* invocation level goes to zero at the end of a rule, we are done
|
||||
* parsing.
|
||||
*/
|
||||
public void terminate();
|
||||
|
||||
|
||||
// T r e e P a r s i n g
|
||||
|
||||
/** Input for a tree parser is an AST, but we know nothing for sure
|
||||
* about a node except its type and text (obtained from the adaptor).
|
||||
* This is the analog of the consumeToken method. Again, the ID is
|
||||
* the hashCode usually of the node so it only works if hashCode is
|
||||
* not implemented. If the type is UP or DOWN, then
|
||||
* the ID is not really meaningful as it's fixed--there is
|
||||
* just one UP node and one DOWN navigation node.
|
||||
* @param t
|
||||
*/
|
||||
public void consumeNode(Object t);
|
||||
|
||||
/** The tree parser lookedahead. If the type is UP or DOWN,
|
||||
* then the ID is not really meaningful as it's fixed--there is
|
||||
* just one UP node and one DOWN navigation node.
|
||||
*/
|
||||
public void LT(int i, Object t);
|
||||
|
||||
|
||||
// A S T E v e n t s
|
||||
|
||||
/** A nil was created (even nil nodes have a unique ID...
|
||||
* they are not "null" per se). As of 4/28/2006, this
|
||||
* seems to be uniquely triggered when starting a new subtree
|
||||
* such as when entering a subrule in automatic mode and when
|
||||
* building a tree in rewrite mode.
|
||||
*
|
||||
* If you are receiving this event over a socket via
|
||||
* RemoteDebugEventSocketListener then only t.ID is set.
|
||||
*/
|
||||
public void nilNode(Object t);
|
||||
|
||||
/** Upon syntax error, recognizers bracket the error with an error node
|
||||
* if they are building ASTs.
|
||||
* @param t
|
||||
*/
|
||||
public void errorNode(Object t);
|
||||
|
||||
/** Announce a new node built from token elements such as type etc...
|
||||
*
|
||||
* If you are receiving this event over a socket via
|
||||
* RemoteDebugEventSocketListener then only t.ID, type, text are
|
||||
* set.
|
||||
*/
|
||||
public void createNode(Object t);
|
||||
|
||||
/** Announce a new node built from an existing token.
|
||||
*
|
||||
* If you are receiving this event over a socket via
|
||||
* RemoteDebugEventSocketListener then only node.ID and token.tokenIndex
|
||||
* are set.
|
||||
*/
|
||||
public void createNode(Object node, Token token);
|
||||
|
||||
/** Make a node the new root of an existing root. See
|
||||
*
|
||||
* Note: the newRootID parameter is possibly different
|
||||
* than the TreeAdaptor.becomeRoot() newRoot parameter.
|
||||
* In our case, it will always be the result of calling
|
||||
* TreeAdaptor.becomeRoot() and not root_n or whatever.
|
||||
*
|
||||
* The listener should assume that this event occurs
|
||||
* only when the current subrule (or rule) subtree is
|
||||
* being reset to newRootID.
|
||||
*
|
||||
* If you are receiving this event over a socket via
|
||||
* RemoteDebugEventSocketListener then only IDs are set.
|
||||
*
|
||||
* @see org.antlr.v4.runtime.tree.TreeAdaptor becomeRoot()
|
||||
*/
|
||||
public void becomeRoot(Object newRoot, Object oldRoot);
|
||||
|
||||
/** Make childID a child of rootID.
|
||||
*
|
||||
* If you are receiving this event over a socket via
|
||||
* RemoteDebugEventSocketListener then only IDs are set.
|
||||
*
|
||||
* @see org.antlr.v4.runtime.tree.TreeAdaptor addChild()
|
||||
*/
|
||||
public void addChild(Object root, Object child);
|
||||
|
||||
/** Set the token start/stop token index for a subtree root or node.
|
||||
*
|
||||
* If you are receiving this event over a socket via
|
||||
* RemoteDebugEventSocketListener then only t.ID is set.
|
||||
*/
|
||||
public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex);
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
/** A simple event repeater (proxy) that delegates all functionality to the
|
||||
* listener sent into the ctor. Useful if you want to listen in on a few
|
||||
* debug events w/o interrupting the debugger. Just subclass the repeater
|
||||
* and override the methods you want to listen in on. Remember to call
|
||||
* the method in this class so the event will continue on to the original
|
||||
* recipient.
|
||||
*
|
||||
* @see DebugEventHub
|
||||
*/
|
||||
public class DebugEventRepeater implements DebugEventListener {
|
||||
protected DebugEventListener listener;
|
||||
|
||||
public DebugEventRepeater(DebugEventListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void enterRule(String grammarFileName, String ruleName) { listener.enterRule(grammarFileName, ruleName); }
|
||||
public void exitRule(String grammarFileName, String ruleName) { listener.exitRule(grammarFileName, ruleName); }
|
||||
public void enterAlt(int alt) { listener.enterAlt(alt); }
|
||||
public void enterSubRule(int decisionNumber) { listener.enterSubRule(decisionNumber); }
|
||||
public void exitSubRule(int decisionNumber) { listener.exitSubRule(decisionNumber); }
|
||||
public void enterDecision(int decisionNumber, boolean couldBacktrack) { listener.enterDecision(decisionNumber, couldBacktrack); }
|
||||
public void exitDecision(int decisionNumber) { listener.exitDecision(decisionNumber); }
|
||||
public void location(int line, int pos) { listener.location(line, pos); }
|
||||
public void consumeToken(Token token) { listener.consumeToken(token); }
|
||||
public void consumeHiddenToken(Token token) { listener.consumeHiddenToken(token); }
|
||||
public void LT(int i, Token t) { listener.LT(i, t); }
|
||||
public void mark(int i) { listener.mark(i); }
|
||||
public void rewind(int i) { listener.rewind(i); }
|
||||
public void seek(int i) { listener.seek(i); }
|
||||
public void recognitionException(RecognitionException e) { listener.recognitionException(e); }
|
||||
public void beginResync() { listener.beginResync(); }
|
||||
public void endResync() { listener.endResync(); }
|
||||
public void semanticPredicate(boolean result, String predicate) { listener.semanticPredicate(result, predicate); }
|
||||
public void commence() { listener.commence(); }
|
||||
public void terminate() { listener.terminate(); }
|
||||
|
||||
// Tree parsing stuff
|
||||
|
||||
public void consumeNode(Object t) { listener.consumeNode(t); }
|
||||
public void LT(int i, Object t) { listener.LT(i, t); }
|
||||
|
||||
// AST Stuff
|
||||
|
||||
public void nilNode(Object t) { listener.nilNode(t); }
|
||||
public void errorNode(Object t) { listener.errorNode(t); }
|
||||
public void createNode(Object t) { listener.createNode(t); }
|
||||
public void createNode(Object node, Token token) { listener.createNode(node, token); }
|
||||
public void becomeRoot(Object newRoot, Object oldRoot) { listener.becomeRoot(newRoot, oldRoot); }
|
||||
public void addChild(Object root, Object child) { listener.addChild(root, child); }
|
||||
public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex) {
|
||||
listener.setTokenBoundaries(t, tokenStartIndex, tokenStopIndex);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.v4.runtime.BaseRecognizer;
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.tree.TreeAdaptor;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
/** A proxy debug event listener that forwards events over a socket to
|
||||
* a debugger (or any other listener) using a simple text-based protocol;
|
||||
* one event per line. ANTLRWorks listens on server socket with a
|
||||
* RemoteDebugEventSocketListener instance. These two objects must therefore
|
||||
* be kept in sync. New events must be handled on both sides of socket.
|
||||
*/
|
||||
public class DebugEventSocketProxy extends BlankDebugEventListener {
|
||||
public static final int DEFAULT_DEBUGGER_PORT = 49100; // was 49153
|
||||
protected int port = DEFAULT_DEBUGGER_PORT;
|
||||
protected ServerSocket serverSocket;
|
||||
protected Socket socket;
|
||||
protected String grammarFileName;
|
||||
protected PrintWriter out;
|
||||
protected BufferedReader in;
|
||||
|
||||
/** Who am i debugging? */
|
||||
protected BaseRecognizer recognizer;
|
||||
|
||||
/** Almost certainly the recognizer will have adaptor set, but
|
||||
* we don't know how to cast it (Parser or TreeParser) to get
|
||||
* the adaptor field. Must be set with a constructor. :(
|
||||
*/
|
||||
protected TreeAdaptor adaptor;
|
||||
|
||||
public DebugEventSocketProxy(BaseRecognizer recognizer, TreeAdaptor adaptor) {
|
||||
this(recognizer, DEFAULT_DEBUGGER_PORT, adaptor);
|
||||
}
|
||||
|
||||
public DebugEventSocketProxy(BaseRecognizer recognizer, int port, TreeAdaptor adaptor) {
|
||||
this.grammarFileName = recognizer.getGrammarFileName();
|
||||
this.adaptor = adaptor;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public void handshake() throws IOException {
|
||||
if ( serverSocket==null ) {
|
||||
serverSocket = new ServerSocket(port);
|
||||
socket = serverSocket.accept();
|
||||
socket.setTcpNoDelay(true);
|
||||
OutputStream os = socket.getOutputStream();
|
||||
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF8");
|
||||
out = new PrintWriter(new BufferedWriter(osw));
|
||||
InputStream is = socket.getInputStream();
|
||||
InputStreamReader isr = new InputStreamReader(is, "UTF8");
|
||||
in = new BufferedReader(isr);
|
||||
out.println("ANTLR "+ DebugEventListener.PROTOCOL_VERSION);
|
||||
out.println("grammar \""+ grammarFileName);
|
||||
out.flush();
|
||||
ack();
|
||||
}
|
||||
}
|
||||
|
||||
public void commence() {
|
||||
// don't bother sending event; listener will trigger upon connection
|
||||
}
|
||||
|
||||
public void terminate() {
|
||||
transmit("terminate");
|
||||
out.close();
|
||||
try {
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
ioe.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
protected void ack() {
|
||||
try {
|
||||
in.readLine();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
ioe.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
protected void transmit(String event) {
|
||||
out.println(event);
|
||||
out.flush();
|
||||
ack();
|
||||
}
|
||||
|
||||
public void enterRule(String grammarFileName, String ruleName) {
|
||||
transmit("enterRule\t"+grammarFileName+"\t"+ruleName);
|
||||
}
|
||||
|
||||
public void enterAlt(int alt) {
|
||||
transmit("enterAlt\t"+alt);
|
||||
}
|
||||
|
||||
public void exitRule(String grammarFileName, String ruleName) {
|
||||
transmit("exitRule\t"+grammarFileName+"\t"+ruleName);
|
||||
}
|
||||
|
||||
public void enterSubRule(int decisionNumber) {
|
||||
transmit("enterSubRule\t"+decisionNumber);
|
||||
}
|
||||
|
||||
public void exitSubRule(int decisionNumber) {
|
||||
transmit("exitSubRule\t"+decisionNumber);
|
||||
}
|
||||
|
||||
public void enterDecision(int decisionNumber, boolean couldBacktrack) {
|
||||
transmit("enterDecision\t"+decisionNumber+"\t"+couldBacktrack);
|
||||
}
|
||||
|
||||
public void exitDecision(int decisionNumber) {
|
||||
transmit("exitDecision\t"+decisionNumber);
|
||||
}
|
||||
|
||||
public void consumeToken(Token t) {
|
||||
String buf = serializeToken(t);
|
||||
transmit("consumeToken\t"+buf);
|
||||
}
|
||||
|
||||
public void consumeHiddenToken(Token t) {
|
||||
String buf = serializeToken(t);
|
||||
transmit("consumeHiddenToken\t"+buf);
|
||||
}
|
||||
|
||||
public void LT(int i, Token t) {
|
||||
if(t != null)
|
||||
transmit("LT\t"+i+"\t"+serializeToken(t));
|
||||
}
|
||||
|
||||
public void mark(int i) {
|
||||
transmit("mark\t"+i);
|
||||
}
|
||||
|
||||
public void rewind(int i) {
|
||||
transmit("rewind\t"+i);
|
||||
}
|
||||
|
||||
public void rewind() {
|
||||
transmit("rewind");
|
||||
}
|
||||
|
||||
public void beginBacktrack(int level) {
|
||||
transmit("beginBacktrack\t"+level);
|
||||
}
|
||||
|
||||
public void endBacktrack(int level, boolean successful) {
|
||||
transmit("endBacktrack\t"+level+"\t"+(successful?TRUE:FALSE));
|
||||
}
|
||||
|
||||
public void location(int line, int pos) {
|
||||
transmit("location\t"+line+"\t"+pos);
|
||||
}
|
||||
|
||||
public void recognitionException(RecognitionException e) {
|
||||
StringBuffer buf = new StringBuffer(50);
|
||||
buf.append("exception\t");
|
||||
buf.append(e.getClass().getName());
|
||||
// dump only the data common to all exceptions for now
|
||||
buf.append("\t");
|
||||
buf.append(e.index);
|
||||
buf.append("\t");
|
||||
buf.append(e.line);
|
||||
buf.append("\t");
|
||||
buf.append(e.charPositionInLine);
|
||||
transmit(buf.toString());
|
||||
}
|
||||
|
||||
public void beginResync() {
|
||||
transmit("beginResync");
|
||||
}
|
||||
|
||||
public void endResync() {
|
||||
transmit("endResync");
|
||||
}
|
||||
|
||||
public void semanticPredicate(boolean result, String predicate) {
|
||||
StringBuffer buf = new StringBuffer(50);
|
||||
buf.append("semanticPredicate\t");
|
||||
buf.append(result);
|
||||
serializeText(buf, predicate);
|
||||
transmit(buf.toString());
|
||||
}
|
||||
|
||||
// A S T P a r s i n g E v e n t s
|
||||
|
||||
public void consumeNode(Object t) {
|
||||
StringBuffer buf = new StringBuffer(50);
|
||||
buf.append("consumeNode");
|
||||
serializeNode(buf, t);
|
||||
transmit(buf.toString());
|
||||
}
|
||||
|
||||
public void LT(int i, Object t) {
|
||||
int ID = adaptor.getUniqueID(t);
|
||||
String text = adaptor.getText(t);
|
||||
int type = adaptor.getType(t);
|
||||
StringBuffer buf = new StringBuffer(50);
|
||||
buf.append("LN\t"); // lookahead node; distinguish from LT in protocol
|
||||
buf.append(i);
|
||||
serializeNode(buf, t);
|
||||
transmit(buf.toString());
|
||||
}
|
||||
|
||||
protected void serializeNode(StringBuffer buf, Object t) {
|
||||
int ID = adaptor.getUniqueID(t);
|
||||
String text = adaptor.getText(t);
|
||||
int type = adaptor.getType(t);
|
||||
buf.append("\t");
|
||||
buf.append(ID);
|
||||
buf.append("\t");
|
||||
buf.append(type);
|
||||
Token token = adaptor.getToken(t);
|
||||
int line = -1;
|
||||
int pos = -1;
|
||||
if ( token!=null ) {
|
||||
line = token.getLine();
|
||||
pos = token.getCharPositionInLine();
|
||||
}
|
||||
buf.append("\t");
|
||||
buf.append(line);
|
||||
buf.append("\t");
|
||||
buf.append(pos);
|
||||
int tokenIndex = adaptor.getTokenStartIndex(t);
|
||||
buf.append("\t");
|
||||
buf.append(tokenIndex);
|
||||
serializeText(buf, text);
|
||||
}
|
||||
|
||||
|
||||
// A S T E v e n t s
|
||||
|
||||
public void nilNode(Object t) {
|
||||
int ID = adaptor.getUniqueID(t);
|
||||
transmit("nilNode\t"+ID);
|
||||
}
|
||||
|
||||
public void errorNode(Object t) {
|
||||
int ID = adaptor.getUniqueID(t);
|
||||
String text = t.toString();
|
||||
StringBuffer buf = new StringBuffer(50);
|
||||
buf.append("errorNode\t");
|
||||
buf.append(ID);
|
||||
buf.append("\t");
|
||||
buf.append(Token.INVALID_TYPE);
|
||||
serializeText(buf, text);
|
||||
transmit(buf.toString());
|
||||
}
|
||||
|
||||
public void createNode(Object t) {
|
||||
int ID = adaptor.getUniqueID(t);
|
||||
String text = adaptor.getText(t);
|
||||
int type = adaptor.getType(t);
|
||||
StringBuffer buf = new StringBuffer(50);
|
||||
buf.append("createNodeFromTokenElements\t");
|
||||
buf.append(ID);
|
||||
buf.append("\t");
|
||||
buf.append(type);
|
||||
serializeText(buf, text);
|
||||
transmit(buf.toString());
|
||||
}
|
||||
|
||||
public void createNode(Object node, Token token) {
|
||||
int ID = adaptor.getUniqueID(node);
|
||||
int tokenIndex = token.getTokenIndex();
|
||||
transmit("createNode\t"+ID+"\t"+tokenIndex);
|
||||
}
|
||||
|
||||
public void becomeRoot(Object newRoot, Object oldRoot) {
|
||||
int newRootID = adaptor.getUniqueID(newRoot);
|
||||
int oldRootID = adaptor.getUniqueID(oldRoot);
|
||||
transmit("becomeRoot\t"+newRootID+"\t"+oldRootID);
|
||||
}
|
||||
|
||||
public void addChild(Object root, Object child) {
|
||||
int rootID = adaptor.getUniqueID(root);
|
||||
int childID = adaptor.getUniqueID(child);
|
||||
transmit("addChild\t"+rootID+"\t"+childID);
|
||||
}
|
||||
|
||||
public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex) {
|
||||
int ID = adaptor.getUniqueID(t);
|
||||
transmit("setTokenBoundaries\t"+ID+"\t"+tokenStartIndex+"\t"+tokenStopIndex);
|
||||
}
|
||||
|
||||
|
||||
// support
|
||||
|
||||
public void setTreeAdaptor(TreeAdaptor adaptor) { this.adaptor = adaptor; }
|
||||
public TreeAdaptor getTreeAdaptor() { return adaptor; }
|
||||
|
||||
protected String serializeToken(Token t) {
|
||||
StringBuffer buf = new StringBuffer(50);
|
||||
buf.append(t.getTokenIndex()); buf.append('\t');
|
||||
buf.append(t.getType()); buf.append('\t');
|
||||
buf.append(t.getChannel()); buf.append('\t');
|
||||
buf.append(t.getLine()); buf.append('\t');
|
||||
buf.append(t.getCharPositionInLine());
|
||||
serializeText(buf, t.getText());
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected void serializeText(StringBuffer buf, String text) {
|
||||
buf.append("\t\"");
|
||||
if ( text==null ) {
|
||||
text = "";
|
||||
}
|
||||
// escape \n and \r all text for token appears to exist on one line
|
||||
// this escape is slow but easy to understand
|
||||
text = escapeNewlines(text);
|
||||
buf.append(text);
|
||||
}
|
||||
|
||||
protected String escapeNewlines(String txt) {
|
||||
txt = txt.replaceAll("%","%25"); // escape all escape char ;)
|
||||
txt = txt.replaceAll("\n","%0A"); // escape \n
|
||||
txt = txt.replaceAll("\r","%0D"); // escape \r
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.v4.runtime.Parser;
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.TokenStream;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DebugParser extends Parser {
|
||||
/** Who to notify when events in the parser occur. */
|
||||
protected DebugEventListener dbg = null;
|
||||
|
||||
/** Create a normal parser except wrap the token stream in a debug
|
||||
* proxy that fires consume events.
|
||||
*/
|
||||
public DebugParser(TokenStream input, DebugEventListener dbg) {
|
||||
super(input instanceof DebugTokenStream?input:new DebugTokenStream(input,dbg));
|
||||
setDebugListener(dbg);
|
||||
}
|
||||
|
||||
public DebugParser(TokenStream input) {
|
||||
super(input instanceof DebugTokenStream ? input : new DebugTokenStream(input, null));
|
||||
}
|
||||
|
||||
/** Provide a new debug event listener for this parser. Notify the
|
||||
* input stream too that it should send events to this listener.
|
||||
*/
|
||||
public void setDebugListener(DebugEventListener dbg) {
|
||||
if ( input instanceof DebugTokenStream ) {
|
||||
((DebugTokenStream)input).setDebugListener(dbg);
|
||||
}
|
||||
this.dbg = dbg;
|
||||
}
|
||||
|
||||
public DebugEventListener getDebugListener() {
|
||||
return dbg;
|
||||
}
|
||||
|
||||
public void reportError(IOException e) {
|
||||
System.err.println(e);
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
public void beginResync() {
|
||||
dbg.beginResync();
|
||||
}
|
||||
|
||||
public void endResync() {
|
||||
dbg.endResync();
|
||||
}
|
||||
|
||||
public void reportError(RecognitionException e) {
|
||||
super.reportError(e);
|
||||
dbg.recognitionException(e);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.TokenSource;
|
||||
import org.antlr.v4.runtime.TokenStream;
|
||||
|
||||
public class DebugTokenStream implements TokenStream {
|
||||
protected DebugEventListener dbg;
|
||||
public TokenStream input;
|
||||
protected boolean initialStreamState = true;
|
||||
|
||||
/** Track the last mark() call result value for use in rewind(). */
|
||||
protected int lastMarker;
|
||||
|
||||
public DebugTokenStream(TokenStream input, DebugEventListener dbg) {
|
||||
this.input = input;
|
||||
setDebugListener(dbg);
|
||||
// force TokenStream to get at least first valid token
|
||||
// so we know if there are any hidden tokens first in the stream
|
||||
input.LT(1);
|
||||
}
|
||||
|
||||
public void setDebugListener(DebugEventListener dbg) {
|
||||
this.dbg = dbg;
|
||||
}
|
||||
|
||||
public void consume() {
|
||||
if ( initialStreamState ) {
|
||||
consumeInitialHiddenTokens();
|
||||
}
|
||||
int a = input.index();
|
||||
Token t = input.LT(1);
|
||||
input.consume();
|
||||
int b = input.index();
|
||||
dbg.consumeToken(t);
|
||||
if ( b>a+1 ) {
|
||||
// then we consumed more than one token; must be off channel tokens
|
||||
for (int i=a+1; i<b; i++) {
|
||||
dbg.consumeHiddenToken(input.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* consume all initial off-channel tokens */
|
||||
protected void consumeInitialHiddenTokens() {
|
||||
int firstOnChannelTokenIndex = input.index();
|
||||
for (int i=0; i<firstOnChannelTokenIndex; i++) {
|
||||
dbg.consumeHiddenToken(input.get(i));
|
||||
}
|
||||
initialStreamState = false;
|
||||
}
|
||||
|
||||
public Token LT(int i) {
|
||||
if ( initialStreamState ) {
|
||||
consumeInitialHiddenTokens();
|
||||
}
|
||||
dbg.LT(i, input.LT(i));
|
||||
return input.LT(i);
|
||||
}
|
||||
|
||||
public int LA(int i) {
|
||||
if ( initialStreamState ) {
|
||||
consumeInitialHiddenTokens();
|
||||
}
|
||||
dbg.LT(i, input.LT(i));
|
||||
return input.LA(i);
|
||||
}
|
||||
|
||||
public Token get(int i) {
|
||||
return input.get(i);
|
||||
}
|
||||
|
||||
public int mark() {
|
||||
lastMarker = input.mark();
|
||||
dbg.mark(lastMarker);
|
||||
return lastMarker;
|
||||
}
|
||||
|
||||
public int index() {
|
||||
return input.index();
|
||||
}
|
||||
|
||||
public int range() {
|
||||
return input.range();
|
||||
}
|
||||
|
||||
public void rewind(int index) {
|
||||
dbg.rewind(index);
|
||||
input.seek(index);
|
||||
}
|
||||
|
||||
public void seek(int index) {
|
||||
// TODO: implement seek in dbg interface
|
||||
// db.seek(index);
|
||||
input.seek(index);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return input.size();
|
||||
}
|
||||
|
||||
public TokenSource getTokenSource() {
|
||||
return input.getTokenSource();
|
||||
}
|
||||
|
||||
public String getSourceName() {
|
||||
return getTokenSource().getSourceName();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return input.toString();
|
||||
}
|
||||
|
||||
public String toString(int start, int stop) {
|
||||
return input.toString(start,stop);
|
||||
}
|
||||
|
||||
public String toString(Token start, Token stop) {
|
||||
return input.toString(start,stop);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.TokenStream;
|
||||
import org.antlr.v4.runtime.tree.TreeAdaptor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** A TreeAdaptor proxy that fires debugging events to a DebugEventListener
|
||||
* delegate and uses the TreeAdaptor delegate to do the actual work. All
|
||||
* AST events are triggered by this adaptor; no code gen changes are needed
|
||||
* in generated rules. Debugging events are triggered *after* invoking
|
||||
* tree adaptor routines.
|
||||
*
|
||||
* Trees created with actions in rewrite actions like "-> ^(ADD {foo} {bar})"
|
||||
* cannot be tracked as they might not use the adaptor to create foo, bar.
|
||||
* The debug listener has to deal with tree node IDs for which it did
|
||||
* not see a createNode event. A single <unknown> node is sufficient even
|
||||
* if it represents a whole tree.
|
||||
*/
|
||||
public class DebugTreeAdaptor implements TreeAdaptor {
|
||||
protected DebugEventListener dbg;
|
||||
protected TreeAdaptor adaptor;
|
||||
|
||||
public DebugTreeAdaptor(DebugEventListener dbg, TreeAdaptor adaptor) {
|
||||
this.dbg = dbg;
|
||||
this.adaptor = adaptor;
|
||||
}
|
||||
|
||||
public Object create(Token payload) {
|
||||
if ( payload.getTokenIndex() < 0 ) {
|
||||
// could be token conjured up during error recovery
|
||||
return create(payload.getType(), payload.getText());
|
||||
}
|
||||
Object node = adaptor.create(payload);
|
||||
dbg.createNode(node, payload);
|
||||
return node;
|
||||
}
|
||||
|
||||
public List<Object> createElementList() {
|
||||
return adaptor.createElementList();
|
||||
}
|
||||
|
||||
public Object errorNode(TokenStream input, Token start, Token stop,
|
||||
RecognitionException e)
|
||||
{
|
||||
Object node = adaptor.errorNode(input, start, stop, e);
|
||||
if ( node!=null ) {
|
||||
dbg.errorNode(node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
public Object dupTree(Object tree) {
|
||||
Object t = adaptor.dupTree(tree);
|
||||
// walk the tree and emit create and add child events
|
||||
// to simulate what dupTree has done. dupTree does not call this debug
|
||||
// adapter so I must simulate.
|
||||
simulateTreeConstruction(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
/** ^(A B C): emit create A, create B, add child, ...*/
|
||||
protected void simulateTreeConstruction(Object t) {
|
||||
dbg.createNode(t);
|
||||
int n = adaptor.getChildCount(t);
|
||||
for (int i=0; i<n; i++) {
|
||||
Object child = adaptor.getChild(t, i);
|
||||
simulateTreeConstruction(child);
|
||||
dbg.addChild(t, child);
|
||||
}
|
||||
}
|
||||
|
||||
public Object dupNode(Object treeNode) {
|
||||
Object d = adaptor.dupNode(treeNode);
|
||||
dbg.createNode(d);
|
||||
return d;
|
||||
}
|
||||
|
||||
public Object nil() {
|
||||
Object node = adaptor.nil();
|
||||
dbg.nilNode(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
public boolean isNil(Object tree) {
|
||||
return adaptor.isNil(tree);
|
||||
}
|
||||
|
||||
public void addChild(Object t, Object child) {
|
||||
if ( t==null || child==null ) {
|
||||
return;
|
||||
}
|
||||
adaptor.addChild(t,child);
|
||||
dbg.addChild(t, child);
|
||||
}
|
||||
|
||||
public Object becomeRoot(Object newRoot, Object oldRoot) {
|
||||
Object n = adaptor.becomeRoot(newRoot, oldRoot);
|
||||
dbg.becomeRoot(newRoot, oldRoot);
|
||||
return n;
|
||||
}
|
||||
|
||||
public Object rulePostProcessing(Object root) {
|
||||
return adaptor.rulePostProcessing(root);
|
||||
}
|
||||
|
||||
public void addChild(Object t, Token child) {
|
||||
Object n = this.create(child);
|
||||
this.addChild(t, n);
|
||||
}
|
||||
|
||||
public Object becomeRoot(Token newRoot, Object oldRoot) {
|
||||
Object n = this.create(newRoot);
|
||||
adaptor.becomeRoot(n, oldRoot);
|
||||
dbg.becomeRoot(newRoot, oldRoot);
|
||||
return n;
|
||||
}
|
||||
|
||||
public Object create(int tokenType, Token fromToken) {
|
||||
Object node = adaptor.create(tokenType, fromToken);
|
||||
dbg.createNode(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
public Object create(int tokenType, Token fromToken, String text) {
|
||||
Object node = adaptor.create(tokenType, fromToken, text);
|
||||
dbg.createNode(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
public Object create(int tokenType, String text) {
|
||||
Object node = adaptor.create(tokenType, text);
|
||||
dbg.createNode(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
public int getType(Object t) {
|
||||
return adaptor.getType(t);
|
||||
}
|
||||
|
||||
public void setType(Object t, int type) {
|
||||
adaptor.setType(t, type);
|
||||
}
|
||||
|
||||
public String getText(Object t) {
|
||||
return adaptor.getText(t);
|
||||
}
|
||||
|
||||
public void setText(Object t, String text) {
|
||||
adaptor.setText(t, text);
|
||||
}
|
||||
|
||||
public Token getToken(Object t) {
|
||||
return adaptor.getToken(t);
|
||||
}
|
||||
|
||||
public void setTokenBoundaries(Object t, Token startToken, Token stopToken) {
|
||||
adaptor.setTokenBoundaries(t, startToken, stopToken);
|
||||
if ( t!=null && startToken!=null && stopToken!=null ) {
|
||||
dbg.setTokenBoundaries(
|
||||
t, startToken.getTokenIndex(),
|
||||
stopToken.getTokenIndex());
|
||||
}
|
||||
}
|
||||
|
||||
public int getTokenStartIndex(Object t) {
|
||||
return adaptor.getTokenStartIndex(t);
|
||||
}
|
||||
|
||||
public int getTokenStopIndex(Object t) {
|
||||
return adaptor.getTokenStopIndex(t);
|
||||
}
|
||||
|
||||
public Object getChild(Object t, int i) {
|
||||
return adaptor.getChild(t, i);
|
||||
}
|
||||
|
||||
public void setChild(Object t, int i, Object child) {
|
||||
adaptor.setChild(t, i, child);
|
||||
}
|
||||
|
||||
public Object deleteChild(Object t, int i) {
|
||||
return deleteChild(t, i);
|
||||
}
|
||||
|
||||
public int getChildCount(Object t) {
|
||||
return adaptor.getChildCount(t);
|
||||
}
|
||||
|
||||
public int getUniqueID(Object node) {
|
||||
return adaptor.getUniqueID(node);
|
||||
}
|
||||
|
||||
public Object getParent(Object t) {
|
||||
return adaptor.getParent(t);
|
||||
}
|
||||
|
||||
public int getChildIndex(Object t) {
|
||||
return adaptor.getChildIndex(t);
|
||||
}
|
||||
|
||||
public void setParent(Object t, Object parent) {
|
||||
adaptor.setParent(t, parent);
|
||||
}
|
||||
|
||||
public void setChildIndex(Object t, int index) {
|
||||
adaptor.setChildIndex(t, index);
|
||||
}
|
||||
|
||||
public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t) {
|
||||
adaptor.replaceChildren(parent, startChildIndex, stopChildIndex, t);
|
||||
}
|
||||
|
||||
// support
|
||||
|
||||
public DebugEventListener getDebugListener() {
|
||||
return dbg;
|
||||
}
|
||||
|
||||
public void setDebugListener(DebugEventListener dbg) {
|
||||
this.dbg = dbg;
|
||||
}
|
||||
|
||||
public TreeAdaptor getTreeAdaptor() {
|
||||
return adaptor;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.v4.runtime.TokenStream;
|
||||
import org.antlr.v4.runtime.tree.TreeAdaptor;
|
||||
import org.antlr.v4.runtime.tree.TreeNodeStream;
|
||||
|
||||
/** Debug any tree node stream. The constructor accepts the stream
|
||||
* and a debug listener. As node stream calls come in, debug events
|
||||
* are triggered.
|
||||
*/
|
||||
public class DebugTreeNodeStream implements TreeNodeStream {
|
||||
protected DebugEventListener dbg;
|
||||
protected TreeAdaptor adaptor;
|
||||
protected TreeNodeStream input;
|
||||
protected boolean initialStreamState = true;
|
||||
|
||||
/** Track the last mark() call result value for use in rewind(). */
|
||||
protected int lastMarker;
|
||||
|
||||
public DebugTreeNodeStream(TreeNodeStream input,
|
||||
DebugEventListener dbg)
|
||||
{
|
||||
this.input = input;
|
||||
this.adaptor = input.getTreeAdaptor();
|
||||
this.input.setUniqueNavigationNodes(true);
|
||||
setDebugListener(dbg);
|
||||
}
|
||||
|
||||
public void setDebugListener(DebugEventListener dbg) {
|
||||
this.dbg = dbg;
|
||||
}
|
||||
|
||||
public TreeAdaptor getTreeAdaptor() {
|
||||
return adaptor;
|
||||
}
|
||||
|
||||
public void consume() {
|
||||
Object node = input.LT(1);
|
||||
input.consume();
|
||||
dbg.consumeNode(node);
|
||||
}
|
||||
|
||||
public Object get(int i) {
|
||||
return input.get(i);
|
||||
}
|
||||
|
||||
public Object LT(int i) {
|
||||
Object node = input.LT(i);
|
||||
int ID = adaptor.getUniqueID(node);
|
||||
String text = adaptor.getText(node);
|
||||
int type = adaptor.getType(node);
|
||||
dbg.LT(i, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
public int LA(int i) {
|
||||
Object node = input.LT(i);
|
||||
int ID = adaptor.getUniqueID(node);
|
||||
String text = adaptor.getText(node);
|
||||
int type = adaptor.getType(node);
|
||||
dbg.LT(i, node);
|
||||
return type;
|
||||
}
|
||||
|
||||
public int mark() {
|
||||
lastMarker = input.mark();
|
||||
dbg.mark(lastMarker);
|
||||
return lastMarker;
|
||||
}
|
||||
|
||||
public void rewind(int marker) {
|
||||
dbg.rewind(marker);
|
||||
input.rewind(marker);
|
||||
}
|
||||
|
||||
public int index() {
|
||||
return input.index();
|
||||
}
|
||||
|
||||
public void seek(int index) {
|
||||
// TODO: implement seek in dbg interface
|
||||
// db.seek(index);
|
||||
input.seek(index);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return input.size();
|
||||
}
|
||||
|
||||
public void reset() { ; }
|
||||
|
||||
public Object getTreeSource() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public String getSourceName() {
|
||||
return getTokenStream().getSourceName();
|
||||
}
|
||||
|
||||
public TokenStream getTokenStream() {
|
||||
return input.getTokenStream();
|
||||
}
|
||||
|
||||
/** It is normally this object that instructs the node stream to
|
||||
* create unique nav nodes, but to satisfy interface, we have to
|
||||
* define it. It might be better to ignore the parameter but
|
||||
* there might be a use for it later, so I'll leave.
|
||||
*/
|
||||
public void setUniqueNavigationNodes(boolean uniqueNavigationNodes) {
|
||||
input.setUniqueNavigationNodes(uniqueNavigationNodes);
|
||||
}
|
||||
|
||||
public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t) {
|
||||
input.replaceChildren(parent, startChildIndex, stopChildIndex, t);
|
||||
}
|
||||
|
||||
public String toString(Object start, Object stop) {
|
||||
return input.toString(start,stop);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.tree.TreeNodeStream;
|
||||
import org.antlr.v4.runtime.tree.TreeParser;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DebugTreeParser extends TreeParser {
|
||||
/** Who to notify when events in the parser occur. */
|
||||
protected DebugEventListener dbg = null;
|
||||
|
||||
/** Used to differentiate between fixed lookahead and cyclic DFA decisions
|
||||
* while profiling.
|
||||
*/
|
||||
public boolean isCyclicDecision = false;
|
||||
|
||||
/** Create a normal parser except wrap the token stream in a debug
|
||||
* proxy that fires consume events.
|
||||
*/
|
||||
public DebugTreeParser(TreeNodeStream input, DebugEventListener dbg) {
|
||||
super(input instanceof DebugTreeNodeStream?input:new DebugTreeNodeStream(input,dbg));
|
||||
setDebugListener(dbg);
|
||||
}
|
||||
|
||||
public DebugTreeParser(TreeNodeStream input) {
|
||||
super(input instanceof DebugTreeNodeStream?input:new DebugTreeNodeStream(input,null));
|
||||
}
|
||||
|
||||
/** Provide a new debug event listener for this parser. Notify the
|
||||
* input stream too that it should send events to this listener.
|
||||
*/
|
||||
public void setDebugListener(DebugEventListener dbg) {
|
||||
if ( input instanceof DebugTreeNodeStream ) {
|
||||
((DebugTreeNodeStream)input).setDebugListener(dbg);
|
||||
}
|
||||
this.dbg = dbg;
|
||||
}
|
||||
|
||||
public DebugEventListener getDebugListener() {
|
||||
return dbg;
|
||||
}
|
||||
|
||||
public void reportError(IOException e) {
|
||||
System.err.println(e);
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
public void reportError(RecognitionException e) {
|
||||
dbg.recognitionException(e);
|
||||
}
|
||||
|
||||
// protected Object getMissingSymbol(IntStream input,
|
||||
// RecognitionException e,
|
||||
// int expectedTokenType,
|
||||
// IntervalSet follow)
|
||||
// {
|
||||
// Object o = super.getMissingSymbol(input, e, expectedTokenType, follow);
|
||||
// dbg.consumeNode(o);
|
||||
// return o;
|
||||
// }
|
||||
|
||||
public void beginResync() {
|
||||
dbg.beginResync();
|
||||
}
|
||||
|
||||
public void endResync() {
|
||||
dbg.endResync();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.runtime.tree.ParseTree;
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/** This parser listener tracks rule entry/exit and token matches
|
||||
* to build a simple parse tree using ParseTree nodes.
|
||||
*/
|
||||
public class ParseTreeBuilder extends BlankDebugEventListener {
|
||||
public static final String EPSILON_PAYLOAD = "<epsilon>";
|
||||
|
||||
Stack callStack = new Stack();
|
||||
List hiddenTokens = new ArrayList();
|
||||
int backtracking = 0;
|
||||
|
||||
public ParseTreeBuilder(String grammarName) {
|
||||
ParseTree root = create("<grammar "+grammarName+">");
|
||||
callStack.push(root);
|
||||
}
|
||||
|
||||
public ParseTree getTree() {
|
||||
return (ParseTree)callStack.elementAt(0);
|
||||
}
|
||||
|
||||
/** What kind of node to create. You might want to override
|
||||
* so I factored out creation here.
|
||||
*/
|
||||
public ParseTree create(Object payload) {
|
||||
return new ParseTree(payload);
|
||||
}
|
||||
|
||||
public ParseTree epsilonNode() {
|
||||
return create(EPSILON_PAYLOAD);
|
||||
}
|
||||
|
||||
/** Backtracking or cyclic DFA, don't want to add nodes to tree */
|
||||
public void enterDecision(int d, boolean couldBacktrack) { backtracking++; }
|
||||
public void exitDecision(int i) { backtracking--; }
|
||||
|
||||
public void enterRule(String filename, String ruleName) {
|
||||
if ( backtracking>0 ) return;
|
||||
ParseTree parentRuleNode = (ParseTree)callStack.peek();
|
||||
ParseTree ruleNode = create(ruleName);
|
||||
parentRuleNode.addChild(ruleNode);
|
||||
callStack.push(ruleNode);
|
||||
}
|
||||
|
||||
public void exitRule(String filename, String ruleName) {
|
||||
if ( backtracking>0 ) return;
|
||||
ParseTree ruleNode = (ParseTree)callStack.peek();
|
||||
if ( ruleNode.getChildCount()==0 ) {
|
||||
ruleNode.addChild(epsilonNode());
|
||||
}
|
||||
callStack.pop();
|
||||
}
|
||||
|
||||
public void consumeToken(Token token) {
|
||||
if ( backtracking>0 ) return;
|
||||
ParseTree ruleNode = (ParseTree)callStack.peek();
|
||||
ParseTree elementNode = create(token);
|
||||
elementNode.hiddenTokens = this.hiddenTokens;
|
||||
this.hiddenTokens = new ArrayList();
|
||||
ruleNode.addChild(elementNode);
|
||||
}
|
||||
|
||||
public void consumeHiddenToken(Token token) {
|
||||
if ( backtracking>0 ) return;
|
||||
hiddenTokens.add(token);
|
||||
}
|
||||
|
||||
public void recognitionException(RecognitionException e) {
|
||||
if ( backtracking>0 ) return;
|
||||
ParseTree ruleNode = (ParseTree)callStack.peek();
|
||||
ParseTree errorNode = create(e);
|
||||
ruleNode.addChild(errorNode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,722 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.runtime.misc.DoubleKeyMap;
|
||||
import org.antlr.v4.runtime.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/** Using the debug event interface, track what is happening in the parser
|
||||
* and record statistics about the runtime.
|
||||
*/
|
||||
public class Profiler extends BlankDebugEventListener {
|
||||
public static final String DATA_SEP = "\t";
|
||||
public static final String newline = System.getProperty("line.separator");
|
||||
|
||||
static boolean dump = false;
|
||||
|
||||
public static class ProfileStats {
|
||||
public String Version;
|
||||
public String name;
|
||||
public int numRuleInvocations;
|
||||
public int numUniqueRulesInvoked;
|
||||
public int numDecisionEvents;
|
||||
public int numDecisionsCovered;
|
||||
public int numDecisionsThatPotentiallyBacktrack;
|
||||
public int numDecisionsThatDoBacktrack;
|
||||
public int maxRuleInvocationDepth;
|
||||
public float avgkPerDecisionEvent;
|
||||
public float avgkPerBacktrackingDecisionEvent;
|
||||
public float averageDecisionPercentBacktracks;
|
||||
public int numBacktrackOccurrences; // doesn't count gated DFA edges
|
||||
|
||||
public int numFixedDecisions;
|
||||
public int minDecisionMaxFixedLookaheads;
|
||||
public int maxDecisionMaxFixedLookaheads;
|
||||
public int avgDecisionMaxFixedLookaheads;
|
||||
public int stddevDecisionMaxFixedLookaheads;
|
||||
public int numCyclicDecisions;
|
||||
public int minDecisionMaxCyclicLookaheads;
|
||||
public int maxDecisionMaxCyclicLookaheads;
|
||||
public int avgDecisionMaxCyclicLookaheads;
|
||||
public int stddevDecisionMaxCyclicLookaheads;
|
||||
// int Stats.min(toArray(decisionMaxSynPredLookaheads);
|
||||
// int Stats.max(toArray(decisionMaxSynPredLookaheads);
|
||||
// int Stats.avg(toArray(decisionMaxSynPredLookaheads);
|
||||
// int Stats.stddev(toArray(decisionMaxSynPredLookaheads);
|
||||
public int numSemanticPredicates;
|
||||
public int numTokens;
|
||||
public int numHiddenTokens;
|
||||
public int numCharsMatched;
|
||||
public int numHiddenCharsMatched;
|
||||
public int numReportedErrors;
|
||||
public int numMemoizationCacheHits;
|
||||
public int numMemoizationCacheMisses;
|
||||
public int numGuessingRuleInvocations;
|
||||
public int numMemoizationCacheEntries;
|
||||
}
|
||||
|
||||
public static class DecisionDescriptor {
|
||||
public int decision;
|
||||
public String fileName;
|
||||
public String ruleName;
|
||||
public int line;
|
||||
public int pos;
|
||||
public boolean couldBacktrack;
|
||||
|
||||
public int n;
|
||||
public float avgk; // avg across all decision events
|
||||
public int maxk;
|
||||
public int numBacktrackOccurrences;
|
||||
public int numSemPredEvals;
|
||||
}
|
||||
|
||||
// all about a specific exec of a single decision
|
||||
public static class DecisionEvent {
|
||||
public DecisionDescriptor decision;
|
||||
public int startIndex;
|
||||
public int k;
|
||||
public boolean backtracks; // doesn't count gated DFA edges
|
||||
public boolean evalSemPred;
|
||||
public long startTime;
|
||||
public long stopTime;
|
||||
public int numMemoizationCacheHits;
|
||||
public int numMemoizationCacheMisses;
|
||||
}
|
||||
|
||||
/** Because I may change the stats, I need to track that for later
|
||||
* computations to be consistent.
|
||||
*/
|
||||
public static final String Version = "3";
|
||||
public static final String RUNTIME_STATS_FILENAME = "runtime.stats";
|
||||
|
||||
/** Ack, should not store parser; can't do remote stuff. Well, we pass
|
||||
* input stream around too so I guess it's ok.
|
||||
*/
|
||||
public DebugParser parser = null;
|
||||
|
||||
// working variables
|
||||
|
||||
protected int ruleLevel = 0;
|
||||
//protected int decisionLevel = 0;
|
||||
protected Token lastRealTokenTouchedInDecision;
|
||||
protected Set<String> uniqueRules = new HashSet<String>();
|
||||
protected Stack<String> currentGrammarFileName = new Stack();
|
||||
protected Stack<String> currentRuleName = new Stack();
|
||||
protected Stack<Integer> currentLine = new Stack();
|
||||
protected Stack<Integer> currentPos = new Stack();
|
||||
|
||||
// Vector<DecisionStats>
|
||||
//protected Vector decisions = new Vector(200); // need setSize
|
||||
protected DoubleKeyMap<String,Integer, DecisionDescriptor> decisions =
|
||||
new DoubleKeyMap<String,Integer, DecisionDescriptor>();
|
||||
|
||||
// Record a DecisionData for each decision we hit while parsing
|
||||
protected List<DecisionEvent> decisionEvents = new ArrayList<DecisionEvent>();
|
||||
protected Stack<DecisionEvent> decisionStack = new Stack<DecisionEvent>();
|
||||
|
||||
protected int backtrackDepth;
|
||||
|
||||
ProfileStats stats = new ProfileStats();
|
||||
|
||||
public Profiler() {
|
||||
}
|
||||
|
||||
public Profiler(DebugParser parser) {
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
public void enterRule(String grammarFileName, String ruleName) {
|
||||
// System.out.println("enterRule "+grammarFileName+":"+ruleName);
|
||||
ruleLevel++;
|
||||
stats.numRuleInvocations++;
|
||||
uniqueRules.add(grammarFileName+":"+ruleName);
|
||||
stats.maxRuleInvocationDepth = Math.max(stats.maxRuleInvocationDepth, ruleLevel);
|
||||
currentGrammarFileName.push(grammarFileName);
|
||||
currentRuleName.push(ruleName);
|
||||
}
|
||||
|
||||
public void exitRule(String grammarFileName, String ruleName) {
|
||||
ruleLevel--;
|
||||
currentGrammarFileName.pop();
|
||||
currentRuleName.pop();
|
||||
}
|
||||
|
||||
/** Track memoization; this is not part of standard debug interface
|
||||
* but is triggered by profiling. Code gen inserts an override
|
||||
* for this method in the recognizer, which triggers this method.
|
||||
* Called from alreadyParsedRule().
|
||||
*/
|
||||
public void examineRuleMemoization(IntStream input,
|
||||
int ruleIndex,
|
||||
int stopIndex, // index or MEMO_RULE_UNKNOWN...
|
||||
String ruleName)
|
||||
{
|
||||
if (dump) System.out.println("examine memo "+ruleName+" at "+input.index()+": "+stopIndex);
|
||||
if ( stopIndex== BaseRecognizer.MEMO_RULE_UNKNOWN ) {
|
||||
//System.out.println("rule "+ruleIndex+" missed @ "+input.index());
|
||||
stats.numMemoizationCacheMisses++;
|
||||
stats.numGuessingRuleInvocations++; // we'll have to enter
|
||||
currentDecision().numMemoizationCacheMisses++;
|
||||
}
|
||||
else {
|
||||
// regardless of rule success/failure, if in cache, we have a cache hit
|
||||
//System.out.println("rule "+ruleIndex+" hit @ "+input.index());
|
||||
stats.numMemoizationCacheHits++;
|
||||
currentDecision().numMemoizationCacheHits++;
|
||||
}
|
||||
}
|
||||
|
||||
/** Warning: doesn't track success/failure, just unique recording event */
|
||||
public void memoize(IntStream input,
|
||||
int ruleIndex,
|
||||
int ruleStartIndex,
|
||||
String ruleName)
|
||||
{
|
||||
// count how many entries go into table
|
||||
if (dump) System.out.println("memoize "+ruleName);
|
||||
stats.numMemoizationCacheEntries++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void location(int line, int pos) {
|
||||
currentLine.push(line);
|
||||
currentPos.push(pos);
|
||||
}
|
||||
|
||||
public void enterDecision(int decisionNumber, boolean couldBacktrack) {
|
||||
lastRealTokenTouchedInDecision = null;
|
||||
stats.numDecisionEvents++;
|
||||
int startingLookaheadIndex = parser.getTokenStream().index();
|
||||
TokenStream input = parser.getTokenStream();
|
||||
if ( dump ) System.out.println("enterDecision canBacktrack="+couldBacktrack+" "+ decisionNumber +
|
||||
" backtrack depth " + backtrackDepth +
|
||||
" @ " + input.get(input.index()) +
|
||||
" rule " +locationDescription());
|
||||
String g = (String) currentGrammarFileName.peek();
|
||||
DecisionDescriptor descriptor = decisions.get(g, decisionNumber);
|
||||
if ( descriptor == null ) {
|
||||
descriptor = new DecisionDescriptor();
|
||||
decisions.put(g, decisionNumber, descriptor);
|
||||
descriptor.decision = decisionNumber;
|
||||
descriptor.fileName = (String)currentGrammarFileName.peek();
|
||||
descriptor.ruleName = (String)currentRuleName.peek();
|
||||
descriptor.line = (Integer)currentLine.peek();
|
||||
descriptor.pos = (Integer)currentPos.peek();
|
||||
descriptor.couldBacktrack = couldBacktrack;
|
||||
}
|
||||
descriptor.n++;
|
||||
|
||||
DecisionEvent d = new DecisionEvent();
|
||||
decisionStack.push(d);
|
||||
d.decision = descriptor;
|
||||
d.startTime = System.currentTimeMillis();
|
||||
d.startIndex = startingLookaheadIndex;
|
||||
}
|
||||
|
||||
public void exitDecision(int decisionNumber) {
|
||||
DecisionEvent d = decisionStack.pop();
|
||||
d.stopTime = System.currentTimeMillis();
|
||||
|
||||
int lastTokenIndex = lastRealTokenTouchedInDecision.getTokenIndex();
|
||||
int numHidden = getNumberOfHiddenTokens(d.startIndex, lastTokenIndex);
|
||||
int depth = lastTokenIndex - d.startIndex - numHidden + 1; // +1 counts consuming start token as 1
|
||||
d.k = depth;
|
||||
d.decision.maxk = Math.max(d.decision.maxk, depth);
|
||||
|
||||
if (dump) System.out.println("exitDecision "+decisionNumber+" in "+d.decision.ruleName+
|
||||
" lookahead "+d.k +" max token "+lastRealTokenTouchedInDecision);
|
||||
decisionEvents.add(d); // done with decision; track all
|
||||
}
|
||||
|
||||
public void consumeToken(Token token) {
|
||||
if (dump) System.out.println("consume token "+token);
|
||||
if ( !inDecision() ) {
|
||||
stats.numTokens++;
|
||||
return;
|
||||
}
|
||||
if ( lastRealTokenTouchedInDecision==null ||
|
||||
lastRealTokenTouchedInDecision.getTokenIndex() < token.getTokenIndex() )
|
||||
{
|
||||
lastRealTokenTouchedInDecision = token;
|
||||
}
|
||||
DecisionEvent d = currentDecision();
|
||||
// compute lookahead depth
|
||||
int thisRefIndex = token.getTokenIndex();
|
||||
int numHidden = getNumberOfHiddenTokens(d.startIndex, thisRefIndex);
|
||||
int depth = thisRefIndex - d.startIndex - numHidden + 1; // +1 counts consuming start token as 1
|
||||
//d.maxk = Math.max(d.maxk, depth);
|
||||
if (dump) System.out.println("consume "+thisRefIndex+" "+depth+" tokens ahead in "+
|
||||
d.decision.ruleName+"-"+d.decision.decision+" start index "+d.startIndex);
|
||||
}
|
||||
|
||||
/** The parser is in a decision if the decision depth > 0. This
|
||||
* works for backtracking also, which can have nested decisions.
|
||||
*/
|
||||
public boolean inDecision() {
|
||||
return decisionStack.size()>0;
|
||||
}
|
||||
|
||||
public void consumeHiddenToken(Token token) {
|
||||
//System.out.println("consume hidden token "+token);
|
||||
if ( !inDecision() ) stats.numHiddenTokens++;
|
||||
}
|
||||
|
||||
/** Track refs to lookahead if in a fixed/nonfixed decision.
|
||||
*/
|
||||
public void LT(int i, Token t) {
|
||||
if ( inDecision() && i>0 ) {
|
||||
DecisionEvent d = currentDecision();
|
||||
if (dump) System.out.println("LT("+i+")="+t+" index "+t.getTokenIndex()+" relative to "+d.decision.ruleName+"-"+
|
||||
d.decision.decision+" start index "+d.startIndex);
|
||||
if ( lastRealTokenTouchedInDecision==null ||
|
||||
lastRealTokenTouchedInDecision.getTokenIndex() < t.getTokenIndex() )
|
||||
{
|
||||
lastRealTokenTouchedInDecision = t;
|
||||
if (dump) System.out.println("set last token "+lastRealTokenTouchedInDecision);
|
||||
}
|
||||
// get starting index off stack
|
||||
// int stackTop = lookaheadStack.size()-1;
|
||||
// Integer startingIndex = (Integer)lookaheadStack.get(stackTop);
|
||||
// // compute lookahead depth
|
||||
// int thisRefIndex = parser.getTokenStream().index();
|
||||
// int numHidden =
|
||||
// getNumberOfHiddenTokens(startingIndex.intValue(), thisRefIndex);
|
||||
// int depth = i + thisRefIndex - startingIndex.intValue() - numHidden;
|
||||
// /*
|
||||
// System.out.println("LT("+i+") @ index "+thisRefIndex+" is depth "+depth+
|
||||
// " max is "+maxLookaheadInCurrentDecision);
|
||||
// */
|
||||
// if ( depth>maxLookaheadInCurrentDecision ) {
|
||||
// maxLookaheadInCurrentDecision = depth;
|
||||
// }
|
||||
// d.maxk = currentDecision()/
|
||||
}
|
||||
}
|
||||
|
||||
/** Track backtracking decisions. You'll see a fixed or cyclic decision
|
||||
* and then a backtrack.
|
||||
*
|
||||
* enter rule
|
||||
* ...
|
||||
* enter decision
|
||||
* LA and possibly consumes (for cyclic DFAs)
|
||||
* begin backtrack level
|
||||
* mark m
|
||||
* rewind m
|
||||
* end backtrack level, success
|
||||
* exit decision
|
||||
* ...
|
||||
* exit rule
|
||||
*/
|
||||
public void beginBacktrack(int level) {
|
||||
if (dump) System.out.println("enter backtrack "+level);
|
||||
backtrackDepth++;
|
||||
DecisionEvent e = currentDecision();
|
||||
if ( e.decision.couldBacktrack ) {
|
||||
stats.numBacktrackOccurrences++;
|
||||
e.decision.numBacktrackOccurrences++;
|
||||
e.backtracks = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Successful or not, track how much lookahead synpreds use */
|
||||
public void endBacktrack(int level, boolean successful) {
|
||||
if (dump) System.out.println("exit backtrack "+level+": "+successful);
|
||||
backtrackDepth--;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek(int i) {
|
||||
if (dump) System.out.println("seek "+i);
|
||||
}
|
||||
|
||||
protected DecisionEvent currentDecision() {
|
||||
return decisionStack.peek();
|
||||
}
|
||||
|
||||
public void recognitionException(RecognitionException e) {
|
||||
stats.numReportedErrors++;
|
||||
}
|
||||
|
||||
public void semanticPredicate(boolean result, String predicate) {
|
||||
stats.numSemanticPredicates++;
|
||||
if ( inDecision() ) {
|
||||
DecisionEvent d = currentDecision();
|
||||
d.evalSemPred = true;
|
||||
d.decision.numSemPredEvals++;
|
||||
if (dump) System.out.println("eval "+predicate+" in "+d.decision.ruleName+"-"+
|
||||
d.decision.decision);
|
||||
}
|
||||
}
|
||||
|
||||
public void terminate() {
|
||||
for (DecisionEvent e : decisionEvents) {
|
||||
//System.out.println("decision "+e.decision.decision+": k="+e.k);
|
||||
e.decision.avgk += e.k;
|
||||
stats.avgkPerDecisionEvent += e.k;
|
||||
if ( e.backtracks ) { // doesn't count gated syn preds on DFA edges
|
||||
stats.avgkPerBacktrackingDecisionEvent += e.k;
|
||||
}
|
||||
}
|
||||
stats.averageDecisionPercentBacktracks = 0.0f;
|
||||
for (DecisionDescriptor d : decisions.values()) {
|
||||
stats.numDecisionsCovered++;
|
||||
d.avgk /= (double)d.n;
|
||||
if ( d.couldBacktrack ) {
|
||||
stats.numDecisionsThatPotentiallyBacktrack++;
|
||||
float percentBacktracks = d.numBacktrackOccurrences / (float)d.n;
|
||||
//System.out.println("dec "+d.decision+" backtracks "+percentBacktracks*100+"%");
|
||||
stats.averageDecisionPercentBacktracks += percentBacktracks;
|
||||
}
|
||||
// ignore rules that backtrack along gated DFA edges
|
||||
if ( d.numBacktrackOccurrences > 0 ) {
|
||||
stats.numDecisionsThatDoBacktrack++;
|
||||
}
|
||||
}
|
||||
stats.averageDecisionPercentBacktracks /= stats.numDecisionsThatPotentiallyBacktrack;
|
||||
stats.averageDecisionPercentBacktracks *= 100; // it's a percentage
|
||||
stats.avgkPerDecisionEvent /= stats.numDecisionEvents;
|
||||
stats.avgkPerBacktrackingDecisionEvent /= (double)stats.numBacktrackOccurrences;
|
||||
|
||||
System.err.println(toString());
|
||||
System.err.println(getDecisionStatsDump());
|
||||
|
||||
// String stats = toNotifyString();
|
||||
// try {
|
||||
// Stats.writeReport(RUNTIME_STATS_FILENAME,stats);
|
||||
// }
|
||||
// catch (IOException ioe) {
|
||||
// System.err.println(ioe);
|
||||
// ioe.printStackTrace(System.err);
|
||||
// }
|
||||
}
|
||||
|
||||
public void setParser(DebugParser parser) {
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
// R E P O R T I N G
|
||||
|
||||
public String toNotifyString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append(Version);
|
||||
buf.append('\t');
|
||||
buf.append(parser.getClass().getName());
|
||||
// buf.append('\t');
|
||||
// buf.append(numRuleInvocations);
|
||||
// buf.append('\t');
|
||||
// buf.append(maxRuleInvocationDepth);
|
||||
// buf.append('\t');
|
||||
// buf.append(numFixedDecisions);
|
||||
// buf.append('\t');
|
||||
// buf.append(Stats.min(decisionMaxFixedLookaheads));
|
||||
// buf.append('\t');
|
||||
// buf.append(Stats.max(decisionMaxFixedLookaheads));
|
||||
// buf.append('\t');
|
||||
// buf.append(Stats.avg(decisionMaxFixedLookaheads));
|
||||
// buf.append('\t');
|
||||
// buf.append(Stats.stddev(decisionMaxFixedLookaheads));
|
||||
// buf.append('\t');
|
||||
// buf.append(numCyclicDecisions);
|
||||
// buf.append('\t');
|
||||
// buf.append(Stats.min(decisionMaxCyclicLookaheads));
|
||||
// buf.append('\t');
|
||||
// buf.append(Stats.max(decisionMaxCyclicLookaheads));
|
||||
// buf.append('\t');
|
||||
// buf.append(Stats.avg(decisionMaxCyclicLookaheads));
|
||||
// buf.append('\t');
|
||||
// buf.append(Stats.stddev(decisionMaxCyclicLookaheads));
|
||||
// buf.append('\t');
|
||||
// buf.append(numBacktrackDecisions);
|
||||
// buf.append('\t');
|
||||
// buf.append(Stats.min(toArray(decisionMaxSynPredLookaheads)));
|
||||
// buf.append('\t');
|
||||
// buf.append(Stats.max(toArray(decisionMaxSynPredLookaheads)));
|
||||
// buf.append('\t');
|
||||
// buf.append(Stats.avg(toArray(decisionMaxSynPredLookaheads)));
|
||||
// buf.append('\t');
|
||||
// buf.append(Stats.stddev(toArray(decisionMaxSynPredLookaheads)));
|
||||
// buf.append('\t');
|
||||
// buf.append(numSemanticPredicates);
|
||||
// buf.append('\t');
|
||||
// buf.append(parser.getTokenStream().size());
|
||||
// buf.append('\t');
|
||||
// buf.append(numHiddenTokens);
|
||||
// buf.append('\t');
|
||||
// buf.append(numCharsMatched);
|
||||
// buf.append('\t');
|
||||
// buf.append(numHiddenCharsMatched);
|
||||
// buf.append('\t');
|
||||
// buf.append(numberReportedErrors);
|
||||
// buf.append('\t');
|
||||
// buf.append(numMemoizationCacheHits);
|
||||
// buf.append('\t');
|
||||
// buf.append(numMemoizationCacheMisses);
|
||||
// buf.append('\t');
|
||||
// buf.append(numGuessingRuleInvocations);
|
||||
// buf.append('\t');
|
||||
// buf.append(numMemoizationCacheEntries);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return toString(getReport());
|
||||
}
|
||||
|
||||
public ProfileStats getReport() {
|
||||
// TokenStream input = parser.getTokenStream();
|
||||
// for (int i=0; i<input.size()&& lastRealTokenTouchedInDecision !=null&&i<= lastRealTokenTouchedInDecision.getTokenIndex(); i++) {
|
||||
// Token t = input.get(i);
|
||||
// if ( t.getChannel()!=Token.DEFAULT_CHANNEL ) {
|
||||
// stats.numHiddenTokens++;
|
||||
// stats.numHiddenCharsMatched += t.getText().length();
|
||||
// }
|
||||
// }
|
||||
stats.Version = Version;
|
||||
stats.name = parser.getClass().getName();
|
||||
stats.numUniqueRulesInvoked = uniqueRules.size();
|
||||
//stats.numCharsMatched = lastTokenConsumed.getStopIndex() + 1;
|
||||
return stats;
|
||||
}
|
||||
|
||||
public DoubleKeyMap getDecisionStats() {
|
||||
return decisions;
|
||||
}
|
||||
|
||||
public List getDecisionEvents() {
|
||||
return decisionEvents;
|
||||
}
|
||||
|
||||
public static String toString(ProfileStats stats) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("ANTLR Runtime Report; Profile Version ");
|
||||
buf.append(stats.Version);
|
||||
buf.append(newline);
|
||||
buf.append("parser name ");
|
||||
buf.append(stats.name);
|
||||
buf.append(newline);
|
||||
buf.append("Number of rule invocations ");
|
||||
buf.append(stats.numRuleInvocations);
|
||||
buf.append(newline);
|
||||
buf.append("Number of unique rules visited ");
|
||||
buf.append(stats.numUniqueRulesInvoked);
|
||||
buf.append(newline);
|
||||
buf.append("Number of decision events ");
|
||||
buf.append(stats.numDecisionEvents);
|
||||
buf.append(newline);
|
||||
buf.append("Overall average k per decision event ");
|
||||
buf.append(stats.avgkPerDecisionEvent);
|
||||
buf.append(newline);
|
||||
buf.append("Number of backtracking occurrences (can be multiple per decision) ");
|
||||
buf.append(stats.numBacktrackOccurrences);
|
||||
buf.append(newline);
|
||||
buf.append("Overall average k per decision event that backtracks ");
|
||||
buf.append(stats.avgkPerBacktrackingDecisionEvent);
|
||||
buf.append(newline);
|
||||
buf.append("Number of rule invocations while backtracking ");
|
||||
buf.append(stats.numGuessingRuleInvocations);
|
||||
buf.append(newline);
|
||||
buf.append("num decisions that potentially backtrack ");
|
||||
buf.append(stats.numDecisionsThatPotentiallyBacktrack);
|
||||
buf.append(newline);
|
||||
buf.append("num decisions that do backtrack ");
|
||||
buf.append(stats.numDecisionsThatDoBacktrack);
|
||||
buf.append(newline);
|
||||
buf.append("num decisions that potentially backtrack but don't ");
|
||||
buf.append(stats.numDecisionsThatPotentiallyBacktrack - stats.numDecisionsThatDoBacktrack);
|
||||
buf.append(newline);
|
||||
buf.append("average % of time a potentially backtracking decision backtracks ");
|
||||
buf.append(stats.averageDecisionPercentBacktracks);
|
||||
buf.append(newline);
|
||||
buf.append("num unique decisions covered ");
|
||||
buf.append(stats.numDecisionsCovered);
|
||||
buf.append(newline);
|
||||
buf.append("max rule invocation nesting depth ");
|
||||
buf.append(stats.maxRuleInvocationDepth);
|
||||
buf.append(newline);
|
||||
|
||||
// buf.append("number of fixed lookahead decisions ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("min lookahead used in a fixed lookahead decision ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("max lookahead used in a fixed lookahead decision ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("average lookahead depth used in fixed lookahead decisions ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("standard deviation of depth used in fixed lookahead decisions ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("number of arbitrary lookahead decisions ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("min lookahead used in an arbitrary lookahead decision ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("max lookahead used in an arbitrary lookahead decision ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("average lookahead depth used in arbitrary lookahead decisions ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("standard deviation of depth used in arbitrary lookahead decisions ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("number of evaluated syntactic predicates ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("min lookahead used in a syntactic predicate ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("max lookahead used in a syntactic predicate ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("average lookahead depth used in syntactic predicates ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
// buf.append("standard deviation of depth used in syntactic predicates ");
|
||||
// buf.append();
|
||||
// buf.append('\n');
|
||||
buf.append("rule memoization cache size ");
|
||||
buf.append(stats.numMemoizationCacheEntries);
|
||||
buf.append(newline);
|
||||
buf.append("number of rule memoization cache hits ");
|
||||
buf.append(stats.numMemoizationCacheHits);
|
||||
buf.append(newline);
|
||||
buf.append("number of rule memoization cache misses ");
|
||||
buf.append(stats.numMemoizationCacheMisses);
|
||||
buf.append(newline);
|
||||
// buf.append("number of evaluated semantic predicates ");
|
||||
// buf.append();
|
||||
// buf.append(newline);
|
||||
buf.append("number of tokens ");
|
||||
buf.append(stats.numTokens);
|
||||
buf.append(newline);
|
||||
buf.append("number of hidden tokens ");
|
||||
buf.append(stats.numHiddenTokens);
|
||||
buf.append(newline);
|
||||
buf.append("number of char ");
|
||||
buf.append(stats.numCharsMatched);
|
||||
buf.append(newline);
|
||||
buf.append("number of hidden char ");
|
||||
buf.append(stats.numHiddenCharsMatched);
|
||||
buf.append(newline);
|
||||
buf.append("number of syntax errors ");
|
||||
buf.append(stats.numReportedErrors);
|
||||
buf.append(newline);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public String getDecisionStatsDump() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("location");
|
||||
buf.append(DATA_SEP);
|
||||
buf.append("n");
|
||||
buf.append(DATA_SEP);
|
||||
buf.append("avgk");
|
||||
buf.append(DATA_SEP);
|
||||
buf.append("maxk");
|
||||
buf.append(DATA_SEP);
|
||||
buf.append("synpred");
|
||||
buf.append(DATA_SEP);
|
||||
buf.append("sempred");
|
||||
buf.append(DATA_SEP);
|
||||
buf.append("canbacktrack");
|
||||
buf.append("\n");
|
||||
for (String fileName : decisions.keySet()) {
|
||||
for (int d : decisions.keySet(fileName)) {
|
||||
DecisionDescriptor s = decisions.get(fileName, d);
|
||||
buf.append(s.decision);
|
||||
buf.append("@");
|
||||
buf.append(locationDescription(s.fileName,s.ruleName,s.line,s.pos)); // decision number
|
||||
buf.append(DATA_SEP);
|
||||
buf.append(s.n);
|
||||
buf.append(DATA_SEP);
|
||||
buf.append(String.format("%.2f",s.avgk));
|
||||
buf.append(DATA_SEP);
|
||||
buf.append(s.maxk);
|
||||
buf.append(DATA_SEP);
|
||||
buf.append(s.numBacktrackOccurrences);
|
||||
buf.append(DATA_SEP);
|
||||
buf.append(s.numSemPredEvals);
|
||||
buf.append(DATA_SEP);
|
||||
buf.append(s.couldBacktrack ?"1":"0");
|
||||
buf.append(newline);
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected int[] trim(int[] X, int n) {
|
||||
if ( n<X.length ) {
|
||||
int[] trimmed = new int[n];
|
||||
System.arraycopy(X,0,trimmed,0,n);
|
||||
X = trimmed;
|
||||
}
|
||||
return X;
|
||||
}
|
||||
|
||||
protected int[] toArray(List a) {
|
||||
int[] x = new int[a.size()];
|
||||
for (int i = 0; i < a.size(); i++) {
|
||||
Integer I = (Integer) a.get(i);
|
||||
x[i] = I.intValue();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/** Get num hidden tokens between i..j inclusive */
|
||||
public int getNumberOfHiddenTokens(int i, int j) {
|
||||
int n = 0;
|
||||
TokenStream input = parser.getTokenStream();
|
||||
for (int ti = i; ti<input.size() && ti <= j; ti++) {
|
||||
Token t = input.get(ti);
|
||||
if ( t.getChannel()!=Token.DEFAULT_CHANNEL ) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
protected String locationDescription() {
|
||||
return locationDescription(
|
||||
currentGrammarFileName.peek(),
|
||||
currentRuleName.peek(),
|
||||
currentLine.peek(),
|
||||
currentPos.peek());
|
||||
}
|
||||
|
||||
protected String locationDescription(String file, String rule, int line, int pos) {
|
||||
return file+":"+line+":"+pos+"(" + rule + ")";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.tree.BaseTree;
|
||||
import org.antlr.v4.runtime.tree.Tree;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.ConnectException;
|
||||
import java.net.Socket;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class RemoteDebugEventSocketListener implements Runnable {
|
||||
static final int MAX_EVENT_ELEMENTS = 8;
|
||||
DebugEventListener listener;
|
||||
String machine;
|
||||
int port;
|
||||
Socket channel = null;
|
||||
PrintWriter out;
|
||||
BufferedReader in;
|
||||
String event;
|
||||
/** Version of ANTLR (dictates events) */
|
||||
public String version;
|
||||
public String grammarFileName;
|
||||
/** Track the last token index we saw during a consume. If same, then
|
||||
* set a flag that we have a problem.
|
||||
*/
|
||||
int previousTokenIndex = -1;
|
||||
boolean tokenIndexesInvalid = false;
|
||||
|
||||
public static class ProxyToken implements Token {
|
||||
int index;
|
||||
int type;
|
||||
int channel;
|
||||
int line;
|
||||
int charPos;
|
||||
String text;
|
||||
public ProxyToken(int index) { this.index = index; }
|
||||
public ProxyToken(int index, int type, int channel,
|
||||
int line, int charPos, String text)
|
||||
{
|
||||
this.index = index;
|
||||
this.type = type;
|
||||
this.channel = channel;
|
||||
this.line = line;
|
||||
this.charPos = charPos;
|
||||
this.text = text;
|
||||
}
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
public void setType(int ttype) {
|
||||
this.type = ttype;
|
||||
}
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
public void setLine(int line) {
|
||||
this.line = line;
|
||||
}
|
||||
public int getCharPositionInLine() {
|
||||
return charPos;
|
||||
}
|
||||
public void setCharPositionInLine(int pos) {
|
||||
this.charPos = pos;
|
||||
}
|
||||
public int getChannel() {
|
||||
return channel;
|
||||
}
|
||||
public void setChannel(int channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
public int getTokenIndex() {
|
||||
return index;
|
||||
}
|
||||
public void setTokenIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
public CharStream getInputStream() {
|
||||
return null;
|
||||
}
|
||||
public void setInputStream(CharStream input) {
|
||||
}
|
||||
public String toString() {
|
||||
String channelStr = "";
|
||||
if ( channel!= Token.DEFAULT_CHANNEL ) {
|
||||
channelStr=",channel="+channel;
|
||||
}
|
||||
return "["+getText()+"/<"+type+">"+channelStr+","+line+":"+getCharPositionInLine()+",@"+index+"]";
|
||||
}
|
||||
}
|
||||
|
||||
public static class ProxyTree extends BaseTree {
|
||||
public int ID;
|
||||
public int type;
|
||||
public int line = 0;
|
||||
public int charPos = -1;
|
||||
public int tokenIndex = -1;
|
||||
public String text;
|
||||
|
||||
public ProxyTree(int ID, int type, int line, int charPos, int tokenIndex, String text) {
|
||||
this.ID = ID;
|
||||
this.type = type;
|
||||
this.line = line;
|
||||
this.charPos = charPos;
|
||||
this.tokenIndex = tokenIndex;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public ProxyTree(int ID) { this.ID = ID; }
|
||||
|
||||
public int getTokenStartIndex() { return tokenIndex; }
|
||||
public void setTokenStartIndex(int index) { }
|
||||
public int getTokenStopIndex() { return 0; }
|
||||
public void setTokenStopIndex(int index) { }
|
||||
public Tree dupNode() { return null; }
|
||||
public int getType() { return type; }
|
||||
public String getText() { return text; }
|
||||
public String toString() {
|
||||
return "fix this";
|
||||
}
|
||||
}
|
||||
|
||||
public RemoteDebugEventSocketListener(DebugEventListener listener,
|
||||
String machine,
|
||||
int port) throws IOException
|
||||
{
|
||||
this.listener = listener;
|
||||
this.machine = machine;
|
||||
this.port = port;
|
||||
|
||||
if( !openConnection() ) {
|
||||
throw new ConnectException();
|
||||
}
|
||||
}
|
||||
|
||||
protected void eventHandler() {
|
||||
try {
|
||||
handshake();
|
||||
event = in.readLine();
|
||||
while ( event!=null ) {
|
||||
dispatch(event);
|
||||
ack();
|
||||
event = in.readLine();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.err.println(e);
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
finally {
|
||||
closeConnection();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean openConnection() {
|
||||
boolean success = false;
|
||||
try {
|
||||
channel = new Socket(machine, port);
|
||||
channel.setTcpNoDelay(true);
|
||||
OutputStream os = channel.getOutputStream();
|
||||
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF8");
|
||||
out = new PrintWriter(new BufferedWriter(osw));
|
||||
InputStream is = channel.getInputStream();
|
||||
InputStreamReader isr = new InputStreamReader(is, "UTF8");
|
||||
in = new BufferedReader(isr);
|
||||
success = true;
|
||||
} catch(Exception e) {
|
||||
System.err.println(e);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
protected void closeConnection() {
|
||||
try {
|
||||
in.close(); in = null;
|
||||
out.close(); out = null;
|
||||
channel.close(); channel=null;
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.err.println(e);
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
finally {
|
||||
if ( in!=null ) {
|
||||
try {in.close();} catch (IOException ioe) {
|
||||
System.err.println(ioe);
|
||||
}
|
||||
}
|
||||
if ( out!=null ) {
|
||||
out.close();
|
||||
}
|
||||
if ( channel!=null ) {
|
||||
try {channel.close();} catch (IOException ioe) {
|
||||
System.err.println(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void handshake() throws IOException {
|
||||
String antlrLine = in.readLine();
|
||||
String[] antlrElements = getEventElements(antlrLine);
|
||||
version = antlrElements[1];
|
||||
String grammarLine = in.readLine();
|
||||
String[] grammarElements = getEventElements(grammarLine);
|
||||
grammarFileName = grammarElements[1];
|
||||
ack();
|
||||
listener.commence(); // inform listener after handshake
|
||||
}
|
||||
|
||||
protected void ack() {
|
||||
out.println("ack");
|
||||
out.flush();
|
||||
}
|
||||
|
||||
protected void dispatch(String line) {
|
||||
//System.out.println("event: "+line);
|
||||
String[] elements = getEventElements(line);
|
||||
if ( elements==null || elements[0]==null ) {
|
||||
System.err.println("unknown debug event: "+line);
|
||||
return;
|
||||
}
|
||||
if ( elements[0].equals("enterRule") ) {
|
||||
listener.enterRule(elements[1], elements[2]);
|
||||
}
|
||||
else if ( elements[0].equals("exitRule") ) {
|
||||
listener.exitRule(elements[1], elements[2]);
|
||||
}
|
||||
else if ( elements[0].equals("enterAlt") ) {
|
||||
listener.enterAlt(Integer.parseInt(elements[1]));
|
||||
}
|
||||
else if ( elements[0].equals("enterSubRule") ) {
|
||||
listener.enterSubRule(Integer.parseInt(elements[1]));
|
||||
}
|
||||
else if ( elements[0].equals("exitSubRule") ) {
|
||||
listener.exitSubRule(Integer.parseInt(elements[1]));
|
||||
}
|
||||
else if ( elements[0].equals("enterDecision") ) {
|
||||
listener.enterDecision(Integer.parseInt(elements[1]), elements[2].equals("true"));
|
||||
}
|
||||
else if ( elements[0].equals("exitDecision") ) {
|
||||
listener.exitDecision(Integer.parseInt(elements[1]));
|
||||
}
|
||||
else if ( elements[0].equals("location") ) {
|
||||
listener.location(Integer.parseInt(elements[1]),
|
||||
Integer.parseInt(elements[2]));
|
||||
}
|
||||
else if ( elements[0].equals("consumeToken") ) {
|
||||
ProxyToken t = deserializeToken(elements, 1);
|
||||
if ( t.getTokenIndex() == previousTokenIndex ) {
|
||||
tokenIndexesInvalid = true;
|
||||
}
|
||||
previousTokenIndex = t.getTokenIndex();
|
||||
listener.consumeToken(t);
|
||||
}
|
||||
else if ( elements[0].equals("consumeHiddenToken") ) {
|
||||
ProxyToken t = deserializeToken(elements, 1);
|
||||
if ( t.getTokenIndex() == previousTokenIndex ) {
|
||||
tokenIndexesInvalid = true;
|
||||
}
|
||||
previousTokenIndex = t.getTokenIndex();
|
||||
listener.consumeHiddenToken(t);
|
||||
}
|
||||
else if ( elements[0].equals("LT") ) {
|
||||
Token t = deserializeToken(elements, 2);
|
||||
listener.LT(Integer.parseInt(elements[1]), t);
|
||||
}
|
||||
else if ( elements[0].equals("exception") ) {
|
||||
String excName = elements[1];
|
||||
String indexS = elements[2];
|
||||
String lineS = elements[3];
|
||||
String posS = elements[4];
|
||||
Class excClass = null;
|
||||
try {
|
||||
excClass = Class.forName(excName);
|
||||
RecognitionException e =
|
||||
(RecognitionException)excClass.newInstance();
|
||||
e.index = Integer.parseInt(indexS);
|
||||
e.line = Integer.parseInt(lineS);
|
||||
e.charPositionInLine = Integer.parseInt(posS);
|
||||
listener.recognitionException(e);
|
||||
}
|
||||
catch (ClassNotFoundException cnfe) {
|
||||
System.err.println("can't find class "+cnfe);
|
||||
cnfe.printStackTrace(System.err);
|
||||
}
|
||||
catch (InstantiationException ie) {
|
||||
System.err.println("can't instantiate class "+ie);
|
||||
ie.printStackTrace(System.err);
|
||||
}
|
||||
catch (IllegalAccessException iae) {
|
||||
System.err.println("can't access class "+iae);
|
||||
iae.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
else if ( elements[0].equals("beginResync") ) {
|
||||
listener.beginResync();
|
||||
}
|
||||
else if ( elements[0].equals("endResync") ) {
|
||||
listener.endResync();
|
||||
}
|
||||
else if ( elements[0].equals("terminate") ) {
|
||||
listener.terminate();
|
||||
}
|
||||
else if ( elements[0].equals("semanticPredicate") ) {
|
||||
Boolean result = Boolean.valueOf(elements[1]);
|
||||
String predicateText = elements[2];
|
||||
predicateText = unEscapeNewlines(predicateText);
|
||||
listener.semanticPredicate(result.booleanValue(),
|
||||
predicateText);
|
||||
}
|
||||
else if ( elements[0].equals("consumeNode") ) {
|
||||
ProxyTree node = deserializeNode(elements, 1);
|
||||
listener.consumeNode(node);
|
||||
}
|
||||
else if ( elements[0].equals("LN") ) {
|
||||
int i = Integer.parseInt(elements[1]);
|
||||
ProxyTree node = deserializeNode(elements, 2);
|
||||
listener.LT(i, node);
|
||||
}
|
||||
else if ( elements[0].equals("createNodeFromTokenElements") ) {
|
||||
int ID = Integer.parseInt(elements[1]);
|
||||
int type = Integer.parseInt(elements[2]);
|
||||
String text = elements[3];
|
||||
text = unEscapeNewlines(text);
|
||||
ProxyTree node = new ProxyTree(ID, type, -1, -1, -1, text);
|
||||
listener.createNode(node);
|
||||
}
|
||||
else if ( elements[0].equals("createNode") ) {
|
||||
int ID = Integer.parseInt(elements[1]);
|
||||
int tokenIndex = Integer.parseInt(elements[2]);
|
||||
// create dummy node/token filled with ID, tokenIndex
|
||||
ProxyTree node = new ProxyTree(ID);
|
||||
ProxyToken token = new ProxyToken(tokenIndex);
|
||||
listener.createNode(node, token);
|
||||
}
|
||||
else if ( elements[0].equals("nilNode") ) {
|
||||
int ID = Integer.parseInt(elements[1]);
|
||||
ProxyTree node = new ProxyTree(ID);
|
||||
listener.nilNode(node);
|
||||
}
|
||||
else if ( elements[0].equals("errorNode") ) {
|
||||
// TODO: do we need a special tree here?
|
||||
int ID = Integer.parseInt(elements[1]);
|
||||
int type = Integer.parseInt(elements[2]);
|
||||
String text = elements[3];
|
||||
text = unEscapeNewlines(text);
|
||||
ProxyTree node = new ProxyTree(ID, type, -1, -1, -1, text);
|
||||
listener.errorNode(node);
|
||||
}
|
||||
else if ( elements[0].equals("becomeRoot") ) {
|
||||
int newRootID = Integer.parseInt(elements[1]);
|
||||
int oldRootID = Integer.parseInt(elements[2]);
|
||||
ProxyTree newRoot = new ProxyTree(newRootID);
|
||||
ProxyTree oldRoot = new ProxyTree(oldRootID);
|
||||
listener.becomeRoot(newRoot, oldRoot);
|
||||
}
|
||||
else if ( elements[0].equals("addChild") ) {
|
||||
int rootID = Integer.parseInt(elements[1]);
|
||||
int childID = Integer.parseInt(elements[2]);
|
||||
ProxyTree root = new ProxyTree(rootID);
|
||||
ProxyTree child = new ProxyTree(childID);
|
||||
listener.addChild(root, child);
|
||||
}
|
||||
else if ( elements[0].equals("setTokenBoundaries") ) {
|
||||
int ID = Integer.parseInt(elements[1]);
|
||||
ProxyTree node = new ProxyTree(ID);
|
||||
listener.setTokenBoundaries(
|
||||
node,
|
||||
Integer.parseInt(elements[2]),
|
||||
Integer.parseInt(elements[3]));
|
||||
}
|
||||
else {
|
||||
System.err.println("unknown debug event: "+line);
|
||||
}
|
||||
}
|
||||
|
||||
protected ProxyTree deserializeNode(String[] elements, int offset) {
|
||||
int ID = Integer.parseInt(elements[offset+0]);
|
||||
int type = Integer.parseInt(elements[offset+1]);
|
||||
int tokenLine = Integer.parseInt(elements[offset+2]);
|
||||
int charPositionInLine = Integer.parseInt(elements[offset+3]);
|
||||
int tokenIndex = Integer.parseInt(elements[offset+4]);
|
||||
String text = elements[offset+5];
|
||||
text = unEscapeNewlines(text);
|
||||
return new ProxyTree(ID, type, tokenLine, charPositionInLine, tokenIndex, text);
|
||||
}
|
||||
|
||||
protected ProxyToken deserializeToken(String[] elements,
|
||||
int offset)
|
||||
{
|
||||
String indexS = elements[offset+0];
|
||||
String typeS = elements[offset+1];
|
||||
String channelS = elements[offset+2];
|
||||
String lineS = elements[offset+3];
|
||||
String posS = elements[offset+4];
|
||||
String text = elements[offset+5];
|
||||
text = unEscapeNewlines(text);
|
||||
int index = Integer.parseInt(indexS);
|
||||
ProxyToken t =
|
||||
new ProxyToken(index,
|
||||
Integer.parseInt(typeS),
|
||||
Integer.parseInt(channelS),
|
||||
Integer.parseInt(lineS),
|
||||
Integer.parseInt(posS),
|
||||
text);
|
||||
return t;
|
||||
}
|
||||
|
||||
/** Create a thread to listen to the remote running recognizer */
|
||||
public void start() {
|
||||
Thread t = new Thread(this);
|
||||
t.start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
eventHandler();
|
||||
}
|
||||
|
||||
// M i s c
|
||||
|
||||
public String[] getEventElements(String event) {
|
||||
if ( event==null ) {
|
||||
return null;
|
||||
}
|
||||
String[] elements = new String[MAX_EVENT_ELEMENTS];
|
||||
String str = null; // a string element if present (must be last)
|
||||
try {
|
||||
int firstQuoteIndex = event.indexOf('"');
|
||||
if ( firstQuoteIndex>=0 ) {
|
||||
// treat specially; has a string argument like "a comment\n
|
||||
// Note that the string is terminated by \n not end quote.
|
||||
// Easier to parse that way.
|
||||
String eventWithoutString = event.substring(0,firstQuoteIndex);
|
||||
str = event.substring(firstQuoteIndex+1,event.length());
|
||||
event = eventWithoutString;
|
||||
}
|
||||
StringTokenizer st = new StringTokenizer(event, "\t", false);
|
||||
int i = 0;
|
||||
while ( st.hasMoreTokens() ) {
|
||||
if ( i>=MAX_EVENT_ELEMENTS ) {
|
||||
// ErrorManager.internalError("event has more than "+MAX_EVENT_ELEMENTS+" args: "+event);
|
||||
return elements;
|
||||
}
|
||||
elements[i] = st.nextToken();
|
||||
i++;
|
||||
}
|
||||
if ( str!=null ) {
|
||||
elements[i] = str;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
protected String unEscapeNewlines(String txt) {
|
||||
// this unescape is slow but easy to understand
|
||||
txt = txt.replaceAll("%0A","\n"); // unescape \n
|
||||
txt = txt.replaceAll("%0D","\r"); // unescape \r
|
||||
txt = txt.replaceAll("%25","%"); // undo escaped escape chars
|
||||
return txt;
|
||||
}
|
||||
|
||||
public boolean tokenIndexesAreInvalid() {
|
||||
return false;
|
||||
//return tokenIndexesInvalid;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.tree.TreeAdaptor;
|
||||
|
||||
/** Print out (most of) the events... Useful for debugging, testing... */
|
||||
public class TraceDebugEventListener extends BlankDebugEventListener {
|
||||
TreeAdaptor adaptor;
|
||||
|
||||
public TraceDebugEventListener(TreeAdaptor adaptor) {
|
||||
this.adaptor = adaptor;
|
||||
}
|
||||
|
||||
public void enterRule(String ruleName) { System.out.println("enterRule "+ruleName); }
|
||||
public void exitRule(String ruleName) { System.out.println("exitRule "+ruleName); }
|
||||
public void enterSubRule(int decisionNumber) { System.out.println("enterSubRule"); }
|
||||
public void exitSubRule(int decisionNumber) { System.out.println("exitSubRule"); }
|
||||
public void location(int line, int pos) {System.out.println("location "+line+":"+pos);}
|
||||
|
||||
// Tree parsing stuff
|
||||
|
||||
public void consumeNode(Object t) {
|
||||
int ID = adaptor.getUniqueID(t);
|
||||
String text = adaptor.getText(t);
|
||||
int type = adaptor.getType(t);
|
||||
System.out.println("consumeNode "+ID+" "+text+" "+type);
|
||||
}
|
||||
|
||||
public void LT(int i, Object t) {
|
||||
int ID = adaptor.getUniqueID(t);
|
||||
String text = adaptor.getText(t);
|
||||
int type = adaptor.getType(t);
|
||||
System.out.println("LT "+i+" "+ID+" "+text+" "+type);
|
||||
}
|
||||
|
||||
|
||||
// AST stuff
|
||||
public void nilNode(Object t) {System.out.println("nilNode "+adaptor.getUniqueID(t));}
|
||||
|
||||
public void createNode(Object t) {
|
||||
int ID = adaptor.getUniqueID(t);
|
||||
String text = adaptor.getText(t);
|
||||
int type = adaptor.getType(t);
|
||||
System.out.println("create "+ID+": "+text+", "+type);
|
||||
}
|
||||
|
||||
public void createNode(Object node, Token token) {
|
||||
int ID = adaptor.getUniqueID(node);
|
||||
String text = adaptor.getText(node);
|
||||
int tokenIndex = token.getTokenIndex();
|
||||
System.out.println("create "+ID+": "+tokenIndex);
|
||||
}
|
||||
|
||||
public void becomeRoot(Object newRoot, Object oldRoot) {
|
||||
System.out.println("becomeRoot "+adaptor.getUniqueID(newRoot)+", "+
|
||||
adaptor.getUniqueID(oldRoot));
|
||||
}
|
||||
|
||||
public void addChild(Object root, Object child) {
|
||||
System.out.println("addChild "+adaptor.getUniqueID(root)+", "+
|
||||
adaptor.getUniqueID(child));
|
||||
}
|
||||
|
||||
public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex) {
|
||||
System.out.println("setTokenBoundaries "+adaptor.getUniqueID(t)+", "+
|
||||
tokenStartIndex+", "+tokenStopIndex);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 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.debug;
|
||||
|
||||
import org.antlr.v4.runtime.IntStream;
|
||||
import org.antlr.v4.runtime.TokenStream;
|
||||
|
||||
/** The default tracer mimics the traceParser behavior of ANTLR 2.x.
|
||||
* This listens for debugging events from the parser and implies
|
||||
* that you cannot debug and trace at the same time.
|
||||
*/
|
||||
public class Tracer extends BlankDebugEventListener {
|
||||
public IntStream input;
|
||||
protected int level = 0;
|
||||
|
||||
public Tracer(IntStream input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public void enterRule(String ruleName) {
|
||||
for (int i=1; i<=level; i++) {System.out.print(" ");}
|
||||
System.out.println("> "+ruleName+" lookahead(1)="+getInputSymbol(1));
|
||||
level++;
|
||||
}
|
||||
|
||||
public void exitRule(String ruleName) {
|
||||
level--;
|
||||
for (int i=1; i<=level; i++) {System.out.print(" ");}
|
||||
System.out.println("< "+ruleName+" lookahead(1)="+getInputSymbol(1));
|
||||
}
|
||||
|
||||
public Object getInputSymbol(int k) {
|
||||
if ( input instanceof TokenStream) {
|
||||
return ((TokenStream)input).LT(k);
|
||||
}
|
||||
return new Character((char)input.LA(k));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +29,8 @@
|
|||
|
||||
package org.antlr.v4.runtime.tree;
|
||||
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.TokenStream;
|
||||
|
||||
/**
|
||||
Cut-n-paste from material I'm not using in the book anymore (edit later
|
||||
|
@ -84,9 +85,6 @@ public class TreeFilter extends TreeParser {
|
|||
protected TreeAdaptor originalAdaptor;
|
||||
|
||||
public TreeFilter(TreeNodeStream input) {
|
||||
this(input, new RecognizerSharedState());
|
||||
}
|
||||
public TreeFilter(TreeNodeStream input, RecognizerSharedState state) {
|
||||
super(input);
|
||||
originalAdaptor = (TreeAdaptor) input.getTreeAdaptor();
|
||||
originalTokenStream = input.getTokenStream();
|
||||
|
|
|
@ -31,7 +31,8 @@ package org.antlr.v4.runtime.tree;
|
|||
|
||||
import org.antlr.v4.runtime.*;
|
||||
|
||||
import java.util.regex.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** A parser for a stream of tree nodes. "tree grammars" result in a subclass
|
||||
* of this. All the error reporting and recovery is shared with Parser via
|
||||
|
@ -54,11 +55,6 @@ public class TreeParser extends BaseRecognizer {
|
|||
setTreeNodeStream(input);
|
||||
}
|
||||
|
||||
public TreeParser(TreeNodeStream input, RecognizerSharedState<?> state) {
|
||||
super((TokenStream)input); // share the state object with another parser
|
||||
setTreeNodeStream(input);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
super.reset(); // reset all recognizer state variables
|
||||
if ( input!=null ) {
|
||||
|
|
Loading…
Reference in New Issue