blob: 26274310cceaa97bb76de0f10144737396467a35 [file] [log] [blame]
/**
* Contains the default implementation of the common token used within
* java. Custom tokens should create this structure and then append to it using the
* custom pointer to install their own structure and API.
*/
// [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>
/* Token API
*/
static pANTLR3_STRING getText (pANTLR3_COMMON_TOKEN token);
static void setText (pANTLR3_COMMON_TOKEN token, pANTLR3_STRING text);
static void setText8 (pANTLR3_COMMON_TOKEN token, pANTLR3_UINT8 text);
static ANTLR3_UINT32 getType (pANTLR3_COMMON_TOKEN token);
static void setType (pANTLR3_COMMON_TOKEN token, ANTLR3_UINT32 type);
static ANTLR3_UINT32 getLine (pANTLR3_COMMON_TOKEN token);
static void setLine (pANTLR3_COMMON_TOKEN token, ANTLR3_UINT32 line);
static ANTLR3_INT32 getCharPositionInLine (pANTLR3_COMMON_TOKEN token);
static void setCharPositionInLine (pANTLR3_COMMON_TOKEN token, ANTLR3_INT32 pos);
static ANTLR3_UINT32 getChannel (pANTLR3_COMMON_TOKEN token);
static void setChannel (pANTLR3_COMMON_TOKEN token, ANTLR3_UINT32 channel);
static ANTLR3_MARKER getTokenIndex (pANTLR3_COMMON_TOKEN token);
static void setTokenIndex (pANTLR3_COMMON_TOKEN token, ANTLR3_MARKER);
static ANTLR3_MARKER getStartIndex (pANTLR3_COMMON_TOKEN token);
static void setStartIndex (pANTLR3_COMMON_TOKEN token, ANTLR3_MARKER index);
static ANTLR3_MARKER getStopIndex (pANTLR3_COMMON_TOKEN token);
static void setStopIndex (pANTLR3_COMMON_TOKEN token, ANTLR3_MARKER index);
static pANTLR3_STRING toString (pANTLR3_COMMON_TOKEN token);
/* Factory API
*/
static void factoryClose (pANTLR3_TOKEN_FACTORY factory);
static pANTLR3_COMMON_TOKEN newToken (void);
static void setInputStream (pANTLR3_TOKEN_FACTORY factory, pANTLR3_INPUT_STREAM input);
static void factoryReset (pANTLR3_TOKEN_FACTORY factory);
/* Internal management functions
*/
static void newPool (pANTLR3_TOKEN_FACTORY factory);
static pANTLR3_COMMON_TOKEN newPoolToken (pANTLR3_TOKEN_FACTORY factory);
ANTLR3_API pANTLR3_COMMON_TOKEN
antlr3CommonTokenNew(ANTLR3_UINT32 ttype)
{
pANTLR3_COMMON_TOKEN token;
// Create a raw token with the interface installed
//
token = newToken();
if (token != NULL)
{
token->setType(token, ttype);
}
// All good
//
return token;
}
ANTLR3_API pANTLR3_TOKEN_FACTORY
antlr3TokenFactoryNew(pANTLR3_INPUT_STREAM input)
{
pANTLR3_TOKEN_FACTORY factory;
/* allocate memory
*/
factory = (pANTLR3_TOKEN_FACTORY) ANTLR3_MALLOC((size_t)sizeof(ANTLR3_TOKEN_FACTORY));
if (factory == NULL)
{
return NULL;
}
/* Install factory API
*/
factory->newToken = newPoolToken;
factory->close = factoryClose;
factory->setInputStream = setInputStream;
factory->reset = factoryReset;
/* Allocate the initial pool
*/
factory->thisPool = -1;
factory->pools = NULL;
factory->maxPool = -1;
newPool(factory);
/* Factory space is good, we now want to initialize our cheating token
* which one it is initialized is the model for all tokens we manufacture
*/
antlr3SetTokenAPI(&factory->unTruc);
/* Set some initial variables for future copying
*/
factory->unTruc.factoryMade = ANTLR3_TRUE;
// Input stream
//
setInputStream(factory, input);
return factory;
}
static void
setInputStream (pANTLR3_TOKEN_FACTORY factory, pANTLR3_INPUT_STREAM input)
{
factory->input = input;
factory->unTruc.input = input;
if (input != NULL)
{
factory->unTruc.strFactory = input->strFactory;
}
else
{
factory->unTruc.strFactory = NULL;
}
}
static void
newPool(pANTLR3_TOKEN_FACTORY factory)
{
/* Increment factory count
*/
factory->thisPool++;
// If we were reusing this token factory then we may already have a pool
// allocated. If we exceeded the max avaible then we must allocate a new
// one.
if (factory->thisPool > factory->maxPool)
{
/* Ensure we have enough pointers allocated
*/
factory->pools = (pANTLR3_COMMON_TOKEN *)
ANTLR3_REALLOC( (void *)factory->pools, /* Current pools pointer (starts at NULL) */
(ANTLR3_UINT32)((factory->thisPool + 1) * sizeof(pANTLR3_COMMON_TOKEN *)) /* Memory for new pool pointers */
);
/* Allocate a new pool for the factory
*/
factory->pools[factory->thisPool] =
(pANTLR3_COMMON_TOKEN)
ANTLR3_CALLOC(1, (size_t)(sizeof(ANTLR3_COMMON_TOKEN) * ANTLR3_FACTORY_POOL_SIZE));
// We now have a new pool and can track it as the maximum we have created so far
//
factory->maxPool = factory->thisPool;
}
/* Reset the counters
*/
factory->nextToken = 0;
/* Done
*/
return;
}
static pANTLR3_COMMON_TOKEN
newPoolToken(pANTLR3_TOKEN_FACTORY factory)
{
pANTLR3_COMMON_TOKEN token;
/* See if we need a new token pool before allocating a new
* one
*/
if (factory->nextToken >= ANTLR3_FACTORY_POOL_SIZE)
{
/* We ran out of tokens in the current pool, so we need a new pool
*/
newPool(factory);
}
/* Assuming everything went well (we are trying for performance here so doing minimal
* error checking. Then we can work out what the pointer is to the next token.
*/
token = factory->pools[factory->thisPool] + factory->nextToken;
factory->nextToken++;
/* We have our token pointer now, so we can initialize it to the predefined model.
* We only need do this though if the token is not already initialized, we just check
* an api function pointer for this as they are allocated via calloc.
*/
if (token->setStartIndex == NULL)
{
antlr3SetTokenAPI(token);
// It is factory made, and we need to copy the string factory pointer
//
token->factoryMade = ANTLR3_TRUE;
token->strFactory = factory->input == NULL ? NULL : factory->input->strFactory;
token->input = factory->input;
}
/* And we are done
*/
return token;
}
static void
factoryReset (pANTLR3_TOKEN_FACTORY factory)
{
// Just start again with pool #0 when we are
// called.
//
factory->thisPool = -1;
newPool(factory);
}
static void
factoryClose (pANTLR3_TOKEN_FACTORY factory)
{
pANTLR3_COMMON_TOKEN pool;
ANTLR3_INT32 poolCount;
ANTLR3_UINT32 limit;
ANTLR3_UINT32 token;
pANTLR3_COMMON_TOKEN check;
/* We iterate the token pools one at a time
*/
for (poolCount = 0; poolCount <= factory->thisPool; poolCount++)
{
/* Pointer to current pool
*/
pool = factory->pools[poolCount];
/* Work out how many tokens we need to check in this pool.
*/
limit = (poolCount == factory->thisPool ? factory->nextToken : ANTLR3_FACTORY_POOL_SIZE);
/* Marginal condition, we might be at the start of a brand new pool
* where the nextToken is 0 and nothing has been allocated.
*/
if (limit > 0)
{
/* We have some tokens allocated from this pool
*/
for (token = 0; token < limit; token++)
{
/* Next one in the chain
*/
check = pool + token;
/* If the programmer made this a custom token, then
* see if we need to call their free routine.
*/
if (check->custom != NULL && check->freeCustom != NULL)
{
check->freeCustom(check->custom);
check->custom = NULL;
}
}
}
/* We can now free this pool allocation
*/
ANTLR3_FREE(factory->pools[poolCount]);
factory->pools[poolCount] = NULL;
}
/* All the pools are deallocated we can free the pointers to the pools
* now.
*/
ANTLR3_FREE(factory->pools);
/* Finally, we can free the space for the factory itself
*/
ANTLR3_FREE(factory);
}
static pANTLR3_COMMON_TOKEN
newToken(void)
{
pANTLR3_COMMON_TOKEN token;
/* Allocate memory for this
*/
token = (pANTLR3_COMMON_TOKEN) ANTLR3_CALLOC(1, (size_t)(sizeof(ANTLR3_COMMON_TOKEN)));
if (token == NULL)
{
return NULL;
}
// Install the API
//
antlr3SetTokenAPI(token);
token->factoryMade = ANTLR3_FALSE;
return token;
}
ANTLR3_API void
antlr3SetTokenAPI(pANTLR3_COMMON_TOKEN token)
{
token->getText = getText;
token->setText = setText;
token->setText8 = setText8;
token->getType = getType;
token->setType = setType;
token->getLine = getLine;
token->setLine = setLine;
token->setLine = setLine;
token->getCharPositionInLine = getCharPositionInLine;
token->setCharPositionInLine = setCharPositionInLine;
token->getChannel = getChannel;
token->setChannel = setChannel;
token->getTokenIndex = getTokenIndex;
token->setTokenIndex = setTokenIndex;
token->getStartIndex = getStartIndex;
token->setStartIndex = setStartIndex;
token->getStopIndex = getStopIndex;
token->setStopIndex = setStopIndex;
token->toString = toString;
return;
}
static pANTLR3_STRING getText (pANTLR3_COMMON_TOKEN token)
{
switch (token->textState)
{
case ANTLR3_TEXT_STRING:
// Someone already created a string for this token, so we just
// use it.
//
return token->tokText.text;
break;
case ANTLR3_TEXT_CHARP:
// We had a straight text pointer installed, now we
// must convert it to a string. Note we have to do this here
// or otherwise setText8() will just install the same char*
//
if (token->strFactory != NULL)
{
token->tokText.text = token->strFactory->newStr8(token->strFactory, (pANTLR3_UINT8)token->tokText.chars);
token->textState = ANTLR3_TEXT_STRING;
return token->tokText.text;
}
else
{
// We cannot do anything here
//
return NULL;
}
break;
default:
// EOF is a special case
//
if (token->type == ANTLR3_TOKEN_EOF)
{
token->tokText.text = token->strFactory->newStr8(token->strFactory, (pANTLR3_UINT8)"<EOF>");
token->textState = ANTLR3_TEXT_STRING;
token->tokText.text->factory = token->strFactory;
return token->tokText.text;
}
// We had nothing installed in the token, create a new string
// from the input stream
//
if (token->input != NULL)
{
return token->input->substr( token->input,
token->getStartIndex(token),
token->getStopIndex(token)
);
}
// Nothing to return, there is no input stream
//
return NULL;
break;
}
}
static void setText8 (pANTLR3_COMMON_TOKEN token, pANTLR3_UINT8 text)
{
// No text to set, so ignore
//
if (text == NULL) return;
switch (token->textState)
{
case ANTLR3_TEXT_NONE:
case ANTLR3_TEXT_CHARP: // Caller must free before setting again, if it needs to be freed
// Nothing in there yet, or just a char *, so just set the
// text as a pointer
//
token->textState = ANTLR3_TEXT_CHARP;
token->tokText.chars = (pANTLR3_UCHAR)text;
break;
default:
// It was already a pANTLR3_STRING, so just override it
//
token->tokText.text->set8(token->tokText.text, (const char *)text);
break;
}
// We are done
//
return;
}
/** \brief Install the supplied text string as teh text for the token.
* The method assumes that the existing text (if any) was created by a factory
* and so does not attempt to release any memory it is using.Text not created
* by a string fctory (not advised) should be released prior to this call.
*/
static void setText (pANTLR3_COMMON_TOKEN token, pANTLR3_STRING text)
{
// Merely replaces and existing pre-defined text with the supplied
// string
//
token->textState = ANTLR3_TEXT_STRING;
token->tokText.text = text;
/* We are done
*/
return;
}
static ANTLR3_UINT32 getType (pANTLR3_COMMON_TOKEN token)
{
return token->type;
}
static void setType (pANTLR3_COMMON_TOKEN token, ANTLR3_UINT32 type)
{
token->type = type;
}
static ANTLR3_UINT32 getLine (pANTLR3_COMMON_TOKEN token)
{
return token->line;
}
static void setLine (pANTLR3_COMMON_TOKEN token, ANTLR3_UINT32 line)
{
token->line = line;
}
static ANTLR3_INT32 getCharPositionInLine (pANTLR3_COMMON_TOKEN token)
{
return token->charPosition;
}
static void setCharPositionInLine (pANTLR3_COMMON_TOKEN token, ANTLR3_INT32 pos)
{
token->charPosition = pos;
}
static ANTLR3_UINT32 getChannel (pANTLR3_COMMON_TOKEN token)
{
return token->channel;
}
static void setChannel (pANTLR3_COMMON_TOKEN token, ANTLR3_UINT32 channel)
{
token->channel = channel;
}
static ANTLR3_MARKER getTokenIndex (pANTLR3_COMMON_TOKEN token)
{
return token->index;
}
static void setTokenIndex (pANTLR3_COMMON_TOKEN token, ANTLR3_MARKER index)
{
token->index = index;
}
static ANTLR3_MARKER getStartIndex (pANTLR3_COMMON_TOKEN token)
{
return token->start == -1 ? (ANTLR3_MARKER)(token->input->data) : token->start;
}
static void setStartIndex (pANTLR3_COMMON_TOKEN token, ANTLR3_MARKER start)
{
token->start = start;
}
static ANTLR3_MARKER getStopIndex (pANTLR3_COMMON_TOKEN token)
{
return token->stop;
}
static void setStopIndex (pANTLR3_COMMON_TOKEN token, ANTLR3_MARKER stop)
{
token->stop = stop;
}
static pANTLR3_STRING toString (pANTLR3_COMMON_TOKEN token)
{
pANTLR3_STRING text;
pANTLR3_STRING outtext;
text = token->getText(token);
if (text == NULL)
{
return NULL;
}
if (text->factory == NULL)
{
return text; // This usally means it is the EOF token
}
/* A new empty string to assemble all the stuff in
*/
outtext = text->factory->newRaw(text->factory);
/* Now we use our handy dandy string utility to assemble the
* the reporting string
* return "[@"+getTokenIndex()+","+start+":"+stop+"='"+txt+"',<"+type+">"+channelStr+","+line+":"+getCharPositionInLine()+"]";
*/
outtext->append8(outtext, "[Index: ");
outtext->addi (outtext, (ANTLR3_INT32)token->getTokenIndex(token));
outtext->append8(outtext, " (Start: ");
outtext->addi (outtext, (ANTLR3_INT32)token->getStartIndex(token));
outtext->append8(outtext, "-Stop: ");
outtext->addi (outtext, (ANTLR3_INT32)token->getStopIndex(token));
outtext->append8(outtext, ") ='");
outtext->appendS(outtext, text);
outtext->append8(outtext, "', type<");
outtext->addi (outtext, token->type);
outtext->append8(outtext, "> ");
if (token->getChannel(token) > ANTLR3_TOKEN_DEFAULT_CHANNEL)
{
outtext->append8(outtext, "(channel = ");
outtext->addi (outtext, (ANTLR3_INT32)token->getChannel(token));
outtext->append8(outtext, ") ");
}
outtext->append8(outtext, "Line: ");
outtext->addi (outtext, (ANTLR3_INT32)token->getLine(token));
outtext->append8(outtext, " LinePos:");
outtext->addi (outtext, token->getCharPositionInLine(token));
outtext->addc (outtext, ']');
return outtext;
}