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