aboutsummaryrefslogtreecommitdiff
path: root/antlr-3.4/runtime/Java/src/main/java/org/antlr/runtime/debug/RemoteDebugEventSocketListener.java
diff options
context:
space:
mode:
Diffstat (limited to 'antlr-3.4/runtime/Java/src/main/java/org/antlr/runtime/debug/RemoteDebugEventSocketListener.java')
-rw-r--r--antlr-3.4/runtime/Java/src/main/java/org/antlr/runtime/debug/RemoteDebugEventSocketListener.java527
1 files changed, 527 insertions, 0 deletions
diff --git a/antlr-3.4/runtime/Java/src/main/java/org/antlr/runtime/debug/RemoteDebugEventSocketListener.java b/antlr-3.4/runtime/Java/src/main/java/org/antlr/runtime/debug/RemoteDebugEventSocketListener.java
new file mode 100644
index 0000000..933fdae
--- /dev/null
+++ b/antlr-3.4/runtime/Java/src/main/java/org/antlr/runtime/debug/RemoteDebugEventSocketListener.java
@@ -0,0 +1,527 @@
+/*
+ [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.runtime.debug;
+
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.tree.BaseTree;
+import org.antlr.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("mark") ) {
+ listener.mark(Integer.parseInt(elements[1]));
+ }
+ else if ( elements[0].equals("rewind") ) {
+ if ( elements[1]!=null ) {
+ listener.rewind(Integer.parseInt(elements[1]));
+ }
+ else {
+ listener.rewind();
+ }
+ }
+ else if ( elements[0].equals("beginBacktrack") ) {
+ listener.beginBacktrack(Integer.parseInt(elements[1]));
+ }
+ else if ( elements[0].equals("endBacktrack") ) {
+ int level = Integer.parseInt(elements[1]);
+ int successI = Integer.parseInt(elements[2]);
+ listener.endBacktrack(level, successI==DebugEventListener.TRUE);
+ }
+ 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;
+ }
+
+}
+