diff options
Diffstat (limited to 'runtime/CSharp3/Sources/Antlr3.Runtime.Debug/DebugEventSocketProxy.cs')
-rw-r--r-- | runtime/CSharp3/Sources/Antlr3.Runtime.Debug/DebugEventSocketProxy.cs | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/runtime/CSharp3/Sources/Antlr3.Runtime.Debug/DebugEventSocketProxy.cs b/runtime/CSharp3/Sources/Antlr3.Runtime.Debug/DebugEventSocketProxy.cs new file mode 100644 index 0000000..64b0fd2 --- /dev/null +++ b/runtime/CSharp3/Sources/Antlr3.Runtime.Debug/DebugEventSocketProxy.cs @@ -0,0 +1,445 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2005-2008 Terence Parr + * All rights reserved. + * + * Conversion to C#: + * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc. + * 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. + */ + +namespace Antlr.Runtime.Debug +{ + using System; + using Antlr.Runtime.JavaExtensions; + + using IOException = System.IO.IOException; + using ITreeAdaptor = Antlr.Runtime.Tree.ITreeAdaptor; + using Socket = System.Net.Sockets.Socket; + using StringBuilder = System.Text.StringBuilder; + using TcpListener = System.Net.Sockets.TcpListener; + + /** <summary> + * 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. + * </summary> + */ + public class DebugEventSocketProxy : BlankDebugEventListener + { + public const int DefaultDebuggerPort = 49100; + protected int port = DefaultDebuggerPort; + protected TcpListener serverSocket; + protected Socket socket; + protected string grammarFileName; + //protected PrintWriter @out; + //protected BufferedReader @in; + + /** <summary>Who am i debugging?</summary> */ + protected BaseRecognizer recognizer; + + /** <summary> + * 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. :( + * </summary> + */ + protected ITreeAdaptor adaptor; + + public DebugEventSocketProxy( BaseRecognizer recognizer, ITreeAdaptor adaptor ) : + this( recognizer, DefaultDebuggerPort, adaptor ) + { + } + + public DebugEventSocketProxy( BaseRecognizer recognizer, int port, ITreeAdaptor adaptor ) + { + this.grammarFileName = recognizer.GrammarFileName; + this.adaptor = adaptor; + this.port = port; + } + + #region Properties + public virtual ITreeAdaptor TreeAdaptor + { + get + { + return adaptor; + } + set + { + adaptor = value; + } + } + #endregion + + public virtual void Handshake() + { + if ( serverSocket == null ) + { + System.Net.IPHostEntry hostInfo = System.Net.Dns.GetHostEntry( "localhost" ); + System.Net.IPAddress ipAddress = hostInfo.AddressList[0]; + serverSocket = new TcpListener( ipAddress, port ); + socket = serverSocket.AcceptSocket(); + socket.NoDelay = true; + + System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); + socket.Send( encoding.GetBytes( "ANTLR " + DebugEventListenerConstants.ProtocolVersion + "\n" ) ); + socket.Send( encoding.GetBytes( "grammar \"" + grammarFileName + "\n" ) ); + Ack(); + + //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 " + DebugEventListenerConstants.PROTOCOL_VERSION ); + //@out.println( "grammar \"" + grammarFileName ); + //@out.flush(); + //ack(); + } + } + + public override void Commence() + { + // don't bother sending event; listener will trigger upon connection + } + + public override void Terminate() + { + Transmit( "terminate" ); + //@out.close(); + try + { + socket.Close(); + } + catch ( IOException ioe ) + { + ExceptionExtensions.PrintStackTrace( ioe, Console.Error ); + } + } + + protected virtual void Ack() + { + try + { + throw new NotImplementedException(); + //@in.readLine(); + } + catch ( IOException ioe ) + { + ExceptionExtensions.PrintStackTrace( ioe, Console.Error ); + } + } + + protected virtual void Transmit( string @event ) + { + socket.Send( new System.Text.UTF8Encoding().GetBytes( @event + "\n" ) ); + //@out.println( @event ); + //@out.flush(); + Ack(); + } + + public override void EnterRule( string grammarFileName, string ruleName ) + { + Transmit( "enterRule\t" + grammarFileName + "\t" + ruleName ); + } + + public override void EnterAlt( int alt ) + { + Transmit( "enterAlt\t" + alt ); + } + + public override void ExitRule( string grammarFileName, string ruleName ) + { + Transmit( "exitRule\t" + grammarFileName + "\t" + ruleName ); + } + + public override void EnterSubRule( int decisionNumber ) + { + Transmit( "enterSubRule\t" + decisionNumber ); + } + + public override void ExitSubRule( int decisionNumber ) + { + Transmit( "exitSubRule\t" + decisionNumber ); + } + + public override void EnterDecision(int decisionNumber, bool couldBacktrack) + { + Transmit( "enterDecision\t" + decisionNumber ); + } + + public override void ExitDecision( int decisionNumber ) + { + Transmit( "exitDecision\t" + decisionNumber ); + } + + public override void ConsumeToken( IToken t ) + { + string buf = SerializeToken( t ); + Transmit( "consumeToken\t" + buf ); + } + + public override void ConsumeHiddenToken( IToken t ) + { + string buf = SerializeToken( t ); + Transmit( "consumeHiddenToken\t" + buf ); + } + + public override void LT( int i, IToken t ) + { + if ( t != null ) + Transmit( "LT\t" + i + "\t" + SerializeToken( t ) ); + } + + public override void Mark( int i ) + { + Transmit( "mark\t" + i ); + } + + public override void Rewind( int i ) + { + Transmit( "rewind\t" + i ); + } + + public override void Rewind() + { + Transmit( "rewind" ); + } + + public override void BeginBacktrack( int level ) + { + Transmit( "beginBacktrack\t" + level ); + } + + public override void EndBacktrack( int level, bool successful ) + { + Transmit( "endBacktrack\t" + level + "\t" + ( successful ? DebugEventListenerConstants.True : DebugEventListenerConstants.False ) ); + } + + public override void Location( int line, int pos ) + { + Transmit( "location\t" + line + "\t" + pos ); + } + + public override void RecognitionException( RecognitionException e ) + { + StringBuilder buf = new StringBuilder( 50 ); + buf.Append( "exception\t" ); + buf.Append( e.GetType().Name ); + // 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 override void BeginResync() + { + Transmit( "beginResync" ); + } + + public override void EndResync() + { + Transmit( "endResync" ); + } + + public override void SemanticPredicate( bool result, string predicate ) + { + StringBuilder buf = new StringBuilder( 50 ); + buf.Append( "semanticPredicate\t" ); + buf.Append( result ); + SerializeText( buf, predicate ); + Transmit( buf.ToString() ); + } + + #region AST Parsing Events + + public override void ConsumeNode( object t ) + { + StringBuilder buf = new StringBuilder( 50 ); + buf.Append( "consumeNode" ); + SerializeNode( buf, t ); + Transmit( buf.ToString() ); + } + + public override void LT( int i, object t ) + { + int ID = adaptor.GetUniqueID( t ); + string text = adaptor.GetText( t ); + int type = adaptor.GetType( t ); + StringBuilder buf = new StringBuilder( 50 ); + buf.Append( "LN\t" ); // lookahead node; distinguish from LT in protocol + buf.Append( i ); + SerializeNode( buf, t ); + Transmit( buf.ToString() ); + } + + protected virtual void SerializeNode( StringBuilder 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 ); + IToken token = adaptor.GetToken( t ); + int line = -1; + int pos = -1; + if ( token != null ) + { + line = token.Line; + pos = token.CharPositionInLine; + } + 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 ); + } + + #endregion + + + #region AST Events + + public override void NilNode( object t ) + { + int ID = adaptor.GetUniqueID( t ); + Transmit( "nilNode\t" + ID ); + } + + public override void ErrorNode( object t ) + { + int ID = adaptor.GetUniqueID( t ); + string text = t.ToString(); + StringBuilder buf = new StringBuilder( 50 ); + buf.Append( "errorNode\t" ); + buf.Append( ID ); + buf.Append( "\t" ); + buf.Append( TokenTypes.Invalid ); + SerializeText( buf, text ); + Transmit( buf.ToString() ); + } + + public override void CreateNode( object t ) + { + int ID = adaptor.GetUniqueID( t ); + string text = adaptor.GetText( t ); + int type = adaptor.GetType( t ); + StringBuilder buf = new StringBuilder( 50 ); + buf.Append( "createNodeFromTokenElements\t" ); + buf.Append( ID ); + buf.Append( "\t" ); + buf.Append( type ); + SerializeText( buf, text ); + Transmit( buf.ToString() ); + } + + public override void CreateNode( object node, IToken token ) + { + int ID = adaptor.GetUniqueID( node ); + int tokenIndex = token.TokenIndex; + Transmit( "createNode\t" + ID + "\t" + tokenIndex ); + } + + public override void BecomeRoot( object newRoot, object oldRoot ) + { + int newRootID = adaptor.GetUniqueID( newRoot ); + int oldRootID = adaptor.GetUniqueID( oldRoot ); + Transmit( "becomeRoot\t" + newRootID + "\t" + oldRootID ); + } + + public override void AddChild( object root, object child ) + { + int rootID = adaptor.GetUniqueID( root ); + int childID = adaptor.GetUniqueID( child ); + Transmit( "addChild\t" + rootID + "\t" + childID ); + } + + public override void SetTokenBoundaries( object t, int tokenStartIndex, int tokenStopIndex ) + { + int ID = adaptor.GetUniqueID( t ); + Transmit( "setTokenBoundaries\t" + ID + "\t" + tokenStartIndex + "\t" + tokenStopIndex ); + } + + #endregion + + + #region Support + + protected virtual string SerializeToken( IToken t ) + { + StringBuilder buf = new StringBuilder( 50 ); + buf.Append( t.TokenIndex ); + buf.Append( '\t' ); + buf.Append( t.Type ); + buf.Append( '\t' ); + buf.Append( t.Channel ); + buf.Append( '\t' ); + buf.Append( t.Line ); + buf.Append( '\t' ); + buf.Append( t.CharPositionInLine ); + SerializeText( buf, t.Text ); + return buf.ToString(); + } + + protected virtual void SerializeText( StringBuilder 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 virtual string EscapeNewlines( string txt ) + { + txt = txt.Replace( "%", "%25" ); // escape all escape char ;) + txt = txt.Replace( "\n", "%0A" ); // escape \n + txt = txt.Replace( "\r", "%0D" ); // escape \r + return txt; + } + + #endregion + } +} |