/// \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
