diff options
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.java | 527 |
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; + } + +} + |