/****************************************************************************
**
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
**
** This file is part of the Qt Script Generator project on Trolltech Labs.
**
** This file may be used under the terms of the GNU General Public
** License version 2.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file.  Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
** http://www.trolltech.com/products/qt/opensource.html
**
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://www.trolltech.com/products/qt/licensing.html or contact the
** sales department at sales@trolltech.com.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/


#include "lexer.h"
#include "tokens.h"
#include "control.h"

#include <cctype>
#include <iostream>

scan_fun_ptr Lexer::s_scan_keyword_table[] = {
  &Lexer::scanKeyword0, &Lexer::scanKeyword0,
  &Lexer::scanKeyword2, &Lexer::scanKeyword3,
  &Lexer::scanKeyword4, &Lexer::scanKeyword5,
  &Lexer::scanKeyword6, &Lexer::scanKeyword7,
  &Lexer::scanKeyword8, &Lexer::scanKeyword9,
  &Lexer::scanKeyword10, &Lexer::scanKeyword11,
  &Lexer::scanKeyword12, &Lexer::scanKeyword13,
  &Lexer::scanKeyword14, &Lexer::scanKeyword0,
  &Lexer::scanKeyword16
};

void LocationManager::extract_line(int offset, int *line, QString *filename) const
{
  *line = 0;
  if (token_stream.size () < 1)
    return;

  const unsigned char *begin_buffer = reinterpret_cast<const unsigned char *>(token_stream[0].text);
  const unsigned char *cursor = begin_buffer + offset;

  ++cursor; // skip '#'
  if (std::isspace(*cursor) && std::isdigit(*(cursor + 1)))
    {
      ++cursor;
      char buffer[1024], *cp = buffer;
      do {
        *cp++ = *cursor++;
      } while (std::isdigit(*cursor));
      *cp = '\0';
      int l = strtol(buffer, 0, 0);

      Q_ASSERT(std::isspace(*cursor));
      ++cursor;

      Q_ASSERT(*cursor == '"');
      ++cursor;

      cp = buffer;
      while (*cursor && *cursor != '"') {
        *cp++ = *cursor++;
      }
      *cp = '\0';
      Q_ASSERT(*cursor == '"');
      ++cursor;

      *filename = buffer;
      *line = l;
      // printf("filename: %s line: %d\n", buffer, line);
    }
}

void LocationManager::positionAt(std::size_t offset, int *line, int *column,
                                 QString *filename) const
{
  int ppline, ppcolumn;
  line_table.positionAt(offset, &ppline, &ppcolumn);

  int base_line;
  extract_line((int) line_table[ppline-1], &base_line, filename);

  int line2, column2;
  location_table.positionAt((int) line_table[ppline-1], &line2, &column2);

  location_table.positionAt(offset, line, column);
  *line = base_line + *line - line2  - 1;
}

scan_fun_ptr Lexer::s_scan_table[256];
bool Lexer::s_initialized = false;

void Lexer::tokenize(const char *contents, std::size_t size)
{
  if (!s_initialized)
    initialize_scan_table();

  token_stream.resize(1024);
  token_stream[0].kind = Token_EOF;
  token_stream[0].text = contents;

  index = 1;

  cursor = (const unsigned char *) contents;
  begin_buffer = (const unsigned char *) contents;
  end_buffer = cursor + size;

  location_table.resize(1024);
  location_table[0] = 0;
  location_table.current_line = 1;

  line_table.resize(1024);
  line_table[0] = 0;
  line_table.current_line = 1;

  do {
    if (index == token_stream.size())
      token_stream.resize(token_stream.size() * 2);

    Token *current_token = &token_stream[(int) index];
    current_token->text = reinterpret_cast<const char*>(begin_buffer);
    current_token->position = cursor - begin_buffer;
    (this->*s_scan_table[*cursor])();
    current_token->size = cursor - begin_buffer - current_token->position;
  } while (cursor < end_buffer);

  if (index == token_stream.size())
      token_stream.resize(token_stream.size() * 2);

  Q_ASSERT(index < token_stream.size());
  token_stream[(int) index].position = cursor - begin_buffer;
  token_stream[(int) index].kind = Token_EOF;
}

void Lexer::reportError(const QString& msg)
{
    int line, column;
    QString fileName;

    std::size_t tok = token_stream.cursor();
    _M_location.positionAt(token_stream.position(tok),
        &line, &column, &fileName);

    Control::ErrorMessage errmsg;
    errmsg.setLine(line + 1);
    errmsg.setColumn(column);
    errmsg.setFileName(fileName);
    errmsg.setMessage(QLatin1String("** LEXER ERROR ") + msg);
    control->reportError(errmsg);
}

void Lexer::initialize_scan_table()
{
  s_initialized = true;

  for (int i=0; i<256; ++i)
    {
      if (isspace(i))
	s_scan_table[i] = &Lexer::scan_white_spaces;
      else if (isalpha(i) || i == '_')
	s_scan_table[i] = &Lexer::scan_identifier_or_keyword;
      else if (isdigit(i))
	s_scan_table[i] = &Lexer::scan_int_constant;
      else
	s_scan_table[i] = &Lexer::scan_invalid_input;
    }

  s_scan_table[int('L')] = &Lexer::scan_identifier_or_literal;
  s_scan_table[int('\n')] = &Lexer::scan_newline;
  s_scan_table[int('#')] = &Lexer::scan_preprocessor;

  s_scan_table[int('\'')] = &Lexer::scan_char_constant;
  s_scan_table[int('"')]  = &Lexer::scan_string_constant;

  s_scan_table[int('.')] = &Lexer::scan_int_constant;

  s_scan_table[int('!')] = &Lexer::scan_not;
  s_scan_table[int('%')] = &Lexer::scan_remainder;
  s_scan_table[int('&')] = &Lexer::scan_and;
  s_scan_table[int('(')] = &Lexer::scan_left_paren;
  s_scan_table[int(')')] = &Lexer::scan_right_paren;
  s_scan_table[int('*')] = &Lexer::scan_star;
  s_scan_table[int('+')] = &Lexer::scan_plus;
  s_scan_table[int(',')] = &Lexer::scan_comma;
  s_scan_table[int('-')] = &Lexer::scan_minus;
  s_scan_table[int('/')] = &Lexer::scan_divide;
  s_scan_table[int(':')] = &Lexer::scan_colon;
  s_scan_table[int(';')] = &Lexer::scan_semicolon;
  s_scan_table[int('<')] = &Lexer::scan_less;
  s_scan_table[int('=')] = &Lexer::scan_equal;
  s_scan_table[int('>')] = &Lexer::scan_greater;
  s_scan_table[int('?')] = &Lexer::scan_question;
  s_scan_table[int('[')] = &Lexer::scan_left_bracket;
  s_scan_table[int(']')] = &Lexer::scan_right_bracket;
  s_scan_table[int('^')] = &Lexer::scan_xor;
  s_scan_table[int('{')] = &Lexer::scan_left_brace;
  s_scan_table[int('|')] = &Lexer::scan_or;
  s_scan_table[int('}')] = &Lexer::scan_right_brace;
  s_scan_table[int('~')] = &Lexer::scan_tilde;

  s_scan_table[0] = &Lexer::scan_EOF;
}

void Lexer::scan_preprocessor()
{
  if (line_table.current_line == line_table.size())
    line_table.resize(line_table.current_line * 2);

  line_table[(int) line_table.current_line++] = (cursor - begin_buffer);

  while (*cursor && *cursor != '\n')
    ++cursor;

  if (*cursor != '\n')
      reportError("expected newline");
}

void Lexer::scan_char_constant()
{
  const unsigned char *begin = cursor;

  ++cursor;
  while (*cursor && *cursor != '\'')
    {
      if (*cursor == '\n')
        reportError("did not expect newline");

      if (*cursor == '\\')
	++cursor;
      ++cursor;
    }

    if (*cursor != '\'')
      reportError("expected \'");

  ++cursor;

  token_stream[(int) index].extra.symbol =
    control->findOrInsertName((const char*) begin, cursor - begin);

  token_stream[(int) index++].kind = Token_char_literal;
}

void Lexer::scan_string_constant()
{
  const unsigned char *begin = cursor;

  ++cursor;
  while (*cursor && *cursor != '"')
    {
      if (*cursor == '\n')
        reportError("did not expect newline");

      if (*cursor == '\\')
	++cursor;
      ++cursor;
    }

  if (*cursor != '"')
    reportError("expected \"");

  ++cursor;

  token_stream[(int) index].extra.symbol =
    control->findOrInsertName((const char*) begin, cursor - begin);

  token_stream[(int) index++].kind = Token_string_literal;
}

void Lexer::scan_newline()
{
  if (location_table.current_line == location_table.size())
    location_table.resize(location_table.current_line * 2);

  location_table[(int) location_table.current_line++] = (cursor - begin_buffer);
  ++cursor;
}

void Lexer::scan_white_spaces()
{
  while (isspace(*cursor))
    {
      if (*cursor == '\n')
	scan_newline();
      else
	++cursor;
    }
}

void Lexer::scan_identifier_or_literal()
{
  switch (*(cursor + 1))
    {
    case '\'':
      ++cursor;
      scan_char_constant();
      break;

    case '\"':
      ++cursor;
      scan_string_constant();
      break;

    default:
      scan_identifier_or_keyword();
      break;
    }
}

void Lexer::scan_identifier_or_keyword()
{
  const unsigned char *skip = cursor;
  while (isalnum(*skip) || *skip== '_')
    ++skip;

  int n = skip - cursor;
  Token *current_token = &token_stream[(int) index];
  (this->*s_scan_keyword_table[n < 17 ? n : 0])();

  if (current_token->kind == Token_identifier)
    {
      current_token->extra.symbol =
	control->findOrInsertName((const char*) cursor, n);
    }

  cursor = skip;
}

void Lexer::scan_int_constant()
{
  if (*cursor == '.' && !std::isdigit(*(cursor + 1)))
    {
      scan_dot();
      return;
    }

  const unsigned char *begin = cursor;

  while (isalnum(*cursor) || *cursor == '.')
    ++cursor;

  token_stream[(int) index].extra.symbol =
    control->findOrInsertName((const char*) begin, cursor - begin);

  token_stream[(int) index++].kind = Token_number_literal;
}

void Lexer::scan_not()
{
  /*
    '!'		::= not
    '!='		::= not_equal
  */

  ++cursor;

  if (*cursor == '=')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_not_eq;
    }
  else
    {
      token_stream[(int) index++].kind = '!';
    }
}

void Lexer::scan_remainder()
{
  /*
    '%'		::= remainder
    '%='		::= remainder_equal
  */

  ++cursor;

  if (*cursor == '=')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_assign;
    }
  else
    {
      token_stream[(int) index++].kind = '%';
    }
}

void Lexer::scan_and()
{
  /*
    '&&'		::= and_and
    '&'		::= and
    '&='		::= and_equal
  */

  ++cursor;
  if (*cursor == '=')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_assign;
    }
  else if (*cursor == '&')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_and;
    }
  else
    {
      token_stream[(int) index++].kind = '&';
    }
}

void Lexer::scan_left_paren()
{
  ++cursor;
  token_stream[(int) index++].kind = '(';
}

void Lexer::scan_right_paren()
{
  ++cursor;
  token_stream[(int) index++].kind = ')';
}

void Lexer::scan_star()
{
  /*
    '*'		::= star
    '*='		::= star_equal
  */

  ++cursor;

  if (*cursor == '=')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_assign;
    }
  else
    {
      token_stream[(int) index++].kind = '*';
    }
}

void Lexer::scan_plus()
{
  /*
    '+'		::= plus
    '++'		::= incr
    '+='		::= plus_equal
  */

  ++cursor;
  if (*cursor == '=')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_assign;
    }
  else if (*cursor == '+')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_incr;
    }
  else
    {
      token_stream[(int) index++].kind = '+';
    }
}

void Lexer::scan_comma()
{
  ++cursor;
  token_stream[(int) index++].kind = ',';
}

void Lexer::scan_minus()
{
  /*
    '-'		::= minus
    '--'		::= decr
    '-='		::= minus_equal
    '->'		::= left_arrow
  */

  ++cursor;
  if (*cursor == '=')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_assign;
    }
  else if (*cursor == '-')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_decr;
    }
  else if (*cursor == '>')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_arrow;
      if (*cursor == '*')
	{
	  ++cursor;
	  token_stream[(int) index++].kind = Token_ptrmem;
	}
    }
  else
    {
      token_stream[(int) index++].kind = '-';
    }
}

void Lexer::scan_dot()
{
  /*
    '.'		::= dot
    '...'		::= ellipsis
  */

  ++cursor;
  if (*cursor == '.' && *(cursor + 1) == '.')
    {
      cursor += 2;
      token_stream[(int) index++].kind = Token_ellipsis;
    }
  else if (*cursor == '.' && *(cursor + 1) == '*')
    {
      cursor += 2;
      token_stream[(int) index++].kind = Token_ptrmem;
    }
  else
    token_stream[(int) index++].kind = '.';
}

void Lexer::scan_divide()
{
  /*
    '/'		::= divide
    '/='	::= divide_equal
  */

  ++cursor;

  if (*cursor == '=')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_assign;
    }
  else
    {
      token_stream[(int) index++].kind = '/';
    }
}

void Lexer::scan_colon()
{
  ++cursor;
  if (*cursor == ':')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_scope;
    }
  else
    {
      token_stream[(int) index++].kind = ':';
    }
}

void Lexer::scan_semicolon()
{
  ++cursor;
  token_stream[(int) index++].kind = ';';
}

void Lexer::scan_less()
{
  /*
    '<'			::= less
    '<<'		::= left_shift
    '<<='		::= left_shift_equal
    '<='		::= less_equal
  */

  ++cursor;
  if (*cursor == '=')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_leq;
    }
  else if (*cursor == '<')
    {
      ++cursor;
      if (*cursor == '=')
	{
	  ++cursor;
	  token_stream[(int) index++].kind = Token_assign;
	}
      else
	{
	  token_stream[(int) index++].kind = Token_shift;
	}
    }
  else
    {
      token_stream[(int) index++].kind = '<';
    }
}

void Lexer::scan_equal()
{
  /*
    '='			::= equal
    '=='		::= equal_equal
  */
  ++cursor;

  if (*cursor == '=')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_eq;
    }
  else
    {
      token_stream[(int) index++].kind = '=';
    }
}

void Lexer::scan_greater()
{
  /*
    '>'			::= greater
    '>='		::= greater_equal
    '>>'		::= right_shift
    '>>='		::= right_shift_equal
  */

  ++cursor;
  if (*cursor == '=')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_geq;
    }
  else if (*cursor == '>')
    {
      ++cursor;
      if (*cursor == '=')
	{
	  ++cursor;
	  token_stream[(int) index++].kind = Token_assign;
	}
      else
	{
	  token_stream[(int) index++].kind = Token_shift;
	}
    }
  else
    {
      token_stream[(int) index++].kind = '>';
    }
}

void Lexer::scan_question()
{
  ++cursor;
  token_stream[(int) index++].kind = '?';
}

void Lexer::scan_left_bracket()
{
  ++cursor;
  token_stream[(int) index++].kind = '[';
}

void Lexer::scan_right_bracket()
{
  ++cursor;
  token_stream[(int) index++].kind = ']';
}

void Lexer::scan_xor()
{
  /*
    '^'			::= xor
    '^='		::= xor_equal
  */
  ++cursor;

  if (*cursor == '=')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_assign;
    }
  else
    {
      token_stream[(int) index++].kind = '^';
    }
}

void Lexer::scan_left_brace()
{
  ++cursor;
  token_stream[(int) index++].kind = '{';
}

void Lexer::scan_or()
{
  /*
    '|'			::= or
    '|='		::= or_equal
    '||'		::= or_or
  */
  ++cursor;
  if (*cursor == '=')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_assign;
    }
  else if (*cursor == '|')
    {
      ++cursor;
      token_stream[(int) index++].kind = Token_or;
    }
  else
    {
    token_stream[(int) index++].kind = '|';
  }
}

void Lexer::scan_right_brace()
{
  ++cursor;
  token_stream[(int) index++].kind = '}';
}

void Lexer::scan_tilde()
{
  ++cursor;
  token_stream[(int) index++].kind = '~';
}

void Lexer::scan_EOF()
{
  ++cursor;
  token_stream[(int) index++].kind = Token_EOF;
}

void Lexer::scan_invalid_input()
{
  QString errmsg("invalid input: %1");
  errmsg.arg(int(*cursor));
  reportError(errmsg);
  ++cursor;
}

void LocationTable::positionAt(std::size_t offset, int max_line,
			       int *line, int *column) const
{
  if (!(line && column && max_line != 0))
    return;

  int first = 0;
  int len = max_line;
  int half;
  int middle;

  while (len > 0)
    {
      half = len >> 1;
      middle = first;

      middle += half;

      if (lines[middle] < offset)
	{
	  first = middle;
	  ++first;
	  len = len - half - 1;
	}
      else
	len = half;
    }

  *line = std::max(first, 1);
  *column = (int) (offset - lines[*line - 1] - 1);

  if (*column < 0)
    {
      *column = 0;
    }
}

void Lexer::scanKeyword0()
{
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword2()
{
  switch (*cursor)
    {
    case 'i':
      if (*(cursor + 1) == 'f')
	{
	  token_stream[(int) index++].kind = Token_if;
	  return;
	}
      break;

    case 'd':
      if (*(cursor + 1) == 'o')
	{
	  token_stream[(int) index++].kind = Token_do;
	  return;
	}
      break;

    case 'o':
      if (*(cursor + 1) == 'r')
	{
	  token_stream[(int) index++].kind = Token_or;
	  return;
	}
      break;

    }
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword3()
{
  switch (*cursor)
    {
    case 'a':
      if (*(cursor + 1) == 'n' &&
	  *(cursor + 2) == 'd')
	{
	  token_stream[(int) index++].kind = Token_and;
	  return;
	}
      if (*(cursor + 1) == 's' &&
	  *(cursor + 2) == 'm')
	{
	  token_stream[(int) index++].kind = Token_asm;
	  return;
	}
      break;

    case 'f':
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 'r')
	{
	  token_stream[(int) index++].kind = Token_for;
	  return;
	}
      break;

    case 'i':
      if (*(cursor + 1) == 'n' &&
	  *(cursor + 2) == 't')
	{
	  token_stream[(int) index++].kind = Token_int;
	  return;
	}
      break;

    case 'n':
      if (*(cursor + 1) == 'e' &&
	  *(cursor + 2) == 'w')
	{
	  token_stream[(int) index++].kind = Token_new;
	  return;
	}
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 't')
	{
	  token_stream[(int) index++].kind = Token_not;
	  return;
	}
      break;

    case 't':
      if (*(cursor + 1) == 'r' &&
	  *(cursor + 2) == 'y')
	{
	  token_stream[(int) index++].kind = Token_try;
	  return;
	}
      break;

    case 'x':
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 'r')
	{
	  token_stream[(int) index++].kind = Token_xor;
	  return;
	}
      break;

    }
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword4()
{
  switch (*cursor)
    {
    case 'a':
      if (*(cursor + 1) == 'u' &&
	  *(cursor + 2) == 't' &&
	  *(cursor + 3) == 'o')
	{
	  token_stream[(int) index++].kind = Token_auto;
	  return;
	}
      break;

    case 'c':
      if (*(cursor + 1) == 'a' &&
	  *(cursor + 2) == 's' &&
	  *(cursor + 3) == 'e')
	{
	  token_stream[(int) index++].kind = Token_case;
	  return;
	}
      if (*(cursor + 1) == 'h' &&
	  *(cursor + 2) == 'a' &&
	  *(cursor + 3) == 'r')
	{
	  token_stream[(int) index++].kind = Token_char;
	  return;
	}
      break;

    case 'b':
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 'o' &&
	  *(cursor + 3) == 'l')
	{
	  token_stream[(int) index++].kind = Token_bool;
	  return;
	}
      break;

    case 'e':
      if (*(cursor + 1) == 'l' &&
	  *(cursor + 2) == 's' &&
	  *(cursor + 3) == 'e')
	{
	  token_stream[(int) index++].kind = Token_else;
	  return;
	}
      if (*(cursor + 1) == 'm' &&
	  *(cursor + 2) == 'i' &&
	  *(cursor + 3) == 't')
	{
	  token_stream[(int) index++].kind = Token_emit;
	  return;
	}
      if (*(cursor + 1) == 'n' &&
	  *(cursor + 2) == 'u' &&
	  *(cursor + 3) == 'm')
	{
	  token_stream[(int) index++].kind = Token_enum;
	  return;
	}
      break;

    case 'g':
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 't' &&
	  *(cursor + 3) == 'o')
	{
	  token_stream[(int) index++].kind = Token_goto;
	  return;
	}
      break;

    case 'l':
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 'n' &&
	  *(cursor + 3) == 'g')
	{
	  token_stream[(int) index++].kind = Token_long;
	  return;
	}
      break;

    case 't':
      if (*(cursor + 1) == 'h' &&
	  *(cursor + 2) == 'i' &&
	  *(cursor + 3) == 's')
	{
	  token_stream[(int) index++].kind = Token_this;
	  return;
	}
      break;

    case 'v':
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 'i' &&
	  *(cursor + 3) == 'd')
	{
	  token_stream[(int) index++].kind = Token_void;
	  return;
	}
      break;

    }
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword5()
{
  switch (*cursor)
    {
    case 'c':
      if (*(cursor + 1) == 'a' &&
	  *(cursor + 2) == 't' &&
	  *(cursor + 3) == 'c' &&
	  *(cursor + 4) == 'h')
	{
	  token_stream[(int) index++].kind = Token_catch;
	  return;
	}
      if (*(cursor + 1) == 'l' &&
	  *(cursor + 2) == 'a' &&
	  *(cursor + 3) == 's' &&
	  *(cursor + 4) == 's')
	{
	  token_stream[(int) index++].kind = Token_class;
	  return;
	}
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 'm' &&
	  *(cursor + 3) == 'p' &&
	  *(cursor + 4) == 'l')
	{
	  token_stream[(int) index++].kind = Token_compl;
	  return;
	}
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 'n' &&
	  *(cursor + 3) == 's' &&
	  *(cursor + 4) == 't')
	{
	  token_stream[(int) index++].kind = Token_const;
	  return;
	}
      break;

    case 'b':
      if (*(cursor + 1) == 'i' &&
	  *(cursor + 2) == 't' &&
	  *(cursor + 3) == 'o' &&
	  *(cursor + 4) == 'r')
	{
	  token_stream[(int) index++].kind = Token_bitor;
	  return;
	}
      if (*(cursor + 1) == 'r' &&
	  *(cursor + 2) == 'e' &&
	  *(cursor + 3) == 'a' &&
	  *(cursor + 4) == 'k')
	{
	  token_stream[(int) index++].kind = Token_break;
	  return;
	}
      break;

    case 'f':
      if (*(cursor + 1) == 'l' &&
	  *(cursor + 2) == 'o' &&
	  *(cursor + 3) == 'a' &&
	  *(cursor + 4) == 't')
	{
	  token_stream[(int) index++].kind = Token_float;
	  return;
	}
      break;

    case 'o':
      if (*(cursor + 1) == 'r' &&
	  *(cursor + 2) == '_' &&
	  *(cursor + 3) == 'e' &&
	  *(cursor + 4) == 'q')
	{
	  token_stream[(int) index++].kind = Token_or_eq;
	  return;
	}
      break;

    case 's':
      if (*(cursor + 1) == 'h' &&
	  *(cursor + 2) == 'o' &&
	  *(cursor + 3) == 'r' &&
	  *(cursor + 4) == 't')
	{
	  token_stream[(int) index++].kind = Token_short;
	  return;
	}
      if (*(cursor + 1) == 'l' &&
	  *(cursor + 2) == 'o' &&
	  *(cursor + 3) == 't' &&
	  *(cursor + 4) == 's')
	{
	  token_stream[(int) index++].kind = Token_slots;
	  return;
	}
      break;

    case 'u':
      if (*(cursor + 1) == 'n' &&
	  *(cursor + 2) == 'i' &&
	  *(cursor + 3) == 'o' &&
	  *(cursor + 4) == 'n')
	{
	  token_stream[(int) index++].kind = Token_union;
	  return;
	}
      if (*(cursor + 1) == 's' &&
	  *(cursor + 2) == 'i' &&
	  *(cursor + 3) == 'n' &&
	  *(cursor + 4) == 'g')
	{
	  token_stream[(int) index++].kind = Token_using;
	  return;
	}
      break;

    case 't':
      if (*(cursor + 1) == 'h' &&
	  *(cursor + 2) == 'r' &&
	  *(cursor + 3) == 'o' &&
	  *(cursor + 4) == 'w')
	{
	  token_stream[(int) index++].kind = Token_throw;
	  return;
	}
      break;

    case 'w':
      if (*(cursor + 1) == 'h' &&
	  *(cursor + 2) == 'i' &&
	  *(cursor + 3) == 'l' &&
	  *(cursor + 4) == 'e')
	{
	  token_stream[(int) index++].kind = Token_while;
	  return;
	}
      break;

    }
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword6()
{
  switch (*cursor)
    {
    case 'a':
      if (*(cursor + 1) == 'n' &&
	  *(cursor + 2) == 'd' &&
	  *(cursor + 3) == '_' &&
	  *(cursor + 4) == 'e' &&
	  *(cursor + 5) == 'q')
	{
	  token_stream[(int) index++].kind = Token_and_eq;
	  return;
	}
      break;

    case 'b':
      if (*(cursor + 1) == 'i' &&
	  *(cursor + 2) == 't' &&
	  *(cursor + 3) == 'a' &&
	  *(cursor + 4) == 'n' &&
	  *(cursor + 5) == 'd')
	{
	  token_stream[(int) index++].kind = Token_bitand;
	  return;
	}
      break;

    case 'e':
      if (*(cursor + 1) == 'x' &&
	  *(cursor + 2) == 'p' &&
	  *(cursor + 3) == 'o' &&
	  *(cursor + 4) == 'r' &&
	  *(cursor + 5) == 't')
	{
	  token_stream[(int) index++].kind = Token_export;
	  return;
	}
      if (*(cursor + 1) == 'x' &&
	  *(cursor + 2) == 't' &&
	  *(cursor + 3) == 'e' &&
	  *(cursor + 4) == 'r' &&
	  *(cursor + 5) == 'n')
	{
	  token_stream[(int) index++].kind = Token_extern;
	  return;
	}
      break;

    case 'd':
      if (*(cursor + 1) == 'e' &&
	  *(cursor + 2) == 'l' &&
	  *(cursor + 3) == 'e' &&
	  *(cursor + 4) == 't' &&
	  *(cursor + 5) == 'e')
	{
	  token_stream[(int) index++].kind = Token_delete;
	  return;
	}
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 'u' &&
	  *(cursor + 3) == 'b' &&
	  *(cursor + 4) == 'l' &&
	  *(cursor + 5) == 'e')
	{
	  token_stream[(int) index++].kind = Token_double;
	  return;
	}
      break;

    case 'f':
      if (*(cursor + 1) == 'r' &&
	  *(cursor + 2) == 'i' &&
	  *(cursor + 3) == 'e' &&
	  *(cursor + 4) == 'n' &&
	  *(cursor + 5) == 'd')
	{
	  token_stream[(int) index++].kind = Token_friend;
	  return;
	}
      break;

    case 'i':
      if (*(cursor + 1) == 'n' &&
	  *(cursor + 2) == 'l' &&
	  *(cursor + 3) == 'i' &&
	  *(cursor + 4) == 'n' &&
	  *(cursor + 5) == 'e')
	{
	  token_stream[(int) index++].kind = Token_inline;
	  return;
	}
      break;

    case 'K':
      if (*(cursor + 1) == '_' &&
	  *(cursor + 2) == 'D' &&
	  *(cursor + 3) == 'C' &&
	  *(cursor + 4) == 'O' &&
	  *(cursor + 5) == 'P')
	{
	  token_stream[(int) index++].kind = Token_K_DCOP;
	  return;
	}
      break;

    case 'n':
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 't' &&
	  *(cursor + 3) == '_' &&
	  *(cursor + 4) == 'e' &&
	  *(cursor + 5) == 'q')
	{
	  token_stream[(int) index++].kind = Token_not_eq;
	  return;
	}
      break;

    case 'p':
      if (*(cursor + 1) == 'u' &&
	  *(cursor + 2) == 'b' &&
	  *(cursor + 3) == 'l' &&
	  *(cursor + 4) == 'i' &&
	  *(cursor + 5) == 'c')
	{
	  token_stream[(int) index++].kind = Token_public;
	  return;
	}
      break;

    case 's':
      if (*(cursor + 1) == 'i' &&
	  *(cursor + 2) == 'g' &&
	  *(cursor + 3) == 'n' &&
	  *(cursor + 4) == 'e' &&
	  *(cursor + 5) == 'd')
	{
	  token_stream[(int) index++].kind = Token_signed;
	  return;
	}
      if (*(cursor + 1) == 'i' &&
	  *(cursor + 2) == 'z' &&
	  *(cursor + 3) == 'e' &&
	  *(cursor + 4) == 'o' &&
	  *(cursor + 5) == 'f')
	{
	  token_stream[(int) index++].kind = Token_sizeof;
	  return;
	}
      if (*(cursor + 1) == 't' &&
	  *(cursor + 2) == 'a' &&
	  *(cursor + 3) == 't' &&
	  *(cursor + 4) == 'i' &&
	  *(cursor + 5) == 'c')
	{
	  token_stream[(int) index++].kind = Token_static;
	  return;
	}
      if (*(cursor + 1) == 't' &&
	  *(cursor + 2) == 'r' &&
	  *(cursor + 3) == 'u' &&
	  *(cursor + 4) == 'c' &&
	  *(cursor + 5) == 't')
	{
	  token_stream[(int) index++].kind = Token_struct;
	  return;
	}
      if (*(cursor + 1) == 'w' &&
	  *(cursor + 2) == 'i' &&
	  *(cursor + 3) == 't' &&
	  *(cursor + 4) == 'c' &&
	  *(cursor + 5) == 'h')
	{
	  token_stream[(int) index++].kind = Token_switch;
	  return;
	}
      break;

    case 'r':
      if (*(cursor + 1) == 'e' &&
	  *(cursor + 2) == 't' &&
	  *(cursor + 3) == 'u' &&
	  *(cursor + 4) == 'r' &&
	  *(cursor + 5) == 'n')
	{
	  token_stream[(int) index++].kind = Token_return;
	  return;
	}
      break;

    case 't':
      if (*(cursor + 1) == 'y' &&
	  *(cursor + 2) == 'p' &&
	  *(cursor + 3) == 'e' &&
	  *(cursor + 4) == 'i' &&
	  *(cursor + 5) == 'd')
	{
	  token_stream[(int) index++].kind = Token_typeid;
	  return;
	}
      break;

    case 'x':
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 'r' &&
	  *(cursor + 3) == '_' &&
	  *(cursor + 4) == 'e' &&
	  *(cursor + 5) == 'q')
	{
	  token_stream[(int) index++].kind = Token_xor_eq;
	  return;
	}
      break;

    case 'k':
      if (*(cursor + 1) == '_' &&
	  *(cursor + 2) == 'd' &&
	  *(cursor + 3) == 'c' &&
	  *(cursor + 4) == 'o' &&
	  *(cursor + 5) == 'p')
	{
	  token_stream[(int) index++].kind = Token_k_dcop;
	  return;
	}
      break;

    }
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword7()
{
  switch (*cursor)
    {
    case 'd':
      if (*(cursor + 1) == 'e' &&
	  *(cursor + 2) == 'f' &&
	  *(cursor + 3) == 'a' &&
	  *(cursor + 4) == 'u' &&
	  *(cursor + 5) == 'l' &&
	  *(cursor + 6) == 't')
	{
	  token_stream[(int) index++].kind = Token_default;
	  return;
	}
      break;

    case 'm':
      if (*(cursor + 1) == 'u' &&
	  *(cursor + 2) == 't' &&
	  *(cursor + 3) == 'a' &&
	  *(cursor + 4) == 'b' &&
	  *(cursor + 5) == 'l' &&
	  *(cursor + 6) == 'e')
	{
	  token_stream[(int) index++].kind = Token_mutable;
	  return;
	}
      break;

    case 'p':
      if (*(cursor + 1) == 'r' &&
	  *(cursor + 2) == 'i' &&
	  *(cursor + 3) == 'v' &&
	  *(cursor + 4) == 'a' &&
	  *(cursor + 5) == 't' &&
	  *(cursor + 6) == 'e')
	{
	  token_stream[(int) index++].kind = Token_private;
	  return;
	}
      break;
    case 's':
      if (*(cursor + 1) == 'i' &&
	  *(cursor + 2) == 'g' &&
	  *(cursor + 3) == 'n' &&
	  *(cursor + 4) == 'a' &&
	  *(cursor + 5) == 'l' &&
	  *(cursor + 6) == 's')
	{
	  token_stream[(int) index++].kind = Token_signals;
	  return;
	}
      break;
    case 't':
      if (*(cursor + 1) == 'y' &&
	  *(cursor + 2) == 'p' &&
	  *(cursor + 3) == 'e' &&
	  *(cursor + 4) == 'd' &&
	  *(cursor + 5) == 'e' &&
	  *(cursor + 6) == 'f')
	{
	  token_stream[(int) index++].kind = Token_typedef;
	  return;
	}
      break;

    case 'v':
      if (*(cursor + 1) == 'i' &&
	  *(cursor + 2) == 'r' &&
	  *(cursor + 3) == 't' &&
	  *(cursor + 4) == 'u' &&
	  *(cursor + 5) == 'a' &&
	  *(cursor + 6) == 'l')
	{
	  token_stream[(int) index++].kind = Token_virtual;
	  return;
	}
      break;

    case 'Q':
      if (*(cursor + 1) == '_' &&
      *(cursor + 2) == 'E' &&
      *(cursor + 3) == 'N' &&
      *(cursor + 4) == 'U' &&
      *(cursor + 5) == 'M' &&
      *(cursor + 6) == 'S')
      {
        token_stream[(int) index++].kind = Token_Q_ENUMS;
        return;
      }
        break;

    }
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword8()
{
  switch (*cursor)
    {
    case '_':
      if (*(cursor + 1) == '_' &&
	  *(cursor + 2) == 't' &&
	  *(cursor + 3) == 'y' &&
	  *(cursor + 4) == 'p' &&
	  *(cursor + 5) == 'e' &&
	  *(cursor + 6) == 'o' &&
	  *(cursor + 7) == 'f')
	{
	  token_stream[(int) index++].kind = Token___typeof;
	  return;
	}
      break;

    case 'c':
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 'n' &&
	  *(cursor + 3) == 't' &&
	  *(cursor + 4) == 'i' &&
	  *(cursor + 5) == 'n' &&
	  *(cursor + 6) == 'u' &&
	  *(cursor + 7) == 'e')
	{
	  token_stream[(int) index++].kind = Token_continue;
	  return;
	}
      break;

    case 'e':
      if (*(cursor + 1) == 'x' &&
	  *(cursor + 2) == 'p' &&
	  *(cursor + 3) == 'l' &&
	  *(cursor + 4) == 'i' &&
	  *(cursor + 5) == 'c' &&
	  *(cursor + 6) == 'i' &&
	  *(cursor + 7) == 't')
	{
	  token_stream[(int) index++].kind = Token_explicit;
	  return;
	}
      break;

    case 'o':
      if (*(cursor + 1) == 'p' &&
	  *(cursor + 2) == 'e' &&
	  *(cursor + 3) == 'r' &&
	  *(cursor + 4) == 'a' &&
	  *(cursor + 5) == 't' &&
	  *(cursor + 6) == 'o' &&
	  *(cursor + 7) == 'r')
	{
	  token_stream[(int) index++].kind = Token_operator;
	  return;
	}
      break;

    case 'Q':
      if (*(cursor + 1) == '_' &&
	  *(cursor + 2) == 'O' &&
	  *(cursor + 3) == 'B' &&
	  *(cursor + 4) == 'J' &&
	  *(cursor + 5) == 'E' &&
	  *(cursor + 6) == 'C' &&
	  *(cursor + 7) == 'T')
	{
	  token_stream[(int) index++].kind = Token_Q_OBJECT;
	  return;
	}
      break;

    case 'r':
      if (*(cursor + 1) == 'e' &&
	  *(cursor + 2) == 'g' &&
	  *(cursor + 3) == 'i' &&
	  *(cursor + 4) == 's' &&
	  *(cursor + 5) == 't' &&
	  *(cursor + 6) == 'e' &&
	  *(cursor + 7) == 'r')
	{
	  token_stream[(int) index++].kind = Token_register;
	  return;
	}
      break;

    case 'u':
      if (*(cursor + 1) == 'n' &&
	  *(cursor + 2) == 's' &&
	  *(cursor + 3) == 'i' &&
	  *(cursor + 4) == 'g' &&
	  *(cursor + 5) == 'n' &&
	  *(cursor + 6) == 'e' &&
	  *(cursor + 7) == 'd')
	{
	  token_stream[(int) index++].kind = Token_unsigned;
	  return;
	}
      break;

    case 't':
      if (*(cursor + 1) == 'e' &&
	  *(cursor + 2) == 'm' &&
	  *(cursor + 3) == 'p' &&
	  *(cursor + 4) == 'l' &&
	  *(cursor + 5) == 'a' &&
	  *(cursor + 6) == 't' &&
	  *(cursor + 7) == 'e')
	{
	  token_stream[(int) index++].kind = Token_template;
	  return;
	}
      if (*(cursor + 1) == 'y' &&
	  *(cursor + 2) == 'p' &&
	  *(cursor + 3) == 'e' &&
	  *(cursor + 4) == 'n' &&
	  *(cursor + 5) == 'a' &&
	  *(cursor + 6) == 'm' &&
	  *(cursor + 7) == 'e')
	{
	  token_stream[(int) index++].kind = Token_typename;
	  return;
	}
      break;

    case 'v':
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 'l' &&
	  *(cursor + 3) == 'a' &&
	  *(cursor + 4) == 't' &&
	  *(cursor + 5) == 'i' &&
	  *(cursor + 6) == 'l' &&
	  *(cursor + 7) == 'e')
	{
	  token_stream[(int) index++].kind = Token_volatile;
	  return;
	}
      break;

    }
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword9()
{
  switch (*cursor)
    {
    case 'p':
      if (*(cursor + 1) == 'r' &&
	  *(cursor + 2) == 'o' &&
	  *(cursor + 3) == 't' &&
	  *(cursor + 4) == 'e' &&
	  *(cursor + 5) == 'c' &&
	  *(cursor + 6) == 't' &&
	  *(cursor + 7) == 'e' &&
	  *(cursor + 8) == 'd')
	{
	  token_stream[(int) index++].kind = Token_protected;
	  return;
	}
      break;

    case 'n':
      if (*(cursor + 1) == 'a' &&
	  *(cursor + 2) == 'm' &&
	  *(cursor + 3) == 'e' &&
	  *(cursor + 4) == 's' &&
	  *(cursor + 5) == 'p' &&
	  *(cursor + 6) == 'a' &&
	  *(cursor + 7) == 'c' &&
	  *(cursor + 8) == 'e')
	{
	  token_stream[(int) index++].kind = Token_namespace;
	  return;
	}
      break;

    }
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword10()
{
  switch (*cursor)
    {
    case 'c':
      if (*(cursor + 1) == 'o' &&
	  *(cursor + 2) == 'n' &&
	  *(cursor + 3) == 's' &&
	  *(cursor + 4) == 't' &&
	  *(cursor + 5) == '_' &&
	  *(cursor + 6) == 'c' &&
	  *(cursor + 7) == 'a' &&
	  *(cursor + 8) == 's' &&
	  *(cursor + 9) == 't')
	{
	  token_stream[(int) index++].kind = Token_const_cast;
	  return;
	}
      break;

    case 'Q':
        if (*(cursor + 1) == '_' &&
            *(cursor + 2) == 'P' &&
            *(cursor + 3) == 'R' &&
            *(cursor + 4) == 'O' &&
            *(cursor + 5) == 'P' &&
            *(cursor + 6) == 'E' &&
            *(cursor + 7) == 'R' &&
            *(cursor + 8) == 'T' &&
            *(cursor + 9) == 'Y')
          {
            token_stream[(int) index++].kind = Token_Q_PROPERTY;
            return;
          }

        break;
    }

  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword11()
{
  switch (*cursor)
    {
    case 'Q':
      if (*(cursor + 1) == '_' &&
	  *(cursor + 2) == 'I' &&
	  *(cursor + 3) == 'N' &&
	  *(cursor + 4) == 'V' &&
	  *(cursor + 5) == 'O' &&
	  *(cursor + 6) == 'K' &&
	  *(cursor + 7) == 'A' &&
	  *(cursor + 8) == 'B' &&
	  *(cursor + 9) == 'L' &&
	  *(cursor + 10) == 'E')
	{
	  token_stream[(int) index++].kind = Token_Q_INVOKABLE;
	  return;
	}
      break;

    case 's':
      if (*(cursor + 1) == 't' &&
	  *(cursor + 2) == 'a' &&
	  *(cursor + 3) == 't' &&
	  *(cursor + 4) == 'i' &&
	  *(cursor + 5) == 'c' &&
	  *(cursor + 6) == '_' &&
	  *(cursor + 7) == 'c' &&
	  *(cursor + 8) == 'a' &&
	  *(cursor + 9) == 's' &&
	  *(cursor + 10) == 't')
	{
	  token_stream[(int) index++].kind = Token_static_cast;
	  return;
	}
      break;

    }
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword12()
{
  switch (*cursor)
    {
    case 'd':
      if (*(cursor + 1) == 'y' &&
	  *(cursor + 2) == 'n' &&
	  *(cursor + 3) == 'a' &&
	  *(cursor + 4) == 'm' &&
	  *(cursor + 5) == 'i' &&
	  *(cursor + 6) == 'c' &&
	  *(cursor + 7) == '_' &&
	  *(cursor + 8) == 'c' &&
	  *(cursor + 9) == 'a' &&
	  *(cursor + 10) == 's' &&
	  *(cursor + 11) == 't')
	{
	  token_stream[(int) index++].kind = Token_dynamic_cast;
	  return;
	}
      break;

    }
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword13()
{
  switch (*cursor)
    {
    case '_':
      if (*(cursor + 1) == '_' &&
	  *(cursor + 2) == 'a' &&
	  *(cursor + 3) == 't' &&
	  *(cursor + 4) == 't' &&
	  *(cursor + 5) == 'r' &&
	  *(cursor + 6) == 'i' &&
	  *(cursor + 7) == 'b' &&
	  *(cursor + 8) == 'u' &&
	  *(cursor + 9) == 't' &&
	  *(cursor + 10) == 'e' &&
	  *(cursor + 11) == '_' &&
	  *(cursor + 12) == '_')
	{
	  token_stream[(int) index++].kind = Token___attribute__;
	  return;
	}
      break;
    }
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword14()
{
  switch (*cursor)
    {
    case 'k':
      if (*(cursor + 1) == '_' &&
	  *(cursor + 2) == 'd' &&
	  *(cursor + 3) == 'c' &&
	  *(cursor + 4) == 'o' &&
	  *(cursor + 5) == 'p' &&
	  *(cursor + 6) == '_' &&
	  *(cursor + 7) == 's' &&
	  *(cursor + 8) == 'i' &&
	  *(cursor + 9) == 'g' &&
	  *(cursor + 10) == 'n' &&
	  *(cursor + 11) == 'a' &&
	  *(cursor + 12) == 'l' &&
	  *(cursor + 13) == 's')
	{
	  token_stream[(int) index++].kind = Token_k_dcop_signals;
	  return;
	}
      break;
    }
  token_stream[(int) index++].kind = Token_identifier;
}

void Lexer::scanKeyword16()
{
  switch (*cursor)
    {
    case 'r':
      if (*(cursor + 1) == 'e' &&
	  *(cursor + 2) == 'i' &&
	  *(cursor + 3) == 'n' &&
	  *(cursor + 4) == 't' &&
	  *(cursor + 5) == 'e' &&
	  *(cursor + 6) == 'r' &&
	  *(cursor + 7) == 'p' &&
	  *(cursor + 8) == 'r' &&
	  *(cursor + 9) == 'e' &&
	  *(cursor + 10) == 't' &&
	  *(cursor + 11) == '_' &&
	  *(cursor + 12) == 'c' &&
	  *(cursor + 13) == 'a' &&
	  *(cursor + 14) == 's' &&
	  *(cursor + 15) == 't')
	{
	  token_stream[(int) index++].kind = Token_reinterpret_cast;
	  return;
	}
      break;
    }

  token_stream[(int) index++].kind = Token_identifier;
}

// kate: space-indent on; indent-width 2; replace-tabs on;
