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 Antlr.Runtime.JavaExtensions; 36 37 using Array = System.Array; 38 using BaseTree = Antlr.Runtime.Tree.BaseTree; 39 using Console = System.Console; 40 using Exception = System.Exception; 41 using IOException = System.IO.IOException; 42 using ITree = Antlr.Runtime.Tree.ITree; 43 using Math = System.Math; 44 using Socket = System.Net.Sockets.Socket; 45 using SocketException = System.Net.Sockets.SocketException; 46 using TextReader = System.IO.TextReader; 47 using TextWriter = System.IO.TextWriter; 48 49 public class RemoteDebugEventSocketListener 50 { 51 const int MAX_EVENT_ELEMENTS = 8; 52 IDebugEventListener listener; 53 string machine; 54 int port; 55 Socket channel = null; 56 TextWriter @out; 57 TextReader @in; 58 string @event; 59 /** <summary>Version of ANTLR (dictates events)</summary> */ 60 public string version; 61 public string grammarFileName; 62 /** <summary> 63 * Track the last token index we saw during a consume. If same, then 64 * set a flag that we have a problem. 65 * </summary> 66 */ 67 int previousTokenIndex = -1; 68 bool tokenIndexesInvalid = false; 69 70 public class ProxyToken : IToken 71 { 72 int index; 73 int type; 74 int channel; 75 int line; 76 int charPos; 77 string text; 78 public ProxyToken( int index ) 79 { 80 this.index = index; 81 } 82 public ProxyToken( int index, int type, int channel, 83 int line, int charPos, string text ) 84 { 85 this.index = index; 86 this.type = type; 87 this.channel = channel; 88 this.line = line; 89 this.charPos = charPos; 90 this.text = text; 91 } 92 93 #region IToken Members 94 public string Text 95 { 96 get 97 { 98 return text; 99 } 100 set 101 { 102 text = value; 103 } 104 } 105 106 public int Type 107 { 108 get 109 { 110 return type; 111 } 112 set 113 { 114 type = value; 115 } 116 } 117 118 public int Line 119 { 120 get 121 { 122 return line; 123 } 124 set 125 { 126 line = value; 127 } 128 } 129 130 public int CharPositionInLine 131 { 132 get 133 { 134 return charPos; 135 } 136 set 137 { 138 charPos = value; 139 } 140 } 141 142 public int Channel 143 { 144 get 145 { 146 return channel; 147 } 148 set 149 { 150 channel = value; 151 } 152 } 153 154 public int StartIndex 155 { 156 get 157 { 158 return -1; 159 } 160 set 161 { 162 } 163 } 164 165 public int StopIndex 166 { 167 get 168 { 169 return -1; 170 } 171 set 172 { 173 } 174 } 175 176 public int TokenIndex 177 { 178 get 179 { 180 return index; 181 } 182 set 183 { 184 index = value; 185 } 186 } 187 188 public ICharStream InputStream 189 { 190 get 191 { 192 return null; 193 } 194 set 195 { 196 } 197 } 198 199 #endregion 200 201 public override string ToString() 202 { 203 string channelStr = ""; 204 if ( channel != TokenChannels.Default ) 205 { 206 channelStr = ",channel=" + channel; 207 } 208 return "[" + Text + "/<" + type + ">" + channelStr + "," + line + ":" + CharPositionInLine + ",@" + index + "]"; 209 } 210 } 211 212 public class ProxyTree : BaseTree 213 { 214 public int ID; 215 int type; 216 int line = 0; 217 public int charPos = -1; 218 public int tokenIndex = -1; 219 string text; 220 221 public ProxyTree( int ID, int type, int line, int charPos, int tokenIndex, string text ) 222 { 223 this.ID = ID; 224 this.type = type; 225 this.line = line; 226 this.charPos = charPos; 227 this.tokenIndex = tokenIndex; 228 this.text = text; 229 } 230 231 public ProxyTree( int ID ) 232 { 233 this.ID = ID; 234 } 235 236 #region Properties 237 public override string Text 238 { 239 get 240 { 241 return text; 242 } 243 set 244 { 245 } 246 } 247 public override int TokenStartIndex 248 { 249 get 250 { 251 return tokenIndex; 252 } 253 set 254 { 255 } 256 } 257 public override int TokenStopIndex 258 { 259 get 260 { 261 return 0; 262 } 263 set 264 { 265 } 266 } 267 public override int Type 268 { 269 get 270 { 271 return type; 272 } 273 set 274 { 275 } 276 } 277 #endregion 278 279 public override ITree DupNode() 280 { 281 return null; 282 } 283 284 public override string ToString() 285 { 286 return "fix this"; 287 } 288 } 289 290 public RemoteDebugEventSocketListener( IDebugEventListener listener, 291 string machine, 292 int port ) 293 { 294 this.listener = listener; 295 this.machine = machine; 296 this.port = port; 297 298 if ( !OpenConnection() ) 299 { 300 throw new SocketException(); 301 } 302 } 303 304 protected virtual void EventHandler() 305 { 306 try 307 { 308 Handshake(); 309 @event = @in.ReadLine(); 310 while ( @event != null ) 311 { 312 Dispatch( @event ); 313 Ack(); 314 @event = @in.ReadLine(); 315 } 316 } 317 catch ( Exception e ) 318 { 319 Console.Error.WriteLine( e ); 320 ExceptionExtensions.PrintStackTrace( e, Console.Error ); 321 } 322 finally 323 { 324 CloseConnection(); 325 } 326 } 327 328 protected virtual bool OpenConnection() 329 { 330 bool success = false; 331 try 332 { 333 throw new System.NotImplementedException(); 334 //channel = new Socket( machine, port ); 335 //channel.setTcpNoDelay( true ); 336 //OutputStream os = channel.getOutputStream(); 337 //OutputStreamWriter osw = new OutputStreamWriter( os, "UTF8" ); 338 //@out = new PrintWriter( new BufferedWriter( osw ) ); 339 //InputStream @is = channel.getInputStream(); 340 //InputStreamReader isr = new InputStreamReader( @is, "UTF8" ); 341 //@in = new BufferedReader( isr ); 342 //success = true; 343 } 344 catch ( Exception e ) 345 { 346 Console.Error.WriteLine( e ); 347 } 348 return success; 349 } 350 351 protected virtual void CloseConnection() 352 { 353 try 354 { 355 @in.Close(); 356 @in = null; 357 @out.Close(); 358 @out = null; 359 channel.Close(); 360 channel = null; 361 } 362 catch ( Exception e ) 363 { 364 Console.Error.WriteLine( e ); 365 ExceptionExtensions.PrintStackTrace( e, Console.Error ); 366 } 367 finally 368 { 369 if ( @in != null ) 370 { 371 try 372 { 373 @in.Close(); 374 } 375 catch ( IOException ioe ) 376 { 377 Console.Error.WriteLine( ioe ); 378 } 379 } 380 if ( @out != null ) 381 { 382 @out.Close(); 383 } 384 if ( channel != null ) 385 { 386 try 387 { 388 channel.Close(); 389 } 390 catch ( IOException ioe ) 391 { 392 Console.Error.WriteLine( ioe ); 393 } 394 } 395 } 396 397 } 398 399 protected virtual void Handshake() 400 { 401 string antlrLine = @in.ReadLine(); 402 string[] antlrElements = GetEventElements( antlrLine ); 403 version = antlrElements[1]; 404 string grammarLine = @in.ReadLine(); 405 string[] grammarElements = GetEventElements( grammarLine ); 406 grammarFileName = grammarElements[1]; 407 Ack(); 408 listener.Commence(); // inform listener after handshake 409 } 410 411 protected virtual void Ack() 412 { 413 @out.WriteLine( "ack" ); 414 @out.Flush(); 415 } 416 417 protected virtual void Dispatch( string line ) 418 { 419 //JSystem.@out.println( "event: " + line ); 420 string[] elements = GetEventElements( line ); 421 if ( elements == null || elements[0] == null ) 422 { 423 Console.Error.WriteLine( "unknown debug event: " + line ); 424 return; 425 } 426 if ( elements[0].Equals( "enterRule" ) ) 427 { 428 listener.EnterRule( elements[1], elements[2] ); 429 } 430 else if ( elements[0].Equals( "exitRule" ) ) 431 { 432 listener.ExitRule( elements[1], elements[2] ); 433 } 434 else if ( elements[0].Equals( "enterAlt" ) ) 435 { 436 listener.EnterAlt( int.Parse( elements[1] ) ); 437 } 438 else if ( elements[0].Equals( "enterSubRule" ) ) 439 { 440 listener.EnterSubRule( int.Parse( elements[1] ) ); 441 } 442 else if ( elements[0].Equals( "exitSubRule" ) ) 443 { 444 listener.ExitSubRule( int.Parse( elements[1] ) ); 445 } 446 else if ( elements[0].Equals( "enterDecision" ) ) 447 { 448 listener.EnterDecision(int.Parse(elements[1]), elements[2].Equals("true")); 449 } 450 else if ( elements[0].Equals( "exitDecision" ) ) 451 { 452 listener.ExitDecision( int.Parse( elements[1] ) ); 453 } 454 else if ( elements[0].Equals( "location" ) ) 455 { 456 listener.Location( int.Parse( elements[1] ), 457 int.Parse( elements[2] ) ); 458 } 459 else if ( elements[0].Equals( "consumeToken" ) ) 460 { 461 ProxyToken t = DeserializeToken( elements, 1 ); 462 if ( t.TokenIndex == previousTokenIndex ) 463 { 464 tokenIndexesInvalid = true; 465 } 466 previousTokenIndex = t.TokenIndex; 467 listener.ConsumeToken( t ); 468 } 469 else if ( elements[0].Equals( "consumeHiddenToken" ) ) 470 { 471 ProxyToken t = DeserializeToken( elements, 1 ); 472 if ( t.TokenIndex == previousTokenIndex ) 473 { 474 tokenIndexesInvalid = true; 475 } 476 previousTokenIndex = t.TokenIndex; 477 listener.ConsumeHiddenToken( t ); 478 } 479 else if ( elements[0].Equals( "LT" ) ) 480 { 481 IToken t = DeserializeToken( elements, 2 ); 482 listener.LT( int.Parse( elements[1] ), t ); 483 } 484 else if ( elements[0].Equals( "mark" ) ) 485 { 486 listener.Mark( int.Parse( elements[1] ) ); 487 } 488 else if ( elements[0].Equals( "rewind" ) ) 489 { 490 if ( elements[1] != null ) 491 { 492 listener.Rewind( int.Parse( elements[1] ) ); 493 } 494 else 495 { 496 listener.Rewind(); 497 } 498 } 499 else if ( elements[0].Equals( "beginBacktrack" ) ) 500 { 501 listener.BeginBacktrack( int.Parse( elements[1] ) ); 502 } 503 else if ( elements[0].Equals( "endBacktrack" ) ) 504 { 505 int level = int.Parse( elements[1] ); 506 int successI = int.Parse( elements[2] ); 507 listener.EndBacktrack( level, successI == DebugEventListenerConstants.True ); 508 } 509 else if ( elements[0].Equals( "exception" ) ) 510 { 511#if true 512 throw new System.NotImplementedException(); 513#else 514 string excName = elements[1]; 515 string indexS = elements[2]; 516 string lineS = elements[3]; 517 string posS = elements[4]; 518 Class excClass = null; 519 try 520 { 521 excClass = Class.forName( excName ); 522 RecognitionException e = 523 (RecognitionException)excClass.newInstance(); 524 e.index = int.Parse( indexS ); 525 e.line = int.Parse( lineS ); 526 e.charPositionInLine = int.Parse( posS ); 527 listener.recognitionException( e ); 528 } 529 catch ( ClassNotFoundException cnfe ) 530 { 531 Console.Error.println( "can't find class " + cnfe ); 532 cnfe.printStackTrace( Console.Error ); 533 } 534 catch ( InstantiationException ie ) 535 { 536 Console.Error.println( "can't instantiate class " + ie ); 537 ie.printStackTrace( Console.Error ); 538 } 539 catch ( IllegalAccessException iae ) 540 { 541 Console.Error.println( "can't access class " + iae ); 542 iae.printStackTrace( Console.Error ); 543 } 544#endif 545 } 546 else if ( elements[0].Equals( "beginResync" ) ) 547 { 548 listener.BeginResync(); 549 } 550 else if ( elements[0].Equals( "endResync" ) ) 551 { 552 listener.EndResync(); 553 } 554 else if ( elements[0].Equals( "terminate" ) ) 555 { 556 listener.Terminate(); 557 } 558 else if ( elements[0].Equals( "semanticPredicate" ) ) 559 { 560 bool result = bool.Parse( elements[1] ); 561 string predicateText = elements[2]; 562 predicateText = UnEscapeNewlines( predicateText ); 563 listener.SemanticPredicate( result, 564 predicateText ); 565 } 566 else if ( elements[0].Equals( "consumeNode" ) ) 567 { 568 ProxyTree node = DeserializeNode( elements, 1 ); 569 listener.ConsumeNode( node ); 570 } 571 else if ( elements[0].Equals( "LN" ) ) 572 { 573 int i = int.Parse( elements[1] ); 574 ProxyTree node = DeserializeNode( elements, 2 ); 575 listener.LT( i, node ); 576 } 577 else if ( elements[0].Equals( "createNodeFromTokenElements" ) ) 578 { 579 int ID = int.Parse( elements[1] ); 580 int type = int.Parse( elements[2] ); 581 string text = elements[3]; 582 text = UnEscapeNewlines( text ); 583 ProxyTree node = new ProxyTree( ID, type, -1, -1, -1, text ); 584 listener.CreateNode( node ); 585 } 586 else if ( elements[0].Equals( "createNode" ) ) 587 { 588 int ID = int.Parse( elements[1] ); 589 int tokenIndex = int.Parse( elements[2] ); 590 // create dummy node/token filled with ID, tokenIndex 591 ProxyTree node = new ProxyTree( ID ); 592 ProxyToken token = new ProxyToken( tokenIndex ); 593 listener.CreateNode( node, token ); 594 } 595 else if ( elements[0].Equals( "nilNode" ) ) 596 { 597 int ID = int.Parse( elements[1] ); 598 ProxyTree node = new ProxyTree( ID ); 599 listener.NilNode( node ); 600 } 601 else if ( elements[0].Equals( "errorNode" ) ) 602 { 603 // TODO: do we need a special tree here? 604 int ID = int.Parse( elements[1] ); 605 int type = int.Parse( elements[2] ); 606 string text = elements[3]; 607 text = UnEscapeNewlines( text ); 608 ProxyTree node = new ProxyTree( ID, type, -1, -1, -1, text ); 609 listener.ErrorNode( node ); 610 } 611 else if ( elements[0].Equals( "becomeRoot" ) ) 612 { 613 int newRootID = int.Parse( elements[1] ); 614 int oldRootID = int.Parse( elements[2] ); 615 ProxyTree newRoot = new ProxyTree( newRootID ); 616 ProxyTree oldRoot = new ProxyTree( oldRootID ); 617 listener.BecomeRoot( newRoot, oldRoot ); 618 } 619 else if ( elements[0].Equals( "addChild" ) ) 620 { 621 int rootID = int.Parse( elements[1] ); 622 int childID = int.Parse( elements[2] ); 623 ProxyTree root = new ProxyTree( rootID ); 624 ProxyTree child = new ProxyTree( childID ); 625 listener.AddChild( root, child ); 626 } 627 else if ( elements[0].Equals( "setTokenBoundaries" ) ) 628 { 629 int ID = int.Parse( elements[1] ); 630 ProxyTree node = new ProxyTree( ID ); 631 listener.SetTokenBoundaries( 632 node, 633 int.Parse( elements[2] ), 634 int.Parse( elements[3] ) ); 635 } 636 else 637 { 638 Console.Error.WriteLine( "unknown debug event: " + line ); 639 } 640 } 641 642 protected virtual ProxyTree DeserializeNode( string[] elements, int offset ) 643 { 644 int ID = int.Parse( elements[offset + 0] ); 645 int type = int.Parse( elements[offset + 1] ); 646 int tokenLine = int.Parse( elements[offset + 2] ); 647 int charPositionInLine = int.Parse( elements[offset + 3] ); 648 int tokenIndex = int.Parse( elements[offset + 4] ); 649 string text = elements[offset + 5]; 650 text = UnEscapeNewlines( text ); 651 return new ProxyTree( ID, type, tokenLine, charPositionInLine, tokenIndex, text ); 652 } 653 654 protected virtual ProxyToken DeserializeToken( string[] elements, 655 int offset ) 656 { 657 string indexS = elements[offset + 0]; 658 string typeS = elements[offset + 1]; 659 string channelS = elements[offset + 2]; 660 string lineS = elements[offset + 3]; 661 string posS = elements[offset + 4]; 662 string text = elements[offset + 5]; 663 text = UnEscapeNewlines( text ); 664 int index = int.Parse( indexS ); 665 ProxyToken t = 666 new ProxyToken( index, 667 int.Parse( typeS ), 668 int.Parse( channelS ), 669 int.Parse( lineS ), 670 int.Parse( posS ), 671 text ); 672 return t; 673 } 674 675 /** <summary>Create a thread to listen to the remote running recognizer</summary> */ 676 public virtual void Start() 677 { 678 System.Threading.Thread t = new System.Threading.Thread( Run ); 679 t.Start(); 680 } 681 682 public virtual void Run() 683 { 684 EventHandler(); 685 } 686 687 #region Misc 688 689 public virtual string[] GetEventElements( string @event ) 690 { 691 if ( @event == null ) 692 { 693 return null; 694 } 695 string[] elements = new string[MAX_EVENT_ELEMENTS]; 696 string str = null; // a string element if present (must be last) 697 try 698 { 699 int firstQuoteIndex = @event.IndexOf( '"' ); 700 if ( firstQuoteIndex >= 0 ) 701 { 702 // treat specially; has a string argument like "a comment\n 703 // Note that the string is terminated by \n not end quote. 704 // Easier to parse that way. 705 string eventWithoutString = @event.Substring( 0, firstQuoteIndex ); 706 str = @event.Substring( firstQuoteIndex + 1 ); 707 @event = eventWithoutString; 708 } 709 710 string[] tokens = @event.Split('\t'); 711 Array.Copy(tokens, elements, Math.Min(tokens.Length, MAX_EVENT_ELEMENTS)); 712 if (tokens.Length >= MAX_EVENT_ELEMENTS) 713 return elements; 714 715 if ( str != null ) 716 { 717 elements[tokens.Length] = str; 718 } 719 } 720 catch ( Exception e ) 721 { 722 ExceptionExtensions.PrintStackTrace( e, Console.Error ); 723 } 724 return elements; 725 } 726 727 protected virtual string UnEscapeNewlines( string txt ) 728 { 729 // this unescape is slow but easy to understand 730 txt = txt.Replace( "%0A", "\n" ); // unescape \n 731 txt = txt.Replace( "%0D", "\r" ); // unescape \r 732 txt = txt.Replace( "%25", "%" ); // undo escaped escape chars 733 return txt; 734 } 735 736 public virtual bool TokenIndexesAreInvalid() 737 { 738 return tokenIndexesInvalid; 739 } 740 741 #endregion 742 743 } 744} 745