/****************************************************************************
**
** Copyright (C) 1992-2008 Nokia. All rights reserved.
** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
**
** This file is part of Qt Jambi.
**
** * Commercial Usage
* Licensees holding valid Qt Commercial licenses may use this file in
* accordance with the Qt Commercial License Agreement provided with the
* Software or, alternatively, in accordance with the terms contained in
* a written agreement between you and Nokia.
*
*
* GNU General Public License Usage
* Alternatively, this file may be used under the terms of the GNU
* General Public License versions 2.0 or 3.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.fsf.org/licensing/licenses/info/GPLv2.html and
* http://www.gnu.org/copyleft/gpl.html.  In addition, as a special
* exception, Nokia gives you certain additional rights. These rights
* are described in the Nokia Qt GPL Exception version 1.2, included in
* the file GPL_EXCEPTION.txt in this package.
* 
* Qt for Windows(R) Licensees
* As a special exception, Nokia, as the sole copyright holder for Qt
* Designer, grants users of the Qt/Eclipse Integration plug-in the
* right for the Qt/Eclipse Integration to link to functionality
* provided by Qt Designer and its related libraries.
*
*
* If you are unsure which license is appropriate for your use, please
* contact the sales department at qt-sales@nokia.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.
**
****************************************************************************/

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */


// c++ support
#include "parser.h"
#include "tokens.h"
#include "lexer.h"
#include "control.h"

#include <cstdlib>
#include <iostream>

#define ADVANCE(tk, descr) \
{ \
  if (token_stream.lookAhead() != tk) { \
      tokenRequiredError(tk); \
      return false; \
  } \
  token_stream.nextToken(); \
}

#define ADVANCE_NR(tk, descr) \
  do { \
    if (token_stream.lookAhead() != tk) { \
      tokenRequiredError(tk); \
    } \
    else \
        token_stream.nextToken(); \
  } while (0)

#define CHECK(tk) \
  do { \
    if (token_stream.lookAhead() != tk) { \
        return false; \
    } \
    token_stream.nextToken(); \
  } while (0)

#define UPDATE_POS(_node, start, end) \
  do { \
      (_node)->start_token = start; \
      (_node)->end_token = end; \
  } while (0)

Parser::Parser(Control *c)
  : _M_location(token_stream, location_table, line_table),
    control(c),
    lexer(_M_location, control)
{
  _M_block_errors = false;
}

Parser::~Parser()
{
}

void Parser::advance()
{
  token_stream.nextToken();
}

TranslationUnitAST *Parser::parse(const char *contents,
                                  std::size_t size, pool *p)
{
  _M_block_errors = false;
  _M_pool = p;
  lexer.tokenize(contents, size);
  token_stream.nextToken(); // skip the first token

  Lexer *oldLexer = control->changeLexer (&lexer);
  Parser *oldParser = control->changeParser (this);

  TranslationUnitAST *ast = 0;
  parseTranslationUnit(ast);

  control->changeLexer (oldLexer);
  control->changeParser (oldParser);

  return ast;
}

bool Parser::parseWinDeclSpec(WinDeclSpecAST *&node)
{
  if (token_stream.lookAhead() != Token_identifier)
    return false;

  std::size_t start = token_stream.cursor();

  const NameSymbol *name_symbol = token_stream.symbol(token_stream.cursor());
  QString name = name_symbol->as_string();
  if (name != QLatin1String("__declspec"))
    return false;
  std::size_t specifier = token_stream.cursor();

  token_stream.nextToken();
  if (token_stream.lookAhead() != '(')
    return false;

  token_stream.nextToken();
  if (token_stream.lookAhead() != Token_identifier)
    return false;
  std::size_t modifier = token_stream.cursor();

  token_stream.nextToken();
  if (token_stream.lookAhead() != ')')
    return false;

  token_stream.nextToken();

  node = CreateNode<WinDeclSpecAST>(_M_pool);
  node->specifier = specifier;
  node->modifier = modifier;

  UPDATE_POS(node, start, token_stream.cursor());

  return true;
}

void Parser::tokenRequiredError(int token)
{
  QString err;

  err += "expected token ";
  err += "``";
  err += token_name(token);
  err += "'' found ``";
  err += token_name(token_stream.lookAhead());
  err += "''";

  reportError(err);
}

void Parser::syntaxError()
{
  QString err;

  err += "unexpected token ";
  err += "``";
  err += token_name(token_stream.lookAhead());
  err += "''";

  reportError(err);
}

void Parser::reportError(const QString& msg)
{
    if (!_M_block_errors)
    {
        int line, column;
        QString fileName;

        std::size_t tok = token_stream.cursor();
        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("** PARSER ERROR ") + msg);
        control->reportError(errmsg);
    }
}

bool Parser::skipUntil(int token)
{
  while (token_stream.lookAhead())
    {
      if (token_stream.lookAhead() == token)
        return true;

      token_stream.nextToken();
    }

  return false;
}

bool Parser::skipUntilDeclaration()
{
  while (token_stream.lookAhead())
    {

      switch(token_stream.lookAhead())
        {
        case ';':
        case '~':
        case Token_scope:
        case Token_identifier:
        case Token_operator:
        case Token_char:
        case Token_wchar_t:
        case Token_bool:
        case Token_short:
        case Token_int:
        case Token_long:
        case Token_signed:
        case Token_unsigned:
        case Token_float:
        case Token_double:
        case Token_void:
        case Token_extern:
        case Token_namespace:
        case Token_using:
        case Token_typedef:
        case Token_asm:
        case Token_template:
        case Token_export:

        case Token_const:       // cv
        case Token_volatile:    // cv

        case Token_public:
        case Token_protected:
        case Token_private:
        case Token_signals:      // Qt
        case Token_slots:        // Qt
          return true;

        default:
          token_stream.nextToken();
        }
    }

  return false;
}

bool Parser::skipUntilStatement()
{
  while (token_stream.lookAhead())
    {
      switch(token_stream.lookAhead())
        {
        case ';':
        case '{':
        case '}':
        case Token_const:
        case Token_volatile:
        case Token_identifier:
        case Token_case:
        case Token_default:
        case Token_if:
        case Token_switch:
        case Token_while:
        case Token_do:
        case Token_for:
        case Token_break:
        case Token_continue:
        case Token_return:
        case Token_goto:
        case Token_try:
        case Token_catch:
        case Token_throw:
        case Token_char:
        case Token_wchar_t:
        case Token_bool:
        case Token_short:
        case Token_int:
        case Token_long:
        case Token_signed:
        case Token_unsigned:
        case Token_float:
        case Token_double:
        case Token_void:
        case Token_class:
        case Token_struct:
        case Token_union:
        case Token_enum:
        case Token_scope:
        case Token_template:
        case Token_using:
          return true;

        default:
          token_stream.nextToken();
        }
    }

  return false;
}

bool Parser::skip(int l, int r)
{
  int count = 0;
  while (token_stream.lookAhead())
    {
      int tk = token_stream.lookAhead();

      if (tk == l)
        ++count;
      else if (tk == r)
        --count;
      else if (l != '{' && (tk == '{' || tk == '}' || tk == ';'))
        return false;

      if (count == 0)
        return true;

      token_stream.nextToken();
    }

  return false;
}

bool Parser::parseName(NameAST *&node, bool acceptTemplateId)
{
  std::size_t start = token_stream.cursor();

  WinDeclSpecAST *winDeclSpec = 0;
  parseWinDeclSpec(winDeclSpec);

  NameAST *ast = CreateNode<NameAST>(_M_pool);

  if (token_stream.lookAhead() == Token_scope)
    {
      ast->global = true;
      token_stream.nextToken();
    }

  std::size_t idx = token_stream.cursor();

  while (true)
    {
      UnqualifiedNameAST *n = 0;
      if (!parseUnqualifiedName(n))
        return false;

      if (token_stream.lookAhead() == Token_scope)
        {
          token_stream.nextToken();

          ast->qualified_names
            = snoc(ast->qualified_names, n, _M_pool);

          if (token_stream.lookAhead() == Token_template)
            {
              /// skip optional template     #### @todo CHECK
              token_stream.nextToken();
            }
        }
      else
        {
          Q_ASSERT(n != 0);
          if (!acceptTemplateId)
            {
              token_stream.rewind((int) n->start_token);
              parseUnqualifiedName(n, false);
            }

          ast->unqualified_name = n;
          break;
        }
    }

  if (idx == token_stream.cursor())
    return false;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseTranslationUnit(TranslationUnitAST *&node)
{
  std::size_t start = token_stream.cursor();
  TranslationUnitAST *ast = CreateNode<TranslationUnitAST>(_M_pool);

  while (token_stream.lookAhead())
    {
      std::size_t startDecl = token_stream.cursor();

      DeclarationAST *declaration = 0;
      if (parseDeclaration(declaration))
        {
          ast->declarations =
            snoc(ast->declarations, declaration, _M_pool);
        }
      else
        {
          // error recovery
          if (startDecl == token_stream.cursor())
            {
              // skip at least one token
              token_stream.nextToken();
            }

          skipUntilDeclaration();
        }
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseDeclaration(DeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  switch(token_stream.lookAhead())
    {
    case ';':
      token_stream.nextToken();
      return true;

    case Token_extern:
      return parseLinkageSpecification(node);

    case Token_namespace:
      return parseNamespace(node);

    case Token_using:
      return parseUsing(node);

    case Token_typedef:
      return parseTypedef(node);

    case Token_asm:
      return parseAsmDefinition(node);

    case Token_Q_ENUMS:
        return parseQ_ENUMS(node);

    case Token_template:
    case Token_export:
      return parseTemplateDeclaration(node);

    default:
      {
        const ListNode<std::size_t> *cv = 0;
        parseCvQualify(cv);

        const ListNode<std::size_t> *storageSpec = 0;
        parseStorageClassSpecifier(storageSpec);

        parseCvQualify(cv);

        TypeSpecifierAST *spec = 0;
        if (parseEnumSpecifier(spec)
            || parseClassSpecifier(spec)
            || parseForwardDeclarationSpecifier(spec))
          {
            parseCvQualify(cv);

            spec->cv = cv;

            const ListNode<InitDeclaratorAST*> *declarators = 0;
            parseInitDeclaratorList(declarators);
            ADVANCE(';', ";");

            SimpleDeclarationAST *ast =
              CreateNode<SimpleDeclarationAST>(_M_pool);

            ast->storage_specifiers = storageSpec;
            ast->type_specifier = spec;
            ast->init_declarators = declarators;
            UPDATE_POS(ast, start, token_stream.cursor());
            node = ast;

            return true;
          }
      }
    } // end switch

  token_stream.rewind((int) start);
  return parseDeclarationInternal(node);
}

bool Parser::parseLinkageSpecification(DeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(Token_extern);

  LinkageSpecificationAST *ast = CreateNode<LinkageSpecificationAST>(_M_pool);

  if (token_stream.lookAhead() == Token_string_literal)
    {
      ast->extern_type = token_stream.cursor();
      token_stream.nextToken();
    }

  if (token_stream.lookAhead() == '{')
    {
      parseLinkageBody(ast->linkage_body);
    }
  else if (!parseDeclaration(ast->declaration))
    {
      reportError(("Declaration syntax error"));
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseLinkageBody(LinkageBodyAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK('{');

  LinkageBodyAST *ast = CreateNode<LinkageBodyAST>(_M_pool);

  while (token_stream.lookAhead())
    {
      int tk = token_stream.lookAhead();

      if (tk == '}')
        break;

      std::size_t startDecl = token_stream.cursor();

      DeclarationAST *declaration = 0;
      if (parseDeclaration(declaration))
        {
          ast->declarations = snoc(ast->declarations, declaration, _M_pool);
        }
      else
        {
          // error recovery
          if (startDecl == token_stream.cursor())
            {
              // skip at least one token
              token_stream.nextToken();
            }

          skipUntilDeclaration();
        }
    }

  if (token_stream.lookAhead() != '}')
    reportError(("} expected"));
  else
    token_stream.nextToken();

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseNamespace(DeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(Token_namespace);

  std::size_t namespace_name = 0;
  if (token_stream.lookAhead() == Token_identifier)
    {
      namespace_name = token_stream.cursor();
      token_stream.nextToken();
    }

  if (token_stream.lookAhead() == '=')
    {
      // namespace alias
      token_stream.nextToken();

      NameAST *name = 0;
      if (parseName(name))
        {
          ADVANCE(';', ";");

          NamespaceAliasDefinitionAST *ast
            = CreateNode<NamespaceAliasDefinitionAST>(_M_pool);
          ast->namespace_name = namespace_name;
          ast->alias_name = name;
          UPDATE_POS(ast, start, token_stream.cursor());
          node = ast;
          return true;
        }
      else
        {
          reportError(("namespace expected"));
          return false;
        }
    }
  else if (token_stream.lookAhead() != '{')
    {
      reportError(("{ expected"));
      return false;
    }

  NamespaceAST *ast = CreateNode<NamespaceAST>(_M_pool);
  ast->namespace_name = namespace_name;
  parseLinkageBody(ast->linkage_body);

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseUsing(DeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(Token_using);

  if (token_stream.lookAhead() == Token_namespace)
    return parseUsingDirective(node);

  UsingAST *ast = CreateNode<UsingAST>(_M_pool);

  if (token_stream.lookAhead() == Token_typename)
    {
      ast->type_name = token_stream.cursor();
      token_stream.nextToken();
    }

  if (!parseName(ast->name))
    return false;

  ADVANCE(';', ";");

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseUsingDirective(DeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(Token_namespace);

  NameAST *name = 0;
  if (!parseName(name))
    {
      reportError(("Namespace name expected"));
      return false;
    }

  ADVANCE(';', ";");

  UsingDirectiveAST *ast = CreateNode<UsingDirectiveAST>(_M_pool);
  ast->name = name;
  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}


bool Parser::parseOperatorFunctionId(OperatorFunctionIdAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(Token_operator);

  OperatorFunctionIdAST *ast = CreateNode<OperatorFunctionIdAST>(_M_pool);

  if (!parseOperator(ast->op))
    {
      ast->op = 0;

      // parse cast operator
      const ListNode<std::size_t> *cv = 0;
      parseCvQualify(cv);

      if (!parseSimpleTypeSpecifier(ast->type_specifier))
        {
          syntaxError();
          return false;
        }

      parseCvQualify(cv);
      ast->type_specifier->cv = cv;

      PtrOperatorAST *ptr_op = 0;
      while (parsePtrOperator(ptr_op))
        ast->ptr_ops = snoc(ast->ptr_ops, ptr_op, _M_pool);
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;
  return true;
}

bool Parser::parseTemplateArgumentList(const ListNode<TemplateArgumentAST*> *&node,
                                       bool reportError)
{
  TemplateArgumentAST *templArg = 0;
  if (!parseTemplateArgument(templArg))
    return false;

  node = snoc(node, templArg, _M_pool);

  while (token_stream.lookAhead() == ',')
    {
      token_stream.nextToken();

      if (!parseTemplateArgument(templArg))
        {
          if (reportError)
            {
              syntaxError();
              break;
            }

          node = 0;
          return false;
        }

      node = snoc(node, templArg, _M_pool);
    }

  return true;
}

bool Parser::parseTypedef(DeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(Token_typedef);

  TypeSpecifierAST *spec = 0;
  if (!parseTypeSpecifierOrClassSpec(spec))
    {
      reportError(("Need a type specifier to declare"));
      return false;
    }

  const ListNode<InitDeclaratorAST*> *declarators = 0;
  if (!parseInitDeclaratorList(declarators))
    {
      //reportError(("Need an identifier to declare"));
      //return false;
    }

  ADVANCE(';', ";");

  TypedefAST *ast = CreateNode<TypedefAST>(_M_pool);
  ast->type_specifier = spec;
  ast->init_declarators = declarators;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseAsmDefinition(DeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  ADVANCE(Token_asm, "asm");

  const ListNode<std::size_t> *cv = 0;
  parseCvQualify(cv);

#if defined(__GNUC__)
#warning "implement me"
#endif
  skip('(', ')');
  token_stream.nextToken();
  ADVANCE(';', ";");

  AsmDefinitionAST *ast = CreateNode<AsmDefinitionAST>(_M_pool);
  ast->cv = cv;
  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseTemplateDeclaration(DeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  std::size_t exported = 0;
  if (token_stream.lookAhead() == Token_export)
    {
      exported = token_stream.cursor();
      token_stream.nextToken();
    }

  CHECK(Token_template);

  const ListNode<TemplateParameterAST*> *params = 0;
  if (token_stream.lookAhead() == '<')
    {
      token_stream.nextToken();
      parseTemplateParameterList(params);

      ADVANCE('>', ">");
    }

  DeclarationAST *declaration = 0;
  if (!parseDeclaration(declaration))
    {
      reportError(("expected a declaration"));
    }

  TemplateDeclarationAST *ast = CreateNode<TemplateDeclarationAST>(_M_pool);
  ast->exported = exported;
  ast->template_parameters = params;
  ast->declaration = declaration;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseOperator(OperatorAST *&node)
{
  std::size_t start = token_stream.cursor();

  OperatorAST *ast = CreateNode<OperatorAST>(_M_pool);

  switch(token_stream.lookAhead())
    {
    case Token_new:
    case Token_delete:
      {
        ast->op = token_stream.cursor();
        token_stream.nextToken();

        if (token_stream.lookAhead() == '['
            && token_stream.lookAhead(1) == ']')
          {
            ast->open = token_stream.cursor();
            token_stream.nextToken();

            ast->close = token_stream.cursor();
            token_stream.nextToken();
          }
      }
      break;

    case '+':
    case '-':
    case '*':
    case '/':
    case '%':
    case '^':
    case '&':
    case '|':
    case '~':
    case '!':
    case '=':
    case '<':
    case '>':
    case ',':
    case Token_assign:
    case Token_shift:
    case Token_eq:
    case Token_not_eq:
    case Token_leq:
    case Token_geq:
    case Token_and:
    case Token_or:
    case Token_incr:
    case Token_decr:
    case Token_ptrmem:
    case Token_arrow:
      ast->op = token_stream.cursor();
      token_stream.nextToken();
      break;

    default:
      if (token_stream.lookAhead() == '('
          && token_stream.lookAhead(1) == ')')
        {
          ast->op = ast->open = token_stream.cursor();
          token_stream.nextToken();
          ast->close = token_stream.cursor();
          token_stream.nextToken();
        }
      else if (token_stream.lookAhead() == '['
               && token_stream.lookAhead(1) == ']')
        {
          ast->op = ast->open = token_stream.cursor();
          token_stream.nextToken();
          ast->close = token_stream.cursor();
          token_stream.nextToken();
        }
      else
        {
          return false;
        }
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseCvQualify(const ListNode<std::size_t> *&node)
{
  std::size_t start = token_stream.cursor();

  int tk;
  while (0 != (tk = token_stream.lookAhead())
         && (tk == Token_const || tk == Token_volatile))
    {
      node = snoc(node, token_stream.cursor(), _M_pool);
      token_stream.nextToken();
    }

  return start != token_stream.cursor();
}

bool Parser::parseSimpleTypeSpecifier(TypeSpecifierAST *&node,
                                      bool onlyIntegral)
{
  std::size_t start = token_stream.cursor();
  bool isIntegral = false;
  bool done = false;

  const ListNode<std::size_t> *integrals = 0;

  while (!done)
    {
      switch(token_stream.lookAhead())
        {
        case Token_char:
        case Token_wchar_t:
        case Token_bool:
        case Token_short:
        case Token_int:
        case Token_long:
        case Token_signed:
        case Token_unsigned:
        case Token_float:
        case Token_double:
        case Token_void:
          integrals = snoc(integrals, token_stream.cursor(), _M_pool);
          isIntegral = true;
          token_stream.nextToken();
          break;

        default:
          done = true;
        }
    }

  SimpleTypeSpecifierAST *ast = CreateNode<SimpleTypeSpecifierAST>(_M_pool);
  if (isIntegral)
    {
      ast->integrals = integrals;
    }
  else if (token_stream.lookAhead() == Token___typeof)
    {
      ast->type_of = token_stream.cursor();
      token_stream.nextToken();

      if (token_stream.lookAhead() == '(')
        {
          token_stream.nextToken();

          std::size_t saved = token_stream.cursor();
          parseTypeId(ast->type_id);
          if (token_stream.lookAhead() != ')')
            {
              ast->type_id = 0;
              token_stream.rewind((int) saved);
              parseUnaryExpression(ast->expression);
            }
          ADVANCE(')', ")");
        }
      else
        {
          parseUnaryExpression(ast->expression);
        }
    }
  else if (onlyIntegral)
    {
      token_stream.rewind((int) start);
      return false;
    }
  else
    {
      if (!parseName(ast->name, true))
        {
          ast->name = 0;
          token_stream.rewind((int) start);
          return false;
        }
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parsePtrOperator(PtrOperatorAST *&node)
{
  int tk = token_stream.lookAhead();

  if (tk != '&' && tk != '*'
      && tk != Token_scope && tk != Token_identifier)
    {
      return false;
    }

  std::size_t start = token_stream.cursor();

  PtrOperatorAST *ast = CreateNode<PtrOperatorAST>(_M_pool);

  switch (token_stream.lookAhead())
    {
    case '&':
    case '*':
      ast->op = token_stream.cursor();
      token_stream.nextToken();
      break;

    case Token_scope:
    case Token_identifier:
      {
        if (!parsePtrToMember(ast->mem_ptr))
          {
            token_stream.rewind((int) start);
            return false;
          }
      }
      break;

    default:
      Q_ASSERT(0);
      break;
    }

  parseCvQualify(ast->cv);

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseTemplateArgument(TemplateArgumentAST *&node)
{
  std::size_t start = token_stream.cursor();

  TypeIdAST *typeId = 0;
  ExpressionAST *expr = 0;

  if (!parseTypeId(typeId) || (token_stream.lookAhead() != ','
                               && token_stream.lookAhead() != '>'))
    {
      token_stream.rewind((int) start);

      if (!parseLogicalOrExpression(expr, true))
        return false;
    }

  TemplateArgumentAST *ast = CreateNode<TemplateArgumentAST>(_M_pool);
  ast->type_id = typeId;
  ast->expression = expr;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseTypeSpecifier(TypeSpecifierAST *&node)
{
  std::size_t start = token_stream.cursor();

  const ListNode<std::size_t> *cv = 0;
  parseCvQualify(cv);

  TypeSpecifierAST *ast = 0;
  if (!parseElaboratedTypeSpecifier(ast) && !parseSimpleTypeSpecifier(ast))
    {
      token_stream.rewind((int) start);
      return false;
    }

  parseCvQualify(cv);
  ast->cv = cv;

  node = ast;

  return true;
}

bool Parser::parseDeclarator(DeclaratorAST *&node)
{
  std::size_t start = token_stream.cursor();

  DeclaratorAST *ast = CreateNode<DeclaratorAST>(_M_pool);

  DeclaratorAST *decl = 0;
  NameAST *declId = 0;

  PtrOperatorAST *ptrOp = 0;
  while (parsePtrOperator(ptrOp))
    {
      ast->ptr_ops = snoc(ast->ptr_ops, ptrOp, _M_pool);
    }

  if (token_stream.lookAhead() == '(')
    {
      token_stream.nextToken();

      if (!parseDeclarator(decl))
        return false;

      ast->sub_declarator = decl;

      CHECK(')');
    }
  else
    {
      if (token_stream.lookAhead() == ':')
        {
          // unnamed bitfield
        }
      else if (parseName(declId, true))
        {
          ast->id = declId;
        }
      else
        {
          token_stream.rewind((int) start);
          return false;
        }

      if (token_stream.lookAhead() == ':')
        {
          token_stream.nextToken();

          if (!parseConstantExpression(ast->bit_expression))
            {
              reportError(("Constant expression expected"));
            }
          goto update_pos;
        }
    }

  {
    bool isVector = true;

    while (token_stream.lookAhead() == '[')
      {
        token_stream.nextToken();

        ExpressionAST *expr = 0;
        parseCommaExpression(expr);

        ADVANCE(']', "]");

        ast->array_dimensions = snoc(ast->array_dimensions, expr, _M_pool);
        isVector = true;
      }

    bool skipParen = false;
    if (token_stream.lookAhead() == Token_identifier
        && token_stream.lookAhead(1) == '('
        && token_stream.lookAhead(2) == '(')
      {
        token_stream.nextToken();
        token_stream.nextToken();
        skipParen = true;
      }

    int tok = token_stream.lookAhead();
    if (ast->sub_declarator
        && !(isVector || tok == '(' || tok == ','
             || tok == ';' || tok == '='))
      {
        token_stream.rewind((int) start);
        return false;
      }

    std::size_t index = token_stream.cursor();
    if (token_stream.lookAhead() == '(')
      {
        token_stream.nextToken();

        ParameterDeclarationClauseAST *params = 0;
        if (!parseParameterDeclarationClause(params))
          {
            token_stream.rewind((int) index);
            goto update_pos;
          }

        ast->parameter_declaration_clause = params;

        if (token_stream.lookAhead() != ')')
          {
            token_stream.rewind((int) index);
            goto update_pos;
          }

        token_stream.nextToken();  // skip ')'

        parseCvQualify(ast->fun_cv);
        parseExceptionSpecification(ast->exception_spec);

        if (token_stream.lookAhead() == Token___attribute__)
          {
          parse_Attribute__();
          }
      }

    if (skipParen)
      {
        if (token_stream.lookAhead() != ')')
          {
            reportError(("')' expected"));
          }
        else
          token_stream.nextToken();
      }
  }

 update_pos:
  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseAbstractDeclarator(DeclaratorAST *&node)
{
  std::size_t start = token_stream.cursor();

  DeclaratorAST *ast = CreateNode<DeclaratorAST>(_M_pool);
  DeclaratorAST *decl = 0;

  PtrOperatorAST *ptrOp = 0;
  while (parsePtrOperator(ptrOp))
    {
      ast->ptr_ops = snoc(ast->ptr_ops, ptrOp, _M_pool);
    }

  int index = (int) token_stream.cursor();
  if (token_stream.lookAhead() == '(')
    {
      token_stream.nextToken();

      if (!parseAbstractDeclarator(decl))
        {
          token_stream.rewind((int) index);
          goto label1;
        }

      ast->sub_declarator = decl;

      if (token_stream.lookAhead() != ')')
        {
          token_stream.rewind((int) start);
          return false;
        }
      token_stream.nextToken();
    }
  else if (token_stream.lookAhead() == ':')
    {
      token_stream.nextToken();
      if (!parseConstantExpression(ast->bit_expression))
        {
          ast->bit_expression = 0;
          reportError(("Constant expression expected"));
        }
      goto update_pos;
    }

 label1:
  {
    bool isVector = true;

    while (token_stream.lookAhead() == '[')
      {
        token_stream.nextToken();

        ExpressionAST *expr = 0;
        parseCommaExpression(expr);

        ADVANCE(']', "]");

        ast->array_dimensions = snoc(ast->array_dimensions, expr, _M_pool);
        isVector = true;
      }

    int tok = token_stream.lookAhead();
    if (ast->sub_declarator
        && !(isVector || tok == '(' || tok == ','
             || tok == ';' || tok == '='))
      {
        token_stream.rewind((int) start);
        return false;
      }

    int index = (int) token_stream.cursor();
    if (token_stream.lookAhead() == '(')
      {
        token_stream.nextToken();

        ParameterDeclarationClauseAST *params = 0;
        if (!parseParameterDeclarationClause(params))
          {
            token_stream.rewind((int) index);
            goto update_pos;
          }

        ast->parameter_declaration_clause = params;

        if (token_stream.lookAhead() != ')')
          {
            token_stream.rewind((int) index);
            goto update_pos;
          }

        token_stream.nextToken();  // skip ')'

        parseCvQualify(ast->fun_cv);
        parseExceptionSpecification(ast->exception_spec);
      }
  }

 update_pos:
  if (token_stream.cursor() == start)
    return false;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseEnumSpecifier(TypeSpecifierAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(Token_enum);

  NameAST *name = 0;
  parseName(name);

  if (token_stream.lookAhead() != '{')
    {
      token_stream.rewind((int) start);
      return false;
    }
  token_stream.nextToken();

  EnumSpecifierAST *ast = CreateNode<EnumSpecifierAST>(_M_pool);
  ast->name = name;

  EnumeratorAST *enumerator = 0;
  if (parseEnumerator(enumerator))
    {
      ast->enumerators = snoc(ast->enumerators, enumerator, _M_pool);

      while (token_stream.lookAhead() == ',')
        {
          token_stream.nextToken();

          if (!parseEnumerator(enumerator))
            {
              //reportError(("Enumerator expected"));
              break;
            }

          ast->enumerators = snoc(ast->enumerators, enumerator, _M_pool);
        }
    }

  ADVANCE_NR('}', "}");

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseTemplateParameterList(const ListNode<TemplateParameterAST*> *&node)
{
  TemplateParameterAST *param = 0;
  if (!parseTemplateParameter(param))
    return false;

  node = snoc(node, param, _M_pool);

  while (token_stream.lookAhead() == ',')
    {
      token_stream.nextToken();

      if (!parseTemplateParameter(param))
        {
          syntaxError();
          break;
        }
      else
        {
          node = snoc(node, param, _M_pool);
        }
    }

  return true;
}

bool Parser::parseTemplateParameter(TemplateParameterAST *&node)
{
  std::size_t start = token_stream.cursor();
  TemplateParameterAST *ast = CreateNode<TemplateParameterAST>(_M_pool);

  int tk = token_stream.lookAhead();

  if ((tk == Token_class || tk == Token_typename || tk == Token_template)
      && parseTypeParameter(ast->type_parameter))
    {
      // nothing to do
    }
  else if (!parseParameterDeclaration(ast->parameter_declaration))
    return false;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseTypeParameter(TypeParameterAST *&node)
{
  std::size_t start = token_stream.cursor();

  TypeParameterAST *ast = CreateNode<TypeParameterAST>(_M_pool);
  ast->type = start;

  switch(token_stream.lookAhead())
    {
    case Token_class:
    case Token_typename:
      {
        token_stream.nextToken(); // skip class

        // parse optional name
        if(parseName(ast->name, true))
          {
            if (token_stream.lookAhead() == '=')
              {
                token_stream.nextToken();

                if(!parseTypeId(ast->type_id))
                  {
                    //syntaxError();
                    token_stream.rewind((int) start);
                    return false;
                  }
              }
            else if (token_stream.lookAhead() != ','
                     && token_stream.lookAhead() != '>')
              {
                token_stream.rewind((int) start);
                return false;
              }
          }
      }
      break;

    case Token_template:
      {
        token_stream.nextToken(); // skip template
        ADVANCE('<', "<");

        if (!parseTemplateParameterList(ast->template_parameters))
          return false;

        ADVANCE('>', ">");

        if (token_stream.lookAhead() == Token_class)
          token_stream.nextToken();

        // parse optional name
        if (parseName(ast->name, true))
          {
            if (token_stream.lookAhead() == '=')
              {
                token_stream.nextToken();

                if (!parseTypeId(ast->type_id))
                  {
                    syntaxError();
                    return false;
                  }
              }
          }

        if (token_stream.lookAhead() == '=')
          {
            token_stream.nextToken();

            parseName(ast->template_name, true);
          }
      }
      break;

    default:
      return false;

    } // end switch


  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;
  return true;
}

bool Parser::parseStorageClassSpecifier(const ListNode<std::size_t> *&node)
{
  std::size_t start = token_stream.cursor();

  int tk;
  while (0 != (tk = token_stream.lookAhead())
         && (tk == Token_friend || tk == Token_auto
             || tk == Token_register || tk == Token_static
             || tk == Token_extern || tk == Token_mutable))
    {
      node = snoc(node, token_stream.cursor(), _M_pool);
      token_stream.nextToken();
    }

  return start != token_stream.cursor();
}

bool Parser::parseFunctionSpecifier(const ListNode<std::size_t> *&node)
{
  std::size_t start = token_stream.cursor();

  int tk;
  while (0 != (tk = token_stream.lookAhead())
         && (tk == Token_inline || tk == Token_virtual
             || tk == Token_explicit || tk == Token_Q_INVOKABLE))
    {
      node = snoc(node, token_stream.cursor(), _M_pool);
      token_stream.nextToken();
    }

  return start != token_stream.cursor();
}

bool Parser::parseTypeId(TypeIdAST *&node)
{
  /// @todo implement the AST for typeId
  std::size_t start = token_stream.cursor();

  TypeSpecifierAST *spec = 0;
  if (!parseTypeSpecifier(spec))
    {
      token_stream.rewind((int) start);
      return false;
    }

  DeclaratorAST *decl = 0;
  parseAbstractDeclarator(decl);

  TypeIdAST *ast = CreateNode<TypeIdAST>(_M_pool);
  ast->type_specifier = spec;
  ast->declarator = decl;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseInitDeclaratorList(const ListNode<InitDeclaratorAST*> *&node)
{
  InitDeclaratorAST *decl = 0;
  if (!parseInitDeclarator(decl))
    return false;

  node = snoc(node, decl, _M_pool);

  while (token_stream.lookAhead() == ',')
    {
      token_stream.nextToken();

      if (!parseInitDeclarator(decl))
        {
          syntaxError();
          break;
        }
      node = snoc(node, decl, _M_pool);
    }

  return true;
}

bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node)
{
  std::size_t start = token_stream.cursor();

  ParameterDeclarationClauseAST *ast
    = CreateNode<ParameterDeclarationClauseAST>(_M_pool);

  if (!parseParameterDeclarationList(ast->parameter_declarations))
    {
      if (token_stream.lookAhead() == ')')
        goto good;

      if (token_stream.lookAhead() == Token_ellipsis
          && token_stream.lookAhead(1) == ')')
        {
          ast->ellipsis = token_stream.cursor();
          goto good;
        }

      return false;
    }

 good:

  if (token_stream.lookAhead() == Token_ellipsis)
    {
      ast->ellipsis = token_stream.cursor();
      token_stream.nextToken();
    }

  /// @todo add ellipsis
  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseParameterDeclarationList(const ListNode<ParameterDeclarationAST*> *&node)
{
  std::size_t start = token_stream.cursor();

  ParameterDeclarationAST *param = 0;
  if (!parseParameterDeclaration(param))
    {
      token_stream.rewind((int) start);
      return false;
    }

  node = snoc(node, param, _M_pool);

  while (token_stream.lookAhead() == ',')
    {
      token_stream.nextToken();

      if (token_stream.lookAhead() == Token_ellipsis)
        break;

      if (!parseParameterDeclaration(param))
        {
          token_stream.rewind((int) start);
          return false;
        }
      node = snoc(node, param, _M_pool);
    }

  return true;
}

bool Parser::parseParameterDeclaration(ParameterDeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  const ListNode<std::size_t> *storage = 0;
  parseStorageClassSpecifier(storage);

  // parse decl spec
  TypeSpecifierAST *spec = 0;
  if (!parseTypeSpecifier(spec))
    {
      token_stream.rewind((int) start);
      return false;
    }

  int index = (int) token_stream.cursor();

  DeclaratorAST *decl = 0;
  if (!parseDeclarator(decl))
    {
      token_stream.rewind((int) index);

      // try with abstract declarator
      parseAbstractDeclarator(decl);
    }

  ExpressionAST *expr = 0;
  if (token_stream.lookAhead() == '=')
    {
      token_stream.nextToken();
      if (!parseLogicalOrExpression(expr,true))
        {
          //reportError(("Expression expected"));
        }
    }

  ParameterDeclarationAST *ast = CreateNode<ParameterDeclarationAST>(_M_pool);
  ast->type_specifier = spec;
  ast->declarator = decl;
  ast->expression = expr;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parse_Attribute__() {
    token_stream.nextToken();

    ADVANCE('(', "(");

    ExpressionAST *expr = 0;
    parseExpression(expr);

    if (token_stream.lookAhead() != ')')
    {
        reportError(("')' expected"));
        return false;
    }
    else
    {
        token_stream.nextToken();
    }
    return true;
}

QString Parser::tokenText(AST *ast) const
{
    if (ast == 0) return QString();

    int start_token = ast->start_token;
    int end_token = ast->end_token;

    Token const &tk = token_stream.token (start_token);
    Token const &end_tk = token_stream.token(end_token);

    return QString::fromLatin1 (&tk.text[tk.position],(int) (end_tk.position - tk.position)).trimmed();
}

bool Parser::parseForwardDeclarationSpecifier(TypeSpecifierAST *&node)
{
  std::size_t start = token_stream.cursor();

  int kind = token_stream.lookAhead();
  if (kind != Token_class && kind != Token_struct && kind != Token_union)
    return false;

  std::size_t class_key = token_stream.cursor();
  token_stream.nextToken();

  NameAST *name = 0;
  if (!parseName(name, false)) {
      token_stream.rewind((int) start);
      return false;
  }

  BaseClauseAST *bases = 0;
  if (token_stream.lookAhead() == ':')
    {
      if (!parseBaseClause(bases))
        {
          token_stream.rewind((int) start);
          return false;
        }
    }

  if (token_stream.lookAhead() != ';')
    {
        token_stream.rewind((int) start);
        return false;
    }

  ForwardDeclarationSpecifierAST *ast = CreateNode<ForwardDeclarationSpecifierAST>(_M_pool);
  ast->class_key = class_key;
  ast->name = name;
  ast->base_clause = bases;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseClassSpecifier(TypeSpecifierAST *&node)
{
  std::size_t start = token_stream.cursor();

  int kind = token_stream.lookAhead();
  if (kind != Token_class && kind != Token_struct && kind != Token_union)
    return false;

  std::size_t class_key = token_stream.cursor();
  token_stream.nextToken();

  WinDeclSpecAST *winDeclSpec = 0;
  parseWinDeclSpec(winDeclSpec);

  if (token_stream.lookAhead() == Token___attribute__) {
      parse_Attribute__();
  }

  while (token_stream.lookAhead() == Token_identifier
         && token_stream.lookAhead(1) == Token_identifier)
    {
      token_stream.nextToken();
    }

  NameAST *name = 0;
  parseName(name, true);

  BaseClauseAST *bases = 0;

  if (token_stream.lookAhead() == ':')
    {
      if (!parseBaseClause(bases))
        {
          skipUntil('{');
        }
    }

  if (token_stream.lookAhead() != '{')
    {

      token_stream.rewind((int) start);
      return false;
    }

  ADVANCE('{', "{");

  ClassSpecifierAST *ast = CreateNode<ClassSpecifierAST>(_M_pool);
  ast->win_decl_specifiers = winDeclSpec;
  ast->class_key = class_key;
  ast->name = name;
  ast->base_clause = bases;

  while (token_stream.lookAhead())
    {
      if (token_stream.lookAhead() == '}')
        break;

      std::size_t startDecl = token_stream.cursor();

      DeclarationAST *memSpec = 0;
      if (!parseMemberSpecification(memSpec))
        {
          if (startDecl == token_stream.cursor())
            token_stream.nextToken(); // skip at least one token
          skipUntilDeclaration();
        }
      else
        ast->member_specs = snoc(ast->member_specs, memSpec, _M_pool);
    }

  ADVANCE_NR('}', "}");

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseAccessSpecifier(DeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  const ListNode<std::size_t> *specs = 0;

  bool done = false;
  while (!done)
    {
      switch(token_stream.lookAhead())
        {
        case Token_signals:
        case Token_slots:
        case Token_k_dcop:
        case Token_k_dcop_signals:
        case Token_public:
        case Token_protected:
        case Token_private:
          specs = snoc(specs, token_stream.cursor(), _M_pool);
          token_stream.nextToken();
          break;

        default:
          done = true;
          break;
        }
    }

  if (!specs)
    return false;

  ADVANCE(':', ":");

  AccessSpecifierAST *ast = CreateNode<AccessSpecifierAST>(_M_pool);
  ast->specs = specs;
  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseMemberSpecification(DeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  if (token_stream.lookAhead() == ';')
    {
      token_stream.nextToken();
      return true;
    }
  else if (token_stream.lookAhead() == Token_Q_OBJECT || token_stream.lookAhead() == Token_K_DCOP)
    {
      token_stream.nextToken();
      return true;
    }
  else if (parseTypedef(node))
    {
      return true;
    }
  else if (parseUsing(node))
    {
      return true;
    }
  else if (parseTemplateDeclaration(node))
    {
      return true;
    }
  else if (parseAccessSpecifier(node))
    {
      return true;
    }
  else if (parseQ_PROPERTY(node))
    {
      return true;
    }
  else if (parseQ_ENUMS(node))
    {
      return true;
    }

  token_stream.rewind((int) start);

  const ListNode<std::size_t> *cv = 0;
  parseCvQualify(cv);

  const ListNode<std::size_t> *storageSpec = 0;
  parseStorageClassSpecifier(storageSpec);

  parseCvQualify(cv);

  TypeSpecifierAST *spec = 0;
  if (parseEnumSpecifier(spec) || parseClassSpecifier(spec))
    {
      parseCvQualify(cv);
      spec->cv = cv;

      const ListNode<InitDeclaratorAST*> *declarators = 0;
      parseInitDeclaratorList(declarators);
      ADVANCE(';', ";");

      SimpleDeclarationAST *ast = CreateNode<SimpleDeclarationAST>(_M_pool);
      ast->type_specifier = spec;
      ast->init_declarators = declarators;
      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;

      return true;
    }

  token_stream.rewind((int) start);
  return parseDeclarationInternal(node);
}

bool Parser::parseCtorInitializer(CtorInitializerAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(':');

  CtorInitializerAST *ast = CreateNode<CtorInitializerAST>(_M_pool);
  ast->colon = start;

  if (!parseMemInitializerList(ast->member_initializers))
    {
      reportError(("Member initializers expected"));
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseElaboratedTypeSpecifier(TypeSpecifierAST *&node)
{
  std::size_t start = token_stream.cursor();

  int tk = token_stream.lookAhead();
  if (tk == Token_class  ||
      tk == Token_struct ||
      tk == Token_union  ||
      tk == Token_enum   ||
      tk == Token_typename)
    {
      std::size_t type = token_stream.cursor();
      token_stream.nextToken();

      NameAST *name = 0;
      if (parseName(name, true))
        {
          ElaboratedTypeSpecifierAST *ast
            = CreateNode<ElaboratedTypeSpecifierAST>(_M_pool);

          ast->type = type;
          ast->name = name;

          UPDATE_POS(ast, start, token_stream.cursor());
          node = ast;

          return true;
        }
    }

  token_stream.rewind((int) start);
  return false;
}

bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(Token_throw);
  ADVANCE('(', "(");

  ExceptionSpecificationAST *ast
    = CreateNode<ExceptionSpecificationAST>(_M_pool);

  if (token_stream.lookAhead() == Token_ellipsis)
    {
      ast->ellipsis = token_stream.cursor();
      token_stream.nextToken();
    }
  else
    {
      parseTypeIdList(ast->type_ids);
    }

  ADVANCE(')', ")");

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseEnumerator(EnumeratorAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(Token_identifier);
  std::size_t id = token_stream.cursor() - 1;

  EnumeratorAST *ast = CreateNode<EnumeratorAST>(_M_pool);
  ast->id = id;

  if (token_stream.lookAhead() == '=')
    {
      token_stream.nextToken();

      if (!parseConstantExpression(ast->expression))
        {
          reportError(("Constant expression expected"));
        }
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseInitDeclarator(InitDeclaratorAST *&node)
{
  std::size_t start = token_stream.cursor();

  DeclaratorAST *decl = 0;
  if (!parseDeclarator(decl))
    {
      return false;
    }

  if (token_stream.lookAhead(0) == Token_asm)
    {
      token_stream.nextToken();
      skip('(', ')');
      token_stream.nextToken();
    }

  InitializerAST *init = 0;
  parseInitializer(init);

  InitDeclaratorAST *ast = CreateNode<InitDeclaratorAST>(_M_pool);
  ast->declarator = decl;
  ast->initializer = init;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseBaseClause(BaseClauseAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(':');

  BaseSpecifierAST *baseSpec = 0;
  if (!parseBaseSpecifier(baseSpec))
    return false;

  BaseClauseAST *ast = CreateNode<BaseClauseAST>(_M_pool);
  ast->base_specifiers = snoc(ast->base_specifiers, baseSpec, _M_pool);

  while (token_stream.lookAhead() == ',')
    {
      token_stream.nextToken();

      if (!parseBaseSpecifier(baseSpec))
        {
          reportError(("Base class specifier expected"));
          break;
        }
      ast->base_specifiers = snoc(ast->base_specifiers, baseSpec, _M_pool);
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseInitializer(InitializerAST *&node)
{
  std::size_t start = token_stream.cursor();

  int tk = token_stream.lookAhead();
  if (tk != '=' && tk != '(')
    return false;

  InitializerAST *ast = CreateNode<InitializerAST>(_M_pool);

  if (tk == '=')
    {
      token_stream.nextToken();

      if (!parseInitializerClause(ast->initializer_clause))
        {
          reportError(("Initializer clause expected"));
        }
    }
  else if (tk == '(')
    {
      token_stream.nextToken();
      parseCommaExpression(ast->expression);
      CHECK(')');
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseMemInitializerList(const ListNode<MemInitializerAST*> *&node)
{
  MemInitializerAST *init = 0;

  if (!parseMemInitializer(init))
    return false;

  node = snoc(node, init, _M_pool);

  while (token_stream.lookAhead() == ',')
    {
      token_stream.nextToken();

      if (!parseMemInitializer(init))
        break;

      node = snoc(node, init, _M_pool);
    }

  return true;
}

bool Parser::parseMemInitializer(MemInitializerAST *&node)
{
  std::size_t start = token_stream.cursor();

  NameAST *initId = 0;
  if (!parseName(initId, true))
    {
      reportError(("Identifier expected"));
      return false;
    }

  ADVANCE('(', "(");
  ExpressionAST *expr = 0;
  parseCommaExpression(expr);
  ADVANCE(')', ")");

  MemInitializerAST *ast = CreateNode<MemInitializerAST>(_M_pool);
  ast->initializer_id = initId;
  ast->expression = expr;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseTypeIdList(const ListNode<TypeIdAST*> *&node)
{
  TypeIdAST *typeId = 0;
  if (!parseTypeId(typeId))
    return false;

  node = snoc(node, typeId, _M_pool);

  while (token_stream.lookAhead() == ',')
    {
      token_stream.nextToken();
      if (parseTypeId(typeId))
        {
          node = snoc(node, typeId, _M_pool);
        }
      else
        {
          reportError(("Type id expected"));
          break;
        }
    }

  return true;
}

bool Parser::parseBaseSpecifier(BaseSpecifierAST *&node)
{
  std::size_t start = token_stream.cursor();

  BaseSpecifierAST *ast = CreateNode<BaseSpecifierAST>(_M_pool);

  if (token_stream.lookAhead() == Token_virtual)
    {
      ast->virt = token_stream.cursor();
      token_stream.nextToken();

      int tk = token_stream.lookAhead();
      if (tk == Token_public || tk == Token_protected
          || tk == Token_private)
        {
          ast->access_specifier = token_stream.cursor();
          token_stream.nextToken();
        }
    }
  else
    {
      int tk = token_stream.lookAhead();
      if (tk == Token_public || tk == Token_protected
          || tk == Token_private)
        {
          ast->access_specifier = token_stream.cursor();
          token_stream.nextToken();
        }

      if (token_stream.lookAhead() == Token_virtual)
        {
          ast->virt = token_stream.cursor();
          token_stream.nextToken();
        }
    }

  if (!parseName(ast->name, true))
    reportError(("Class name expected"));

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseInitializerClause(InitializerClauseAST *&node)
{
  std::size_t start = token_stream.cursor();

  InitializerClauseAST *ast = CreateNode<InitializerClauseAST>(_M_pool);

  if (token_stream.lookAhead() == '{')
    {
#if defined(__GNUC__)
#warning "implement me"
#endif
      if (skip('{','}'))
        token_stream.nextToken();
      else
        reportError(("} missing"));
    }
  else
    {
      if (!parseAssignmentExpression(ast->expression))
        {
          //reportError(("Expression expected"));
        }
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parsePtrToMember(PtrToMemberAST *&node)
{
#if defined(__GNUC__)
#warning "implemente me (AST)"
#endif

  std::size_t start = token_stream.cursor();

  std::size_t global_scope = 0;
  if (token_stream.lookAhead() == Token_scope)
    {
      global_scope = token_stream.cursor();
      token_stream.nextToken();
    }

  UnqualifiedNameAST *name = 0;
  while (token_stream.lookAhead() == Token_identifier)
    {
      if (!parseUnqualifiedName(name))
        break;

      if (token_stream.lookAhead() == Token_scope
          && token_stream.lookAhead(1) == '*')
        {
          token_stream.nextToken();
          token_stream.nextToken();

          PtrToMemberAST *ast = CreateNode<PtrToMemberAST>(_M_pool);
          UPDATE_POS(ast, start, token_stream.cursor());
          node = ast;

          return true;
        }

      if (token_stream.lookAhead() == Token_scope)
        token_stream.nextToken();
    }

  token_stream.rewind((int) start);
  return false;
}

bool Parser::parseUnqualifiedName(UnqualifiedNameAST *&node,
                                  bool parseTemplateId)
{
  std::size_t start = token_stream.cursor();

  std::size_t tilde = 0;
  std::size_t id = 0;
  OperatorFunctionIdAST *operator_id = 0;

  if (token_stream.lookAhead() == Token_identifier)
    {
      id = token_stream.cursor();
      token_stream.nextToken();
    }
  else if (token_stream.lookAhead() == '~'
           && token_stream.lookAhead(1) == Token_identifier)
    {
      tilde = token_stream.cursor();
      token_stream.nextToken(); // skip ~

      id = token_stream.cursor();
      token_stream.nextToken(); // skip classname
    }
  else if (token_stream.lookAhead() == Token_operator)
    {
      if (!parseOperatorFunctionId(operator_id))
        return false;
    }
  else
    {
      return false;
    }

  UnqualifiedNameAST *ast = CreateNode<UnqualifiedNameAST>(_M_pool);
  ast->tilde = tilde;
  ast->id = id;
  ast->operator_id = operator_id;

  if (parseTemplateId && !tilde)
    {
      std::size_t index = token_stream.cursor();

      if (token_stream.lookAhead() == '<')
        {
          token_stream.nextToken();

          // optional template arguments
          parseTemplateArgumentList(ast->template_arguments);

          if (token_stream.lookAhead() == '>')
            {
              token_stream.nextToken();
            }
          else
            {
              ast->template_arguments = 0;
              token_stream.rewind((int) index);
            }
        }
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseStringLiteral(StringLiteralAST *&node)
{
  std::size_t start = token_stream.cursor();

  if (token_stream.lookAhead() != Token_string_literal)
    return false;

  StringLiteralAST *ast = CreateNode<StringLiteralAST>(_M_pool);

  while (token_stream.lookAhead() == Token_string_literal)
    {
      ast->literals = snoc(ast->literals, token_stream.cursor(), _M_pool);
      token_stream.nextToken();
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseExpressionStatement(StatementAST *&node)
{
  std::size_t start = token_stream.cursor();

  ExpressionAST *expr = 0;
  parseCommaExpression(expr);

  ADVANCE(';', ";");

  ExpressionStatementAST *ast = CreateNode<ExpressionStatementAST>(_M_pool);
  ast->expression = expr;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseStatement(StatementAST *&node)
{
  std::size_t start = token_stream.cursor();

  switch(token_stream.lookAhead())
    {
    case Token_while:
      return parseWhileStatement(node);

    case Token_do:
      return parseDoStatement(node);

    case Token_for:
      return parseForStatement(node);

    case Token_if:
      return parseIfStatement(node);

    case Token_switch:
      return parseSwitchStatement(node);

    case Token_try:
      return parseTryBlockStatement(node);

    case Token_case:
    case Token_default:
      return parseLabeledStatement(node);

    case Token_break:
    case Token_continue:
#if defined(__GNUC__)
#warning "implement me"
#endif
      token_stream.nextToken();
      ADVANCE(';', ";");
      return true;

    case Token_goto:
#if defined(__GNUC__)
#warning "implement me"
#endif
      token_stream.nextToken();
      ADVANCE(Token_identifier, "identifier");
      ADVANCE(';', ";");
      return true;

    case Token_return:
      {
        token_stream.nextToken();
        ExpressionAST *expr = 0;
        parseCommaExpression(expr);

        ADVANCE(';', ";");

        ReturnStatementAST *ast = CreateNode<ReturnStatementAST>(_M_pool);
        ast->expression = expr;

        UPDATE_POS(ast, start, token_stream.cursor());
        node = ast;
      }
      return true;

    case '{':
      return parseCompoundStatement(node);

    case Token_identifier:
      if (parseLabeledStatement(node))
        return true;
      break;
    }

  return parseExpressionOrDeclarationStatement(node);
}

bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node)
{
  bool blocked = block_errors(true);

  std::size_t start = token_stream.cursor();

  StatementAST *decl_ast = 0;
  bool maybe_amb = parseDeclarationStatement(decl_ast);
  maybe_amb &= token_stream.kind(token_stream.cursor() - 1) == ';';

  std::size_t end = token_stream.cursor();

  token_stream.rewind((int) start);
  StatementAST *expr_ast = 0;
  maybe_amb &= parseExpressionStatement(expr_ast);
  maybe_amb &= token_stream.kind(token_stream.cursor() - 1) == ';';

  if (maybe_amb)
    {
      Q_ASSERT(decl_ast != 0 && expr_ast != 0);
      ExpressionOrDeclarationStatementAST *ast
        = CreateNode<ExpressionOrDeclarationStatementAST>(_M_pool);
      ast->declaration = decl_ast;
      ast->expression = expr_ast;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }
  else
    {
      token_stream.rewind((int) std::max(end, token_stream.cursor()));

      node = decl_ast;
      if (!node)
        node = expr_ast;
    }

  block_errors(blocked);

  if (!node)
    syntaxError();

  return node != 0;
}

bool Parser::parseCondition(ConditionAST *&node, bool initRequired)
{
  std::size_t start = token_stream.cursor();

  ConditionAST *ast = CreateNode<ConditionAST>(_M_pool);
  TypeSpecifierAST *spec = 0;

  if (parseTypeSpecifier(spec))
    {
      ast->type_specifier = spec;

      std::size_t declarator_start = token_stream.cursor();

      DeclaratorAST *decl = 0;
      if (!parseDeclarator(decl))
        {
          token_stream.rewind((int) declarator_start);
          if (!initRequired && !parseAbstractDeclarator(decl))
            decl = 0;
        }

      if (decl && (!initRequired || token_stream.lookAhead() == '='))
        {
          ast->declarator = decl;

          if (token_stream.lookAhead() == '=')
            {
              token_stream.nextToken();

              parseExpression(ast->expression);
            }

          UPDATE_POS(ast, start, token_stream.cursor());
          node = ast;

          return true;
        }
    }

  token_stream.rewind((int) start);

  if (!parseCommaExpression(ast->expression))
    return false;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}


bool Parser::parseWhileStatement(StatementAST *&node)
{
  std::size_t start = token_stream.cursor();

  ADVANCE(Token_while, "while");
  ADVANCE('(' , "(");

  ConditionAST *cond = 0;
  if (!parseCondition(cond))
    {
      reportError(("condition expected"));
      return false;
    }
  ADVANCE(')', ")");

  StatementAST *body = 0;
  if (!parseStatement(body))
    {
      reportError(("statement expected"));
      return false;
    }

  WhileStatementAST *ast = CreateNode<WhileStatementAST>(_M_pool);
  ast->condition = cond;
  ast->statement = body;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseDoStatement(StatementAST *&node)
{
  std::size_t start = token_stream.cursor();

  ADVANCE(Token_do, "do");

  StatementAST *body = 0;
  if (!parseStatement(body))
    {
      reportError(("statement expected"));
      //return false;
    }

  ADVANCE_NR(Token_while, "while");
  ADVANCE_NR('(' , "(");

  ExpressionAST *expr = 0;
  if (!parseCommaExpression(expr))
    {
      reportError(("expression expected"));
      //return false;
    }

  ADVANCE_NR(')', ")");
  ADVANCE_NR(';', ";");

  DoStatementAST *ast = CreateNode<DoStatementAST>(_M_pool);
  ast->statement = body;
  ast->expression = expr;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseForStatement(StatementAST *&node)
{
  std::size_t start = token_stream.cursor();

  ADVANCE(Token_for, "for");
  ADVANCE('(', "(");

  StatementAST *init = 0;
  if (!parseForInitStatement(init))
    {
      reportError(("for initialization expected"));
      return false;
    }

  ConditionAST *cond = 0;
  parseCondition(cond);
  ADVANCE(';', ";");

  ExpressionAST *expr = 0;
  parseCommaExpression(expr);
  ADVANCE(')', ")");

  StatementAST *body = 0;
  if (!parseStatement(body))
    return false;

  ForStatementAST *ast = CreateNode<ForStatementAST>(_M_pool);
  ast->init_statement = init;
  ast->condition = cond;
  ast->expression = expr;
  ast->statement = body;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseForInitStatement(StatementAST *&node)
{
  if (parseDeclarationStatement(node))
    return true;

  return parseExpressionStatement(node);
}

bool Parser::parseCompoundStatement(StatementAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK('{');

  CompoundStatementAST *ast = CreateNode<CompoundStatementAST>(_M_pool);

  while (token_stream.lookAhead())
    {
      if (token_stream.lookAhead() == '}')
        break;

      std::size_t startStmt = token_stream.cursor();

      StatementAST *stmt = 0;
      if (!parseStatement(stmt))
        {
          if (startStmt == token_stream.cursor())
            token_stream.nextToken();

          skipUntilStatement();
        }
      else
        {
          ast->statements = snoc(ast->statements, stmt, _M_pool);
        }
    }

  ADVANCE_NR('}', "}");

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseIfStatement(StatementAST *&node)
{
  std::size_t start = token_stream.cursor();

  ADVANCE(Token_if, "if");

  ADVANCE('(' , "(");

  IfStatementAST *ast = CreateNode<IfStatementAST>(_M_pool);

  ConditionAST *cond = 0;
  if (!parseCondition(cond))
    {
      reportError(("condition expected"));
      return false;
    }
  ADVANCE(')', ")");

  StatementAST *stmt = 0;
  if (!parseStatement(stmt))
    {
      reportError(("statement expected"));
      return false;
    }

  ast->condition = cond;
  ast->statement = stmt;

  if (token_stream.lookAhead() == Token_else)
    {
      token_stream.nextToken();

      if (!parseStatement(ast->else_statement))
        {
          reportError(("statement expected"));
          return false;
        }
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseSwitchStatement(StatementAST *&node)
{
  std::size_t start = token_stream.cursor();
  ADVANCE(Token_switch, "switch");

  ADVANCE('(' , "(");

  ConditionAST *cond = 0;
  if (!parseCondition(cond))
    {
      reportError(("condition expected"));
      return false;
    }
  ADVANCE(')', ")");

  StatementAST *stmt = 0;
  if (!parseCompoundStatement(stmt))
    {
      syntaxError();
      return false;
    }

  SwitchStatementAST *ast = CreateNode<SwitchStatementAST>(_M_pool);
  ast->condition = cond;
  ast->statement = stmt;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseLabeledStatement(StatementAST *&node)
{
  switch(token_stream.lookAhead())
    {
    case Token_identifier:
    case Token_default:
      if (token_stream.lookAhead(1) == ':')
        {
          token_stream.nextToken();
          token_stream.nextToken();

          StatementAST *stmt = 0;
          if (parseStatement(stmt))
            {
              node = stmt;
              return true;
            }
        }
      break;

    case Token_case:
      {
        token_stream.nextToken();
        ExpressionAST *expr = 0;
        if (!parseConstantExpression(expr))
          {
            reportError(("expression expected"));
          }
        else if (token_stream.lookAhead() == Token_ellipsis)
          {
            token_stream.nextToken();

            ExpressionAST *expr2 = 0;
            if (!parseConstantExpression(expr2))
              {
                reportError(("expression expected"));
              }
          }
        ADVANCE(':', ":");

        StatementAST *stmt = 0;
        if (parseStatement(stmt))
          {
            node = stmt;
            return true;
          }
      }
      break;

    }

  return false;
}

bool Parser::parseBlockDeclaration(DeclarationAST *&node)
{
  switch(token_stream.lookAhead())
    {
    case Token_typedef:
      return parseTypedef(node);
    case Token_using:
      return parseUsing(node);
    case Token_asm:
      return parseAsmDefinition(node);
    case Token_namespace:
      return parseNamespaceAliasDefinition(node);
    }

  std::size_t start = token_stream.cursor();

  const ListNode<std::size_t> *cv = 0;
  parseCvQualify(cv);

  const ListNode<std::size_t> *storageSpec = 0;
  parseStorageClassSpecifier(storageSpec);

  parseCvQualify(cv);

  TypeSpecifierAST *spec = 0;
  if (!parseTypeSpecifierOrClassSpec(spec))
    { // replace with simpleTypeSpecifier?!?!
      token_stream.rewind((int) start);
      return false;
    }

  parseCvQualify(cv);
  spec->cv = cv;

  const ListNode<InitDeclaratorAST*> *declarators = 0;
  parseInitDeclaratorList(declarators);

  if (token_stream.lookAhead() != ';')
    {
      token_stream.rewind((int) start);
      return false;
    }
  token_stream.nextToken();

  SimpleDeclarationAST *ast = CreateNode<SimpleDeclarationAST>(_M_pool);
  ast->type_specifier = spec;
  ast->init_declarators = declarators;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseNamespaceAliasDefinition(DeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(Token_namespace);

  NamespaceAliasDefinitionAST *ast
    = CreateNode<NamespaceAliasDefinitionAST>(_M_pool);

  ADVANCE(Token_identifier,  "identifier");
  ast->namespace_name = token_stream.cursor() - 1;

  ADVANCE('=', "=");

  if (!parseName(ast->alias_name))
    {
      reportError(("Namespace name expected"));
    }

  ADVANCE(';', ";");

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseDeclarationStatement(StatementAST *&node)
{
  std::size_t start = token_stream.cursor();

  DeclarationAST *decl = 0;
  if (!parseBlockDeclaration(decl))
    return false;

  DeclarationStatementAST *ast = CreateNode<DeclarationStatementAST>(_M_pool);
  ast->declaration = decl;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseDeclarationInternal(DeclarationAST *&node)
{
  std::size_t start = token_stream.cursor();

  // that is for the case '__declspec(dllexport) int ...' or
  // '__declspec(dllexport) inline int ...', etc.
  WinDeclSpecAST *winDeclSpec = 0;
  parseWinDeclSpec(winDeclSpec);

  const ListNode<std::size_t> *funSpec = 0;
  bool hasFunSpec = parseFunctionSpecifier(funSpec);

  const ListNode<std::size_t> *cv = 0;
  parseCvQualify(cv);

  const ListNode<std::size_t> *storageSpec = 0;
  bool hasStorageSpec = parseStorageClassSpecifier(storageSpec);

  if (hasStorageSpec && !hasFunSpec)
    hasFunSpec = parseFunctionSpecifier(funSpec);

  // that is for the case 'friend __declspec(dllexport) ....'
  parseWinDeclSpec(winDeclSpec);

  if (!cv)
    parseCvQualify(cv);

  int index = (int) token_stream.cursor();
  NameAST *name = 0;
  if (parseName(name, true) && token_stream.lookAhead() == '(')
    {
      // no type specifier, maybe a constructor or a cast operator??

      token_stream.rewind((int) index);

      InitDeclaratorAST *declarator = 0;
      if (parseInitDeclarator(declarator))
        {
          switch(token_stream.lookAhead())
            {
            case ';':
              {
                token_stream.nextToken();

                SimpleDeclarationAST *ast
                  = CreateNode<SimpleDeclarationAST>(_M_pool);

                ast->storage_specifiers = storageSpec;
                ast->function_specifiers = funSpec;
                ast->init_declarators = snoc(ast->init_declarators,
                                             declarator, _M_pool);

                UPDATE_POS(ast, start, token_stream.cursor());
                node = ast;
              }
              return true;

            case ':':
              {
                CtorInitializerAST *ctorInit = 0;
                StatementAST *funBody = 0;

                if (parseCtorInitializer(ctorInit)
                    && parseFunctionBody(funBody))
                  {
                    FunctionDefinitionAST *ast
                      = CreateNode<FunctionDefinitionAST>(_M_pool);

                    ast->storage_specifiers = storageSpec;
                    ast->function_specifiers = funSpec;
                    ast->init_declarator = declarator;
                    ast->function_body = funBody;

                    UPDATE_POS(ast, start, token_stream.cursor());
                    node = ast;

                    return true;
                  }
              }
              break;

            case '{':
              {
                StatementAST *funBody = 0;
                if (parseFunctionBody(funBody))
                  {
                    FunctionDefinitionAST *ast
                      = CreateNode<FunctionDefinitionAST>(_M_pool);

                    ast->storage_specifiers = storageSpec;
                    ast->function_specifiers = funSpec;
                    ast->init_declarator = declarator;
                    ast->function_body = funBody;

                    UPDATE_POS(ast, start, token_stream.cursor());
                    node = ast;

                    return true;
                  }
              }
              break;

            case '(':
            case '[':
              // ops!! it seems a declarator
              goto start_decl;
              break;
            }

        }
    }

 start_decl:
  token_stream.rewind((int) index);

  if (token_stream.lookAhead() == Token_const
      && token_stream.lookAhead(1) == Token_identifier
      && token_stream.lookAhead(2) == '=')
    {
      // constant definition
      token_stream.nextToken(); // skip const

      const ListNode<InitDeclaratorAST*> *declarators = 0;
      if (!parseInitDeclaratorList(declarators))
        {
          syntaxError();
          return false;
        }

      ADVANCE(';', ";");

#if defined(__GNUC__)
#warning "mark the ast as constant"
#endif
      SimpleDeclarationAST *ast = CreateNode<SimpleDeclarationAST>(_M_pool);
      ast->init_declarators = declarators;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;

      return true;
    }

  TypeSpecifierAST *spec = 0;
  if (parseTypeSpecifier(spec))
    {
      Q_ASSERT(spec != 0);

      if (!hasFunSpec)
        parseFunctionSpecifier(funSpec);         // e.g. "void inline"

      spec->cv = cv;

      const ListNode<InitDeclaratorAST*> *declarators = 0;
      InitDeclaratorAST *decl = 0;
      int startDeclarator = (int) token_stream.cursor();
      bool maybeFunctionDefinition = false;

      if (token_stream.lookAhead() != ';')
        {
          if (parseInitDeclarator(decl) && token_stream.lookAhead() == '{')
            {
              // function definition
              maybeFunctionDefinition = true;
            }
          else
            {
              token_stream.rewind((int) startDeclarator);
              if (!parseInitDeclaratorList(declarators))
                {
                  syntaxError();
                  return false;
                }
            }
        }

      switch(token_stream.lookAhead())
        {
        case ';':
          {
            token_stream.nextToken();
            SimpleDeclarationAST *ast
              = CreateNode<SimpleDeclarationAST>(_M_pool);

            ast->storage_specifiers = storageSpec;
            ast->function_specifiers = funSpec;
            ast->type_specifier = spec;
            ast->win_decl_specifiers = winDeclSpec;
            ast->init_declarators = declarators;

            UPDATE_POS(ast, start, token_stream.cursor());
            node = ast;
          }
          return true;

        case '{':
          {
            if (!maybeFunctionDefinition)
              {
                syntaxError();
                return false;
              }

            StatementAST *funBody = 0;
            if (parseFunctionBody(funBody))
              {
                FunctionDefinitionAST *ast
                  = CreateNode<FunctionDefinitionAST>(_M_pool);

                ast->win_decl_specifiers = winDeclSpec;
                ast->storage_specifiers = storageSpec;
                ast->function_specifiers = funSpec;
                ast->type_specifier = spec;
                ast->init_declarator = decl;
                ast->function_body = funBody;

                UPDATE_POS(ast, start, token_stream.cursor());
                node = ast;

                return true;
              }
          }
          break;
        } // end switch
    }

  syntaxError();
  return false;
}

bool Parser::skipFunctionBody(StatementAST *&)
{
#if defined(__GNUC__)
#warning "Parser::skipFunctionBody() -- implement me"
#endif
  Q_ASSERT(0); // ### not implemented
  return 0;
}

bool Parser::parseFunctionBody(StatementAST *&node)
{
  if (control->skipFunctionBody())
    return skipFunctionBody(node);

  return parseCompoundStatement(node);
}

bool Parser::parseTypeSpecifierOrClassSpec(TypeSpecifierAST *&node)
{
  if (parseClassSpecifier(node))
    return true;
  else if (parseEnumSpecifier(node))
    return true;
  else if (parseTypeSpecifier(node))
    return true;

  return false;
}

bool Parser::parseTryBlockStatement(StatementAST *&node)
{
#if defined(__GNUC__)
#warning "implement me"
#endif
  CHECK(Token_try);

  StatementAST *stmt = 0;
  if (!parseCompoundStatement(stmt))
    {
      syntaxError();
      return false;
    }

  if (token_stream.lookAhead() != Token_catch)
    {
      reportError(("catch expected"));
      return false;
    }

  while (token_stream.lookAhead() == Token_catch)
    {
      token_stream.nextToken();
      ADVANCE('(', "(");
      ConditionAST *cond = 0;
      if (token_stream.lookAhead() == Token_ellipsis)
        {
          token_stream.nextToken();
        }
      else if (!parseCondition(cond, false))
        {
          reportError(("condition expected"));
          return false;
        }
      ADVANCE(')', ")");

      StatementAST *body = 0;
      if (!parseCompoundStatement(body))
        {
          syntaxError();
          return false;
        }
    }

  node = stmt;
  return true;
}

bool Parser::parsePrimaryExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  PrimaryExpressionAST *ast = CreateNode<PrimaryExpressionAST>(_M_pool);

  switch(token_stream.lookAhead())
    {
    case Token_string_literal:
      parseStringLiteral(ast->literal);
      break;

    case Token_number_literal:
    case Token_char_literal:
    case Token_true:
    case Token_false:
    case Token_this:
      ast->token = token_stream.cursor();
      token_stream.nextToken();
      break;

    case '(':
      token_stream.nextToken();

      if (token_stream.lookAhead() == '{')
        {
          if (!parseCompoundStatement(ast->expression_statement))
            return false;
        }
      else
        {
          if (!parseExpression(ast->sub_expression))
            return false;
        }

      CHECK(')');
      break;

    default:
      if (!parseName(ast->name))
        return false;

      break;
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}


/*
  postfix-expression-internal:
  [ expression ]
  ( expression-list [opt] )
  (.|->) template [opt] id-expression
  (.|->) pseudo-destructor-name
  ++
  --
*/
bool Parser::parsePostfixExpressionInternal(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  switch (token_stream.lookAhead())
    {
    case '[':
      {
        token_stream.nextToken();
        ExpressionAST *expr = 0;
        parseExpression(expr);
        CHECK(']');

        SubscriptExpressionAST *ast
          = CreateNode<SubscriptExpressionAST>(_M_pool);

        ast->subscript = expr;

        UPDATE_POS(ast, start, token_stream.cursor());
        node = ast;
      }
      return true;

    case '(':
      {
        token_stream.nextToken();
        ExpressionAST *expr = 0;
        parseExpression(expr);
        CHECK(')');

        FunctionCallAST *ast = CreateNode<FunctionCallAST>(_M_pool);
        ast->arguments = expr;

        UPDATE_POS(ast, start, token_stream.cursor());
        node = ast;
      }
      return true;

    case '.':
    case Token_arrow:
      {
        std::size_t op = token_stream.cursor();
        token_stream.nextToken();

        std::size_t templ = 0;
        if (token_stream.lookAhead() == Token_template)
          {
            templ = token_stream.cursor();
            token_stream.nextToken();
          }

        int saved = int(token_stream.cursor());
        NameAST *name = 0;

        if (parseName(name, true) && name->unqualified_name
            && name->unqualified_name->template_arguments != 0
            && token_stream.lookAhead() == '(') {
          // a template method call
          // ### reverse the logic
        } else {
          token_stream.rewind(saved);
          name = 0;

          if (! parseName (name, templ != 0))
            return false;
        }

        ClassMemberAccessAST *ast = CreateNode<ClassMemberAccessAST>(_M_pool);
        ast->op = op;
        ast->name = name;

        UPDATE_POS(ast, start, token_stream.cursor());
        node = ast;
      }
      return true;

    case Token_incr:
    case Token_decr:
      {
        std::size_t op = token_stream.cursor();
        token_stream.nextToken();

        IncrDecrExpressionAST *ast = CreateNode<IncrDecrExpressionAST>(_M_pool);
        ast->op = op;

        UPDATE_POS(ast, start, token_stream.cursor());
        node = ast;
      }
      return true;

    default:
      return false;
    }
}

/*
  postfix-expression:
  simple-type-specifier ( expression-list [opt] )
  primary-expression postfix-expression-internal*
*/
bool Parser::parsePostfixExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  switch (token_stream.lookAhead())
    {
    case Token_dynamic_cast:
    case Token_static_cast:
    case Token_reinterpret_cast:
    case Token_const_cast:
      {
        std::size_t castOp = token_stream.cursor();
        token_stream.nextToken();

        CHECK('<');
        TypeIdAST *typeId = 0;
        parseTypeId(typeId);
        CHECK('>');

        CHECK('(');
        ExpressionAST *expr = 0;
        parseCommaExpression(expr);
        CHECK(')');

        CppCastExpressionAST *ast = CreateNode<CppCastExpressionAST>(_M_pool);
        ast->op = castOp;
        ast->type_id = typeId;
        ast->expression = expr;

        ExpressionAST *e = 0;
        while (parsePostfixExpressionInternal(e))
          {
            ast->sub_expressions = snoc(ast->sub_expressions, e, _M_pool);
          }

        UPDATE_POS(ast, start, token_stream.cursor());
        node = ast;
      }
      return true;

    case Token_typename:
      {
        std::size_t token = token_stream.cursor();
        token_stream.nextToken();

        NameAST* name = 0;
        if (!parseName(name, true))
          return false;

        CHECK('(');
        ExpressionAST *expr = 0;
        parseCommaExpression(expr);
        CHECK(')');

        TypeIdentificationAST *ast = CreateNode<TypeIdentificationAST>(_M_pool);
        ast->typename_token = token;
        ast->name = name;
        ast->expression = expr;

        UPDATE_POS(ast, start, token_stream.cursor());
        node = ast;
      }
      return true;

    case Token_typeid:
      {
        token_stream.nextToken();

        CHECK('(');
        TypeIdAST *typeId = 0;
        parseTypeId(typeId);
        CHECK(')');

        TypeIdentificationAST *ast = CreateNode<TypeIdentificationAST>(_M_pool);
        UPDATE_POS(ast, start, token_stream.cursor());
        node = ast;
      }
      return true;

    default:
      break;
    }

  std::size_t saved_pos = token_stream.cursor();

  TypeSpecifierAST *typeSpec = 0;
  ExpressionAST *expr = 0;

  // let's try to parse a type
  NameAST *name = 0;
  if (parseName(name, true))
    {
      Q_ASSERT(name->unqualified_name != 0);

      bool has_template_args
        = name->unqualified_name->template_arguments != 0;

      if (has_template_args && token_stream.lookAhead() == '(')
        {
          ExpressionAST *cast_expr = 0;
          if (parseCastExpression(cast_expr)
              && cast_expr->kind == AST::Kind_CastExpression)
            {
              token_stream.rewind((int) saved_pos);
              parsePrimaryExpression(expr);
              goto L_no_rewind;
            }
        }
    }

  token_stream.rewind((int) saved_pos);

 L_no_rewind:
  if (!expr && parseSimpleTypeSpecifier(typeSpec)
      && token_stream.lookAhead() == '(')
    {
      token_stream.nextToken(); // skip '('
      parseCommaExpression(expr);
      CHECK(')');
    }
  else if (expr)
    {
      typeSpec = 0;
    }
  else
    {
      typeSpec = 0;
      token_stream.rewind((int) start);

      if (!parsePrimaryExpression(expr))
        return false;
    }

  const ListNode<ExpressionAST*> *sub_expressions = 0;
  ExpressionAST *sub_expression = 0;

  while (parsePostfixExpressionInternal(sub_expression))
    sub_expressions = snoc(sub_expressions, sub_expression, _M_pool);

  if (sub_expressions || ! expr || (typeSpec && expr))
    {
      PostfixExpressionAST *ast = CreateNode<PostfixExpressionAST>(_M_pool);
      ast->type_specifier = typeSpec;
      ast->expression = expr;
      ast->sub_expressions = sub_expressions;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }
  else
    node = expr;

  return true;
}

bool Parser::parseUnaryExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  switch(token_stream.lookAhead())
    {
    case Token_incr:
    case Token_decr:
    case '*':
    case '&':
    case '+':
    case '-':
    case '!':
    case '~':
      {
        std::size_t op = token_stream.cursor();
        token_stream.nextToken();

        ExpressionAST *expr = 0;
        if (!parseCastExpression(expr))
          return false;

        UnaryExpressionAST *ast = CreateNode<UnaryExpressionAST>(_M_pool);
        ast->op = op;
        ast->expression = expr;

        UPDATE_POS(ast, start, token_stream.cursor());
        node = ast;
      }
      return true;

    case Token_sizeof:
      {
        std::size_t sizeof_token = token_stream.cursor();
        token_stream.nextToken();

        SizeofExpressionAST *ast = CreateNode<SizeofExpressionAST>(_M_pool);
        ast->sizeof_token = sizeof_token;

        std::size_t index = token_stream.cursor();
        if (token_stream.lookAhead() == '(')
          {
            token_stream.nextToken();
            if (parseTypeId(ast->type_id) && token_stream.lookAhead() == ')')
              {
                token_stream.nextToken(); // skip )

                UPDATE_POS(ast, start, token_stream.cursor());
                node = ast;
                return true;
              }

            ast->type_id = 0;
            token_stream.rewind((int) index);
          }

        if (!parseUnaryExpression(ast->expression))
          return false;

        UPDATE_POS(ast, start, token_stream.cursor());
        node = ast;
        return true;
      }

    default:
      break;
    }

  int token = token_stream.lookAhead();

  if (token == Token_new
      || (token == Token_scope && token_stream.lookAhead(1) == Token_new))
    return parseNewExpression(node);

  if (token == Token_delete
      || (token == Token_scope && token_stream.lookAhead(1) == Token_delete))
    return parseDeleteExpression(node);

  return parsePostfixExpression(node);
}

bool Parser::parseNewExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  NewExpressionAST *ast = CreateNode<NewExpressionAST>(_M_pool);

  if (token_stream.lookAhead() == Token_scope
      && token_stream.lookAhead(1) == Token_new)
    {
      ast->scope_token = token_stream.cursor();
      token_stream.nextToken();
    }

  CHECK(Token_new);
  ast->new_token = token_stream.cursor() - 1;

  if (token_stream.lookAhead() == '(')
    {
      token_stream.nextToken();
      parseCommaExpression(ast->expression);
      CHECK(')');
    }

  if (token_stream.lookAhead() == '(')
    {
      token_stream.nextToken();
      parseTypeId(ast->type_id);
      CHECK(')');
    }
  else
    {
      parseNewTypeId(ast->new_type_id);
    }

  parseNewInitializer(ast->new_initializer);

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseNewTypeId(NewTypeIdAST *&node)
{
  std::size_t start = token_stream.cursor();

  TypeSpecifierAST *typeSpec = 0;
  if (!parseTypeSpecifier(typeSpec))
    return false;

  NewTypeIdAST *ast = CreateNode<NewTypeIdAST>(_M_pool);
  ast->type_specifier = typeSpec;

  parseNewDeclarator(ast->new_declarator);

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseNewDeclarator(NewDeclaratorAST *&node)
{
  std::size_t start = token_stream.cursor();

  NewDeclaratorAST *ast = CreateNode<NewDeclaratorAST>(_M_pool);

  PtrOperatorAST *ptrOp = 0;
  if (parsePtrOperator(ptrOp))
    {
      ast->ptr_op = ptrOp;
      parseNewDeclarator(ast->sub_declarator);
    }

  while (token_stream.lookAhead() == '[')
    {
      token_stream.nextToken();
      ExpressionAST *expr = 0;
      parseExpression(expr);
      ast->expressions = snoc(ast->expressions, expr, _M_pool);
      ADVANCE(']', "]");
    }

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseNewInitializer(NewInitializerAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK('(');

  NewInitializerAST *ast = CreateNode<NewInitializerAST>(_M_pool);

  parseCommaExpression(ast->expression);

  CHECK(')');

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseDeleteExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  DeleteExpressionAST *ast = CreateNode<DeleteExpressionAST>(_M_pool);

  if (token_stream.lookAhead() == Token_scope
      && token_stream.lookAhead(1) == Token_delete)
    {
      ast->scope_token = token_stream.cursor();
      token_stream.nextToken();
    }

  CHECK(Token_delete);
  ast->delete_token = token_stream.cursor() - 1;

  if (token_stream.lookAhead() == '[')
    {
      ast->lbracket_token = token_stream.cursor();
      token_stream.nextToken();
      CHECK(']');
      ast->rbracket_token = token_stream.cursor() - 1;
    }

  if (!parseCastExpression(ast->expression))
    return false;

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseCastExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  if (token_stream.lookAhead() == '(')
    {
      token_stream.nextToken();

      CastExpressionAST *ast = CreateNode<CastExpressionAST>(_M_pool);

      if (parseTypeId(ast->type_id))
        {
          if (token_stream.lookAhead() == ')')
            {
              token_stream.nextToken();

              if (parseCastExpression(ast->expression))
                {
                  UPDATE_POS(ast, start, token_stream.cursor());
                  node = ast;

                  return true;
                }
            }
        }
    }

  token_stream.rewind((int) start);
  return parseUnaryExpression(node);
}

bool Parser::parsePmExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  if (!parseCastExpression(node) || !node) // ### fixme
    return false;

  while (token_stream.lookAhead() == Token_ptrmem)
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parseCastExpression(rightExpr))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseMultiplicativeExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  if (!parsePmExpression(node))
    return false;

  while (token_stream.lookAhead() == '*'
         || token_stream.lookAhead() == '/'
         || token_stream.lookAhead() == '%')
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parsePmExpression(rightExpr))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}


bool Parser::parseAdditiveExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  if (!parseMultiplicativeExpression(node))
    return false;

  while (token_stream.lookAhead() == '+' || token_stream.lookAhead() == '-')
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parseMultiplicativeExpression(rightExpr))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseShiftExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  if (!parseAdditiveExpression(node))
    return false;

  while (token_stream.lookAhead() == Token_shift)
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parseAdditiveExpression(rightExpr))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseRelationalExpression(ExpressionAST *&node, bool templArgs)
{
  std::size_t start = token_stream.cursor();

  if (!parseShiftExpression(node))
    return false;

  while (token_stream.lookAhead() == '<'
         || (token_stream.lookAhead() == '>' && !templArgs)
         || token_stream.lookAhead() == Token_leq
         || token_stream.lookAhead() == Token_geq)
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parseShiftExpression(rightExpr))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseEqualityExpression(ExpressionAST *&node, bool templArgs)
{
  std::size_t start = token_stream.cursor();

  if (!parseRelationalExpression(node, templArgs))
    return false;

  while (token_stream.lookAhead() == Token_eq
         || token_stream.lookAhead() == Token_not_eq)
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parseRelationalExpression(rightExpr, templArgs))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseAndExpression(ExpressionAST *&node, bool templArgs)
{
  std::size_t start = token_stream.cursor();

  if (!parseEqualityExpression(node, templArgs))
    return false;

  while (token_stream.lookAhead() == '&')
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parseEqualityExpression(rightExpr, templArgs))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseExclusiveOrExpression(ExpressionAST *&node, bool templArgs)
{
  std::size_t start = token_stream.cursor();

  if (!parseAndExpression(node, templArgs))
    return false;

  while (token_stream.lookAhead() == '^')
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parseAndExpression(rightExpr, templArgs))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseInclusiveOrExpression(ExpressionAST *&node, bool templArgs)
{
  std::size_t start = token_stream.cursor();

  if (!parseExclusiveOrExpression(node, templArgs))
    return false;

  while (token_stream.lookAhead() == '|')
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parseExclusiveOrExpression(rightExpr, templArgs))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseLogicalAndExpression(ExpressionAST *&node, bool templArgs)
{
  std::size_t start = token_stream.cursor();

  if (!parseInclusiveOrExpression(node, templArgs))
    return false;

  while (token_stream.lookAhead() == Token_and)
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parseInclusiveOrExpression(rightExpr, templArgs))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseLogicalOrExpression(ExpressionAST *&node, bool templArgs)
{
  std::size_t start = token_stream.cursor();

  if (!parseLogicalAndExpression(node, templArgs))
    return false;

  while (token_stream.lookAhead() == Token_or)
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parseLogicalAndExpression(rightExpr, templArgs))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseConditionalExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  if (!parseLogicalOrExpression(node))
    return false;

  if (token_stream.lookAhead() == '?')
    {
      token_stream.nextToken();

      ExpressionAST *leftExpr = 0;
      if (!parseExpression(leftExpr))
        return false;

      CHECK(':');

      ExpressionAST *rightExpr = 0;
      if (!parseAssignmentExpression(rightExpr))
        return false;

      ConditionalExpressionAST *ast
        = CreateNode<ConditionalExpressionAST>(_M_pool);

      ast->condition = node;
      ast->left_expression = leftExpr;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseAssignmentExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  if (token_stream.lookAhead() == Token_throw && !parseThrowExpression(node))
    return false;
  else if (!parseConditionalExpression(node))
    return false;

  while (token_stream.lookAhead() == Token_assign
         || token_stream.lookAhead() == '=')
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parseConditionalExpression(rightExpr))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseConstantExpression(ExpressionAST *&node)
{
  return parseConditionalExpression(node);
}

bool Parser::parseExpression(ExpressionAST *&node)
{
  return parseCommaExpression(node);
}

bool Parser::parseCommaExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  if (!parseAssignmentExpression(node))
    return false;

  while (token_stream.lookAhead() == ',')
    {
      std::size_t op = token_stream.cursor();
      token_stream.nextToken();

      ExpressionAST *rightExpr = 0;
      if (!parseAssignmentExpression(rightExpr))
        return false;

      BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool);
      ast->op = op;
      ast->left_expression = node;
      ast->right_expression = rightExpr;

      UPDATE_POS(ast, start, token_stream.cursor());
      node = ast;
    }

  return true;
}

bool Parser::parseThrowExpression(ExpressionAST *&node)
{
  std::size_t start = token_stream.cursor();

  CHECK(Token_throw);

  ThrowExpressionAST *ast = CreateNode<ThrowExpressionAST>(_M_pool);
  ast->throw_token = token_stream.cursor() - 1;

  parseAssignmentExpression(ast->expression);

  UPDATE_POS(ast, start, token_stream.cursor());
  node = ast;

  return true;
}

bool Parser::parseQ_ENUMS(DeclarationAST *&node)
{
  if (token_stream.lookAhead() != Token_Q_ENUMS)
    return false;

  if (token_stream.lookAhead(1) != '(')
    return false;

  token_stream.nextToken();
  token_stream.nextToken();

  int firstToken = token_stream.cursor();
  while (token_stream.lookAhead() != ')') {
    token_stream.nextToken();
  }
  QEnumsAST *ast = CreateNode<QEnumsAST>(_M_pool);
  UPDATE_POS(ast, firstToken, token_stream.cursor());
  node = ast;

  token_stream.nextToken();

  return true;
}

bool Parser::parseQ_PROPERTY(DeclarationAST *&node)
{
  if (token_stream.lookAhead() != Token_Q_PROPERTY)
    return false;

  if (token_stream.lookAhead(1) != '(')
    return false;

  token_stream.nextToken();
  token_stream.nextToken();

  int firstToken = token_stream.cursor();
  while (token_stream.lookAhead() != ')') {
    token_stream.nextToken();
  }
  QPropertyAST *ast = CreateNode<QPropertyAST>(_M_pool);
  UPDATE_POS(ast, firstToken, token_stream.cursor());
  node = ast;

//   const Token &t1 = token_stream[firstToken];
//   const Token &t2 = token_stream[token_stream.cursor()];
//   printf("property: %s\n",
//          qPrintable(QString::fromLatin1(t1.text + t1.position, t2.position - t1.position)));

  token_stream.nextToken();

  return true;
}

bool Parser::block_errors(bool block)
{
  bool current = _M_block_errors;
  _M_block_errors = block;
  return current;
}


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