/** * 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; }