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

