| /// \file |
| /// Provides the debugging functions invoked by a recognizer |
| /// built using the debug generator mode of the antlr tool. |
| /// See antlr3debugeventlistener.h for documentation. |
| /// |
| |
| // [The "BSD licence"] |
| // Copyright (c) 2005-2009 Jim Idle, Temporal Wave LLC |
| // http://www.temporal-wave.com |
| // http://www.linkedin.com/in/jimidle |
| // |
| // 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. |
| |
| #include <antlr3.h> |
| |
| // Not everyone wishes to include the debugger stuff in their final deployment because |
| // it will then rely on being linked with the socket libraries. Hence if the programmer turns |
| // off the debugging, we do some dummy stuff that satifies compilers etc but means there is |
| // no debugger and no reliance on the socket librarires. If you set this flag, then using the -debug |
| // option to generate your code will produce code that just crashes, but then I presme you are smart |
| // enough to realize that building the libraries without debugger support means you can't call the |
| // debugger ;-) |
| // |
| #ifdef ANTLR3_NODEBUGGER |
| ANTLR3_API pANTLR3_DEBUG_EVENT_LISTENER |
| antlr3DebugListenerNew() |
| { |
| ANTLR3_PRINTF("C runtime was compiled without debugger support. This program will crash!!"); |
| return NULL; |
| } |
| #else |
| |
| static ANTLR3_BOOLEAN handshake (pANTLR3_DEBUG_EVENT_LISTENER delboy); |
| static void enterRule (pANTLR3_DEBUG_EVENT_LISTENER delboy, const char * grammarFileName, const char * ruleName); |
| static void enterAlt (pANTLR3_DEBUG_EVENT_LISTENER delboy, int alt); |
| static void exitRule (pANTLR3_DEBUG_EVENT_LISTENER delboy, const char * grammarFileName, const char * ruleName); |
| static void enterSubRule (pANTLR3_DEBUG_EVENT_LISTENER delboy, int decisionNumber); |
| static void exitSubRule (pANTLR3_DEBUG_EVENT_LISTENER delboy, int decisionNumber); |
| static void enterDecision (pANTLR3_DEBUG_EVENT_LISTENER delboy, int decisionNumber); |
| static void exitDecision (pANTLR3_DEBUG_EVENT_LISTENER delboy, int decisionNumber); |
| static void consumeToken (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_COMMON_TOKEN t); |
| static void consumeHiddenToken (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_COMMON_TOKEN t); |
| static void LT (pANTLR3_DEBUG_EVENT_LISTENER delboy, int i, pANTLR3_COMMON_TOKEN t); |
| static void mark (pANTLR3_DEBUG_EVENT_LISTENER delboy, ANTLR3_MARKER marker); |
| static void rewindMark (pANTLR3_DEBUG_EVENT_LISTENER delboy, ANTLR3_MARKER marker); |
| static void rewindLast (pANTLR3_DEBUG_EVENT_LISTENER delboy); |
| static void beginBacktrack (pANTLR3_DEBUG_EVENT_LISTENER delboy, int level); |
| static void endBacktrack (pANTLR3_DEBUG_EVENT_LISTENER delboy, int level, ANTLR3_BOOLEAN successful); |
| static void location (pANTLR3_DEBUG_EVENT_LISTENER delboy, int line, int pos); |
| static void recognitionException (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_EXCEPTION e); |
| static void beginResync (pANTLR3_DEBUG_EVENT_LISTENER delboy); |
| static void endResync (pANTLR3_DEBUG_EVENT_LISTENER delboy); |
| static void semanticPredicate (pANTLR3_DEBUG_EVENT_LISTENER delboy, ANTLR3_BOOLEAN result, const char * predicate); |
| static void commence (pANTLR3_DEBUG_EVENT_LISTENER delboy); |
| static void terminate (pANTLR3_DEBUG_EVENT_LISTENER delboy); |
| static void consumeNode (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE t); |
| static void LTT (pANTLR3_DEBUG_EVENT_LISTENER delboy, int i, pANTLR3_BASE_TREE t); |
| static void nilNode (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE t); |
| static void errorNode (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE t); |
| static void createNode (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE t); |
| static void createNodeTok (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE node, pANTLR3_COMMON_TOKEN token); |
| static void becomeRoot (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE newRoot, pANTLR3_BASE_TREE oldRoot); |
| static void addChild (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE root, pANTLR3_BASE_TREE child); |
| static void setTokenBoundaries (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE t, ANTLR3_MARKER tokenStartIndex, ANTLR3_MARKER tokenStopIndex); |
| static void ack (pANTLR3_DEBUG_EVENT_LISTENER delboy); |
| |
| /// Create and initialize a new debug event listener that can be connected to |
| /// by ANTLRWorks and any other debugger via a socket. |
| /// |
| ANTLR3_API pANTLR3_DEBUG_EVENT_LISTENER |
| antlr3DebugListenerNew() |
| { |
| pANTLR3_DEBUG_EVENT_LISTENER delboy; |
| |
| delboy = (pANTLR3_DEBUG_EVENT_LISTENER)ANTLR3_CALLOC(1, sizeof(ANTLR3_DEBUG_EVENT_LISTENER)); |
| |
| if (delboy == NULL) |
| { |
| return NULL; |
| } |
| |
| // Initialize the API |
| // |
| delboy->addChild = addChild; |
| delboy->becomeRoot = becomeRoot; |
| delboy->beginBacktrack = beginBacktrack; |
| delboy->beginResync = beginResync; |
| delboy->commence = commence; |
| delboy->consumeHiddenToken = consumeHiddenToken; |
| delboy->consumeNode = consumeNode; |
| delboy->consumeToken = consumeToken; |
| delboy->createNode = createNode; |
| delboy->createNodeTok = createNodeTok; |
| delboy->endBacktrack = endBacktrack; |
| delboy->endResync = endResync; |
| delboy->enterAlt = enterAlt; |
| delboy->enterDecision = enterDecision; |
| delboy->enterRule = enterRule; |
| delboy->enterSubRule = enterSubRule; |
| delboy->exitDecision = exitDecision; |
| delboy->exitRule = exitRule; |
| delboy->exitSubRule = exitSubRule; |
| delboy->handshake = handshake; |
| delboy->location = location; |
| delboy->LT = LT; |
| delboy->LTT = LTT; |
| delboy->mark = mark; |
| delboy->nilNode = nilNode; |
| delboy->recognitionException = recognitionException; |
| delboy->rewind = rewindMark; |
| delboy->rewindLast = rewindLast; |
| delboy->semanticPredicate = semanticPredicate; |
| delboy->setTokenBoundaries = setTokenBoundaries; |
| delboy->terminate = terminate; |
| delboy->errorNode = errorNode; |
| |
| delboy->protocol_version = 2; // ANTLR 3.1 is at protocol version 2 |
| |
| delboy->port = DEFAULT_DEBUGGER_PORT; |
| |
| return delboy; |
| } |
| |
| pANTLR3_DEBUG_EVENT_LISTENER |
| antlr3DebugListenerNewPort(ANTLR3_UINT32 port) |
| { |
| pANTLR3_DEBUG_EVENT_LISTENER delboy; |
| |
| delboy = antlr3DebugListenerNew(); |
| |
| if (delboy != NULL) |
| { |
| delboy->port = port; |
| } |
| |
| return delboy; |
| } |
| |
| //-------------------------------------------------------------------------------- |
| // Support functions for sending stuff over the socket interface |
| // |
| static int |
| sockSend(SOCKET sock, const char * ptr, int len) |
| { |
| int sent; |
| int thisSend; |
| |
| sent = 0; |
| |
| while (sent < len) |
| { |
| // Send as many bytes as we can |
| // |
| thisSend = send(sock, ptr, len - sent, 0); |
| |
| // Check for errors and tell the user if we got one |
| // |
| if (thisSend == -1) |
| { |
| return ANTLR3_FALSE; |
| } |
| |
| // Increment our offset by how many we were able to send |
| // |
| ptr += thisSend; |
| sent += thisSend; |
| } |
| return ANTLR3_TRUE; |
| } |
| |
| static ANTLR3_BOOLEAN |
| handshake (pANTLR3_DEBUG_EVENT_LISTENER delboy) |
| { |
| /// Connection structure with which to wait and accept a connection from |
| /// a debugger. |
| /// |
| SOCKET serverSocket; |
| |
| // Connection structures to deal with the client after we accept the connection |
| // and the server while we accept a connection. |
| // |
| ANTLR3_SOCKADDRT client; |
| ANTLR3_SOCKADDRT server; |
| |
| // Buffer to construct our message in |
| // |
| char message[256]; |
| |
| // Specifies the length of the connection structure to accept() |
| // Windows use int, everyone else uses size_t |
| // |
| ANTLR3_SALENT sockaddr_len; |
| |
| // Option holder for setsockopt() |
| // |
| int optVal; |
| |
| if (delboy->initialized == ANTLR3_FALSE) |
| { |
| // Windows requires us to initialize WinSock. |
| // |
| #ifdef ANTLR3_WINDOWS |
| { |
| WORD wVersionRequested; |
| WSADATA wsaData; |
| int err; // Return code from WSAStartup |
| |
| // We must initialise the Windows socket system when the DLL is loaded. |
| // We are asking for Winsock 1.1 or better as we don't need anything |
| // too complicated for this. |
| // |
| wVersionRequested = MAKEWORD( 1, 1); |
| |
| err = WSAStartup( wVersionRequested, &wsaData ); |
| |
| if ( err != 0 ) |
| { |
| // Tell the user that we could not find a usable |
| // WinSock DLL |
| // |
| return FALSE; |
| } |
| } |
| #endif |
| |
| // Create the server socket, we are the server because we just wait until |
| // a debugger connects to the port we are listening on. |
| // |
| serverSocket = socket(AF_INET, SOCK_STREAM, 0); |
| |
| if (serverSocket == INVALID_SOCKET) |
| { |
| return ANTLR3_FALSE; |
| } |
| |
| // Set the listening port |
| // |
| server.sin_port = htons((unsigned short)delboy->port); |
| server.sin_family = AF_INET; |
| server.sin_addr.s_addr = htonl (INADDR_ANY); |
| |
| // We could allow a rebind on the same addr/port pair I suppose, but |
| // I imagine that most people will just want to start debugging one parser at once. |
| // Maybe change this at some point, but rejecting the bind at this point will ensure |
| // that people realize they have left something running in the background. |
| // |
| if (bind(serverSocket, (pANTLR3_SOCKADDRC)&server, sizeof(server)) == -1) |
| { |
| return ANTLR3_FALSE; |
| } |
| |
| // We have bound the socket to the port and address so we now ask the TCP subsystem |
| // to start listening on that address/port |
| // |
| if (listen(serverSocket, 1) == -1) |
| { |
| // Some error, just fail |
| // |
| return ANTLR3_FALSE; |
| } |
| |
| // Now we can try to accept a connection on the port |
| // |
| sockaddr_len = sizeof(client); |
| delboy->socket = accept(serverSocket, (pANTLR3_SOCKADDRC)&client, &sockaddr_len); |
| |
| // Having accepted a connection, we can stop listening and close down the socket |
| // |
| shutdown (serverSocket, 0x02); |
| ANTLR3_CLOSESOCKET (serverSocket); |
| |
| if (delboy->socket == -1) |
| { |
| return ANTLR3_FALSE; |
| } |
| |
| // Disable Nagle as this is essentially a chat exchange |
| // |
| optVal = 1; |
| setsockopt(delboy->socket, SOL_SOCKET, TCP_NODELAY, (const char *)&optVal, sizeof(optVal)); |
| |
| } |
| |
| // We now have a good socket connection with the debugging client, so we |
| // send it the protocol version we are using and what the name of the grammar |
| // is that we represent. |
| // |
| sprintf (message, "ANTLR %d\n", delboy->protocol_version); |
| sockSend (delboy->socket, message, (int)strlen(message)); |
| sprintf (message, "grammar \"%s\n", delboy->grammarFileName->chars); |
| sockSend (delboy->socket, message, (int)strlen(message)); |
| ack (delboy); |
| |
| delboy->initialized = ANTLR3_TRUE; |
| |
| return ANTLR3_TRUE; |
| } |
| |
| // Send the supplied text and wait for an ack from the client |
| static void |
| transmit(pANTLR3_DEBUG_EVENT_LISTENER delboy, const char * ptr) |
| { |
| sockSend(delboy->socket, ptr, (int)strlen(ptr)); |
| ack(delboy); |
| } |
| |
| static void |
| ack (pANTLR3_DEBUG_EVENT_LISTENER delboy) |
| { |
| // Local buffer to read the next character in to |
| // |
| char buffer; |
| int rCount; |
| |
| // Ack terminates in a line feed, so we just wait for |
| // one of those. Speed is not of the essence so we don't need |
| // to buffer the input or anything. |
| // |
| do |
| { |
| rCount = recv(delboy->socket, &buffer, 1, 0); |
| } |
| while (rCount == 1 && buffer != '\n'); |
| |
| // If the socket ws closed on us, then we will get an error or |
| // (with a graceful close), 0. We can assume the the debugger stopped for some reason |
| // (such as Java crashing again). Therefore we just exit the program |
| // completely if we don't get the terminating '\n' for the ack. |
| // |
| if (rCount != 1) |
| { |
| ANTLR3_PRINTF("Exiting debugger as remote client closed the socket\n"); |
| ANTLR3_PRINTF("Received char count was %d, and last char received was %02X\n", rCount, buffer); |
| exit(0); |
| } |
| } |
| |
| // Given a buffer string and a source string, serialize the |
| // text, escaping any newlines and linefeeds. We have no need |
| // for speed here, this is the debugger. |
| // |
| void |
| serializeText(pANTLR3_STRING buffer, pANTLR3_STRING text) |
| { |
| ANTLR3_UINT32 c; |
| ANTLR3_UCHAR character; |
| |
| // strings lead in with a " |
| // |
| buffer->append(buffer, "\t\""); |
| |
| if (text == NULL) |
| { |
| return; |
| } |
| |
| // Now we replace linefeeds, newlines and the escape |
| // leadin character '%' with their hex equivalents |
| // prefixed by '%' |
| // |
| for (c = 0; c < text->len; c++) |
| { |
| switch (character = text->charAt(text, c)) |
| { |
| case '\n': |
| |
| buffer->append(buffer, "%0A"); |
| break; |
| |
| case '\r': |
| |
| buffer->append(buffer, "%0D"); |
| break; |
| |
| case '\\': |
| |
| buffer->append(buffer, "%25"); |
| break; |
| |
| // Other characters: The Song Remains the Same. |
| // |
| default: |
| |
| buffer->addc(buffer, character); |
| break; |
| } |
| } |
| } |
| |
| // Given a token, create a stringified version of it, in the supplied |
| // buffer. We create a string for this in the debug 'object', if there |
| // is not one there already, and then reuse it here if asked to do this |
| // again. |
| // |
| pANTLR3_STRING |
| serializeToken(pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_COMMON_TOKEN t) |
| { |
| // Do we already have a serialization buffer? |
| // |
| if (delboy->tokenString == NULL) |
| { |
| // No, so create one, using the string factory that |
| // the grammar name used, which is guaranteed to exist. |
| // 64 bytes will do us here for starters. |
| // |
| delboy->tokenString = delboy->grammarFileName->factory->newSize(delboy->grammarFileName->factory, 64); |
| } |
| |
| // Empty string |
| // |
| delboy->tokenString->set(delboy->tokenString, (const char *)""); |
| |
| // Now we serialize the elements of the token.Note that the debugger only |
| // uses 32 bits. |
| // |
| delboy->tokenString->addi(delboy->tokenString, (ANTLR3_INT32)(t->getTokenIndex(t))); |
| delboy->tokenString->addc(delboy->tokenString, '\t'); |
| delboy->tokenString->addi(delboy->tokenString, (ANTLR3_INT32)(t->getType(t))); |
| delboy->tokenString->addc(delboy->tokenString, '\t'); |
| delboy->tokenString->addi(delboy->tokenString, (ANTLR3_INT32)(t->getChannel(t))); |
| delboy->tokenString->addc(delboy->tokenString, '\t'); |
| delboy->tokenString->addi(delboy->tokenString, (ANTLR3_INT32)(t->getLine(t))); |
| delboy->tokenString->addc(delboy->tokenString, '\t'); |
| delboy->tokenString->addi(delboy->tokenString, (ANTLR3_INT32)(t->getCharPositionInLine(t))); |
| |
| // Now send the text that the token represents. |
| // |
| serializeText(delboy->tokenString, t->getText(t)); |
| |
| // Finally, as the debugger is a Java program it will expect to get UTF-8 |
| // encoded strings. We don't use UTF-8 internally to the C runtime, so we |
| // must force encode it. We have a method to do this in the string class, but |
| // it returns malloc space that we must free afterwards. |
| // |
| return delboy->tokenString->toUTF8(delboy->tokenString); |
| } |
| |
| // Given a tree node, create a stringified version of it in the supplied |
| // buffer. |
| // |
| pANTLR3_STRING |
| serializeNode(pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE node) |
| { |
| pANTLR3_COMMON_TOKEN token; |
| |
| |
| // Do we already have a serialization buffer? |
| // |
| if (delboy->tokenString == NULL) |
| { |
| // No, so create one, using the string factory that |
| // the grammar name used, which is guaranteed to exist. |
| // 64 bytes will do us here for starters. |
| // |
| delboy->tokenString = delboy->grammarFileName->factory->newSize(delboy->grammarFileName->factory, 64); |
| } |
| |
| // Empty string |
| // |
| delboy->tokenString->set(delboy->tokenString, (const char *)""); |
| |
| // Protect against bugs/errors etc |
| // |
| if (node == NULL) |
| { |
| return delboy->tokenString; |
| } |
| |
| // Now we serialize the elements of the node.Note that the debugger only |
| // uses 32 bits. |
| // |
| delboy->tokenString->addc(delboy->tokenString, '\t'); |
| |
| // Adaptor ID |
| // |
| delboy->tokenString->addi(delboy->tokenString, delboy->adaptor->getUniqueID(delboy->adaptor, node)); |
| delboy->tokenString->addc(delboy->tokenString, '\t'); |
| |
| // Type of the current token (which may be imaginary) |
| // |
| delboy->tokenString->addi(delboy->tokenString, delboy->adaptor->getType(delboy->adaptor, node)); |
| |
| // See if we have an actual token or just an imaginary |
| // |
| token = delboy->adaptor->getToken(delboy->adaptor, node); |
| |
| delboy->tokenString->addc(delboy->tokenString, '\t'); |
| if (token != NULL) |
| { |
| // Real token |
| // |
| delboy->tokenString->addi(delboy->tokenString, (ANTLR3_INT32)(token->getLine(token))); |
| delboy->tokenString->addc(delboy->tokenString, ' '); |
| delboy->tokenString->addi(delboy->tokenString, (ANTLR3_INT32)(token->getCharPositionInLine(token))); |
| } |
| else |
| { |
| // Imaginary tokens have no location |
| // |
| delboy->tokenString->addi(delboy->tokenString, -1); |
| delboy->tokenString->addc(delboy->tokenString, '\t'); |
| delboy->tokenString->addi(delboy->tokenString, -1); |
| } |
| |
| // Start Index of the node |
| // |
| delboy->tokenString->addc(delboy->tokenString, '\t'); |
| delboy->tokenString->addi(delboy->tokenString, (ANTLR3_UINT32)(delboy->adaptor->getTokenStartIndex(delboy->adaptor, node))); |
| |
| // Now send the text that the node represents. |
| // |
| serializeText(delboy->tokenString, delboy->adaptor->getText(delboy->adaptor, node)); |
| |
| // Finally, as the debugger is a Java program it will expect to get UTF-8 |
| // encoded strings. We don't use UTF-8 internally to the C runtime, so we |
| // must force encode it. We have a method to do this in the string class, but |
| // there is no utf8 string implementation as of yet |
| // |
| return delboy->tokenString->toUTF8(delboy->tokenString); |
| } |
| |
| //------------------------------------------------------------------------------------------------------------------ |
| // EVENTS |
| // |
| static void |
| enterRule (pANTLR3_DEBUG_EVENT_LISTENER delboy, const char * grammarFileName, const char * ruleName) |
| { |
| char buffer[512]; |
| |
| // Create the message (speed is not of the essence) |
| // |
| sprintf(buffer, "enterRule\t%s\t%s\n", grammarFileName, ruleName); |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| enterAlt (pANTLR3_DEBUG_EVENT_LISTENER delboy, int alt) |
| { |
| char buffer[512]; |
| |
| // Create the message (speed is not of the essence) |
| // |
| sprintf(buffer, "enterAlt\t%d\n", alt); |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| exitRule (pANTLR3_DEBUG_EVENT_LISTENER delboy, const char * grammarFileName, const char * ruleName) |
| { |
| char buffer[512]; |
| |
| // Create the message (speed is not of the essence) |
| // |
| sprintf(buffer, "exitRule\t%s\t%s\n", grammarFileName, ruleName); |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| enterSubRule (pANTLR3_DEBUG_EVENT_LISTENER delboy, int decisionNumber) |
| { |
| char buffer[512]; |
| |
| // Create the message (speed is not of the essence) |
| // |
| sprintf(buffer, "enterSubRule\t%d\n", decisionNumber); |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| exitSubRule (pANTLR3_DEBUG_EVENT_LISTENER delboy, int decisionNumber) |
| { |
| char buffer[512]; |
| |
| // Create the message (speed is not of the essence) |
| // |
| sprintf(buffer, "exitSubRule\t%d\n", decisionNumber); |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| enterDecision (pANTLR3_DEBUG_EVENT_LISTENER delboy, int decisionNumber) |
| { |
| char buffer[512]; |
| |
| // Create the message (speed is not of the essence) |
| // |
| sprintf(buffer, "enterDecision\t%d\n", decisionNumber); |
| transmit(delboy, buffer); |
| |
| } |
| |
| static void |
| exitDecision (pANTLR3_DEBUG_EVENT_LISTENER delboy, int decisionNumber) |
| { |
| char buffer[512]; |
| |
| // Create the message (speed is not of the essence) |
| // |
| sprintf(buffer, "exitDecision\t%d\n", decisionNumber); |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| consumeToken (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_COMMON_TOKEN t) |
| { |
| pANTLR3_STRING msg; |
| |
| // Create the serialized token |
| // |
| msg = serializeToken(delboy, t); |
| |
| // Insert the debug event indicator |
| // |
| msg->insert8(msg, 0, "consumeToken\t"); |
| |
| msg->addc(msg, '\n'); |
| |
| // Transmit the message and wait for ack |
| // |
| transmit(delboy, (const char *)(msg->chars)); |
| } |
| |
| static void |
| consumeHiddenToken (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_COMMON_TOKEN t) |
| { |
| pANTLR3_STRING msg; |
| |
| // Create the serialized token |
| // |
| msg = serializeToken(delboy, t); |
| |
| // Insert the debug event indicator |
| // |
| msg->insert8(msg, 0, "consumeHiddenToken\t"); |
| |
| msg->addc(msg, '\n'); |
| |
| // Transmit the message and wait for ack |
| // |
| transmit(delboy, (const char *)(msg->chars)); |
| } |
| |
| // Looking at the next token event. |
| // |
| static void |
| LT (pANTLR3_DEBUG_EVENT_LISTENER delboy, int i, pANTLR3_COMMON_TOKEN t) |
| { |
| pANTLR3_STRING msg; |
| |
| if (t != NULL) |
| { |
| // Create the serialized token |
| // |
| msg = serializeToken(delboy, t); |
| |
| // Insert the index parameter |
| // |
| msg->insert8(msg, 0, "\t"); |
| msg->inserti(msg, 0, i); |
| |
| // Insert the debug event indicator |
| // |
| msg->insert8(msg, 0, "LT\t"); |
| |
| msg->addc(msg, '\n'); |
| |
| // Transmit the message and wait for ack |
| // |
| transmit(delboy, (const char *)(msg->chars)); |
| } |
| } |
| |
| static void |
| mark (pANTLR3_DEBUG_EVENT_LISTENER delboy, ANTLR3_MARKER marker) |
| { |
| char buffer[128]; |
| |
| sprintf(buffer, "mark\t%d\n", (ANTLR3_UINT32)(marker & 0xFFFFFFFF)); |
| |
| // Transmit the message and wait for ack |
| // |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| rewindMark (pANTLR3_DEBUG_EVENT_LISTENER delboy, ANTLR3_MARKER marker) |
| { |
| char buffer[128]; |
| |
| sprintf(buffer, "rewind\t%d\n", (ANTLR3_UINT32)(marker & 0xFFFFFFFF)); |
| |
| // Transmit the message and wait for ack |
| // |
| transmit(delboy, buffer); |
| |
| } |
| |
| static void |
| rewindLast (pANTLR3_DEBUG_EVENT_LISTENER delboy) |
| { |
| transmit(delboy, (const char *)"rewind\n"); |
| } |
| |
| static void |
| beginBacktrack (pANTLR3_DEBUG_EVENT_LISTENER delboy, int level) |
| { |
| char buffer[128]; |
| |
| sprintf(buffer, "beginBacktrack\t%d\n", (ANTLR3_UINT32)(level & 0xFFFFFFFF)); |
| |
| // Transmit the message and wait for ack |
| // |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| endBacktrack (pANTLR3_DEBUG_EVENT_LISTENER delboy, int level, ANTLR3_BOOLEAN successful) |
| { |
| char buffer[128]; |
| |
| sprintf(buffer, "endBacktrack\t%d\t%d\n", level, successful); |
| |
| // Transmit the message and wait for ack |
| // |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| location (pANTLR3_DEBUG_EVENT_LISTENER delboy, int line, int pos) |
| { |
| char buffer[128]; |
| |
| sprintf(buffer, "location\t%d\t%d\n", line, pos); |
| |
| // Transmit the message and wait for ack |
| // |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| recognitionException (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_EXCEPTION e) |
| { |
| char buffer[256]; |
| |
| sprintf(buffer, "exception\t%s\t%d\t%d\t%d\n", (char *)(e->name), (ANTLR3_INT32)(e->index), e->line, e->charPositionInLine); |
| |
| // Transmit the message and wait for ack |
| // |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| beginResync (pANTLR3_DEBUG_EVENT_LISTENER delboy) |
| { |
| transmit(delboy, (const char *)"beginResync\n"); |
| } |
| |
| static void |
| endResync (pANTLR3_DEBUG_EVENT_LISTENER delboy) |
| { |
| transmit(delboy, (const char *)"endResync\n"); |
| } |
| |
| static void |
| semanticPredicate (pANTLR3_DEBUG_EVENT_LISTENER delboy, ANTLR3_BOOLEAN result, const char * predicate) |
| { |
| unsigned char * buffer; |
| unsigned char * out; |
| |
| if (predicate != NULL) |
| { |
| buffer = (unsigned char *)ANTLR3_MALLOC(64 + 2*strlen(predicate)); |
| |
| if (buffer != NULL) |
| { |
| out = buffer + sprintf((char *)buffer, "semanticPredicate\t%s\t", result == ANTLR3_TRUE ? "true" : "false"); |
| |
| while (*predicate != '\0') |
| { |
| switch(*predicate) |
| { |
| case '\n': |
| |
| *out++ = '%'; |
| *out++ = '0'; |
| *out++ = 'A'; |
| break; |
| |
| case '\r': |
| |
| *out++ = '%'; |
| *out++ = '0'; |
| *out++ = 'D'; |
| break; |
| |
| case '%': |
| |
| *out++ = '%'; |
| *out++ = '0'; |
| *out++ = 'D'; |
| break; |
| |
| |
| default: |
| |
| *out++ = *predicate; |
| break; |
| } |
| |
| predicate++; |
| } |
| *out++ = '\n'; |
| *out++ = '\0'; |
| } |
| |
| // Send it and wait for the ack |
| // |
| transmit(delboy, (const char *)buffer); |
| } |
| } |
| |
| #ifdef ANTLR3_WINDOWS |
| #pragma warning (push) |
| #pragma warning (disable : 4100) |
| #endif |
| |
| static void |
| commence (pANTLR3_DEBUG_EVENT_LISTENER delboy) |
| { |
| // Nothing to see here |
| // |
| } |
| |
| #ifdef ANTLR3_WINDOWS |
| #pragma warning (pop) |
| #endif |
| |
| static void |
| terminate (pANTLR3_DEBUG_EVENT_LISTENER delboy) |
| { |
| // Terminate sequence |
| // |
| sockSend(delboy->socket, "terminate\n", 10); // Send out the command |
| } |
| |
| //---------------------------------------------------------------- |
| // Tree parsing events |
| // |
| static void |
| consumeNode (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE t) |
| { |
| pANTLR3_STRING buffer; |
| |
| buffer = serializeNode (delboy, t); |
| |
| // Now prepend the command |
| // |
| buffer->insert8 (buffer, 0, "consumeNode\t"); |
| buffer->addc (buffer, '\n'); |
| |
| // Send to the debugger and wait for the ack |
| // |
| transmit (delboy, (const char *)(delboy->tokenString->toUTF8(delboy->tokenString)->chars)); |
| } |
| |
| static void |
| LTT (pANTLR3_DEBUG_EVENT_LISTENER delboy, int i, pANTLR3_BASE_TREE t) |
| { |
| pANTLR3_STRING buffer; |
| |
| buffer = serializeNode (delboy, t); |
| |
| // Now prepend the command |
| // |
| buffer->insert8 (buffer, 0, "\t"); |
| buffer->inserti (buffer, 0, i); |
| buffer->insert8 (buffer, 0, "LN\t"); |
| buffer->addc (buffer, '\n'); |
| |
| // Send to the debugger and wait for the ack |
| // |
| transmit (delboy, (const char *)(delboy->tokenString->toUTF8(delboy->tokenString)->chars)); |
| } |
| |
| static void |
| nilNode (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE t) |
| { |
| char buffer[128]; |
| sprintf(buffer, "nilNode\t%d\n", delboy->adaptor->getUniqueID(delboy->adaptor, t)); |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| createNode (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE t) |
| { |
| // Do we already have a serialization buffer? |
| // |
| if (delboy->tokenString == NULL) |
| { |
| // No, so create one, using the string factory that |
| // the grammar name used, which is guaranteed to exist. |
| // 64 bytes will do us here for starters. |
| // |
| delboy->tokenString = delboy->grammarFileName->factory->newSize(delboy->grammarFileName->factory, 64); |
| } |
| |
| // Empty string |
| // |
| delboy->tokenString->set8(delboy->tokenString, (const char *)"createNodeFromTokenElements "); |
| |
| // Now we serialize the elements of the node.Note that the debugger only |
| // uses 32 bits. |
| // |
| // Adaptor ID |
| // |
| delboy->tokenString->addi(delboy->tokenString, delboy->adaptor->getUniqueID(delboy->adaptor, t)); |
| delboy->tokenString->addc(delboy->tokenString, '\t'); |
| |
| // Type of the current token (which may be imaginary) |
| // |
| delboy->tokenString->addi(delboy->tokenString, delboy->adaptor->getType(delboy->adaptor, t)); |
| |
| // The text that this node represents |
| // |
| serializeText(delboy->tokenString, delboy->adaptor->getText(delboy->adaptor, t)); |
| delboy->tokenString->addc(delboy->tokenString, '\n'); |
| |
| // Finally, as the debugger is a Java program it will expect to get UTF-8 |
| // encoded strings. We don't use UTF-8 internally to the C runtime, so we |
| // must force encode it. We have a method to do this in the string class, but |
| // there is no utf8 string implementation as of yet |
| // |
| transmit(delboy, (const char *)(delboy->tokenString->toUTF8(delboy->tokenString)->chars)); |
| |
| } |
| static void |
| errorNode (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE t) |
| { |
| // Do we already have a serialization buffer? |
| // |
| if (delboy->tokenString == NULL) |
| { |
| // No, so create one, using the string factory that |
| // the grammar name used, which is guaranteed to exist. |
| // 64 bytes will do us here for starters. |
| // |
| delboy->tokenString = delboy->grammarFileName->factory->newSize(delboy->grammarFileName->factory, 64); |
| } |
| |
| // Empty string |
| // |
| delboy->tokenString->set8(delboy->tokenString, (const char *)"errorNode\t"); |
| |
| // Now we serialize the elements of the node.Note that the debugger only |
| // uses 32 bits. |
| // |
| // Adaptor ID |
| // |
| delboy->tokenString->addi(delboy->tokenString, delboy->adaptor->getUniqueID(delboy->adaptor, t)); |
| delboy->tokenString->addc(delboy->tokenString, '\t'); |
| |
| // Type of the current token (which is an error) |
| // |
| delboy->tokenString->addi(delboy->tokenString, ANTLR3_TOKEN_INVALID); |
| |
| // The text that this node represents |
| // |
| serializeText(delboy->tokenString, delboy->adaptor->getText(delboy->adaptor, t)); |
| delboy->tokenString->addc(delboy->tokenString, '\n'); |
| |
| // Finally, as the debugger is a Java program it will expect to get UTF-8 |
| // encoded strings. We don't use UTF-8 internally to the C runtime, so we |
| // must force encode it. We have a method to do this in the string class, but |
| // there is no utf8 string implementation as of yet |
| // |
| transmit(delboy, (const char *)(delboy->tokenString->toUTF8(delboy->tokenString)->chars)); |
| |
| } |
| |
| static void |
| createNodeTok (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE node, pANTLR3_COMMON_TOKEN token) |
| { |
| char buffer[128]; |
| |
| sprintf(buffer, "createNode\t%d\t%d\n", delboy->adaptor->getUniqueID(delboy->adaptor, node), (ANTLR3_UINT32)token->getTokenIndex(token)); |
| |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| becomeRoot (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE newRoot, pANTLR3_BASE_TREE oldRoot) |
| { |
| char buffer[128]; |
| |
| sprintf(buffer, "becomeRoot\t%d\t%d\n", delboy->adaptor->getUniqueID(delboy->adaptor, newRoot), |
| delboy->adaptor->getUniqueID(delboy->adaptor, oldRoot) |
| ); |
| transmit(delboy, buffer); |
| } |
| |
| |
| static void |
| addChild (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE root, pANTLR3_BASE_TREE child) |
| { |
| char buffer[128]; |
| |
| sprintf(buffer, "addChild\t%d\t%d\n", delboy->adaptor->getUniqueID(delboy->adaptor, root), |
| delboy->adaptor->getUniqueID(delboy->adaptor, child) |
| ); |
| transmit(delboy, buffer); |
| } |
| |
| static void |
| setTokenBoundaries (pANTLR3_DEBUG_EVENT_LISTENER delboy, pANTLR3_BASE_TREE t, ANTLR3_MARKER tokenStartIndex, ANTLR3_MARKER tokenStopIndex) |
| { |
| char buffer[128]; |
| |
| sprintf(buffer, "becomeRoot\t%d\t%d\t%d\n", delboy->adaptor->getUniqueID(delboy->adaptor, t), |
| (ANTLR3_UINT32)tokenStartIndex, |
| (ANTLR3_UINT32)tokenStopIndex |
| ); |
| transmit(delboy, buffer); |
| } |
| #endif |
| |