1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2005-2008 Terence Parr 4 * All rights reserved. 5 * 6 * Conversion to C#: 7 * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33namespace Antlr.Runtime.Debug 34{ 35 using System; 36 using Antlr.Runtime.JavaExtensions; 37 38 using IOException = System.IO.IOException; 39 using ITreeAdaptor = Antlr.Runtime.Tree.ITreeAdaptor; 40 using Socket = System.Net.Sockets.Socket; 41 using StringBuilder = System.Text.StringBuilder; 42 using TcpListener = System.Net.Sockets.TcpListener; 43 44 /** <summary> 45 * A proxy debug event listener that forwards events over a socket to 46 * a debugger (or any other listener) using a simple text-based protocol; 47 * one event per line. ANTLRWorks listens on server socket with a 48 * RemoteDebugEventSocketListener instance. These two objects must therefore 49 * be kept in sync. New events must be handled on both sides of socket. 50 * </summary> 51 */ 52 public class DebugEventSocketProxy : BlankDebugEventListener 53 { 54 public const int DefaultDebuggerPort = 49100; 55 protected int port = DefaultDebuggerPort; 56 protected TcpListener serverSocket; 57 protected Socket socket; 58 protected string grammarFileName; 59 //protected PrintWriter @out; 60 //protected BufferedReader @in; 61 62 /** <summary>Who am i debugging?</summary> */ 63 protected BaseRecognizer recognizer; 64 65 /** <summary> 66 * Almost certainly the recognizer will have adaptor set, but 67 * we don't know how to cast it (Parser or TreeParser) to get 68 * the adaptor field. Must be set with a constructor. :( 69 * </summary> 70 */ 71 protected ITreeAdaptor adaptor; 72 73 public DebugEventSocketProxy( BaseRecognizer recognizer, ITreeAdaptor adaptor ) : 74 this( recognizer, DefaultDebuggerPort, adaptor ) 75 { 76 } 77 78 public DebugEventSocketProxy( BaseRecognizer recognizer, int port, ITreeAdaptor adaptor ) 79 { 80 this.grammarFileName = recognizer.GrammarFileName; 81 this.adaptor = adaptor; 82 this.port = port; 83 } 84 85 #region Properties 86 public virtual ITreeAdaptor TreeAdaptor 87 { 88 get 89 { 90 return adaptor; 91 } 92 set 93 { 94 adaptor = value; 95 } 96 } 97 #endregion 98 99 public virtual void Handshake() 100 { 101 if ( serverSocket == null ) 102 { 103 System.Net.IPHostEntry hostInfo = System.Net.Dns.GetHostEntry( "localhost" ); 104 System.Net.IPAddress ipAddress = hostInfo.AddressList[0]; 105 serverSocket = new TcpListener( ipAddress, port ); 106 socket = serverSocket.AcceptSocket(); 107 socket.NoDelay = true; 108 109 System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); 110 socket.Send( encoding.GetBytes( "ANTLR " + DebugEventListenerConstants.ProtocolVersion + "\n" ) ); 111 socket.Send( encoding.GetBytes( "grammar \"" + grammarFileName + "\n" ) ); 112 Ack(); 113 114 //serverSocket = new ServerSocket( port ); 115 //socket = serverSocket.accept(); 116 //socket.setTcpNoDelay( true ); 117 //OutputStream os = socket.getOutputStream(); 118 //OutputStreamWriter osw = new OutputStreamWriter( os, "UTF8" ); 119 //@out = new PrintWriter( new BufferedWriter( osw ) ); 120 //InputStream @is = socket.getInputStream(); 121 //InputStreamReader isr = new InputStreamReader( @is, "UTF8" ); 122 //@in = new BufferedReader( isr ); 123 //@out.println( "ANTLR " + DebugEventListenerConstants.PROTOCOL_VERSION ); 124 //@out.println( "grammar \"" + grammarFileName ); 125 //@out.flush(); 126 //ack(); 127 } 128 } 129 130 public override void Commence() 131 { 132 // don't bother sending event; listener will trigger upon connection 133 } 134 135 public override void Terminate() 136 { 137 Transmit( "terminate" ); 138 //@out.close(); 139 try 140 { 141 socket.Close(); 142 } 143 catch ( IOException ioe ) 144 { 145 ExceptionExtensions.PrintStackTrace( ioe, Console.Error ); 146 } 147 } 148 149 protected virtual void Ack() 150 { 151 try 152 { 153 throw new NotImplementedException(); 154 //@in.readLine(); 155 } 156 catch ( IOException ioe ) 157 { 158 ExceptionExtensions.PrintStackTrace( ioe, Console.Error ); 159 } 160 } 161 162 protected virtual void Transmit( string @event ) 163 { 164 socket.Send( new System.Text.UTF8Encoding().GetBytes( @event + "\n" ) ); 165 //@out.println( @event ); 166 //@out.flush(); 167 Ack(); 168 } 169 170 public override void EnterRule( string grammarFileName, string ruleName ) 171 { 172 Transmit( "enterRule\t" + grammarFileName + "\t" + ruleName ); 173 } 174 175 public override void EnterAlt( int alt ) 176 { 177 Transmit( "enterAlt\t" + alt ); 178 } 179 180 public override void ExitRule( string grammarFileName, string ruleName ) 181 { 182 Transmit( "exitRule\t" + grammarFileName + "\t" + ruleName ); 183 } 184 185 public override void EnterSubRule( int decisionNumber ) 186 { 187 Transmit( "enterSubRule\t" + decisionNumber ); 188 } 189 190 public override void ExitSubRule( int decisionNumber ) 191 { 192 Transmit( "exitSubRule\t" + decisionNumber ); 193 } 194 195 public override void EnterDecision(int decisionNumber, bool couldBacktrack) 196 { 197 Transmit( "enterDecision\t" + decisionNumber ); 198 } 199 200 public override void ExitDecision( int decisionNumber ) 201 { 202 Transmit( "exitDecision\t" + decisionNumber ); 203 } 204 205 public override void ConsumeToken( IToken t ) 206 { 207 string buf = SerializeToken( t ); 208 Transmit( "consumeToken\t" + buf ); 209 } 210 211 public override void ConsumeHiddenToken( IToken t ) 212 { 213 string buf = SerializeToken( t ); 214 Transmit( "consumeHiddenToken\t" + buf ); 215 } 216 217 public override void LT( int i, IToken t ) 218 { 219 if ( t != null ) 220 Transmit( "LT\t" + i + "\t" + SerializeToken( t ) ); 221 } 222 223 public override void Mark( int i ) 224 { 225 Transmit( "mark\t" + i ); 226 } 227 228 public override void Rewind( int i ) 229 { 230 Transmit( "rewind\t" + i ); 231 } 232 233 public override void Rewind() 234 { 235 Transmit( "rewind" ); 236 } 237 238 public override void BeginBacktrack( int level ) 239 { 240 Transmit( "beginBacktrack\t" + level ); 241 } 242 243 public override void EndBacktrack( int level, bool successful ) 244 { 245 Transmit( "endBacktrack\t" + level + "\t" + ( successful ? DebugEventListenerConstants.True : DebugEventListenerConstants.False ) ); 246 } 247 248 public override void Location( int line, int pos ) 249 { 250 Transmit( "location\t" + line + "\t" + pos ); 251 } 252 253 public override void RecognitionException( RecognitionException e ) 254 { 255 StringBuilder buf = new StringBuilder( 50 ); 256 buf.Append( "exception\t" ); 257 buf.Append( e.GetType().Name ); 258 // dump only the data common to all exceptions for now 259 buf.Append( "\t" ); 260 buf.Append( e.Index ); 261 buf.Append( "\t" ); 262 buf.Append( e.Line ); 263 buf.Append( "\t" ); 264 buf.Append( e.CharPositionInLine ); 265 Transmit( buf.ToString() ); 266 } 267 268 public override void BeginResync() 269 { 270 Transmit( "beginResync" ); 271 } 272 273 public override void EndResync() 274 { 275 Transmit( "endResync" ); 276 } 277 278 public override void SemanticPredicate( bool result, string predicate ) 279 { 280 StringBuilder buf = new StringBuilder( 50 ); 281 buf.Append( "semanticPredicate\t" ); 282 buf.Append( result ); 283 SerializeText( buf, predicate ); 284 Transmit( buf.ToString() ); 285 } 286 287 #region AST Parsing Events 288 289 public override void ConsumeNode( object t ) 290 { 291 StringBuilder buf = new StringBuilder( 50 ); 292 buf.Append( "consumeNode" ); 293 SerializeNode( buf, t ); 294 Transmit( buf.ToString() ); 295 } 296 297 public override void LT( int i, object t ) 298 { 299 int ID = adaptor.GetUniqueID( t ); 300 string text = adaptor.GetText( t ); 301 int type = adaptor.GetType( t ); 302 StringBuilder buf = new StringBuilder( 50 ); 303 buf.Append( "LN\t" ); // lookahead node; distinguish from LT in protocol 304 buf.Append( i ); 305 SerializeNode( buf, t ); 306 Transmit( buf.ToString() ); 307 } 308 309 protected virtual void SerializeNode( StringBuilder buf, object t ) 310 { 311 int ID = adaptor.GetUniqueID( t ); 312 string text = adaptor.GetText( t ); 313 int type = adaptor.GetType( t ); 314 buf.Append( "\t" ); 315 buf.Append( ID ); 316 buf.Append( "\t" ); 317 buf.Append( type ); 318 IToken token = adaptor.GetToken( t ); 319 int line = -1; 320 int pos = -1; 321 if ( token != null ) 322 { 323 line = token.Line; 324 pos = token.CharPositionInLine; 325 } 326 buf.Append( "\t" ); 327 buf.Append( line ); 328 buf.Append( "\t" ); 329 buf.Append( pos ); 330 int tokenIndex = adaptor.GetTokenStartIndex( t ); 331 buf.Append( "\t" ); 332 buf.Append( tokenIndex ); 333 SerializeText( buf, text ); 334 } 335 336 #endregion 337 338 339 #region AST Events 340 341 public override void NilNode( object t ) 342 { 343 int ID = adaptor.GetUniqueID( t ); 344 Transmit( "nilNode\t" + ID ); 345 } 346 347 public override void ErrorNode( object t ) 348 { 349 int ID = adaptor.GetUniqueID( t ); 350 string text = t.ToString(); 351 StringBuilder buf = new StringBuilder( 50 ); 352 buf.Append( "errorNode\t" ); 353 buf.Append( ID ); 354 buf.Append( "\t" ); 355 buf.Append( TokenTypes.Invalid ); 356 SerializeText( buf, text ); 357 Transmit( buf.ToString() ); 358 } 359 360 public override void CreateNode( object t ) 361 { 362 int ID = adaptor.GetUniqueID( t ); 363 string text = adaptor.GetText( t ); 364 int type = adaptor.GetType( t ); 365 StringBuilder buf = new StringBuilder( 50 ); 366 buf.Append( "createNodeFromTokenElements\t" ); 367 buf.Append( ID ); 368 buf.Append( "\t" ); 369 buf.Append( type ); 370 SerializeText( buf, text ); 371 Transmit( buf.ToString() ); 372 } 373 374 public override void CreateNode( object node, IToken token ) 375 { 376 int ID = adaptor.GetUniqueID( node ); 377 int tokenIndex = token.TokenIndex; 378 Transmit( "createNode\t" + ID + "\t" + tokenIndex ); 379 } 380 381 public override void BecomeRoot( object newRoot, object oldRoot ) 382 { 383 int newRootID = adaptor.GetUniqueID( newRoot ); 384 int oldRootID = adaptor.GetUniqueID( oldRoot ); 385 Transmit( "becomeRoot\t" + newRootID + "\t" + oldRootID ); 386 } 387 388 public override void AddChild( object root, object child ) 389 { 390 int rootID = adaptor.GetUniqueID( root ); 391 int childID = adaptor.GetUniqueID( child ); 392 Transmit( "addChild\t" + rootID + "\t" + childID ); 393 } 394 395 public override void SetTokenBoundaries( object t, int tokenStartIndex, int tokenStopIndex ) 396 { 397 int ID = adaptor.GetUniqueID( t ); 398 Transmit( "setTokenBoundaries\t" + ID + "\t" + tokenStartIndex + "\t" + tokenStopIndex ); 399 } 400 401 #endregion 402 403 404 #region Support 405 406 protected virtual string SerializeToken( IToken t ) 407 { 408 StringBuilder buf = new StringBuilder( 50 ); 409 buf.Append( t.TokenIndex ); 410 buf.Append( '\t' ); 411 buf.Append( t.Type ); 412 buf.Append( '\t' ); 413 buf.Append( t.Channel ); 414 buf.Append( '\t' ); 415 buf.Append( t.Line ); 416 buf.Append( '\t' ); 417 buf.Append( t.CharPositionInLine ); 418 SerializeText( buf, t.Text ); 419 return buf.ToString(); 420 } 421 422 protected virtual void SerializeText( StringBuilder buf, string text ) 423 { 424 buf.Append( "\t\"" ); 425 if ( text == null ) 426 { 427 text = ""; 428 } 429 // escape \n and \r all text for token appears to exist on one line 430 // this escape is slow but easy to understand 431 text = EscapeNewlines( text ); 432 buf.Append( text ); 433 } 434 435 protected virtual string EscapeNewlines( string txt ) 436 { 437 txt = txt.Replace( "%", "%25" ); // escape all escape char ;) 438 txt = txt.Replace( "\n", "%0A" ); // escape \n 439 txt = txt.Replace( "\r", "%0D" ); // escape \r 440 return txt; 441 } 442 443 #endregion 444 } 445} 446