コード例 #1
0
ファイル: verilog.c プロジェクト: Luoben/ctags
static void dropContext (tokenInfo *const token)
{
	verbose ("current context %s; context kind %0d; nest level %0d\n", vStringValue (currentContext->name), currentContext->kind, currentContext->nestLevel);
	vString *endTokenName = vStringNewInit("end");
	if ((currentContext->kind == K_COVERGROUP && strcmp (vStringValue (token->name), "endgroup") == 0) ||
	    (currentContext->kind == K_BLOCK && currentContext->nestLevel == 0 && strcmp (vStringValue (token->name), vStringValue (endTokenName)) == 0)
	    )
	{
		verbose ("Dropping context %s\n", vStringValue (currentContext->name));
		currentContext = popToken (currentContext);
	}
	else
	{
		vStringCatS (endTokenName, kindFromKind (currentContext->kind)->name);
		if (strcmp (vStringValue (token->name), vStringValue (endTokenName)) == 0)
		{
			verbose ("Dropping context %s\n", vStringValue (currentContext->name));
			currentContext = popToken (currentContext);
			if (currentContext->classScope)
			{
				verbose ("Dropping local context %s\n", vStringValue (currentContext->name));
				currentContext = popToken (currentContext);
			}
		}
	}
	vStringDelete(endTokenName);
}
コード例 #2
0
/*
    parseLine
    
    From a line of input, sets outKey and outValue.
    If the line parses correctly, function returns true.
    Otherwise function returns false.
    
    In the case of true return and the line contains a key/value pair, outKey and
    outValue contain that data.
    In the case of true return and the line contains only whitespace or comments,
    outKey and outValue are set to "".
    In the case of false return, outKey and outValue are set to "".
*/
static
bool parseLine(const string &line, string &outKey, string &outValue)
{
    string parsedLine = line;
    size_t numWhitespace = 0;
    string key = "";
    string value = "";
    
    // Set outKey, outValue to default ""
    outKey = "";
    outValue = "";
    
    // Get rid of comments in line
    getRidOfComments(parsedLine);
    
    // Delete whitespace
    deleteWhitespace(parsedLine);
    
    // Check for empty line
    if (parsedLine.size() == 0) {
        return true;
    }
    
    // Get key
    popToken(parsedLine, key);
    if (key == "") {
    	return false;
    }
    
    // Delete whitespace
    numWhitespace = deleteWhitespace(parsedLine);
    if (numWhitespace == 0) {
    	return false;
    }
    
    // Get value
    popToken(parsedLine, value);
    if (value == "") {
    	return false;
    }
    
    // Delete whitespace
    deleteWhitespace(parsedLine);
    
    // Check for non-empty line
    if (parsedLine.size() != 0) {
    	return false;
    }
    
    // If here, the line parsed correctly
    outKey = key;
    outValue = value;
    return true;
}
コード例 #3
0
ファイル: VHMSG.cpp プロジェクト: leuski-ict/jerome
 void onMessage(std::string in_message)
 {
   String head = popToken(in_message);
   for (auto& h : mHandlers) {
     if (h->head() != head) continue;
     if (h->command() != "") {
       String message = in_message;
       String command = popToken(message);
       if (h->command() != command) continue;
       h->operator () (message);
     } else {
       h->operator () (in_message);
     }
   }
 }
コード例 #4
0
ファイル: verilog.c プロジェクト: shunlir/ctags
static void processBlock (tokenInfo *const token)
{
	boolean blockStart = FALSE;
	boolean blockEnd   = FALSE;

	if (strcmp (vStringValue (token->name), "begin") == 0)
	{
		currentContext->nestLevel++;
		blockStart = TRUE;
	}
	else if (strcmp (vStringValue (token->name), "end") == 0)
	{
		currentContext->nestLevel--;
		blockEnd = TRUE;
	}

	if (findBlockName (token))
	{
		verbose ("Found block: %s\n", vStringValue (token->name));
		if (blockStart)
		{
			createTag (token);
			verbose ("Current context %s\n", vStringValue (currentContext->name));
		}
		if (blockEnd && currentContext->kind == K_BLOCK && currentContext->nestLevel <= 1)
		{
			verbose ("Dropping context %s\n", vStringValue (currentContext->name));
			currentContext = popToken (currentContext);
		}
	}
}
コード例 #5
0
ファイル: templatizer.cpp プロジェクト: Kiddinglife/ryzom
/*
 * Parse bloc internal data
 */
CTemplatizerParser	CTemplatizerCommentBloc::parseInternal(CTemplatizerParser ptr)
{
	ptr = skipSpace(ptr);

	if (!popToken(ptr, CommentStart, true))
		return NULL;

	while (*ptr != '\0' && !isNextToken(ptr, CommentEnd, false))
		++ptr;

	if (!popToken(ptr, CommentEnd, false))
	{
		ptr.invalidate();
		return ptr;
	}

	return ptr;
}
コード例 #6
0
ファイル: verilog.c プロジェクト: Luoben/ctags
static void findVerilogTags (void)
{
	tokenInfo *const token = newToken ();
	int c = '\0';
	currentContext = newToken ();

	while (c != EOF)
	{
		c = vGetc ();
		c = skipWhite (c);
		switch (c)
		{
			/* Store current block name whenever a : is found
			 * This is used later by any tag type that requires this information
			 * */
			case ':':
				vStringCopy (currentContext->blockName, token->name);
				break;
			/* Skip interface modport port declarations */
			case '(':
				if (currentContext && currentContext->lastKind == K_MODPORT)
				{
					skipPastMatch ("()");
				}
				break;
			/* Drop context on prototypes because they don't have an end
			 * statement */
			case ';':
				if (currentContext->scope && currentContext->scope->prototype)
				{
					verbose ("Dropping context %s\n", vStringValue (currentContext->name));
					currentContext = popToken (currentContext);
					currentContext->prototype = FALSE;
				}
				/* Prototypes end at the end of statement */
				if (currentContext->prototype)
				{
					currentContext->prototype = FALSE;
				}
				break;
			default :
				if (isIdentifierCharacter (c))
				{
					readIdentifier (token, c);
					updateKind (token);
					findTag (token);
				}
		}
	}

	deleteToken (token);
	pruneTokens (currentContext);
	currentContext = NULL;
}
コード例 #7
0
ファイル: templatizer.cpp プロジェクト: Kiddinglife/ryzom
/*
 * Parse bloc header
 */
CTemplatizerParser	ITemplatizerBloc::parseHeader(CTemplatizerParser ptr)
{
	if (popToken(ptr, OpenParenth, true))
	{
		uint			currentDefArg = 0;
		const char**	args = getDefParamList();

		if (popToken(ptr, CloseParenth, true))
			return ptr;

		do
		{
			std::string	paramName;
			if (!popToken(ptr, Identifier, true, &paramName))
			{
				if (args == NULL || args[currentDefArg] == NULL)
				{
					ptr.invalidate();
					return ptr;
				}

				paramName = args[currentDefArg++];
			}
			else
			{
				if (!popToken(ptr, Equal, true))
				{
					ptr.invalidate();
					return ptr;
				}
			}

			ITemplatizerBloc*	bloc = parseBloc(ptr);

			if (bloc == NULL)
			{
				ptr.invalidate();
				return ptr;
			}

			Params[paramName] = bloc;

			if (!popToken(ptr, Comma, true))
				break;
		}
		while (true);

		if (!popToken(ptr, CloseParenth, true))
		{
			ptr.invalidate();
			return ptr;
		}
	}

	return ptr;
}
コード例 #8
0
ファイル: read-command.c プロジェクト: vravish/CS-111-lab1
token* infixToPostfix(token* start)
{
	token* final_start = NULL;
	token* final_end = NULL;
	
	token* stack_start = NULL;
	token* stack_end = NULL;
	
	for (; start != NULL; start = start->next)
		if (start->t == WORD_TOKEN) //if operand, then add to final
			addToken(&final_start, &final_end, start);
		else if (start->t == LEFT_PAREN_TOKEN) //if left paren, then add it to stack
			addToken(&stack_start, &stack_end, start);
		else if (start->t == RIGHT_PAREN_TOKEN) //if right paren, pop stack until matching left paren
		{
			while (stack_end && stack_end->t != LEFT_PAREN_TOKEN)
			{
				token* output = popToken(&stack_start, &stack_end);
				addToken(&final_start, &final_end, output);
			}
			popToken(&stack_start, &stack_end);
		}
		else if (start->t == SEMICOLON_TOKEN && start->sub == 1)
		{
			while (stack_end && stack_end->t != LEFT_PAREN_TOKEN)
				addToken(&final_start, &final_end, popToken(&stack_start, &stack_end));
			token* semitoken = malloc(sizeof(token));
			semitoken->t = SEMICOLON_TOKEN;
			semitoken->sub = 1;
			addToken(&final_start, &final_end, semitoken);
		}
		else if (stack_end == NULL || precedence(start->t) > precedence(stack_end->t)) //if more important operator than top, then add to stack
			addToken(&stack_start, &stack_end, start);
		else if (precedence(start->t) < precedence(stack_end->t)) //if less important operator than top, then keep transferring until I'm more important and then add me to stack
		{
			token* output;
			while (stack_end != NULL)
			{
				if (precedence(start->t) > precedence(stack_end->t))
					break;
				addToken(&final_start, &final_end, popToken(&stack_start, &stack_end));
			}
			addToken(&stack_start, &stack_end, start);
		}
		else if (precedence(start->t) ==precedence(stack_end->t)) //if same, then pop stack and push me to stack
		{
			addToken(&final_start, &final_end, popToken(&stack_start, &stack_end));
			addToken(&stack_start, &stack_end, start);
		}
	while (stack_end)
		addToken(&final_start, &final_end, popToken(&stack_start, &stack_end));
	return final_start;
}
コード例 #9
0
ファイル: mlex.cpp プロジェクト: LaMaisonOrchard/Sire
Ttoken *Tmlex::getToken()
{
    Ttoken        *token   = NULL;
    TstrBuf        text    = "";
    unsigned long  textIdx = 0;
    int            found = 0;

    if (NULL != (token = popToken()))
    {
        return(token);
    }
    else
    {
        token = new Ttoken;
    }

    token->setType(TOK_ILLEGAL);

    while (!found)
    {
        int ch = Dinput.get();
        if (EOF != ch) text[textIdx++] = ch;

        if (EOF == ch)
        {
            // End of file
            token->setType(TOK_END);
            token->setText("");
            token->setPosn(Dinput.posn());
            found = 1;
        }
        else if ('\n' == ch)
        {
            token->setType(TOK_EOL);
            token->setText("");
            found = 1;
        }
        else if (isspace(ch))
        {
            // Ignore white space
        }
        else if (SEP_ESC == ch)
        {
            // excape
            ch = Dinput.get();

            if ('\n' == ch)
            {
                // ignore the end-of-line
            }
            else if (SEP_ESC == ch)
            {
                // Litteral
                Dinput.putBack(ch);
                token->setPosn(Dinput.posn());
                found = readIdent(*token);
            }
            else
            {
                // Excaped charactor
                Dinput.putBack(ch);
            }
        }
        else if ('#' == ch)
        {
            // Check for comment
            token->setPosn(Dinput.posn());
            ch = Dinput.get();

            found = readComment(*token);
        }
        else if (SEP_TEXT == ch)
        {
            // Text
            token->setPosn(Dinput.posn());
            found = readText(*token);
        }
        else if (SEP_S_VAR == ch)
        {
            // Start an evaluated variable (define)
            readVar();
        }
        else if (SEP_CALL == ch)
        {
            // Call
            token->setPosn(Dinput.posn());
            found = readCall(*token);
        }
        else if (isSymb(ch))
        {
            // Symbol
            token->setPosn(Dinput.posn());
            Dinput.putBack(ch);
            found = readSymb(*token);
        }
        else if (isIdent(ch))
        {
            // Ident
            token->setPosn(Dinput.posn());
            Dinput.putBack(ch);
            found = readIdent(*token);
        }
        else
        {
            while ((EOF != ch) && !isspace(ch)) ch = Dinput.get();
            if (EOF != ch) Dinput.putBack(ch);
        }
    }

    return(token);
}
コード例 #10
0
ファイル: verilog.c プロジェクト: shunlir/ctags
static void processClass (tokenInfo *const token)
{
	/*Note: At the moment, only identifies typedef name and not its contents */
	int c;
	tokenInfo *extra;
	tokenInfo *parameters = NULL;

	/* Get identifiers */
	c = skipWhite (vGetc ());
	if (isIdentifierCharacter (c))
	{
		readIdentifier (token, c);
		c = skipWhite (vGetc ());
	}

	/* Find class parameters list */
	if (c == '#')
	{
		c = skipWhite (vGetc ());
		if (c == '(')
		{
			parameters = newToken ();
			do
			{
				c = skipWhite (vGetc ());
				readIdentifier (parameters, c);
				updateKind (parameters);
				verbose ("Found class parameter %s\n", vStringValue (parameters->name));
				if (parameters->kind == K_UNDEFINED)
				{
					parameters->kind = K_CONSTANT;
					parameters = pushToken (parameters, newToken ());
					c = vGetc();
					while (c != ',' && c != ')' && c != EOF)
					{
						c = vGetc();
					}
				}
			} while (c != ')' && c != EOF);
			c = vGetc ();
			parameters = popToken (parameters);
		}
		c = skipWhite (vGetc ());
	}

	/* Search for inheritance information */
	if (isIdentifierCharacter (c))
	{
		extra = newToken ();

		readIdentifier (extra, c);
		c = skipWhite (vGetc ());
		if (strcmp (vStringValue (extra->name), "extends") == 0)
		{
			readIdentifier (extra, c);
			vStringCopy (token->inheritance, extra->name);
			verbose ("Inheritance %s\n", vStringValue (token->inheritance));
		}
		deleteToken (extra);
	}

	/* Use last identifier to create tag */
	createTag (token);

	/* Add parameter list */
	while (parameters)
	{
		createTag (parameters);
		parameters = popToken (parameters);
	}
}
コード例 #11
0
ファイル: verilog.c プロジェクト: shunlir/ctags
static void pruneTokens (tokenInfo * token)
{
	while ((token = popToken (token)));
}
コード例 #12
0
ファイル: templatizer.cpp プロジェクト: Kiddinglife/ryzom
/*
 * Parse bloc
 */
ITemplatizerBloc*	ITemplatizerBloc::parseBloc(CTemplatizerParser& ptr)
{
	std::string			blocType;
	ITemplatizerBloc*	bloc = NULL;

	if (popToken(ptr, Identifier, true, &blocType) || popToken(ptr, ListIdentifier, true, &blocType))
	{
		if		(blocType == "root")				bloc = new CTemplatizerRootBloc();
		else if (blocType == "sub")					bloc = new CTemplatizerSubBloc();
		else if (blocType == "loop")				bloc = new CTemplatizerLoopBloc();
		else if (blocType == "ifdefenv")			bloc = new CTemplatizerIfDefEnvBloc();
		else if (blocType == "ifdef")				bloc = new CTemplatizerIfDefBloc();
		else if (blocType == "ifnotdefenv")			bloc = new CTemplatizerIfNotDefEnvBloc();
		else if (blocType == "ifnotdef")			bloc = new CTemplatizerIfNotDefBloc();
		else if (blocType == "switch")				bloc = new CTemplatizerSwitchBloc();
		else if (blocType == "file")				bloc = new CTemplatizerFileBloc();
		else if (blocType == "set")					bloc = new CTemplatizerSetBloc();
		else if (blocType == "append")				bloc = new CTemplatizerAppendBloc();
		else if (blocType == "define")				bloc = new CTemplatizerDefineBloc();
		else if (blocType == "if")					bloc = new CTemplatizerIfBloc();
		else if (blocType == "ifnot")				bloc = new CTemplatizerIfNotBloc();
		else if (blocType == "join")				bloc = new CTemplatizerJoinBloc();
		else if (blocType == "class")				bloc = new CTemplatizerClassBloc();
		else if (blocType == "object")				bloc = new CTemplatizerObjectBloc();
		else if (blocType == "ref")					bloc = new CTemplatizerReferenceBloc();
		else if (blocType == "refenv")				bloc = new CTemplatizerRefEnvBloc();
		else if (blocType == "breakpoint")			bloc = new CTemplatizerBreakpointBloc();
		else										bloc = new CTemplatizerUserFunctionBloc(blocType);

		if (bloc == NULL)
		{
			nlwarning("Templatizer: failed to decode bloc '%s' at line %d", blocType.c_str(), ptr.getLine());
			return NULL;
		}

		ptr = bloc->parseHeader(ptr);

		if (!ptr.isValid())
		{
			nlwarning("Templatizer: failed to decode header of bloc '%s' at line %d", blocType.c_str(), ptr.getLine());
			delete bloc;
			return NULL;
		}

		if (bloc->hasInternal())
		{
			if (!popToken(ptr, BlocStart, true))
			{
				nlwarning("Templatizer: failed to decode start of bloc '%s' at line %d", blocType.c_str(), ptr.getLine());
				delete bloc;
				return NULL;
			}

			ptr = bloc->parseInternal(ptr);

			if (!ptr.isValid())
			{
				nlwarning("Templatizer: failed to parse bloc '%s' at line %d", blocType.c_str(), ptr.getLine());
				delete bloc;
				return NULL;
			}

			if (!popToken(ptr, BlocEnd, true))
			{
				nlwarning("Templatizer: failed to decode end of bloc '%s' at line %d", blocType.c_str(), ptr.getLine());
				delete bloc;
				return NULL;
			}
		}
	}
	else if (isNextToken(ptr, CommentStart, true))
	{
		bloc = new CTemplatizerCommentBloc();
		ptr = bloc->parseInternal(ptr);
		if (!ptr.isValid())
			nlwarning("Templatizer: failed to parse bloc 'Comment' at line %d", ptr.getLine());
	}
	else if (isNextToken(ptr, Quote, true))
	{
		bloc = new CTemplatizerTextBloc();
		ptr = bloc->parseInternal(ptr);
		if (!ptr.isValid())
			nlwarning("Templatizer: failed to parse bloc 'Text' at line %d", ptr.getLine());
	}

	if (!ptr.isValid())
	{
		delete bloc;
		return NULL;
	}

	return bloc;
}
コード例 #13
0
  XPathParser::Token*
  XPathParser::tokenize(const char* xpath, TokenFactory* tokenFactory)
  {
    /*
     * First, Define some convenient Macros.
     * These macros operate on the current Token, on the last Token, and on the token Stack
     *
     * allocToken : allocates a new token, puts it in current
     * nextToken  : puts a new token in current, update last <- current
     * newSymbolToken : creates a new token, initiated to the current symbol character
     * pushQName : push the qname string buffer as a new QName token
     * pushToken : push the current token at the top of the stack
     * pushSingleToken : push the current token at the top of the stack, but just for one QName token
     * popToken : pop the top of the stack to current token.
     */

#define allocToken() do { current = tokenFactory->allocToken(); } while(0)

#define nextToken() \
    do { allocToken(); \
    Log_XPathParser_Tokenize ( "New Token at %p\n", current ); \
    if ( ! headToken ) { headToken = current; last = current; }\
    else if ( last ) { last->next = current; last = current; } \
    else if ( tokenStack.size() ) \
    { AssertBug ( ! tokenStack.front()->subExpression, "Front token has already a subExpression !\n" ); \
      tokenStack.front()->subExpression = current; last = current; } \
    else { Bug ( "Don't know how to link this token !\n" ); } } while (0)

#define newSymbolToken() \
    Log_XPathParser_Tokenize ( "New Symbol Token '%c'\n", *c ); \
    nextToken();  \
    current->type = Token::Symbol; \
    current->symbol = *c;

#define pushQName() \
    if ( qname.size() ) \
    { 	\
      if ( last && last->isQName() && ( qname == "::" || stringEndsWith(last->token,String("::") ) ) ) \
      { \
        last->token += qname; qname = ""; \
      } \
      else \
      { \
        nextToken(); \
        current->token = qname; \
        qname = ""; \
        Log_XPathParser_Tokenize ( "New QName : '%s'\n", current->token.c_str() ); \
        if ( pushedSingleToken ) \
        { popToken (); } \
      } \
    }

#define pushToken() \
    pushedSingleToken = false; \
    Log_XPathParser_Tokenize ( "Pushing token '%p'\n", current ); \
    tokenStack.push_front ( current ); \
    current = last = NULL;    

#define pushSingleToken() \
    pushToken (); \
    pushedSingleToken = true;

#define popToken() \
    AssertBug ( tokenStack.size(), "Empty Stack, can't pop !\n" ); \
    current = tokenStack.front ( ); \
    Log_XPathParser_Tokenize ( "Popped token '%p'\n", current ); \
    tokenStack.pop_front (); \
    last = current; \
    pushedSingleToken = false; 

    Log_XPathParser_Tokenize ( "**** Tokenize : '%s' *****\n", xpath );

    Token* current = NULL, *last = NULL, *headToken = NULL;
    char lastChar = '\0';
    std::list<Token*> tokenStack;
    String qname, text;
    bool pushedSingleToken = false;

    for (const char* c = xpath; *c; c++)
      {
        Log_XPathParser_Tokenize ( "At Char '%c'\n", *c );
        if (lastChar == '!' && *c != '=')
          {
            Bug ( "Invalid character following '!' : '%c'\n", *c );
          }
        switch (*c)
          {
        case '\'':
        case '"':
          {
            char start = *c;
            c++;
            text = "";
            for (; *c && (*c != start); c++)
              {
                text += *c;
              }
            if (!*c)
              {
                throwXPathException ( "Unbalanced quote caracter '%c'\n", start );
              }
            nextToken ();
            current->type = Token::Text;
            current->token = text;
            break;
          }
        case '{':
        case '(':
        case '[':
          pushQName ();
          if (*c == '[' && last && last->symbol == '*')
            {
              last->type = Token::QName;
              last->token = "*";
            }
          newSymbolToken ();
          pushToken ();
          break;
        case ']':
        case '}':
        case ')':
          {
            pushQName ();
            popToken ();
            char mustBe;
            if (*c == ']')
              mustBe = '[';
            else if (*c == ')')
              mustBe = '(';
            else if (*c == '}')
              mustBe = '{';
            else
              {
                mustBe = '\0';
                Bug ( "Invalid section matcher from character '%c'\n", *c );
              }

            if (!current->isSymbol())
              {
                throwXPathException ( "Originating token is not a symbol !\n" );
              }
            if (current->symbol != mustBe)
              {
                throwXPathException ( "Unmatched closing symbols : openned with '%c', close with '%c'\n",
                    *c, current->symbol );
              }
            if (*c == ')')
              {
                Token* lastArg = current->subExpression, *lastArg0 = NULL;
                while (lastArg)
                  {
                    if (lastArg->isSymbol() && lastArg->symbol == ',')
                      lastArg0 = lastArg;
                    lastArg = lastArg->next;
                  }
                if (lastArg0)
                  {
                    Token* father = current;
                    allocToken ();
                    current->type = Token::Symbol;
                    current->symbol = ',';
                    current->subExpression = lastArg0->next;
                    lastArg0->next = current;
                    current = last = father;
                  }
              }
          }
          break;
        case '$':
        case '@':
          /*
           * Variable and attribute short form
           * These short forms expect a QName defined after.
           */
          pushQName ();
          newSymbolToken ();
          pushSingleToken ();
          break;
        case ',':
          {
            /*
             * Here we must re-arrange the tokens
             * so that the ',' symbol appears with the contents underneath
             */
            pushQName ();
            AssertBug ( tokenStack.size(), "Empty token stack !\n" );
            Token* father = tokenStack.front();
            AssertBug ( father->isSymbol(), "father token is not a symbol !\n" );
            AssertBug ( father->symbol == '(', "father token is not the '(' symbol : %c\n", father->symbol );

            if (!father->subExpression)
              throwXPathException ( "Empty XPath function argument after '%c'", father->symbol );

            AssertBug ( father->subExpression, "father token has no subExpression !\n" );
            Token* lastArg = father->subExpression, *lastArg0 = NULL;
            while (lastArg)
              {
                if (lastArg->isSymbol() && lastArg->symbol == ',')
                  lastArg0 = lastArg;
                lastArg = lastArg->next;
              }
            allocToken ();
            current->type = Token::Symbol;
            current->symbol = ',';
            if (lastArg0)
              {
                current->subExpression = lastArg0->next;
                lastArg0->next = current;
              }
            else
              {
                current->subExpression = father->subExpression;
                father->subExpression = current;
              }
            last = current;
            break;
          }
        case '*':
          {
            /*
             * Meaning of the '*' character is ambiguous :
             * It may be a wildcard for node testing (as in '@*', 'axis::*', 'namespace:*', ..)
             * Or it may be the multiplication symbol.
             */
            bool isQName = false;
            if (qname.c_str() && *qname.c_str())
              {
                Log_XPathParser_Tokenize ( "QName : %s\n", qname.c_str() );
                if (__endsWith(qname.c_str(), ':'))
                  isQName = true;
              }
            else if (last && last->isQName())
              {
                Log_XPathParser_Tokenize ( "Last is qname : %s\n", last->token.c_str() );
                if (__endsWith(last->token.c_str(), ':') || last->token == "or") //< Fixup for docbook.xsl */self::ng:* or */self::db:*
                  isQName = true;
              }
            else if (!last || isCharIn(last->symbol, "/~|,+*-"))
              {
                isQName = true;
              }
            if (qname == "mod" || qname == "div")
              {
                /*
                 *  We must find the token before this one.
                 */
                if (last)
                  {
                    isQName = true;
                  }
                else
                  {
                    isQName = false;
                  }
                pushQName ();
                Log_XPathParser_Tokenize ( "Multiply with qname='%s', last=%p(%c/%s), qname=%d\n",
                    qname.c_str(), last, last ? last->symbol : '?',
                    last ? last->token.c_str() : "", isQName );
              }

            Log_XPathParser_Tokenize ( "While at char '*' : last=%p(%d,q=%d/%c/%s), qname='%s' isQName=%d\n",
                last, last ? last->type : -1, last ? last->isQName() : -1,
                last ? last->symbol : '?', last ? last->token.c_str() : "",
                qname.c_str(), isQName );

            if (isQName)
              {
                qname += *c;
              }
            else
              {
                pushQName ();
                newSymbolToken ();
              }
          }
          break;

        case '-':
          /*
           * Meaning of the '-' character is ambiguous :
           * It may be a character inside of a QName (as in 'xsl:for-each')
           * Or it may be the substraction operator ('op1 - op2')
           * Or it may be the unary negative operator ('-op1')
           */
          if (isNumeric(qname.c_str()) || lastChar == '\0' || isCharIn(
              lastChar, "\n\r ([)]=<>+-*"))
            {
              pushQName ();
              bool isUnary = false;
              if (!last || (last->isSymbol() && isCharIn(last->symbol,
                  "*+-=><|[/~,")))
                {
                  Log_XPathParser_Tokenize ( "Negate : lastChar='%c', last=%p, last->symbol=%c, c[1]=%c\n",
                      lastChar, last, last ? last->symbol : ' ', c[1] );
                  isUnary = true;
                }
              if (last && (last->token == "mod" || last->token == "div"))
                {
                  // We must find the token before this one.
                  Token* before = NULL;
                  if (tokenStack.size())
                    {
                      before = tokenStack.front()->subExpression;
                      if (before == last)
                        before = NULL;
                    }
                  else
                    before = headToken;
                  while (before)
                    {
                      if (before->next == last)
                        break;
                      before = before->next;
                    }
                  if (before)
                    isUnary = true;
                  Log_XPathParser_Tokenize ( "Minus with last='%s', before=%p(%c/%s), unary=%d\n",
                      last->token.c_str(), before, before ? before->symbol : '?',
                      before ? before->token.c_str() : "", isUnary );
                }
              newSymbolToken ( );
              if (isUnary)
                current->symbol = 'N'; // Negate !
            }
          else if (c[1] == '>')
            {
              pushQName ();
              newSymbolToken ();
            }
          else
            {
              qname += *c;
            }
          break;

        case '/':
          /*
           * The '/' character only appears in single step separator ('step/step') or initial root ('/step')
           * Or in descendant short form (as initial '//step' or inside 'step//step').
           */
          if (lastChar == '/')
            {
              AssertBug ( last->isSymbol() && last->symbol == lastChar, "Dropped the last in a lastChar\n" );
              last->token = last->symbol;
              last->token += *c;
              last->symbol = '~';
              break;
            }
        case '=':
          if (*c == '=' && (lastChar == '<' || lastChar == '>' || lastChar
              == '!'))
            {
              AssertBug ( last->isSymbol() && last->symbol == lastChar, "Dropped the last in a lastChar\n" );
              last->token = last->symbol;
              last->token += *c;
              break;
            }
        case '<':
        case '>':
          if (lastChar == '-')
            {
              if (last)
                {
                  Log_XPathParser_Tokenize ( "ElementFunctionCall : last=%c/'%s'\n", last->symbol, last->token.c_str() );
                  last->symbol = '#';
                }
              else
                {
                  Bug ( "No last !\n" );
                }
              Log_XPathParser_Tokenize ( "Operator '->' found !\n" );
              break;
            }
        case '+':
        case '!':
        case '|':
          pushQName ();
          newSymbolToken ( );
          break;
        case '\t':
        case ' ':
        case '\n':
        case '\r':
          pushQName ();
          break;

        default:
          qname += *c;
          break;
          }
        lastChar = *c;
      }
    pushQName ();
    if (tokenStack.size())
      {
        throwXPathException ( "Unbalanced parentheses : still %ld tokens on stack.\n", (unsigned long) tokenStack.size() );
      }
    return headToken;
#undef allocToken
#undef nextToken
#undef newSymbolToken
#undef pushQName
#undef pushToken
#undef pushSingleToken
#undef popToken
  }