tools/icheck/parser/src/shared/cplusplus/Parser.cpp
changeset 0 876b1a06bc25
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/icheck/parser/src/shared/cplusplus/Parser.cpp	Wed Aug 25 15:49:42 2010 +0300
@@ -0,0 +1,5295 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "Parser.h"
+#include "Token.h"
+#include "Lexer.h"
+#include "Control.h"
+#include "AST.h"
+#include "Literals.h"
+#include "ObjectiveCTypeQualifiers.h"
+#include <cstdio> // for putchar
+#ifdef ICHECK_BUILD
+#  include <QString>
+#endif
+
+#define CPLUSPLUS_NO_DEBUG_RULE
+#define MAX_EXPRESSION_DEPTH 100
+
+using namespace CPlusPlus;
+
+namespace {
+
+class DebugRule {
+    const char *name;
+    static int depth;
+
+public:
+    DebugRule(const char *name)
+        : name(name)
+    {
+        for (int i = 0; i < depth; ++i)
+            putchar(' ');
+
+        ++depth;
+        printf("%s\n", name);
+    }
+
+    ~DebugRule()
+    { --depth; }
+};
+
+int DebugRule::depth = 0;
+
+inline bool lookAtAssignmentOperator(int tokenKind)
+{
+    switch (tokenKind) {
+    case T_EQUAL:
+    case T_AMPER_EQUAL:
+    case T_CARET_EQUAL:
+    case T_SLASH_EQUAL:
+    case T_GREATER_GREATER_EQUAL:
+    case T_LESS_LESS_EQUAL:
+    case T_MINUS_EQUAL:
+    case T_PERCENT_EQUAL:
+    case T_PIPE_EQUAL:
+    case T_PLUS_EQUAL:
+    case T_STAR_EQUAL:
+    case T_TILDE_EQUAL:
+        return true;
+    default:
+        return false;
+    } // switch
+}
+
+namespace Prec {
+enum {
+    Unknown         = 0,
+    Comma           = 1,
+    Assignment      = 2,
+    Conditional     = 3,
+    LogicalOr       = 4,
+    LogicalAnd      = 5,
+    InclusiveOr     = 6,
+    ExclusiveOr     = 7,
+    And             = 8,
+    Equality        = 9,
+    Relational      = 10,
+    Shift           = 11,
+    Additive        = 12,
+    Multiplicative  = 13,
+    PointerToMember = 14
+};
+} // end of namespace Precedece
+
+inline int precedence(int tokenKind, bool templateArguments)
+{
+    // ### this will/might need some tuning for C++0x
+    // (see: [temp.names]p3)
+    if (templateArguments && tokenKind == T_GREATER)
+        return -1;
+
+    if (lookAtAssignmentOperator(tokenKind))
+        return Prec::Assignment;
+
+    switch (tokenKind) {
+    case T_COMMA:           return Prec::Comma;
+    case T_QUESTION:        return Prec::Conditional;
+    case T_PIPE_PIPE:       return Prec::LogicalOr;
+    case T_AMPER_AMPER:     return Prec::LogicalAnd;
+    case T_PIPE:            return Prec::InclusiveOr;
+    case T_CARET:           return Prec::ExclusiveOr;
+    case T_AMPER:           return Prec::And;
+    case T_EQUAL_EQUAL:
+    case T_EXCLAIM_EQUAL:   return Prec::Equality;
+    case T_GREATER:
+    case T_LESS:
+    case T_LESS_EQUAL:
+    case T_GREATER_EQUAL:   return Prec::Relational;
+    case T_LESS_LESS:
+    case T_GREATER_GREATER: return Prec::ExclusiveOr;
+    case T_PLUS:
+    case T_MINUS:           return Prec::Additive;
+    case T_STAR:
+    case T_SLASH:
+    case T_PERCENT:         return Prec::Multiplicative;
+    case T_ARROW_STAR:
+    case T_DOT_STAR:        return Prec::PointerToMember;
+    default:                return Prec::Unknown;
+    }
+}
+
+inline bool isBinaryOperator(int tokenKind)
+{ return precedence(tokenKind, false) != Prec::Unknown; }
+
+inline bool isRightAssociative(int tokenKind)
+{
+    const int prec = precedence(tokenKind, false);
+    return prec == Prec::Conditional || prec == Prec::Assignment;
+}
+
+} // end of anonymous namespace
+
+#ifndef CPLUSPLUS_NO_DEBUG_RULE
+#  define DEBUG_THIS_RULE() DebugRule __debug_rule__(__func__)
+#else
+#  define DEBUG_THIS_RULE() do {} while (0)
+#endif
+
+#define PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, minPrecedence) { \
+    if (LA() == T_THROW) { \
+        if (!parseThrowExpression(node)) \
+            return false; \
+    } else if (!parseCastExpression(node)) \
+        return false; \
+    \
+    parseExpressionWithOperatorPrecedence(node, minPrecedence); \
+    return true; \
+}
+
+class Parser::Rewind
+{
+    Parser *_parser;
+    MemoryPool::State _state;
+
+public:
+    inline Rewind(Parser *parser)
+        : _parser(parser) {}
+
+    inline void operator()(unsigned tokenIndex)
+    { rewind(tokenIndex); }
+
+    inline void mark()
+    { _state = _parser->_pool->state(); }
+
+    inline void rewind(unsigned tokenIndex)
+    {
+        _parser->rewind(tokenIndex);
+
+        if (_state.isValid())
+            _parser->_pool->rewind(_state);
+    }
+};
+
+Parser::Parser(TranslationUnit *unit)
+    : _translationUnit(unit),
+      _control(_translationUnit->control()),
+      _pool(_translationUnit->memoryPool()),
+      _tokenIndex(1),
+      _templateArguments(0),
+      _qtMocRunEnabled(false),
+      _objCEnabled(false),
+      _inFunctionBody(false),
+      _inObjCImplementationContext(false),
+      _expressionDepth(0)
+{ }
+
+Parser::~Parser()
+{ }
+
+bool Parser::qtMocRunEnabled() const
+{ return _qtMocRunEnabled; }
+
+void Parser::setQtMocRunEnabled(bool onoff)
+{ _qtMocRunEnabled = onoff; }
+
+bool Parser::objCEnabled() const
+{ return _objCEnabled; }
+
+void Parser::setObjCEnabled(bool onoff)
+{ _objCEnabled = onoff; }
+
+bool Parser::switchTemplateArguments(bool templateArguments)
+{
+    bool previousTemplateArguments = _templateArguments;
+    _templateArguments = templateArguments;
+    return previousTemplateArguments;
+}
+
+bool Parser::blockErrors(bool block)
+{ return _translationUnit->blockErrors(block); }
+
+bool Parser::skipUntil(int token)
+{
+    while (int tk = LA()) {
+        if (tk == token)
+            return true;
+
+        consumeToken();
+    }
+
+    return false;
+}
+
+void Parser::skipUntilDeclaration()
+{
+    for (; ; consumeToken()) {
+        switch (LA()) {
+        case T_EOF_SYMBOL:
+
+        // names
+        case T_IDENTIFIER:
+        case T_COLON_COLON:
+        case T_TILDE:
+        case T_OPERATOR:
+
+        // empty declaration
+        case T_SEMICOLON:
+
+        // member specification
+        case T_USING:
+        case T_TEMPLATE:
+        case T_PUBLIC:
+        case T_PROTECTED:
+        case T_PRIVATE:
+        case T_Q_SIGNALS:
+        case T_Q_SLOTS:
+
+        // declarations
+        case T_ENUM:
+        case T_NAMESPACE:
+        case T_ASM:
+        case T_EXPORT:
+        case T_AT_CLASS:
+        case T_AT_INTERFACE:
+        case T_AT_PROTOCOL:
+        case T_AT_IMPLEMENTATION:
+        case T_AT_END:
+            return;
+
+        default:
+            if (lookAtBuiltinTypeSpecifier() || lookAtClassKey() ||
+                lookAtFunctionSpecifier() || lookAtStorageClassSpecifier())
+                return;
+        } // switch
+    }
+}
+
+bool Parser::skipUntilStatement()
+{
+    while (int tk = LA()) {
+        switch (tk) {
+            case T_SEMICOLON:
+            case T_LBRACE:
+            case T_RBRACE:
+            case T_CONST:
+            case T_VOLATILE:
+            case T_IDENTIFIER:
+            case T_CASE:
+            case T_DEFAULT:
+            case T_IF:
+            case T_SWITCH:
+            case T_WHILE:
+            case T_DO:
+            case T_FOR:
+            case T_BREAK:
+            case T_CONTINUE:
+            case T_RETURN:
+            case T_GOTO:
+            case T_TRY:
+            case T_CATCH:
+            case T_THROW:
+            case T_CHAR:
+            case T_WCHAR_T:
+            case T_BOOL:
+            case T_SHORT:
+            case T_INT:
+            case T_LONG:
+            case T_SIGNED:
+            case T_UNSIGNED:
+            case T_FLOAT:
+            case T_DOUBLE:
+            case T_VOID:
+            case T_CLASS:
+            case T_STRUCT:
+            case T_UNION:
+            case T_ENUM:
+            case T_COLON_COLON:
+            case T_TEMPLATE:
+            case T_USING:
+                return true;
+
+            case T_AT_SYNCHRONIZED:
+                if (objCEnabled())
+                    return true;
+
+            default:
+                consumeToken();
+        }
+    }
+
+    return false;
+}
+
+bool Parser::skip(int l, int r)
+{
+    int count = 0;
+
+    while (int tk = LA()) {
+        if (tk == l)
+            ++count;
+        else if (tk == r)
+            --count;
+        else if (l != T_LBRACE && (tk == T_LBRACE ||
+                                   tk == T_RBRACE ||
+                                   tk == T_SEMICOLON))
+            return false;
+
+        if (count == 0)
+            return true;
+
+        consumeToken();
+    }
+
+    return false;
+}
+
+void Parser::match(int kind, unsigned *token)
+{
+    if (LA() == kind)
+        *token = consumeToken();
+    else {
+        *token = 0;
+        _translationUnit->error(_tokenIndex, "expected token `%s' got `%s'",
+                                Token::name(kind), tok().spell());
+    }
+}
+
+bool Parser::parseClassOrNamespaceName(NameAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_IDENTIFIER) {
+        unsigned identifier_token = cursor();
+
+        if (LA(2) == T_LESS && parseTemplateId(node) && LA() == T_COLON_COLON)
+            return true;
+
+        rewind(identifier_token);
+
+        if (LA(2) == T_COLON_COLON) {
+            SimpleNameAST *ast = new (_pool) SimpleNameAST;
+            ast->identifier_token = consumeToken();
+            node = ast;
+            return true;
+        }
+    } else if (LA() == T_TEMPLATE) {
+        unsigned template_token = consumeToken();
+        if (parseTemplateId(node))
+            return true;
+        rewind(template_token);
+    }
+    return false;
+}
+
+bool Parser::parseTemplateId(NameAST *&node)
+{
+    DEBUG_THIS_RULE();
+
+    const unsigned start = cursor();
+
+    if (LA() == T_IDENTIFIER && LA(2) == T_LESS) {
+        TemplateIdAST *ast = new (_pool) TemplateIdAST;
+        ast->identifier_token = consumeToken();
+        ast->less_token = consumeToken();
+        if (LA() == T_GREATER || parseTemplateArgumentList(
+                ast->template_argument_list)) {
+            if (LA() == T_GREATER) {
+                ast->greater_token = consumeToken();
+                node = ast;
+                return true;
+            }
+        }
+    }
+
+    rewind(start);
+
+    return false;
+}
+
+bool Parser::parseNestedNameSpecifier(NestedNameSpecifierListAST *&node,
+                                      bool /*acceptTemplateId*/)
+{
+    DEBUG_THIS_RULE();
+    NestedNameSpecifierListAST **nested_name_specifier = &node;
+    NameAST *class_or_namespace_name = 0;
+    if (parseClassOrNamespaceName(class_or_namespace_name) && LA() == T_COLON_COLON) {
+        unsigned scope_token = consumeToken();
+
+        NestedNameSpecifierAST *name = new (_pool) NestedNameSpecifierAST;
+        name->class_or_namespace_name = class_or_namespace_name;
+        name->scope_token = scope_token;
+
+        *nested_name_specifier = new (_pool) NestedNameSpecifierListAST(name);
+        nested_name_specifier = &(*nested_name_specifier)->next;
+
+        while (parseClassOrNamespaceName(class_or_namespace_name) && LA() == T_COLON_COLON) {
+            scope_token = consumeToken();
+
+            name = new (_pool) NestedNameSpecifierAST;
+            name->class_or_namespace_name = class_or_namespace_name;
+            name->scope_token = scope_token;
+
+            *nested_name_specifier = new (_pool) NestedNameSpecifierListAST(name);
+            nested_name_specifier = &(*nested_name_specifier)->next;
+        }
+
+        // ### ugly hack
+        rewind(scope_token);
+        consumeToken();
+        return true;
+    }
+
+    return false;
+}
+
+bool Parser::parseNestedNameSpecifierOpt(NestedNameSpecifierListAST *&name, bool acceptTemplateId)
+{
+    DEBUG_THIS_RULE();
+    unsigned start = cursor();
+    if (! parseNestedNameSpecifier(name, acceptTemplateId))
+        rewind(start);
+    return true;
+}
+
+bool Parser::parseName(NameAST *&node, bool acceptTemplateId)
+{
+    DEBUG_THIS_RULE();
+    unsigned global_scope_token = 0;
+    if (LA() == T_COLON_COLON)
+        global_scope_token = consumeToken();
+
+    NestedNameSpecifierListAST *nested_name_specifier = 0;
+    parseNestedNameSpecifierOpt(nested_name_specifier,
+                                /*acceptTemplateId=*/ true);
+
+    NameAST *unqualified_name = 0;
+    if (parseUnqualifiedName(unqualified_name,
+                             /*acceptTemplateId=*/ acceptTemplateId || nested_name_specifier != 0)) {
+        if (! global_scope_token && ! nested_name_specifier) {
+            node = unqualified_name;
+            return true;
+        }
+
+        QualifiedNameAST *ast = new (_pool) QualifiedNameAST;
+        ast->global_scope_token = global_scope_token;
+        ast->nested_name_specifier_list = nested_name_specifier;
+        ast->unqualified_name = unqualified_name;
+        node = ast;
+        return true;
+    }
+
+    return false;
+}
+
+bool Parser::parseTranslationUnit(TranslationUnitAST *&node)
+{
+    DEBUG_THIS_RULE();
+    TranslationUnitAST *ast = new (_pool) TranslationUnitAST;
+    DeclarationListAST **decl = &ast->declaration_list;
+
+    while (LA()) {
+        unsigned start_declaration = cursor();
+
+        DeclarationAST *declaration = 0;
+
+        if (parseDeclaration(declaration)) {
+            *decl = new (_pool) DeclarationListAST;
+            (*decl)->value = declaration;
+            decl = &(*decl)->next;
+        } else {
+            _translationUnit->error(start_declaration, "expected a declaration");
+            rewind(start_declaration + 1);
+            skipUntilDeclaration();
+        }
+
+        _templateArgumentList.clear();
+    }
+
+    node = ast;
+    return true;
+}
+
+bool Parser::parseEmptyDeclaration(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_SEMICOLON) {
+        EmptyDeclarationAST *ast = new (_pool) EmptyDeclarationAST;
+        ast->semicolon_token = consumeToken();
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseDeclaration(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    switch (LA()) {
+    case T_SEMICOLON:
+        return parseEmptyDeclaration(node);
+
+    case T_NAMESPACE:
+        return parseNamespace(node);
+
+    case T_USING:
+        return parseUsing(node);
+
+    case T_ASM:
+        return parseAsmDefinition(node);
+
+    case T_TEMPLATE:
+    case T_EXPORT:
+        return parseTemplateDeclaration(node);
+
+    // ObjcC++
+    case T_AT_CLASS:
+        return parseObjCClassForwardDeclaration(node);
+
+    case T_AT_INTERFACE:
+        return parseObjCInterface(node);
+
+    case T_AT_PROTOCOL:
+        return parseObjCProtocol(node);
+
+    case T_AT_IMPLEMENTATION:
+        return parseObjCImplementation(node);
+
+    case T_AT_END:
+        // TODO: should this be done here, or higher-up?
+        _translationUnit->error(cursor(), "skip stray token `%s'", tok().spell());
+        consumeToken();
+        break;
+
+    default: {
+        if (_objCEnabled && LA() == T___ATTRIBUTE__) {
+            const unsigned start = cursor();
+            SpecifierListAST *attributes = 0, **attr = &attributes;
+            while (parseAttributeSpecifier(*attr))
+                attr = &(*attr)->next;
+            if (LA() == T_AT_INTERFACE)
+                return parseObjCInterface(node, attributes);
+            else if (LA() == T_AT_PROTOCOL)
+                return parseObjCProtocol(node, attributes);
+            else if (LA() == T_AT_PROPERTY)
+                return parseObjCPropertyDeclaration(node, attributes);
+            rewind(start);
+        }
+
+        if (LA() == T_EXTERN && LA(2) == T_TEMPLATE)
+            return parseTemplateDeclaration(node);
+        else if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL)
+            return parseLinkageSpecification(node);
+        else
+            return parseSimpleDeclaration(node);
+    }   break; // default
+
+    } // end switch
+
+    return false;
+}
+
+bool Parser::parseLinkageSpecification(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL) {
+        LinkageSpecificationAST *ast = new (_pool) LinkageSpecificationAST;
+        ast->extern_token = consumeToken();
+        ast->extern_type_token = consumeToken();
+
+        if (LA() == T_LBRACE)
+            parseLinkageBody(ast->declaration);
+        else
+            parseDeclaration(ast->declaration);
+
+        node = ast;
+        return true;
+    }
+
+    return false;
+}
+
+bool Parser::parseLinkageBody(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_LBRACE) {
+        LinkageBodyAST *ast = new (_pool) LinkageBodyAST;
+        ast->lbrace_token = consumeToken();
+        DeclarationListAST **declaration_ptr = &ast->declaration_list;
+
+        while (int tk = LA()) {
+            if (tk == T_RBRACE)
+                break;
+
+            unsigned start_declaration = cursor();
+            DeclarationAST *declaration = 0;
+            if (parseDeclaration(declaration)) {
+                *declaration_ptr = new (_pool) DeclarationListAST;
+                (*declaration_ptr)->value = declaration;
+                declaration_ptr = &(*declaration_ptr)->next;
+            } else {
+                _translationUnit->error(start_declaration, "expected a declaration");
+                rewind(start_declaration + 1);
+                skipUntilDeclaration();
+            }
+
+            _templateArgumentList.clear();
+        }
+        match(T_RBRACE, &ast->rbrace_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+// ### rename parseNamespaceAliarOrDeclaration?
+bool Parser::parseNamespace(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_NAMESPACE)
+        return false;
+
+    unsigned namespace_token = consumeToken();
+
+    if (LA() == T_IDENTIFIER && LA(2) == T_EQUAL) {
+        NamespaceAliasDefinitionAST *ast =
+                new (_pool) NamespaceAliasDefinitionAST;
+        ast->namespace_token = namespace_token;
+        ast->namespace_name_token = consumeToken();
+        ast->equal_token = consumeToken();
+        parseName(ast->name);
+        match(T_SEMICOLON, &ast->semicolon_token);
+        node = ast;
+        return true;
+    }
+
+    NamespaceAST *ast = new (_pool) NamespaceAST;
+    ast->namespace_token = namespace_token;
+    if (LA() == T_IDENTIFIER)
+        ast->identifier_token = consumeToken();
+    SpecifierListAST **attr_ptr = &ast->attribute_list;
+    while (LA() == T___ATTRIBUTE__) {
+        parseAttributeSpecifier(*attr_ptr);
+        attr_ptr = &(*attr_ptr)->next;
+    }
+    if (LA() == T_LBRACE)
+        parseLinkageBody(ast->linkage_body);
+    node = ast;
+    return true;
+}
+
+bool Parser::parseUsing(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_USING)
+        return false;
+
+    if (LA(2) == T_NAMESPACE)
+        return parseUsingDirective(node);
+
+    UsingAST *ast = new (_pool) UsingAST;
+    ast->using_token = consumeToken();
+
+    if (LA() == T_TYPENAME)
+        ast->typename_token = consumeToken();
+
+    parseName(ast->name);
+    match(T_SEMICOLON, &ast->semicolon_token);
+    node = ast;
+    return true;
+}
+
+bool Parser::parseUsingDirective(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_USING && LA(2) == T_NAMESPACE) {
+        UsingDirectiveAST *ast = new (_pool) UsingDirectiveAST;
+        ast->using_token = consumeToken();
+        ast->namespace_token = consumeToken();
+        if (! parseName(ast->name))
+            _translationUnit->warning(cursor(), "expected `namespace name' before `%s'",
+                                      tok().spell());
+        match(T_SEMICOLON, &ast->semicolon_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseConversionFunctionId(NameAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_OPERATOR)
+        return false;
+    unsigned operator_token = consumeToken();
+    SpecifierListAST *type_specifier = 0;
+    if (! parseTypeSpecifier(type_specifier)) {
+        return false;
+    }
+    PtrOperatorListAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
+    while (parsePtrOperator(*ptr_operators_tail))
+        ptr_operators_tail = &(*ptr_operators_tail)->next;
+
+    ConversionFunctionIdAST *ast = new (_pool) ConversionFunctionIdAST;
+    ast->operator_token = operator_token;
+    ast->type_specifier_list = type_specifier;
+    ast->ptr_operator_list = ptr_operators;
+    node = ast;
+    return true;
+}
+
+bool Parser::parseOperatorFunctionId(NameAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_OPERATOR)
+        return false;
+    unsigned operator_token = consumeToken();
+
+    OperatorAST *op = 0;
+    if (! parseOperator(op))
+        return false;
+
+    OperatorFunctionIdAST *ast = new (_pool) OperatorFunctionIdAST;
+    ast->operator_token = operator_token;
+    ast->op = op;
+    node = ast;
+    return true;
+}
+
+Parser::TemplateArgumentListEntry *Parser::templateArgumentListEntry(unsigned tokenIndex)
+{
+    std::map<unsigned, TemplateArgumentListEntry>::iterator it =_templateArgumentList.find(tokenIndex);
+    if (it != _templateArgumentList.end())
+        return &it->second;
+
+    return 0;
+}
+
+bool Parser::parseTemplateArgumentList(TemplateArgumentListAST *&node)
+{
+    if (TemplateArgumentListEntry *entry = templateArgumentListEntry(cursor())) {
+        rewind(entry->cursor);
+        node = entry->ast;
+        return entry->ast != 0;
+    }
+
+    unsigned start = cursor();
+
+    DEBUG_THIS_RULE();
+    TemplateArgumentListAST **template_argument_ptr = &node;
+    ExpressionAST *template_argument = 0;
+    if (parseTemplateArgument(template_argument)) {
+        *template_argument_ptr = new (_pool) TemplateArgumentListAST;
+        (*template_argument_ptr)->value = template_argument;
+        template_argument_ptr = &(*template_argument_ptr)->next;
+        while (LA() == T_COMMA) {
+            consumeToken(); // consume T_COMMA
+
+            if (parseTemplateArgument(template_argument)) {
+                *template_argument_ptr = new (_pool) TemplateArgumentListAST;
+                (*template_argument_ptr)->value = template_argument;
+                template_argument_ptr = &(*template_argument_ptr)->next;
+            }
+        }
+
+        _templateArgumentList.insert(std::make_pair(cursor(), TemplateArgumentListEntry(start, cursor(), node)));
+        return true;
+    }
+
+    _templateArgumentList.insert(std::make_pair(cursor(), TemplateArgumentListEntry(start, cursor(), 0)));
+
+    return false;
+}
+
+bool Parser::parseAsmDefinition(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_ASM)
+        return false;
+
+    AsmDefinitionAST *ast = new (_pool) AsmDefinitionAST;
+    ast->asm_token = consumeToken();
+
+    if (LA() == T_VOLATILE)
+        ast->volatile_token = consumeToken();
+
+    match(T_LPAREN, &ast->lparen_token);
+    unsigned string_literal_token = 0;
+    match(T_STRING_LITERAL, &string_literal_token);
+    while (LA() == T_STRING_LITERAL) {
+        consumeToken();
+    }
+    if (LA() == T_COLON) {
+        consumeToken(); // skip T_COLON
+        parseAsmOperandList();
+        if (LA() == T_COLON) {
+            consumeToken();
+            parseAsmOperandList();
+            if (LA() == T_COLON) {
+                consumeToken();
+                parseAsmClobberList();
+            }
+        } else if (LA() == T_COLON_COLON) {
+            consumeToken();
+            parseAsmClobberList();
+        }
+    } else if (LA() == T_COLON_COLON) {
+        consumeToken();
+        parseAsmClobberList();
+    }
+    match(T_RPAREN, &ast->rparen_token);
+    match(T_SEMICOLON, &ast->semicolon_token);
+    node = ast;
+    return true;
+}
+
+bool Parser::parseAsmOperandList()
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_STRING_LITERAL)
+        return true;
+
+    if (parseAsmOperand()) {
+        while (LA() == T_COMMA) {
+            consumeToken();
+            parseAsmOperand();
+        }
+        return true;
+    }
+
+    return false;
+}
+
+bool Parser::parseAsmOperand()
+{
+    DEBUG_THIS_RULE();
+    unsigned string_literal_token = 0;
+    match(T_STRING_LITERAL, &string_literal_token);
+
+    if (LA() == T_LBRACKET) {
+        /*unsigned lbracket_token = */ consumeToken();
+        match(T_STRING_LITERAL, &string_literal_token);
+        unsigned rbracket_token = 0;
+        match(T_RBRACKET, &rbracket_token);
+    }
+
+    unsigned lparen_token = 0, rparen_token = 0;
+    match(T_LPAREN, &lparen_token);
+    ExpressionAST *expression = 0;
+    parseExpression(expression);
+    match(T_RPAREN, &rparen_token);
+    return true;
+}
+
+bool Parser::parseAsmClobberList()
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_STRING_LITERAL)
+        return false;
+
+    unsigned string_literal_token = consumeToken();
+
+    while (LA() == T_COMMA) {
+        consumeToken();
+        match(T_STRING_LITERAL, &string_literal_token);
+    }
+
+    return true;
+}
+
+bool Parser::parseTemplateDeclaration(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (! (LA(1) == T_TEMPLATE || ((LA(1) == T_EXPORT || LA(1) == T_EXTERN)
+            && LA(2) == T_TEMPLATE)))
+        return false;
+
+    TemplateDeclarationAST *ast = new (_pool) TemplateDeclarationAST;
+
+    if (LA() == T_EXPORT || LA() == T_EXPORT)
+        ast->export_token = consumeToken();
+
+    ast->template_token = consumeToken();
+
+    if (LA() == T_LESS) {
+        ast->less_token = consumeToken();
+        if (LA() == T_GREATER || parseTemplateParameterList(ast->template_parameter_list))
+            match(T_GREATER, &ast->greater_token);
+    }
+
+    parseDeclaration(ast->declaration);
+    node = ast;
+    return true;
+}
+
+bool Parser::parseOperator(OperatorAST *&node) // ### FIXME
+{
+    DEBUG_THIS_RULE();
+    OperatorAST *ast = new (_pool) OperatorAST;
+
+    switch (LA()) {
+    case T_NEW:
+    case T_DELETE: {
+        ast->op_token = consumeToken();
+        if (LA() == T_LBRACKET) {
+            ast->open_token = consumeToken();
+            match(T_RBRACKET, &ast->close_token);
+        }
+    } break;
+
+    case T_PLUS:
+    case T_MINUS:
+    case T_STAR:
+    case T_SLASH:
+    case T_PERCENT:
+    case T_CARET:
+    case T_AMPER:
+    case T_PIPE:
+    case T_TILDE:
+    case T_EXCLAIM:
+    case T_LESS:
+    case T_GREATER:
+    case T_COMMA:
+    case T_AMPER_EQUAL:
+    case T_CARET_EQUAL:
+    case T_SLASH_EQUAL:
+    case T_EQUAL:
+    case T_EQUAL_EQUAL:
+    case T_EXCLAIM_EQUAL:
+    case T_GREATER_EQUAL:
+    case T_GREATER_GREATER_EQUAL:
+    case T_LESS_EQUAL:
+    case T_LESS_LESS_EQUAL:
+    case T_MINUS_EQUAL:
+    case T_PERCENT_EQUAL:
+    case T_PIPE_EQUAL:
+    case T_PLUS_EQUAL:
+    case T_STAR_EQUAL:
+    case T_TILDE_EQUAL:
+    case T_LESS_LESS:
+    case T_GREATER_GREATER:
+    case T_AMPER_AMPER:
+    case T_PIPE_PIPE:
+    case T_PLUS_PLUS:
+    case T_MINUS_MINUS:
+    case T_ARROW_STAR:
+    case T_DOT_STAR:
+    case T_ARROW:
+        ast->op_token = consumeToken();
+        break;
+
+    default:
+        if (LA() == T_LPAREN && LA(2) == T_RPAREN) {
+            ast->op_token = ast->open_token = consumeToken();
+            ast->close_token = consumeToken();
+        } else if (LA() == T_LBRACKET && LA(2) == T_RBRACKET) {
+            ast->op_token = ast->open_token = consumeToken();
+            ast->close_token = consumeToken();
+        } else {
+            return false;
+        }
+    }
+
+    node = ast;
+    return true;
+}
+
+bool Parser::parseCvQualifiers(SpecifierListAST *&node)
+{
+    DEBUG_THIS_RULE();
+
+    unsigned start = cursor();
+
+    SpecifierListAST **ast = &node;
+    while (*ast)
+        ast = &(*ast)->next;
+
+    while (int tk = LA()) {
+        if (tk == T_CONST || tk == T_VOLATILE) {
+            SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
+            spec->specifier_token = consumeToken();
+            *ast = new (_pool) SpecifierListAST(spec);
+            ast = &(*ast)->next;
+        } else if(LA() == T___ATTRIBUTE__) {
+            parseAttributeSpecifier(*ast);
+            ast = &(*ast)->next;
+        } else {
+            break;
+        }
+    }
+
+    return start != cursor();
+}
+
+bool Parser::parsePtrOperator(PtrOperatorListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_AMPER) {
+        ReferenceAST *ast = new (_pool) ReferenceAST;
+        ast->amp_token = consumeToken();
+        node = new (_pool) PtrOperatorListAST(ast);
+        return true;
+    } else if (LA() == T_STAR) {
+        PointerAST *ast = new (_pool) PointerAST;
+        ast->star_token = consumeToken();
+        parseCvQualifiers(ast->cv_qualifier_list);
+        node = new (_pool) PtrOperatorListAST(ast);
+        return true;
+    } else if (LA() == T_COLON_COLON || LA() == T_IDENTIFIER) {
+        unsigned scope_or_identifier_token = cursor();
+
+        unsigned global_scope_token = 0;
+        if (LA() == T_COLON_COLON)
+            global_scope_token = consumeToken();
+
+        NestedNameSpecifierListAST *nested_name_specifiers = 0;
+        bool has_nested_name_specifier = parseNestedNameSpecifier(nested_name_specifiers, true);
+        if (has_nested_name_specifier && LA() == T_STAR) {
+            PointerToMemberAST *ast = new (_pool) PointerToMemberAST;
+            ast->global_scope_token = global_scope_token;
+            ast->nested_name_specifier_list = nested_name_specifiers;
+            ast->star_token = consumeToken();
+            parseCvQualifiers(ast->cv_qualifier_list);
+            node = new (_pool) PtrOperatorListAST(ast);
+            return true;
+        }
+        rewind(scope_or_identifier_token);
+    }
+    return false;
+}
+
+bool Parser::parseTemplateArgument(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    unsigned start = cursor();
+    if (parseTypeId(node) && (LA() == T_COMMA || LA() == T_GREATER))
+        return true;
+
+    rewind(start);
+    bool previousTemplateArguments = switchTemplateArguments(true);
+    bool parsed = parseLogicalOrExpression(node);
+    (void) switchTemplateArguments(previousTemplateArguments);
+    return parsed;
+}
+
+bool Parser::parseDeclSpecifierSeq(SpecifierListAST *&decl_specifier_seq,
+                                   bool onlyTypeSpecifiers,
+                                   bool simplified)
+{
+    DEBUG_THIS_RULE();
+    bool has_type_specifier = false;
+    NameAST *named_type_specifier = 0;
+    SpecifierListAST **decl_specifier_seq_ptr = &decl_specifier_seq;
+    for (;;) {
+        if (lookAtCVQualifier()) {
+            SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
+            spec->specifier_token = consumeToken();
+            *decl_specifier_seq_ptr = new (_pool) SpecifierListAST(spec);
+            decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+        } else if (! onlyTypeSpecifiers && lookAtStorageClassSpecifier()) {
+            SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
+            spec->specifier_token = consumeToken();
+            *decl_specifier_seq_ptr = new (_pool) SpecifierListAST(spec);
+            decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+        } else if (! named_type_specifier && lookAtBuiltinTypeSpecifier()) {
+            parseBuiltinTypeSpecifier(*decl_specifier_seq_ptr);
+            decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+            has_type_specifier = true;
+        } else if (! has_type_specifier && (LA() == T_COLON_COLON ||
+                                            LA() == T_IDENTIFIER)) {
+            if (! parseName(named_type_specifier))
+                return false;
+            NamedTypeSpecifierAST *spec = new (_pool) NamedTypeSpecifierAST;
+            spec->name = named_type_specifier;
+            *decl_specifier_seq_ptr = new (_pool) SpecifierListAST(spec);
+            decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+            has_type_specifier = true;
+        } else if (! simplified && ! has_type_specifier && (LA() == T_TYPENAME ||
+                                                            LA() == T_ENUM     ||
+                                                            lookAtClassKey())) {
+            unsigned startOfElaboratedTypeSpecifier = cursor();
+            if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr)) {
+                _translationUnit->error(startOfElaboratedTypeSpecifier,
+                                        "expected an elaborated type specifier");
+                break;
+            }
+            decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+            has_type_specifier = true;
+        } else
+            break;
+    }
+
+    return decl_specifier_seq != 0;
+}
+
+bool Parser::parseDeclaratorOrAbstractDeclarator(DeclaratorAST *&node)
+{
+    DEBUG_THIS_RULE();
+    unsigned start = cursor();
+    bool blocked = blockErrors(true);
+    if (parseDeclarator(node)) {
+        blockErrors(blocked);
+        return true;
+    }
+    blockErrors(blocked);
+    rewind(start);
+    return parseAbstractDeclarator(node);
+}
+
+bool Parser::parseCoreDeclarator(DeclaratorAST *&node)
+{
+    DEBUG_THIS_RULE();
+    unsigned start = cursor();
+    SpecifierListAST *attributes = 0;
+    SpecifierListAST **attribute_ptr = &attributes;
+    while (LA() == T___ATTRIBUTE__) {
+        parseAttributeSpecifier(*attribute_ptr);
+        attribute_ptr = &(*attribute_ptr)->next;
+    }
+
+    PtrOperatorListAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
+    while (parsePtrOperator(*ptr_operators_tail))
+        ptr_operators_tail = &(*ptr_operators_tail)->next;
+
+    if (LA() == T_COLON_COLON || LA() == T_IDENTIFIER || LA() == T_TILDE
+            || LA() == T_OPERATOR) {
+        NameAST *name = 0;
+        if (parseName(name)) {
+            DeclaratorIdAST *declarator_id = new (_pool) DeclaratorIdAST;
+            declarator_id->name = name;
+            DeclaratorAST *ast = new (_pool) DeclaratorAST;
+            ast->attribute_list = attributes;
+            ast->ptr_operator_list = ptr_operators;
+            ast->core_declarator = declarator_id;
+            node = ast;
+            return true;
+        }
+    } else if (LA() == T_LPAREN) {
+        if (attributes)
+            _translationUnit->warning(attributes->firstToken(), "unexpected attribtues");
+
+        unsigned lparen_token = consumeToken();
+        DeclaratorAST *declarator = 0;
+        if (parseDeclarator(declarator) && LA() == T_RPAREN) {
+            NestedDeclaratorAST *nested_declarator = new (_pool) NestedDeclaratorAST;
+            nested_declarator->lparen_token = lparen_token;
+            nested_declarator->declarator = declarator;
+            nested_declarator->rparen_token = consumeToken();
+            DeclaratorAST *ast = new (_pool) DeclaratorAST;
+            ast->ptr_operator_list = ptr_operators;
+            ast->core_declarator = nested_declarator;
+            node = ast;
+            return true;
+        }
+    }
+    rewind(start);
+    return false;
+}
+
+bool Parser::parseDeclarator(DeclaratorAST *&node, bool stopAtCppInitializer)
+{
+    DEBUG_THIS_RULE();
+    if (! parseCoreDeclarator(node))
+        return false;
+
+    PostfixDeclaratorListAST **postfix_ptr = &node->postfix_declarator_list;
+
+    for (;;) {
+        unsigned startOfPostDeclarator = cursor();
+
+        if (LA() == T_LPAREN) {
+            if (stopAtCppInitializer) {
+                unsigned lparen_token = cursor();
+                ExpressionAST *initializer = 0;
+
+                bool blocked = blockErrors(true);
+                if (parseInitializer(initializer, &node->equals_token)) {
+                    if (NestedExpressionAST *expr = initializer->asNestedExpression()) {
+                        if (expr->expression && expr->rparen_token && (LA() == T_COMMA || LA() == T_SEMICOLON)) {
+                            rewind(lparen_token);
+
+                            // check for ambiguous declarators.
+
+                            consumeToken();
+                            ParameterDeclarationClauseAST *parameter_declaration_clause = 0;
+                            if (parseParameterDeclarationClause(parameter_declaration_clause) && LA() == T_RPAREN) {
+                                unsigned rparen_token = consumeToken();
+
+                                FunctionDeclaratorAST *ast = new (_pool) FunctionDeclaratorAST;
+                                ast->lparen_token = lparen_token;
+                                ast->parameters = parameter_declaration_clause;
+                                ast->as_cpp_initializer = initializer;
+                                ast->rparen_token = rparen_token;
+                                *postfix_ptr = new (_pool) PostfixDeclaratorListAST(ast);
+                                postfix_ptr = &(*postfix_ptr)->next;
+
+                                blockErrors(blocked);
+                                return true;
+                            }
+
+
+                            blockErrors(blocked);
+                            rewind(lparen_token);
+                            return true;
+                        }
+                    }
+                }
+
+                blockErrors(blocked);
+                rewind(lparen_token);
+            }
+
+            FunctionDeclaratorAST *ast = new (_pool) FunctionDeclaratorAST;
+            ast->lparen_token = consumeToken();
+            parseParameterDeclarationClause(ast->parameters);
+            if (LA() != T_RPAREN) {
+                rewind(startOfPostDeclarator);
+                break;
+            }
+
+            ast->rparen_token = consumeToken();
+            parseCvQualifiers(ast->cv_qualifier_list);
+            parseExceptionSpecification(ast->exception_specification);
+            *postfix_ptr = new (_pool) PostfixDeclaratorListAST(ast);
+            postfix_ptr = &(*postfix_ptr)->next;
+        } else if (LA() == T_LBRACKET) {
+            ArrayDeclaratorAST *ast = new (_pool) ArrayDeclaratorAST;
+            ast->lbracket_token = consumeToken();
+            if (LA() == T_RBRACKET || parseConstantExpression(ast->expression)) {
+                match(T_RBRACKET, &ast->rbracket_token);
+            }
+            *postfix_ptr = new (_pool) PostfixDeclaratorListAST(ast);
+            postfix_ptr = &(*postfix_ptr)->next;
+        } else
+            break;
+    }
+
+    if (LA() == T___ASM__ && LA(2) == T_LPAREN) { // ### store the asm specifier in the AST
+        consumeToken(); // skip __asm__
+        consumeToken(); // skip T_LPAREN
+
+        if (skipUntil(T_RPAREN))
+            consumeToken(); // skip T_RPAREN
+    }
+
+    SpecifierListAST **spec_ptr = &node->post_attribute_list;
+    while (LA() == T___ATTRIBUTE__) {
+        parseAttributeSpecifier(*spec_ptr);
+        spec_ptr = &(*spec_ptr)->next;
+    }
+
+    return true;
+}
+
+bool Parser::parseAbstractCoreDeclarator(DeclaratorAST *&node)
+{
+    DEBUG_THIS_RULE();
+
+    PtrOperatorListAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators;
+    while (parsePtrOperator(*ptr_operators_tail))
+        ptr_operators_tail = &(*ptr_operators_tail)->next;
+
+    unsigned after_ptr_operators = cursor();
+
+    if (LA() == T_LPAREN) {
+        unsigned lparen_token = consumeToken();
+        DeclaratorAST *declarator = 0;
+        if (parseAbstractDeclarator(declarator) && LA() == T_RPAREN) {
+            NestedDeclaratorAST *nested_declarator = new (_pool) NestedDeclaratorAST;
+            nested_declarator->lparen_token = lparen_token;
+            nested_declarator->declarator = declarator;
+            nested_declarator->rparen_token = consumeToken();
+            DeclaratorAST *ast = new (_pool) DeclaratorAST;
+            ast->ptr_operator_list = ptr_operators;
+            ast->core_declarator = nested_declarator;
+            node = ast;
+            return true;
+        }
+    }
+
+    rewind(after_ptr_operators);
+    if (ptr_operators) {
+        DeclaratorAST *ast = new (_pool) DeclaratorAST;
+        ast->ptr_operator_list = ptr_operators;
+        node = ast;
+    }
+
+    return true;
+}
+
+bool Parser::parseAbstractDeclarator(DeclaratorAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (! parseAbstractCoreDeclarator(node))
+        return false;
+
+    PostfixDeclaratorListAST *postfix_declarators = 0,
+        **postfix_ptr = &postfix_declarators;
+
+    for (;;) {
+        if (LA() == T_LPAREN) {
+            FunctionDeclaratorAST *ast = new (_pool) FunctionDeclaratorAST;
+            ast->lparen_token = consumeToken();
+            if (LA() == T_RPAREN || parseParameterDeclarationClause(ast->parameters)) {
+                if (LA() == T_RPAREN)
+                    ast->rparen_token = consumeToken();
+            }
+            parseCvQualifiers(ast->cv_qualifier_list);
+            parseExceptionSpecification(ast->exception_specification);
+            *postfix_ptr = new (_pool) PostfixDeclaratorListAST(ast);
+            postfix_ptr = &(*postfix_ptr)->next;
+        } else if (LA() == T_LBRACKET) {
+            ArrayDeclaratorAST *ast = new (_pool) ArrayDeclaratorAST;
+            ast->lbracket_token = consumeToken();
+            if (LA() == T_RBRACKET || parseConstantExpression(ast->expression)) {
+                if (LA() == T_RBRACKET)
+                    ast->rbracket_token = consumeToken();
+            }
+            *postfix_ptr = new (_pool) PostfixDeclaratorListAST(ast);
+            postfix_ptr = &(*postfix_ptr)->next;
+        } else
+            break;
+    }
+
+    if (postfix_declarators) {
+        if (! node)
+            node = new (_pool) DeclaratorAST;
+
+        node->postfix_declarator_list = postfix_declarators;
+    }
+
+    return true;
+}
+
+bool Parser::parseEnumSpecifier(SpecifierListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_ENUM) {
+        unsigned enum_token = consumeToken();
+        NameAST *name = 0;
+        parseName(name);
+        if (LA() == T_LBRACE) {
+            EnumSpecifierAST *ast = new (_pool) EnumSpecifierAST;
+            ast->enum_token = enum_token;
+            ast->name = name;
+            ast->lbrace_token = consumeToken();
+            unsigned comma_token = 0;
+            EnumeratorListAST **enumerator_ptr = &ast->enumerator_list;
+            while (int tk = LA()) {
+                if (tk == T_RBRACE)
+                    break;
+
+                if (LA() != T_IDENTIFIER) {
+                    _translationUnit->error(cursor(), "expected identifier before '%s'", tok().spell());
+                    skipUntil(T_IDENTIFIER);
+                }
+
+                if (parseEnumerator(*enumerator_ptr)) {
+                    enumerator_ptr = &(*enumerator_ptr)->next;
+                }
+
+                if (LA() != T_RBRACE)
+                    match(T_COMMA, &comma_token);
+            }
+            match(T_RBRACE, &ast->rbrace_token);
+            node = new (_pool) SpecifierListAST(ast);
+            return true;
+        }
+    }
+    return false;
+}
+
+bool Parser::parseTemplateParameterList(DeclarationListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    DeclarationListAST **template_parameter_ptr = &node;
+    DeclarationAST *declaration = 0;
+    if (parseTemplateParameter(declaration)) {
+        *template_parameter_ptr = new (_pool) DeclarationListAST;
+        (*template_parameter_ptr)->value = declaration;
+        template_parameter_ptr = &(*template_parameter_ptr)->next;
+
+        while (LA() == T_COMMA) {
+            consumeToken(); // XXX Store this token somewhere
+
+            declaration = 0;
+            if (parseTemplateParameter(declaration)) {
+                *template_parameter_ptr = new (_pool) DeclarationListAST;
+                (*template_parameter_ptr)->value = declaration;
+                template_parameter_ptr = &(*template_parameter_ptr)->next;
+            }
+        }
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseTemplateParameter(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (parseTypeParameter(node))
+        return true;
+    bool previousTemplateArguments = switchTemplateArguments(true);
+    bool parsed = parseParameterDeclaration(node);
+    (void) switchTemplateArguments(previousTemplateArguments);
+    return parsed;
+}
+
+bool Parser::parseTypenameTypeParameter(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_CLASS || LA() == T_TYPENAME) {
+        TypenameTypeParameterAST *ast = new (_pool) TypenameTypeParameterAST;
+        ast->classkey_token = consumeToken();
+        parseName(ast->name);
+        if (LA() == T_EQUAL) {
+            ast->equal_token = consumeToken();
+            parseTypeId(ast->type_id);
+        }
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseTemplateTypeParameter(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_TEMPLATE) {
+        TemplateTypeParameterAST *ast = new (_pool) TemplateTypeParameterAST;
+        ast->template_token = consumeToken();
+        if (LA() == T_LESS)
+            ast->less_token = consumeToken();
+        parseTemplateParameterList(ast->template_parameter_list);
+        if (LA() == T_GREATER)
+            ast->greater_token = consumeToken();
+        if (LA() == T_CLASS)
+            ast->class_token = consumeToken();
+
+        // parse optional name
+        parseName(ast->name);
+
+        if (LA() == T_EQUAL) {
+            ast->equal_token = consumeToken();
+            parseTypeId(ast->type_id);
+        }
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseTypeParameter(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_CLASS || LA() == T_TYPENAME)
+        return parseTypenameTypeParameter(node);
+    else if (LA() == T_TEMPLATE)
+        return parseTemplateTypeParameter(node);
+    else
+        return false;
+}
+
+bool Parser::parseTypeId(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    SpecifierListAST *type_specifier = 0;
+    if (parseTypeSpecifier(type_specifier)) {
+        TypeIdAST *ast = new (_pool) TypeIdAST;
+        ast->type_specifier_list = type_specifier;
+        parseAbstractDeclarator(ast->declarator);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_RPAREN)
+        return true; // nothing to do
+
+    DeclarationListAST *parameter_declarations = 0;
+
+    unsigned dot_dot_dot_token = 0;
+    if (LA() == T_DOT_DOT_DOT)
+        dot_dot_dot_token = consumeToken();
+    else {
+        parseParameterDeclarationList(parameter_declarations);
+
+        if (LA() == T_DOT_DOT_DOT) {
+            dot_dot_dot_token = consumeToken();
+        } else if (LA() == T_COMMA && LA(2) == T_DOT_DOT_DOT) {
+            consumeToken(); // skip comma
+            dot_dot_dot_token = consumeToken();
+        }
+    }
+
+    if (parameter_declarations || dot_dot_dot_token) {
+        ParameterDeclarationClauseAST *ast = new (_pool) ParameterDeclarationClauseAST;
+        ast->parameter_declaration_list = parameter_declarations;
+        ast->dot_dot_dot_token = dot_dot_dot_token;
+        node = ast;
+    }
+
+    return true;
+}
+
+bool Parser::parseParameterDeclarationList(DeclarationListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_DOT_DOT_DOT || (LA() == T_COMMA && LA(2) == T_DOT_DOT_DOT))
+        return false; // nothing to do.
+
+    DeclarationListAST **parameter_declaration_ptr = &node;
+    DeclarationAST *declaration = 0;
+    if (parseParameterDeclaration(declaration)) {
+        *parameter_declaration_ptr = new (_pool) DeclarationListAST;
+        (*parameter_declaration_ptr)->value = declaration;
+        parameter_declaration_ptr = &(*parameter_declaration_ptr)->next;
+        while (LA() == T_COMMA) {
+            consumeToken();
+
+            if (LA() == T_DOT_DOT_DOT)
+                break;
+
+            declaration = 0;
+            if (parseParameterDeclaration(declaration)) {
+                *parameter_declaration_ptr = new (_pool) DeclarationListAST;
+                (*parameter_declaration_ptr)->value = declaration;
+                parameter_declaration_ptr = &(*parameter_declaration_ptr)->next;
+            }
+        }
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseParameterDeclaration(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    SpecifierListAST *decl_specifier_seq = 0;
+    if (parseDeclSpecifierSeq(decl_specifier_seq)) {
+        ParameterDeclarationAST *ast = new (_pool) ParameterDeclarationAST;
+        ast->type_specifier_list = decl_specifier_seq;
+        parseDeclaratorOrAbstractDeclarator(ast->declarator);
+        if (LA() == T_EQUAL) {
+            ast->equal_token = consumeToken();
+            parseLogicalOrExpression(ast->expression);
+        }
+
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseClassSpecifier(SpecifierListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (! lookAtClassKey())
+        return false;
+
+    unsigned classkey_token = consumeToken();
+
+    SpecifierListAST *attributes = 0, **attr_ptr = &attributes;
+    while (LA() == T___ATTRIBUTE__) {
+        parseAttributeSpecifier(*attr_ptr);
+        attr_ptr = &(*attr_ptr)->next;
+    }
+
+    if (LA(1) == T_IDENTIFIER && LA(2) == T_IDENTIFIER) {
+        _translationUnit->warning(cursor(), "skip identifier `%s'",
+                                  tok().spell());
+        consumeToken();
+    }
+
+    NameAST *name = 0;
+    parseName(name);
+
+    bool parsed = false;
+
+    const bool previousInFunctionBody = _inFunctionBody;
+    _inFunctionBody = false;
+
+    unsigned colon_token = 0;
+
+    if (LA() == T_COLON || LA() == T_LBRACE) {
+        BaseSpecifierListAST *base_clause_list = 0;
+
+        if (LA() == T_COLON) {
+            colon_token = cursor();
+
+            parseBaseClause(base_clause_list);
+
+            if (LA() != T_LBRACE) {
+                _translationUnit->error(cursor(), "expected `{' before `%s'", tok().spell());
+
+                const unsigned saved = cursor();
+
+                for (int n = 0; n < 3 && LA() != T_EOF_SYMBOL; ++n, consumeToken()) {
+                    if (LA() == T_LBRACE)
+                        break;
+                }
+
+                if (LA() != T_LBRACE)
+                    rewind(saved);
+            }
+        }
+
+        ClassSpecifierAST *ast = new (_pool) ClassSpecifierAST;
+        ast->classkey_token = classkey_token;
+        ast->attribute_list = attributes;
+        ast->name = name;
+        ast->colon_token = colon_token;
+        ast->base_clause_list = base_clause_list;
+
+        if (LA() == T_LBRACE)
+            ast->lbrace_token = consumeToken();
+
+        DeclarationListAST **declaration_ptr = &ast->member_specifier_list;
+        while (int tk = LA()) {
+            if (tk == T_RBRACE) {
+                ast->rbrace_token = consumeToken();
+                break;
+            }
+
+            unsigned start_declaration = cursor();
+            DeclarationAST *declaration = 0;
+            if (parseMemberSpecification(declaration)) {
+                if (declaration) {  // paranoia check
+                    *declaration_ptr = new (_pool) DeclarationListAST;
+                    (*declaration_ptr)->value = declaration;
+                    declaration_ptr = &(*declaration_ptr)->next;
+                }
+
+                if (cursor() == start_declaration) { // more paranoia
+                    rewind(start_declaration + 1);
+                    skipUntilDeclaration();
+                }
+            } else {
+                _translationUnit->error(start_declaration, "expected a declaration");
+                rewind(start_declaration + 1);
+                skipUntilDeclaration();
+            }
+        }
+        node = new (_pool) SpecifierListAST(ast);
+        parsed = true;
+    }
+
+    _inFunctionBody = previousInFunctionBody;
+
+    return parsed;
+}
+
+bool Parser::parseAccessSpecifier(SpecifierAST *&node)
+{
+    DEBUG_THIS_RULE();
+    switch (LA()) {
+    case T_PUBLIC:
+    case T_PROTECTED:
+    case T_PRIVATE: {
+        SimpleSpecifierAST *ast = new (_pool) SimpleSpecifierAST;
+        ast->specifier_token = consumeToken();
+        node = ast;
+        return true;
+    }
+
+    default:
+        return false;
+    } // switch
+}
+
+bool Parser::parseAccessDeclaration(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_PUBLIC || LA() == T_PROTECTED || LA() == T_PRIVATE || LA() == T_Q_SIGNALS || LA() == T_Q_SLOTS) {
+        bool isSignals = LA() == T_Q_SIGNALS;
+        bool isSlots = LA() == T_Q_SLOTS;
+        AccessDeclarationAST *ast = new (_pool) AccessDeclarationAST;
+        ast->access_specifier_token = consumeToken();
+        if (! isSignals && (LA() == T_Q_SLOTS || isSlots))
+            ast->slots_token = consumeToken();
+        match(T_COLON, &ast->colon_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+#ifdef ICHECK_BUILD
+bool Parser::parseQPropertyDeclaration(DeclarationAST *&node)
+{
+    /*
+     Q_PROPERTY(type name
+            READ getFunction
+            [WRITE setFunction]
+            [RESET resetFunction]
+            [NOTIFY notifySignal]
+            [DESIGNABLE bool]
+            [SCRIPTABLE bool]
+            [STORED bool]
+            [USER bool]
+            [CONSTANT]
+            [FINAL])*/
+    DEBUG_THIS_RULE();
+    if (LA() == T_Q_PROPERTY) {
+        QPropertyDeclarationAST *ast = new (_pool)QPropertyDeclarationAST;
+        ast->property_specifier_token = consumeToken();
+        if(LA() == T_LPAREN){
+            ast->lparen_token = consumeToken();
+            QString tokenstr;
+            tokenstr = tok().spell();
+            //read the type and the name of the type
+            if(tokenstr !=  "READ" ){
+                ast->type_token = consumeToken();
+                tokenstr = tok().spell();
+            }
+            if(tokenstr !=  "READ" ){
+                ast->type_name_token = consumeToken();
+                tokenstr = tok().spell();
+            }
+            unsigned fctdefinition = 0;
+            unsigned fctname = 0;
+            for(int i = 0; i < 18; i++){
+                if(cursor() < _translationUnit->tokenCount() - 1){
+                    if(LA() == T_RPAREN){
+                        ast->rparen_token = consumeToken();
+                        break;
+                    }
+                    tokenstr = tok().spell();
+                    fctdefinition = consumeToken();
+                    fctname = consumeToken();
+                    if(tokenstr == "READ"){
+                        ast->read_token = fctdefinition;
+                        ast->read_function_token = fctname;
+                    }
+                    else if(tokenstr == "WRITE"){
+                        ast->write_token = fctdefinition;
+                        ast->write_function_token = fctname;
+                    }
+                    else if(tokenstr == "RESET"){
+                        ast->reset_token = fctdefinition;
+                        ast->reset_function_token = fctname;
+                    }
+                    else if(tokenstr == "NOTIFY"){
+                        ast->notify_token = fctdefinition;
+                        ast->notify_function_token = fctname;
+                    }
+                }
+            }
+        }
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseQEnumDeclaration(DeclarationAST *&node)
+{
+     /*Q_ENUMS(ConnectionState)*/
+    DEBUG_THIS_RULE();
+    if (LA() == T_Q_ENUMS) {
+        QEnumDeclarationAST *ast = new (_pool)QEnumDeclarationAST;
+        ast->enum_specifier_token = consumeToken();
+        EnumeratorListAST** enumerator_list_ptr;
+        enumerator_list_ptr = &ast->enumerator_list;
+
+        if(LA() == T_LPAREN){
+            ast->lparen_token = consumeToken();
+            while(LA() != T_EOF_SYMBOL && LA() != T_RPAREN){
+                *enumerator_list_ptr = new (_pool) EnumeratorListAST;
+                EnumeratorAST *pdecl = new (_pool) EnumeratorAST;
+                pdecl->identifier_token = consumeToken();
+                (*enumerator_list_ptr)->value = pdecl;
+                enumerator_list_ptr = &(*enumerator_list_ptr)->next;
+                if (LA() == T_COMMA)
+                    consumeToken();
+            }
+            if(LA() == T_RPAREN)
+                ast->rparen_token = consumeToken();
+        }
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseQFlags(DeclarationAST *&node)
+{
+     /*Q_FLAGS(enum1 enum2 flags1)*/
+    DEBUG_THIS_RULE();
+    if (LA() == T_Q_FLAGS) {
+        QFlagsDeclarationAST *ast = new (_pool)QFlagsDeclarationAST;
+        ast->flags_specifier_token = consumeToken();
+        EnumeratorListAST** enumerator_list_ptr;
+        enumerator_list_ptr = &ast->enumerator_list;
+        if(LA() == T_LPAREN){
+            ast->lparen_token = consumeToken();
+            while(LA() != T_EOF_SYMBOL && LA() != T_RPAREN){
+                *enumerator_list_ptr = new (_pool) EnumeratorListAST;
+                EnumeratorAST *pdecl = new (_pool) EnumeratorAST;
+                pdecl->identifier_token = consumeToken();
+                (*enumerator_list_ptr)->value = pdecl;
+                enumerator_list_ptr = &(*enumerator_list_ptr)->next;
+                if (LA() == T_COMMA)
+                    consumeToken();
+            }
+            if(LA() == T_RPAREN)
+                ast->rparen_token = consumeToken();
+        }
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseQDeclareFlags(DeclarationAST *&node)
+{
+     /*Q_DECLARE_FLAGS(flag enum)*/
+    DEBUG_THIS_RULE();
+    if (LA() == T_Q_DECLARE_FLAGS) {
+        QDeclareFlagsDeclarationAST *ast = new (_pool)QDeclareFlagsDeclarationAST;
+        ast->declareflags_specifier_token = consumeToken();
+        if(LA() == T_LPAREN){
+            ast->lparen_token = consumeToken();
+            if(LA() != T_EOF_SYMBOL)
+                ast->flag_token = consumeToken();
+            if(LA() == T_COMMA && LA() != T_EOF_SYMBOL)
+                consumeToken();
+            if(LA() != T_EOF_SYMBOL)
+                ast->enum_token = consumeToken();
+            if(LA() != T_EOF_SYMBOL && LA() == T_RPAREN)
+                ast->rparen_token = consumeToken();
+        }
+        node = ast;
+        return true;
+    }
+    return false;
+}
+#endif
+
+bool Parser::parseMemberSpecification(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    switch (LA()) {
+    case T_SEMICOLON:
+        return parseEmptyDeclaration(node);
+
+    case T_USING:
+        return parseUsing(node);
+
+    case T_TEMPLATE:
+        return parseTemplateDeclaration(node);
+
+    case T_Q_SIGNALS:
+    case T_PUBLIC:
+    case T_PROTECTED:
+    case T_PRIVATE:
+    case T_Q_SLOTS:
+        return parseAccessDeclaration(node);
+
+#ifdef ICHECK_BUILD
+    case T_Q_PROPERTY:
+        return parseQPropertyDeclaration(node);
+
+    case T_Q_ENUMS:
+        return parseQEnumDeclaration(node);
+
+    case T_Q_FLAGS:
+        return parseQFlags(node);
+
+    case T_Q_DECLARE_FLAGS:
+        return parseQDeclareFlags(node);
+#endif
+
+    default:
+        return parseSimpleDeclaration(node, /*acceptStructDeclarator=*/true);
+    } // switch
+}
+
+bool Parser::parseCtorInitializer(CtorInitializerAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_COLON) {
+        unsigned colon_token = consumeToken();
+
+        CtorInitializerAST *ast = new (_pool) CtorInitializerAST;
+        ast->colon_token = colon_token;
+
+        parseMemInitializerList(ast->member_initializer_list);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseElaboratedTypeSpecifier(SpecifierListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (lookAtClassKey() || LA() == T_ENUM || LA() == T_TYPENAME) {
+        unsigned classkey_token = consumeToken();
+        NameAST *name = 0;
+        if (parseName(name)) {
+            ElaboratedTypeSpecifierAST *ast = new (_pool) ElaboratedTypeSpecifierAST;
+            ast->classkey_token = classkey_token;
+            ast->name = name;
+            node = new (_pool) SpecifierListAST(ast);
+            return true;
+        }
+    }
+    return false;
+}
+
+bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_THROW) {
+        ExceptionSpecificationAST *ast = new (_pool) ExceptionSpecificationAST;
+        ast->throw_token = consumeToken();
+        if (LA() == T_LPAREN)
+            ast->lparen_token = consumeToken();
+        if (LA() == T_DOT_DOT_DOT)
+            ast->dot_dot_dot_token = consumeToken();
+        else
+            parseTypeIdList(ast->type_id_list);
+        if (LA() == T_RPAREN)
+            ast->rparen_token = consumeToken();
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseEnumerator(EnumeratorListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_IDENTIFIER) {
+        EnumeratorAST *ast = new (_pool) EnumeratorAST;
+        ast->identifier_token = consumeToken();
+
+        if (LA() == T_EQUAL) {
+            ast->equal_token = consumeToken();
+            parseConstantExpression(ast->expression);
+        }
+
+        node = new (_pool) EnumeratorListAST;
+        node->value = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseInitDeclarator(DeclaratorAST *&node,
+        bool acceptStructDeclarator)
+{
+    DEBUG_THIS_RULE();
+    unsigned start = cursor();
+
+    if (acceptStructDeclarator && LA() == T_COLON) {
+        // anonymous bit-field declaration.
+        // ### TODO create the AST
+    } else if (! parseDeclarator(node, /*stopAtCppInitializer = */ ! acceptStructDeclarator)) {
+        return false;
+    }
+
+    if (LA() == T_ASM && LA(2) == T_LPAREN) { // ### FIXME
+        consumeToken();
+
+        if (skip(T_LPAREN, T_RPAREN))
+            consumeToken();
+    }
+
+    if (acceptStructDeclarator && node &&
+            ! node->postfix_declarator_list &&
+            node->core_declarator &&
+            node->core_declarator->asNestedDeclarator()) {
+        rewind(start);
+        return false;
+    }
+
+    if (acceptStructDeclarator && LA() == T_COLON
+            && (! node || ! node->postfix_declarator_list)) {
+        unsigned colon_token = consumeToken();
+        ExpressionAST *expression = 0;
+        if (parseConstantExpression(expression) && (LA() == T_COMMA ||
+                                                    LA() == T_SEMICOLON)) {
+            // recognized a bitfielddeclarator.
+            // ### TODO create the AST
+            return true;
+        }
+        rewind(colon_token);
+    } else if (LA() == T_EQUAL || (! acceptStructDeclarator && LA() == T_LPAREN)) {
+        parseInitializer(node->initializer, &node->equals_token);
+    }
+    return true;
+}
+
+bool Parser::parseBaseClause(BaseSpecifierListAST *&node)
+{
+    DEBUG_THIS_RULE();
+
+    if (LA() == T_COLON) {
+        consumeToken(); // ### remove me
+
+        BaseSpecifierListAST **ast = &node;
+        if (parseBaseSpecifier(*ast)) {
+            ast = &(*ast)->next;
+
+            while (LA() == T_COMMA) {
+                consumeToken(); // consume T_COMMA
+
+                if (parseBaseSpecifier(*ast))
+                    ast = &(*ast)->next;
+            }
+        }
+
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseInitializer(ExpressionAST *&node, unsigned *equals_token)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_LPAREN) {
+        return parsePrimaryExpression(node);
+    } else if (LA() == T_EQUAL) {
+        (*equals_token) = consumeToken();
+        return parseInitializerClause(node);
+    }
+    return false;
+}
+
+bool Parser::parseMemInitializerList(MemInitializerListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    MemInitializerListAST **initializer = &node;
+
+    if (parseMemInitializer(*initializer)) {
+        initializer = &(*initializer)->next;
+
+        while (true) {
+
+            if (LA() == T_LBRACE)
+                break;
+
+            else if (LA() == T_COMMA || (LA() == T_IDENTIFIER && (LA(2) == T_LPAREN || LA(2) == T_COLON_COLON))) {
+                if (LA() != T_COMMA)
+                    _translationUnit->error(cursor(), "expected `,'");
+                else
+                    consumeToken();
+
+                if (parseMemInitializer(*initializer))
+                    initializer = &(*initializer)->next;
+                else
+                    _translationUnit->error(cursor(), "expected a member initializer");
+
+            } else break;
+        }
+
+        if (LA() != T_LBRACE)
+            _translationUnit->error(cursor(), "expected `{'");
+
+        return true;
+    }
+
+    return false;
+}
+
+bool Parser::parseMemInitializer(MemInitializerListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    NameAST *name = 0;
+    if (! parseName(name))
+        return false;
+
+    MemInitializerAST *ast = new (_pool) MemInitializerAST;
+    ast->name = name;
+    match(T_LPAREN, &ast->lparen_token);
+    parseExpressionList(ast->expression_list);
+    match(T_RPAREN, &ast->rparen_token);
+
+    node = new (_pool) MemInitializerListAST;
+    node->value = ast;
+    return true;
+}
+
+bool Parser::parseTypeIdList(ExpressionListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    ExpressionListAST **expression_list_ptr = &node;
+    ExpressionAST *typeId = 0;
+    if (parseTypeId(typeId)) {
+        *expression_list_ptr = new (_pool) ExpressionListAST;
+        (*expression_list_ptr)->value = typeId;
+        expression_list_ptr = &(*expression_list_ptr)->next;
+        while (LA() == T_COMMA) {
+            consumeToken();
+
+            if (parseTypeId(typeId)) {
+                *expression_list_ptr = new (_pool) ExpressionListAST;
+                (*expression_list_ptr)->value = typeId;
+                expression_list_ptr = &(*expression_list_ptr)->next;
+            }
+        }
+        return true;
+    }
+
+    return false;
+}
+
+bool Parser::parseExpressionList(ExpressionListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    ExpressionListAST **expression_list_ptr = &node;
+    ExpressionAST *expression = 0;
+    if (parseAssignmentExpression(expression)) {
+        *expression_list_ptr = new (_pool) ExpressionListAST;
+        (*expression_list_ptr)->value = expression;
+        expression_list_ptr = &(*expression_list_ptr)->next;
+        while (LA() == T_COMMA) {
+            consumeToken(); // consume T_COMMA
+
+            if (parseAssignmentExpression(expression)) {
+                *expression_list_ptr = new (_pool) ExpressionListAST;
+                (*expression_list_ptr)->value = expression;
+                expression_list_ptr = &(*expression_list_ptr)->next;
+            }
+        }
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseBaseSpecifier(BaseSpecifierListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    BaseSpecifierAST *ast = new (_pool) BaseSpecifierAST;
+
+    if (LA() == T_VIRTUAL) {
+        ast->virtual_token = consumeToken();
+
+        int tk = LA();
+        if (tk == T_PUBLIC || tk == T_PROTECTED || tk == T_PRIVATE)
+            ast->access_specifier_token = consumeToken();
+    } else {
+        int tk = LA();
+        if (tk == T_PUBLIC || tk == T_PROTECTED || tk == T_PRIVATE)
+            ast->access_specifier_token = consumeToken();
+
+        if (LA() == T_VIRTUAL)
+            ast->virtual_token = consumeToken();
+    }
+
+    parseName(ast->name);
+    if (! ast->name)
+        _translationUnit->error(cursor(), "expected class-name");
+
+    node = new (_pool) BaseSpecifierListAST;
+    node->value = ast;
+    return true;
+}
+
+bool Parser::parseInitializerList(ExpressionListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    ExpressionListAST **initializer_ptr = &node;
+    ExpressionAST *initializer = 0;
+    if (parseInitializerClause(initializer)) {
+        *initializer_ptr = new (_pool) ExpressionListAST;
+        (*initializer_ptr)->value = initializer;
+        initializer_ptr = &(*initializer_ptr)->next;
+        while (LA() == T_COMMA) {
+            consumeToken(); // consume T_COMMA
+            initializer = 0;
+            parseInitializerClause(initializer);
+            *initializer_ptr = new (_pool) ExpressionListAST;
+            (*initializer_ptr)->value = initializer;
+            initializer_ptr = &(*initializer_ptr)->next;
+        }
+    }
+    return true;
+}
+
+bool Parser::parseInitializerClause(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_LBRACE) {
+        ArrayInitializerAST *ast = new (_pool) ArrayInitializerAST;
+        ast->lbrace_token = consumeToken();
+        parseInitializerList(ast->expression_list);
+        match(T_RBRACE, &ast->rbrace_token);
+        node = ast;
+        return true;
+    }
+    return parseAssignmentExpression(node);
+}
+
+bool Parser::parseUnqualifiedName(NameAST *&node, bool acceptTemplateId)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_TILDE && LA(2) == T_IDENTIFIER) {
+        DestructorNameAST *ast = new (_pool) DestructorNameAST;
+        ast->tilde_token = consumeToken();
+        ast->identifier_token = consumeToken();
+        node = ast;
+        return true;
+    } else if (LA() == T_OPERATOR) {
+        unsigned operator_token = cursor();
+        if (parseOperatorFunctionId(node))
+            return true;
+        rewind(operator_token);
+        return parseConversionFunctionId(node);
+     } else if (LA() == T_IDENTIFIER) {
+         unsigned identifier_token = cursor();
+         if (acceptTemplateId && LA(2) == T_LESS && parseTemplateId(node)) {
+             if (! _templateArguments || (LA() == T_COMMA  || LA() == T_GREATER ||
+                                          LA() == T_LPAREN || LA() == T_RPAREN  ||
+                                          LA() == T_COLON_COLON))
+                 return true;
+         }
+         rewind(identifier_token);
+         SimpleNameAST *ast = new (_pool) SimpleNameAST;
+         ast->identifier_token = consumeToken();
+         node = ast;
+         return true;
+    } else if (LA() == T_TEMPLATE) {
+        unsigned template_token = consumeToken();
+        if (parseTemplateId(node))
+            return true;
+        rewind(template_token);
+    }
+    return false;
+}
+
+bool Parser::parseStringLiteral(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (! (LA() == T_STRING_LITERAL || LA() == T_WIDE_STRING_LITERAL))
+        return false;
+
+    StringLiteralAST **ast = reinterpret_cast<StringLiteralAST **> (&node);
+
+    while (LA() == T_STRING_LITERAL || LA() == T_WIDE_STRING_LITERAL) {
+        *ast = new (_pool) StringLiteralAST;
+        (*ast)->literal_token = consumeToken();
+        ast = &(*ast)->next;
+    }
+    return true;
+}
+
+bool Parser::parseExpressionStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_SEMICOLON) {
+        ExpressionStatementAST *ast = new (_pool) ExpressionStatementAST;
+        match(T_SEMICOLON, &ast->semicolon_token);
+        node = ast;
+        return true;
+    }
+
+    ExpressionAST *expression = 0;
+    MemoryPool *oldPool = _pool;
+    MemoryPool tmp;
+    _pool = &tmp;
+    if (parseExpression(expression)) {
+        ExpressionStatementAST *ast = new (oldPool) ExpressionStatementAST;
+        ast->expression = expression->clone(oldPool);
+        match(T_SEMICOLON, &ast->semicolon_token);
+        node = ast;
+        _pool = oldPool;
+        return true;
+    }
+    _pool = oldPool;
+
+    return false;
+}
+
+bool Parser::parseStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    switch (LA()) {
+    case T_WHILE:
+        return parseWhileStatement(node);
+
+    case T_DO:
+        return parseDoStatement(node);
+
+    case T_Q_FOREACH:
+        return parseForeachStatement(node);
+
+    case T_FOR:
+        return parseForStatement(node);
+
+    case T_IF:
+        return parseIfStatement(node);
+
+    case T_SWITCH:
+        return parseSwitchStatement(node);
+
+    case T_TRY:
+        return parseTryBlockStatement(node);
+
+    case T_CASE:
+    case T_DEFAULT:
+        return parseLabeledStatement(node);
+
+    case T_BREAK:
+        return parseBreakStatement(node);
+
+    case T_CONTINUE:
+        return parseContinueStatement(node);
+
+    case T_GOTO:
+        return parseGotoStatement(node);
+
+    case T_RETURN:
+        return parseReturnStatement(node);
+
+    case T_LBRACE:
+        return parseCompoundStatement(node);
+
+    case T_ASM:
+    case T_NAMESPACE:
+    case T_USING:
+    case T_TEMPLATE:
+    case T_CLASS: case T_STRUCT: case T_UNION:
+        return parseDeclarationStatement(node);
+
+    case T_SEMICOLON: {
+        ExpressionStatementAST *ast = new (_pool) ExpressionStatementAST;
+        ast->semicolon_token = consumeToken();
+        node = ast;
+        return true;
+    }
+
+    case T_AT_SYNCHRONIZED:
+        return objCEnabled() && parseObjCSynchronizedStatement(node);
+
+    case T_Q_D:
+    case T_Q_Q: {
+        QtMemberDeclarationAST *ast = new (_pool) QtMemberDeclarationAST;
+        ast->q_token = consumeToken();
+        match(T_LPAREN, &ast->lparen_token);
+        parseTypeId(ast->type_id);
+        match(T_RPAREN, &ast->rparen_token);
+        node = ast;
+    } return true;
+
+    default:
+        if (LA() == T_IDENTIFIER && LA(2) == T_COLON)
+            return parseLabeledStatement(node);
+
+        return parseExpressionOrDeclarationStatement(node);
+    } // switch
+    return false; //Avoid compiler warning
+}
+
+bool Parser::parseBreakStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_BREAK) {
+        BreakStatementAST *ast = new (_pool) BreakStatementAST;
+        ast->break_token = consumeToken();
+        match(T_SEMICOLON, &ast->semicolon_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseContinueStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_CONTINUE) {
+        ContinueStatementAST *ast = new (_pool) ContinueStatementAST;
+        ast->continue_token = consumeToken();
+        match(T_SEMICOLON, &ast->semicolon_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseGotoStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_GOTO) {
+        GotoStatementAST *ast = new (_pool) GotoStatementAST;
+        ast->goto_token = consumeToken();
+        match(T_IDENTIFIER, &ast->identifier_token);
+        match(T_SEMICOLON, &ast->semicolon_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseReturnStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_RETURN) {
+        ReturnStatementAST *ast = new (_pool) ReturnStatementAST;
+        ast->return_token = consumeToken();
+        parseExpression(ast->expression);
+        match(T_SEMICOLON, &ast->semicolon_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::isPointerDeclaration(DeclarationStatementAST *ast) const
+{
+    if (! ast)
+        return false;
+
+    if (SimpleDeclarationAST *declaration = ast->declaration->asSimpleDeclaration()) {
+        if (SpecifierListAST *spec = declaration->decl_specifier_list) {
+            if (spec->value->asNamedTypeSpecifier() && ! spec->next) {
+                if (DeclaratorListAST *declarators = declaration->declarator_list) {
+                    if (DeclaratorAST *declarator = declarators->value) {
+                        if (declarator->ptr_operator_list && declarator->equals_token && declarator->initializer) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return false;
+}
+
+bool Parser::maybeAmbiguousStatement(DeclarationStatementAST *ast) const
+{
+    if (! ast)
+        return false;
+
+    if (SimpleDeclarationAST *declaration = ast->declaration->asSimpleDeclaration()) {
+        if (SpecifierListAST *spec = declaration->decl_specifier_list) {
+            if (spec->value->asNamedTypeSpecifier() && ! spec->next) {
+                if (DeclaratorListAST *declarators = declaration->declarator_list) {
+                    if (DeclaratorAST *declarator = declarators->value) {
+                        if (declarator->core_declarator &&
+                            declarator->core_declarator->asNestedDeclarator()) {
+                            // recognized name(id-expression)
+                            return true;
+                        }
+                    }
+                }
+            }
+
+        } else if (DeclaratorListAST *declarators = declaration->declarator_list) {
+            // no decl_specifiers...
+            if (DeclaratorAST *declarator = declarators->value) {
+                if (declarator->postfix_declarator_list && declarator->postfix_declarator_list->value->asFunctionDeclarator()
+                                                     && ! declarator->initializer) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_SEMICOLON)
+        return parseExpressionStatement(node);
+
+    unsigned start = cursor();
+    bool blocked = blockErrors(true);
+
+    if (parseDeclarationStatement(node)) {
+        DeclarationStatementAST *stmt = static_cast<DeclarationStatementAST *>(node);
+
+        if (isPointerDeclaration(stmt)) {
+            blockErrors(blocked);
+            return true;
+        }
+
+        if (! maybeAmbiguousStatement(stmt)) {
+            unsigned end_of_declaration_statement = cursor();
+            rewind(start);
+
+            StatementAST *expression = 0;
+            if (parseExpressionStatement(expression) && cursor() == end_of_declaration_statement) {
+                // it's an ambiguous expression-or-declaration statement.
+                ExpressionOrDeclarationStatementAST *ast = new (_pool) ExpressionOrDeclarationStatementAST;
+                ast->declaration = node;
+                ast->expression = expression;
+                node = ast;
+            }
+
+            rewind(end_of_declaration_statement);
+            blockErrors(blocked);
+            return true;
+        }
+    }
+
+    // it's not a declaration statement.
+    blockErrors(blocked);
+    rewind(start);
+    return parseExpressionStatement(node);
+}
+
+bool Parser::parseCondition(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    unsigned start = cursor();
+
+    bool blocked = blockErrors(true);
+    SpecifierListAST *type_specifier = 0;
+    if (parseTypeSpecifier(type_specifier)) {
+        DeclaratorAST *declarator = 0;
+        if (parseInitDeclarator(declarator, /*acceptStructDeclarator=*/false)) {
+            if (declarator->initializer) {
+                ConditionAST *ast = new (_pool) ConditionAST;
+                ast->type_specifier_list = type_specifier;
+                ast->declarator = declarator;
+                node = ast;
+                blockErrors(blocked);
+                return true;
+            }
+        }
+    }
+
+    blockErrors(blocked);
+    rewind(start);
+    return parseExpression(node);
+}
+
+bool Parser::parseWhileStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_WHILE) {
+        WhileStatementAST *ast = new (_pool) WhileStatementAST;
+        ast->while_token = consumeToken();
+        match(T_LPAREN, &ast->lparen_token);
+        parseCondition(ast->condition);
+        match(T_RPAREN, &ast->rparen_token);
+        parseStatement(ast->statement);
+        node = ast;
+        return true;
+    }
+    return true;
+}
+
+bool Parser::parseDoStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_DO) {
+        DoStatementAST *ast = new (_pool) DoStatementAST;
+        ast->do_token = consumeToken();
+        parseStatement(ast->statement);
+        match(T_WHILE, &ast->while_token);
+        match(T_LPAREN, &ast->lparen_token);
+        parseExpression(ast->expression);
+        match(T_RPAREN, &ast->rparen_token);
+        match(T_SEMICOLON, &ast->semicolon_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseForeachStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_Q_FOREACH) {
+        ForeachStatementAST *ast = new (_pool) ForeachStatementAST;
+        ast->foreach_token = consumeToken();
+        match(T_LPAREN, &ast->lparen_token);
+
+        unsigned startOfTypeSpecifier = cursor();
+        bool blocked = blockErrors(true);
+
+        if (parseTypeSpecifier(ast->type_specifier_list))
+            parseDeclarator(ast->declarator);
+
+        if (! ast->type_specifier_list || ! ast->declarator) {
+            ast->type_specifier_list = 0;
+            ast->declarator = 0;
+
+            blockErrors(blocked);
+            rewind(startOfTypeSpecifier);
+            parseAssignmentExpression(ast->initializer);
+        }
+
+        blockErrors(blocked);
+
+        match(T_COMMA, &ast->comma_token);
+        parseExpression(ast->expression);
+        match(T_RPAREN, &ast->rparen_token);
+        parseStatement(ast->statement);
+
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseForStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_FOR)
+        return false;
+
+    unsigned for_token = consumeToken();
+    unsigned lparen_token = 0;
+    match(T_LPAREN, &lparen_token);
+
+    unsigned startOfTypeSpecifier = cursor();
+    bool blocked = blockErrors(true);
+
+    if (objCEnabled()) {
+        ObjCFastEnumerationAST *ast = new (_pool) ObjCFastEnumerationAST;
+        ast->for_token = for_token;
+        ast->lparen_token = lparen_token;
+
+        if (parseTypeSpecifier(ast->type_specifier_list))
+            parseDeclarator(ast->declarator);
+
+        if ((ast->type_specifier_list || ast->declarator) && !peekAtObjCContextKeyword(Token_in)) {
+            // woops, probably parsed too much: "in" got parsed as a declarator. Let's redo it:
+            ast->type_specifier_list = 0;
+            ast->declarator = 0;
+
+            rewind(startOfTypeSpecifier);
+            parseDeclarator(ast->declarator);
+        }
+
+        if (! ast->type_specifier_list || ! ast->declarator) {
+            ast->type_specifier_list = 0;
+            ast->declarator = 0;
+
+            rewind(startOfTypeSpecifier);
+            parseAssignmentExpression(ast->initializer);
+        }
+
+        if (parseObjCContextKeyword(Token_in, ast->in_token)) {
+            blockErrors(blocked);
+
+            parseExpression(ast->fast_enumeratable_expression);
+            match(T_RPAREN, &ast->rparen_token);
+            parseStatement(ast->statement);
+
+            node = ast;
+            return true;
+        }
+
+        // there was no "in" token, so we continue with a normal for-statement
+        rewind(startOfTypeSpecifier);
+    }
+
+    blockErrors(blocked);
+
+    // Normal C/C++ for-statement parsing
+    ForStatementAST *ast = new (_pool) ForStatementAST;
+
+    ast->for_token = for_token;
+    ast->lparen_token = lparen_token;
+    parseForInitStatement(ast->initializer);
+    parseCondition(ast->condition);
+    match(T_SEMICOLON, &ast->semicolon_token);
+    parseExpression(ast->expression);
+    match(T_RPAREN, &ast->rparen_token);
+    parseStatement(ast->statement);
+
+    node = ast;
+    return true;
+}
+
+bool Parser::parseForInitStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    return parseExpressionOrDeclarationStatement(node);
+}
+
+bool Parser::parseCompoundStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_LBRACE) {
+        CompoundStatementAST *ast = new (_pool) CompoundStatementAST;
+        ast->lbrace_token = consumeToken();
+
+        // ### TODO: the GNU "local label" extension: "__label__ X, Y, Z;"
+        // These are only allowed at the start of a compound stmt regardless of the language.
+
+        StatementListAST **statement_ptr = &ast->statement_list;
+        while (int tk = LA()) {
+            if (tk == T_RBRACE)
+                break;
+
+            unsigned start_statement = cursor();
+            StatementAST *statement = 0;
+            if (! parseStatement(statement)) {
+                rewind(start_statement + 1);
+                skipUntilStatement();
+            } else {
+                *statement_ptr = new (_pool) StatementListAST;
+                (*statement_ptr)->value = statement;
+                statement_ptr = &(*statement_ptr)->next;
+            }
+        }
+        match(T_RBRACE, &ast->rbrace_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseIfStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_IF) {
+        IfStatementAST *ast = new (_pool) IfStatementAST;
+        ast->if_token = consumeToken();
+        match(T_LPAREN, &ast->lparen_token);
+        parseCondition(ast->condition);
+        match(T_RPAREN, &ast->rparen_token);
+        if (! parseStatement(ast->statement))
+            _translationUnit->error(cursor(), "expected statement");
+        if (LA() == T_ELSE) {
+            ast->else_token = consumeToken();
+            if (! parseStatement(ast->else_statement))
+                _translationUnit->error(cursor(), "expected statement");
+        }
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseSwitchStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_SWITCH) {
+        SwitchStatementAST *ast = new (_pool) SwitchStatementAST;
+        ast->switch_token = consumeToken();
+        match(T_LPAREN, &ast->lparen_token);
+        parseCondition(ast->condition);
+        match(T_RPAREN, &ast->rparen_token);
+        parseStatement(ast->statement);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseLabeledStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    switch (LA()) {
+    case T_IDENTIFIER:
+        if (LA(2) == T_COLON) {
+            LabeledStatementAST *ast = new (_pool) LabeledStatementAST;
+            ast->label_token = consumeToken();
+            ast->colon_token = consumeToken();
+            parseStatement(ast->statement);
+            node = ast;
+            return true;
+        }
+        break;
+
+    case T_DEFAULT: {
+        LabeledStatementAST *ast = new (_pool) LabeledStatementAST;
+        ast->label_token = consumeToken();
+        match(T_COLON, &ast->colon_token);
+        parseStatement(ast->statement);
+        node = ast;
+        return true;
+    }
+
+    case T_CASE: {
+        CaseStatementAST *ast = new (_pool) CaseStatementAST;
+        ast->case_token = consumeToken();
+        parseConstantExpression(ast->expression);
+        match(T_COLON, &ast->colon_token);
+        parseStatement(ast->statement);
+        node = ast;
+        return true;
+    }
+
+    default:
+        break;
+    } // switch
+    return false;
+}
+
+bool Parser::parseBlockDeclaration(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    switch (LA()) {
+    case T_USING:
+        return parseUsing(node);
+
+    case T_ASM:
+        return parseAsmDefinition(node);
+
+    case T_NAMESPACE:
+        return parseNamespaceAliasDefinition(node);
+
+    default:
+        return parseSimpleDeclaration(node);
+    } // switch
+
+}
+
+bool Parser::parseNamespaceAliasDefinition(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_NAMESPACE && LA(2) == T_IDENTIFIER && LA(3) == T_EQUAL) {
+        NamespaceAliasDefinitionAST *ast = new (_pool) NamespaceAliasDefinitionAST;
+        ast->namespace_token = consumeToken();
+        ast->namespace_name_token = consumeToken();
+        ast->equal_token = consumeToken();
+        parseName(ast->name);
+        match(T_SEMICOLON, &ast->semicolon_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseDeclarationStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    unsigned start = cursor();
+    DeclarationAST *declaration = 0;
+    if (! parseBlockDeclaration(declaration))
+        return false;
+
+    if (SimpleDeclarationAST *simpleDeclaration = declaration->asSimpleDeclaration()) {
+        if (! simpleDeclaration->decl_specifier_list) {
+            rewind(start);
+            return false;
+        }
+    }
+
+    DeclarationStatementAST *ast = new (_pool) DeclarationStatementAST;
+    ast->declaration = declaration;
+    node = ast;
+    return true;
+}
+
+bool Parser::lookAtCVQualifier() const
+{
+    switch (LA()) {
+    case T_CONST:
+    case T_VOLATILE:
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool Parser::lookAtFunctionSpecifier() const
+{
+    switch (LA()) {
+    case T_INLINE:
+    case T_VIRTUAL:
+    case T_EXPLICIT:
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool Parser::lookAtStorageClassSpecifier() const
+{
+    switch (LA()) {
+    case T_FRIEND:
+    case T_AUTO:
+    case T_REGISTER:
+    case T_STATIC:
+    case T_EXTERN:
+    case T_MUTABLE:
+    case T_TYPEDEF:
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool Parser::lookAtBuiltinTypeSpecifier() const
+{
+    switch (LA()) {
+    case T_CHAR:
+    case T_WCHAR_T:
+    case T_BOOL:
+    case T_SHORT:
+    case T_INT:
+    case T_LONG:
+    case T_SIGNED:
+    case T_UNSIGNED:
+    case T_FLOAT:
+    case T_DOUBLE:
+    case T_VOID:
+        return true;
+    // [gcc] extensions
+    case T___TYPEOF__:
+    case T___ATTRIBUTE__:
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool Parser::lookAtClassKey() const
+{
+    switch (LA()) {
+    case T_CLASS:
+    case T_STRUCT:
+    case T_UNION:
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool Parser::parseAttributeSpecifier(SpecifierListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T___ATTRIBUTE__)
+        return false;
+
+    AttributeSpecifierAST *ast = new (_pool) AttributeSpecifierAST;
+    ast->attribute_token = consumeToken();
+    match(T_LPAREN, &ast->first_lparen_token);
+    match(T_LPAREN, &ast->second_lparen_token);
+    parseAttributeList(ast->attribute_list);
+    match(T_RPAREN, &ast->first_rparen_token);
+    match(T_RPAREN, &ast->second_rparen_token);
+    node = new (_pool) SpecifierListAST(ast);
+    return true;
+}
+
+bool Parser::parseAttributeList(AttributeListAST *&node)
+{
+    DEBUG_THIS_RULE();
+
+    AttributeListAST **iter = &node;
+    while (LA() == T_CONST || LA() == T_IDENTIFIER) {
+        *iter = new (_pool) AttributeListAST;
+
+        if (LA() == T_CONST) {
+            AttributeAST *attr = new (_pool) AttributeAST;
+            attr->identifier_token = consumeToken();
+
+            (*iter)->value = attr;
+            iter = &(*iter)->next;
+        } else if (LA() == T_IDENTIFIER) {
+            AttributeAST *attr = new (_pool) AttributeAST;
+            attr->identifier_token = consumeToken();
+            if (LA() == T_LPAREN) {
+                attr->lparen_token = consumeToken();
+                parseExpressionList(attr->expression_list);
+                match(T_RPAREN, &attr->rparen_token);
+            }
+
+            (*iter)->value = attr;
+            iter = &(*iter)->next;
+        }
+
+        if (LA() != T_COMMA)
+            break;
+
+        consumeToken(); // skip T_COMMA
+    }
+
+    return true;
+}
+
+bool Parser::parseBuiltinTypeSpecifier(SpecifierListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T___ATTRIBUTE__) {
+        return parseAttributeSpecifier(node);
+    } else if (LA() == T___TYPEOF__) {
+        TypeofSpecifierAST *ast = new (_pool) TypeofSpecifierAST;
+        ast->typeof_token = consumeToken();
+        if (LA() == T_LPAREN) {
+            unsigned lparen_token = consumeToken();
+            if (parseTypeId(ast->expression) && LA() == T_RPAREN) {
+                ast->lparen_token = lparen_token;
+                ast->rparen_token = consumeToken();
+                node = new (_pool) SpecifierListAST(ast);
+                return true;
+            }
+            rewind(lparen_token);
+        }
+        parseUnaryExpression(ast->expression);
+        node = new (_pool) SpecifierListAST(ast);
+        return true;
+    } else if (lookAtBuiltinTypeSpecifier()) {
+        SimpleSpecifierAST *ast = new (_pool) SimpleSpecifierAST;
+        ast->specifier_token = consumeToken();
+        node = new (_pool) SpecifierListAST(ast);
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseSimpleDeclaration(DeclarationAST *&node,
+                                    bool acceptStructDeclarator)
+{
+    DEBUG_THIS_RULE();
+    unsigned qt_invokable_token = 0;
+    if (acceptStructDeclarator && (LA() == T_Q_SIGNAL || LA() == T_Q_SLOT))
+        qt_invokable_token = consumeToken();
+#ifdef ICHECK_BUILD
+    unsigned invoke_token = 0;
+    if (LA() == T_Q_INVOKABLE)
+        invoke_token = consumeToken();
+#endif
+
+    // parse a simple declaration, a function definition,
+    // or a contructor declaration.
+    bool has_type_specifier = false;
+    bool has_complex_type_specifier = false;
+    unsigned startOfNamedTypeSpecifier = 0;
+    NameAST *named_type_specifier = 0;
+    SpecifierListAST *decl_specifier_seq = 0,
+         **decl_specifier_seq_ptr = &decl_specifier_seq;
+    for (;;) {
+        if (lookAtCVQualifier() || lookAtFunctionSpecifier()
+                || lookAtStorageClassSpecifier()) {
+            SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST;
+            spec->specifier_token = consumeToken();
+            *decl_specifier_seq_ptr = new (_pool) SpecifierListAST(spec);
+            decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+        } else if (LA() == T___ATTRIBUTE__) {
+            parseAttributeSpecifier(*decl_specifier_seq_ptr);
+            decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+        } else if (! named_type_specifier && ! has_complex_type_specifier && lookAtBuiltinTypeSpecifier()) {
+            parseBuiltinTypeSpecifier(*decl_specifier_seq_ptr);
+            decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+            has_type_specifier = true;
+        } else if (! has_type_specifier && (LA() == T_COLON_COLON ||
+                                            LA() == T_IDENTIFIER)) {
+            startOfNamedTypeSpecifier = cursor();
+            if (parseName(named_type_specifier)) {
+                NamedTypeSpecifierAST *spec = new (_pool) NamedTypeSpecifierAST;
+                spec->name = named_type_specifier;
+                *decl_specifier_seq_ptr = new (_pool) SpecifierListAST(spec);
+                decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+                has_type_specifier = true;
+            } else {
+                rewind(startOfNamedTypeSpecifier);
+                break;
+            }
+        } else if (! has_type_specifier && LA() == T_ENUM) {
+            unsigned startOfTypeSpecifier = cursor();
+            if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr) || LA() == T_LBRACE) {
+                rewind(startOfTypeSpecifier);
+                if (! parseEnumSpecifier(*decl_specifier_seq_ptr)) {
+                    _translationUnit->error(startOfTypeSpecifier,
+                                            "expected an enum specifier");
+                    break;
+                }
+                has_complex_type_specifier = true;
+            }
+            decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+            has_type_specifier = true;
+        } else if (! has_type_specifier && LA() == T_TYPENAME) {
+            unsigned startOfElaboratedTypeSpecifier = cursor();
+            if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr)) {
+                _translationUnit->error(startOfElaboratedTypeSpecifier,
+                                        "expected an elaborated type specifier");
+                break;
+            }
+            decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+            has_type_specifier = true;
+        } else if (! has_type_specifier && lookAtClassKey()) {
+            unsigned startOfTypeSpecifier = cursor();
+            if (! parseElaboratedTypeSpecifier(*decl_specifier_seq_ptr) ||
+                (LA() == T_COLON || LA() == T_LBRACE || (LA(0) == T_IDENTIFIER && LA(1) == T_IDENTIFIER &&
+                                                         (LA(2) == T_COLON || LA(2) == T_LBRACE)))) {
+                rewind(startOfTypeSpecifier);
+                if (! parseClassSpecifier(*decl_specifier_seq_ptr)) {
+                    _translationUnit->error(startOfTypeSpecifier,
+                                            "wrong type specifier");
+                    break;
+                }
+                has_complex_type_specifier = true;
+            }
+            decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next;
+            has_type_specifier = true;
+        } else
+            break;
+    }
+
+    DeclaratorListAST *declarator_list = 0,
+        **declarator_ptr = &declarator_list;
+
+    DeclaratorAST *declarator = 0;
+
+    if (LA() != T_SEMICOLON) {
+        const bool maybeCtor = (LA() == T_LPAREN && named_type_specifier);
+        if (! parseInitDeclarator(declarator, acceptStructDeclarator) && maybeCtor) {
+            rewind(startOfNamedTypeSpecifier);
+            named_type_specifier = 0;
+            // pop the named type specifier from the decl-specifier-seq
+            SpecifierListAST **spec_ptr = &decl_specifier_seq;
+            for (; *spec_ptr; spec_ptr = &(*spec_ptr)->next) {
+                if (! (*spec_ptr)->next) {
+                    *spec_ptr = 0;
+                    break;
+                }
+            }
+            if (! parseInitDeclarator(declarator, acceptStructDeclarator))
+                return false;
+        }
+    }
+
+    // if there is no valid declarator
+    // and it doesn't look like a fwd or a class declaration
+    // then it's not a declarations
+    if (! declarator && ! maybeForwardOrClassDeclaration(decl_specifier_seq))
+        return false;
+
+    DeclaratorAST *firstDeclarator = declarator;
+
+    if (declarator) {
+        *declarator_ptr = new (_pool) DeclaratorListAST;
+        (*declarator_ptr)->value = declarator;
+        declarator_ptr = &(*declarator_ptr)->next;
+    }
+
+    if (LA() == T_COMMA || LA() == T_SEMICOLON || has_complex_type_specifier) {
+        while (LA() == T_COMMA) {
+            consumeToken(); // consume T_COMMA
+
+            declarator = 0;
+            if (parseInitDeclarator(declarator, acceptStructDeclarator)) {
+                *declarator_ptr = new (_pool) DeclaratorListAST;
+                (*declarator_ptr)->value = declarator;
+                declarator_ptr = &(*declarator_ptr)->next;
+            }
+        }
+        SimpleDeclarationAST *ast = new (_pool) SimpleDeclarationAST;
+        ast->qt_invokable_token = qt_invokable_token;
+#ifdef ICHECK_BUILD
+        ast->invoke_token = invoke_token;
+#endif
+        ast->decl_specifier_list = decl_specifier_seq;
+        ast->declarator_list = declarator_list;
+        match(T_SEMICOLON, &ast->semicolon_token);
+        node = ast;
+        return true;
+    } else if (! _inFunctionBody && declarator && (LA() == T_COLON || LA() == T_LBRACE || LA() == T_TRY)) {
+        CtorInitializerAST *ctor_initializer = 0;
+        bool hasCtorInitializer = false;
+        if (LA() == T_COLON) {
+            hasCtorInitializer = true;
+            parseCtorInitializer(ctor_initializer);
+
+            if (LA() != T_LBRACE) {
+                const unsigned pos = cursor();
+
+                for (int n = 0; n < 3 && LA(); consumeToken(), ++n)
+                    if (LA() == T_LBRACE)
+                        break;
+
+                if (LA() != T_LBRACE) {
+                    _translationUnit->error(pos, "unexpected token `%s'", _translationUnit->spell(pos));
+                    rewind(pos);
+                }
+            }
+        }
+
+        if (LA() == T_LBRACE || hasCtorInitializer) {
+            FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST;
+            ast->qt_invokable_token = qt_invokable_token;
+#ifdef ICHECK_BUILD
+            ast->invoke_token = invoke_token;
+#endif
+            ast->decl_specifier_list = decl_specifier_seq;
+            ast->declarator = firstDeclarator;
+            ast->ctor_initializer = ctor_initializer;
+            parseFunctionBody(ast->function_body);
+            node = ast;
+            return true; // recognized a function definition.
+        } else if (LA() == T_TRY) {
+            FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST;
+            ast->qt_invokable_token = qt_invokable_token;
+#ifdef ICHECK_BUILD
+            ast->invoke_token = invoke_token;
+#endif
+            ast->decl_specifier_list = decl_specifier_seq;
+            ast->declarator = firstDeclarator;
+            ast->ctor_initializer = ctor_initializer;
+            parseTryBlockStatement(ast->function_body);
+            node = ast;
+            return true; // recognized a function definition.
+        }
+    }
+
+    _translationUnit->error(cursor(), "unexpected token `%s'", tok().spell());
+    return false;
+}
+
+bool Parser::maybeForwardOrClassDeclaration(SpecifierListAST *decl_specifier_seq) const
+{
+    // look at the decl_specifier for possible fwd or class declarations.
+    if (SpecifierListAST *it = decl_specifier_seq) {
+        while (it) {
+            SimpleSpecifierAST *spec = it->value->asSimpleSpecifier();
+            if (spec && _translationUnit->tokenKind(spec->specifier_token) == T_FRIEND)
+                it = it->next;
+            else
+                break;
+        }
+
+        if (it) {
+            SpecifierAST *spec = it->value;
+
+            if (! it->next && (spec->asElaboratedTypeSpecifier() ||
+                               spec->asEnumSpecifier() ||
+                               spec->asClassSpecifier()))
+                return true;
+        }
+    }
+
+    return false;
+}
+
+bool Parser::parseFunctionBody(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (_translationUnit->skipFunctionBody()) {
+        unsigned token_lbrace = 0;
+        match(T_LBRACE, &token_lbrace);
+        if (! token_lbrace)
+            return false;
+
+        const Token &tk = _translationUnit->tokenAt(token_lbrace);
+        if (tk.close_brace)
+            rewind(tk.close_brace);
+        unsigned token_rbrace = 0;
+        match(T_RBRACE, &token_rbrace);
+        return true;
+    }
+
+    _inFunctionBody = true;
+    const bool parsed = parseCompoundStatement(node);
+    _inFunctionBody = false;
+    return parsed;
+}
+
+bool Parser::parseTryBlockStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_TRY) {
+        TryBlockStatementAST *ast = new (_pool) TryBlockStatementAST;
+        ast->try_token = consumeToken();
+        parseCompoundStatement(ast->statement);
+        CatchClauseListAST **catch_clause_ptr = &ast->catch_clause_list;
+        while (parseCatchClause(*catch_clause_ptr))
+            catch_clause_ptr = &(*catch_clause_ptr)->next;
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseCatchClause(CatchClauseListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_CATCH) {
+        CatchClauseAST *ast = new (_pool) CatchClauseAST;
+        ast->catch_token = consumeToken();
+        match(T_LPAREN, &ast->lparen_token);
+        parseExceptionDeclaration(ast->exception_declaration);
+        match(T_RPAREN, &ast->rparen_token);
+        parseCompoundStatement(ast->statement);
+        node = new (_pool) CatchClauseListAST(ast);
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseExceptionDeclaration(ExceptionDeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_DOT_DOT_DOT) {
+        ExceptionDeclarationAST *ast = new (_pool) ExceptionDeclarationAST;
+        ast->dot_dot_dot_token = consumeToken();
+        node = ast;
+        return true;
+    }
+
+    SpecifierListAST *type_specifier = 0;
+    if (parseTypeSpecifier(type_specifier)) {
+        ExceptionDeclarationAST *ast = new (_pool) ExceptionDeclarationAST;
+        ast->type_specifier_list = type_specifier;
+        parseDeclaratorOrAbstractDeclarator(ast->declarator);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseBoolLiteral(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_TRUE || LA() == T_FALSE) {
+        BoolLiteralAST *ast = new (_pool) BoolLiteralAST;
+        ast->literal_token = consumeToken();
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseNumericLiteral(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_NUMERIC_LITERAL  ||
+        LA() == T_CHAR_LITERAL     ||
+        LA() == T_WIDE_CHAR_LITERAL) {
+        NumericLiteralAST *ast = new (_pool) NumericLiteralAST;
+        ast->literal_token = consumeToken();
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseThisExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_THIS) {
+        ThisExpressionAST *ast = new (_pool) ThisExpressionAST;
+        ast->this_token = consumeToken();
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parsePrimaryExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    switch (LA()) {
+    case T_STRING_LITERAL:
+    case T_WIDE_STRING_LITERAL:
+        return parseStringLiteral(node);
+
+    case T_CHAR_LITERAL: // ### FIXME don't use NumericLiteral for chars
+    case T_WIDE_CHAR_LITERAL:
+    case T_NUMERIC_LITERAL:
+        return parseNumericLiteral(node);
+
+    case T_TRUE:
+    case T_FALSE:
+        return parseBoolLiteral(node);
+
+    case T_THIS:
+        return parseThisExpression(node);
+
+    case T_LPAREN:
+        return parseNestedExpression(node);
+
+    case T_SIGNAL:
+    case T_SLOT:
+        return parseQtMethod(node);
+
+    case T_LBRACKET:
+    case T_AT_STRING_LITERAL:
+    case T_AT_ENCODE:
+    case T_AT_PROTOCOL:
+    case T_AT_SELECTOR:
+        return parseObjCExpression(node);
+
+    default: {
+        NameAST *name = 0;
+        if (parseNameId(name)) {
+            node = name;
+            return true;
+        }
+        break;
+    } // default
+
+    } // switch
+
+    return false;
+}
+
+bool Parser::parseObjCExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    switch (LA()) {
+    case T_AT_ENCODE:
+        return parseObjCEncodeExpression(node);
+
+    case T_AT_PROTOCOL:
+        return parseObjCProtocolExpression(node);
+
+    case T_AT_SELECTOR:
+        return parseObjCSelectorExpression(node);
+
+    case T_LBRACKET:
+        return parseObjCMessageExpression(node);
+
+    case T_AT_STRING_LITERAL:
+        return parseObjCStringLiteral(node);
+
+    default:
+        break;
+    } // switch
+    return false;
+}
+
+bool Parser::parseObjCStringLiteral(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_AT_STRING_LITERAL)
+        return false;
+
+    StringLiteralAST **ast = reinterpret_cast<StringLiteralAST **> (&node);
+
+    while (LA() == T_AT_STRING_LITERAL) {
+        *ast = new (_pool) StringLiteralAST;
+        (*ast)->literal_token = consumeToken();
+        ast = &(*ast)->next;
+    }
+    return true;
+}
+
+bool Parser::parseObjCSynchronizedStatement(StatementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_AT_SYNCHRONIZED)
+        return false;
+
+    ObjCSynchronizedStatementAST *ast = new (_pool) ObjCSynchronizedStatementAST;
+
+    ast->synchronized_token = consumeToken();
+    match(T_LPAREN, &ast->lparen_token);
+    parseExpression(ast->synchronized_object);
+    match(T_RPAREN, &ast->rparen_token);
+    parseStatement(ast->statement);
+
+    node = ast;
+    return true;
+}
+
+bool Parser::parseObjCEncodeExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_AT_ENCODE)
+        return false;
+
+    ObjCEncodeExpressionAST *ast = new (_pool) ObjCEncodeExpressionAST;
+    ast->encode_token = consumeToken();
+    parseObjCTypeName(ast->type_name);
+    node = ast;
+    return true;
+}
+
+bool Parser::parseObjCProtocolExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_AT_PROTOCOL)
+        return false;
+
+    ObjCProtocolExpressionAST *ast = new (_pool) ObjCProtocolExpressionAST;
+    ast->protocol_token = consumeToken();
+    match(T_LPAREN, &ast->lparen_token);
+    match(T_IDENTIFIER, &ast->identifier_token);
+    match(T_RPAREN, &ast->rparen_token);
+    node = ast;
+    return true;
+}
+
+bool Parser::parseObjCSelectorExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_AT_SELECTOR)
+        return false;
+
+    ObjCSelectorExpressionAST *ast = new (_pool) ObjCSelectorExpressionAST;
+    ast->selector_token = consumeToken();
+    match(T_LPAREN, &ast->lparen_token);
+
+    unsigned identifier_token = 0;
+    match(T_IDENTIFIER, &identifier_token);
+    if (LA() == T_COLON) {
+        ObjCSelectorWithArgumentsAST *args = new (_pool) ObjCSelectorWithArgumentsAST;
+        ast->selector = args;
+        ObjCSelectorArgumentListAST *last = new (_pool) ObjCSelectorArgumentListAST;
+        args->selector_argument_list = last;
+        last->value = new (_pool) ObjCSelectorArgumentAST;
+        last->value->name_token = identifier_token;
+        last->value->colon_token = consumeToken();
+
+        while (LA() != T_RPAREN) {
+            last->next = new (_pool) ObjCSelectorArgumentListAST;
+            last = last->next;
+            last->value = new (_pool) ObjCSelectorArgumentAST;
+            match(T_IDENTIFIER, &last->value->name_token);
+            match(T_COLON, &last->value->colon_token);
+        }
+    } else {
+        ObjCSelectorWithoutArgumentsAST *args = new (_pool) ObjCSelectorWithoutArgumentsAST;
+        ast->selector = args;
+        args->name_token = identifier_token;
+    }
+
+    match(T_RPAREN, &ast->rparen_token);
+    node = ast;
+    return true;
+}
+
+bool Parser::parseObjCMessageExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_LBRACKET)
+        return false;
+
+    unsigned start = cursor();
+
+    unsigned lbracket_token = consumeToken();
+    ExpressionAST *receiver_expression = 0;
+    ObjCSelectorAST *selector = 0;
+    ObjCMessageArgumentListAST *argument_list = 0;
+
+    if (parseObjCMessageReceiver(receiver_expression) &&
+        parseObjCMessageArguments(selector, argument_list)) {
+
+        ObjCMessageExpressionAST *ast = new (_pool) ObjCMessageExpressionAST;
+        ast->lbracket_token = lbracket_token;
+        ast->receiver_expression = receiver_expression;
+        ast->selector = selector;
+        ast->argument_list = argument_list;
+
+        match(T_RBRACKET, &ast->rbracket_token);
+        node = ast;
+
+        return true;
+    }
+
+    rewind(start);
+    return false;
+}
+
+bool Parser::parseObjCMessageReceiver(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    return parseExpression(node);
+}
+
+bool Parser::parseObjCMessageArguments(ObjCSelectorAST *&selNode, ObjCMessageArgumentListAST *& argNode)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_RBRACKET)
+        return false; // nothing to do.
+
+    unsigned start = cursor();
+
+    ObjCSelectorArgumentAST *selectorArgument = 0;
+    ObjCMessageArgumentAST *messageArgument = 0;
+
+    if (parseObjCSelectorArg(selectorArgument, messageArgument)) {
+        ObjCSelectorArgumentListAST *selAst = new (_pool) ObjCSelectorArgumentListAST;
+        selAst->value = selectorArgument;
+        ObjCSelectorArgumentListAST *lastSelector = selAst;
+
+        ObjCMessageArgumentListAST *argAst = new (_pool) ObjCMessageArgumentListAST;
+        argAst->value = messageArgument;
+        ObjCMessageArgumentListAST *lastArgument = argAst;
+
+        while (parseObjCSelectorArg(selectorArgument, messageArgument)) {
+            // accept the selector args.
+            lastSelector->next = new (_pool) ObjCSelectorArgumentListAST;
+            lastSelector = lastSelector->next;
+            lastSelector->value = selectorArgument;
+
+            lastArgument->next = new (_pool) ObjCMessageArgumentListAST;
+            lastArgument = lastArgument->next;
+            lastArgument->value = messageArgument;
+        }
+
+        if (LA() == T_COMMA) {
+            ExpressionAST **lastExpression = &lastArgument->value->parameter_value_expression;
+
+            while (LA() == T_COMMA) {
+                BinaryExpressionAST *binaryExpression = new (_pool) BinaryExpressionAST;
+                binaryExpression->left_expression = *lastExpression;
+                binaryExpression->binary_op_token = consumeToken(); // T_COMMA
+                parseAssignmentExpression(binaryExpression->right_expression);
+                lastExpression = &binaryExpression->right_expression;
+            }
+        }
+
+        ObjCSelectorWithArgumentsAST *selWithArgs = new (_pool) ObjCSelectorWithArgumentsAST;
+        selWithArgs->selector_argument_list = selAst;
+
+        selNode = selWithArgs;
+        argNode = argAst;
+        return true;
+    } else {
+        rewind(start);
+        unsigned name_token = 0;
+        if (!parseObjCSelector(name_token))
+            return false;
+        ObjCSelectorWithoutArgumentsAST *sel = new (_pool) ObjCSelectorWithoutArgumentsAST;
+        sel->name_token = name_token;
+        selNode = sel;
+        argNode = 0;
+        return true;
+    }
+
+    return false;
+}
+
+bool Parser::parseObjCSelectorArg(ObjCSelectorArgumentAST *&selNode, ObjCMessageArgumentAST *&argNode)
+{
+    DEBUG_THIS_RULE();
+    unsigned selector_token = 0;
+    if (!parseObjCSelector(selector_token))
+        return false;
+
+    if (LA() != T_COLON)
+        return false;
+
+    selNode = new (_pool) ObjCSelectorArgumentAST;
+    selNode->name_token = selector_token;
+    selNode->colon_token = consumeToken();
+
+    argNode = new (_pool) ObjCMessageArgumentAST;
+    ExpressionAST **expr = &argNode->parameter_value_expression;
+    unsigned expressionStart = cursor();
+    if (parseAssignmentExpression(*expr) && LA() == T_COLON && (*expr)->asCastExpression()) {
+        rewind(expressionStart);
+        parseUnaryExpression(*expr);
+        //
+    }
+    return true;
+}
+
+bool Parser::parseNameId(NameAST *&name)
+{
+    DEBUG_THIS_RULE();
+    unsigned start = cursor();
+    if (! parseName(name))
+        return false;
+
+    if (LA() == T_RPAREN || LA() == T_COMMA)
+        return true;
+
+    QualifiedNameAST *qualified_name_id = name->asQualifiedName();
+
+    TemplateIdAST *template_id = 0;
+    if (qualified_name_id) {
+        if (NameAST *unqualified_name = qualified_name_id->unqualified_name)
+            template_id = unqualified_name->asTemplateId();
+    } else {
+        template_id = name->asTemplateId();
+    }
+
+    if (! template_id)
+        return true; // it's not a template-id, there's nothing to rewind.
+
+    else if (LA() == T_LPAREN) {
+        // a template-id followed by a T_LPAREN
+        if (TemplateArgumentListAST *template_arguments = template_id->template_argument_list) {
+            if (! template_arguments->next && template_arguments->value &&
+                    template_arguments->value->asBinaryExpression()) {
+
+                unsigned saved = cursor();
+                ExpressionAST *expr = 0;
+
+                bool blocked = blockErrors(true);
+                bool lookAtCastExpression = parseCastExpression(expr);
+                (void) blockErrors(blocked);
+
+                if (lookAtCastExpression) {
+                    if (CastExpressionAST *cast_expression = expr->asCastExpression()) {
+                        if (cast_expression->lparen_token && cast_expression->rparen_token
+                                && cast_expression->type_id && cast_expression->expression) {
+                            rewind(start);
+
+                            name = 0;
+                            return parseName(name, false);
+                        }
+                    }
+                }
+                rewind(saved);
+            }
+        }
+    }
+
+    switch (LA()) {
+    case T_COMMA:
+    case T_SEMICOLON:
+    case T_LBRACKET:
+    case T_LPAREN:
+        return true;
+
+    case T_IDENTIFIER:
+    case T_STATIC_CAST:
+    case T_DYNAMIC_CAST:
+    case T_REINTERPRET_CAST:
+    case T_CONST_CAST:
+        rewind(start);
+        return parseName(name, false);
+
+    default:
+        if (tok().isLiteral() || tok().isOperator()) {
+            rewind(start);
+            return parseName(name, false);
+        }
+    } // switch
+
+    return true;
+}
+
+bool Parser::parseNestedExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_LPAREN) {
+        unsigned lparen_token = consumeToken();
+
+        if (LA() == T_LBRACE) {
+            NestedExpressionAST *ast = new (_pool) NestedExpressionAST;
+            ast->lparen_token = lparen_token;
+
+            // ### ast
+            StatementAST *statement = 0;
+            parseCompoundStatement(statement);
+            match(T_RPAREN, &ast->rparen_token);
+            node = ast;
+            return true;
+        }
+
+        bool previousTemplateArguments = switchTemplateArguments(false);
+
+        ExpressionAST *expression = 0;
+        if (parseExpression(expression) && LA() == T_RPAREN) {
+            NestedExpressionAST *ast = new (_pool) NestedExpressionAST;
+            ast->lparen_token = lparen_token;
+            ast->expression = expression;
+            ast->rparen_token = consumeToken();
+            node = ast;
+            (void) switchTemplateArguments(previousTemplateArguments);
+            return true;
+        }
+        (void) switchTemplateArguments(previousTemplateArguments);
+    }
+    return false;
+}
+
+bool Parser::parseCppCastExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_DYNAMIC_CAST     || LA() == T_STATIC_CAST ||
+        LA() == T_REINTERPRET_CAST || LA() == T_CONST_CAST) {
+        CppCastExpressionAST *ast = new (_pool) CppCastExpressionAST;
+        ast->cast_token = consumeToken();
+        match(T_LESS, &ast->less_token);
+        parseTypeId(ast->type_id);
+        match(T_GREATER, &ast->greater_token);
+        match(T_LPAREN, &ast->lparen_token);
+        parseExpression(ast->expression);
+        match(T_RPAREN, &ast->rparen_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+// typename ::opt  nested-name-specifier identifier ( expression-listopt )
+// typename ::opt  nested-name-specifier templateopt  template-id ( expression-listopt )
+bool Parser::parseTypenameCallExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_TYPENAME) {
+        unsigned typename_token = consumeToken();
+        NameAST *name = 0;
+        if (parseName(name) && LA() == T_LPAREN) {
+            TypenameCallExpressionAST *ast = new (_pool) TypenameCallExpressionAST;
+            ast->typename_token = typename_token;
+            ast->name = name;
+            ast->lparen_token = consumeToken();
+            parseExpressionList(ast->expression_list);
+            match(T_RPAREN, &ast->rparen_token);
+            node = ast;
+            return true;
+        }
+    }
+    return false;
+}
+
+// typeid ( expression )
+// typeid ( type-id )
+bool Parser::parseTypeidExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_TYPEID) {
+        TypeidExpressionAST *ast = new (_pool) TypeidExpressionAST;
+        ast->typeid_token = consumeToken();
+        if (LA() == T_LPAREN)
+            ast->lparen_token = consumeToken();
+        unsigned saved = cursor();
+        if (! (parseTypeId(ast->expression) && LA() == T_RPAREN)) {
+            rewind(saved);
+            parseExpression(ast->expression);
+        }
+        match(T_RPAREN, &ast->rparen_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseCorePostfixExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+
+    switch (LA()) {
+    case T_DYNAMIC_CAST:
+    case T_STATIC_CAST:
+    case T_REINTERPRET_CAST:
+    case T_CONST_CAST:
+        return parseCppCastExpression(node);
+
+    case T_TYPENAME:
+        return parseTypenameCallExpression(node);
+
+    case T_TYPEID:
+        return parseTypeidExpression(node);
+
+    default: {
+        unsigned start = cursor();
+        SpecifierListAST *type_specifier = 0;
+        bool blocked = blockErrors(true);
+        if (lookAtBuiltinTypeSpecifier() &&
+                parseSimpleTypeSpecifier(type_specifier) &&
+                LA() == T_LPAREN) {
+            unsigned lparen_token = consumeToken();
+            ExpressionListAST *expression_list = 0;
+            parseExpressionList(expression_list);
+            if (LA() == T_RPAREN) {
+                unsigned rparen_token = consumeToken();
+                TypeConstructorCallAST *ast = new (_pool) TypeConstructorCallAST;
+                ast->type_specifier_list = type_specifier;
+                ast->lparen_token = lparen_token;
+                ast->expression_list = expression_list;
+                ast->rparen_token = rparen_token;
+                node = ast;
+                blockErrors(blocked);
+                return true;
+            }
+        }
+        rewind(start);
+
+        // look for compound literals
+        if (LA() == T_LPAREN) {
+            unsigned lparen_token = consumeToken();
+            ExpressionAST *type_id = 0;
+            if (parseTypeId(type_id) && LA() == T_RPAREN) {
+                unsigned rparen_token = consumeToken();
+                if (LA() == T_LBRACE) {
+                    blockErrors(blocked);
+
+                    CompoundLiteralAST *ast = new (_pool) CompoundLiteralAST;
+                    ast->lparen_token = lparen_token;
+                    ast->type_id = type_id;
+                    ast->rparen_token = rparen_token;
+                    parseInitializerClause(ast->initializer);
+                    node = ast;
+                    return true;
+                }
+            }
+            rewind(start);
+        }
+
+        blockErrors(blocked);
+        return parsePrimaryExpression(node);
+    } // default
+    } // switch
+}
+
+bool Parser::parsePostfixExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (parseCorePostfixExpression(node)) {
+        PostfixListAST *postfix_expressions = 0,
+            **postfix_ptr = &postfix_expressions;
+        while (LA()) {
+            if (LA() == T_LPAREN) {
+                CallAST *ast = new (_pool) CallAST;
+                ast->lparen_token = consumeToken();
+                parseExpressionList(ast->expression_list);
+                match(T_RPAREN, &ast->rparen_token);
+                *postfix_ptr = new (_pool) PostfixListAST(ast);
+                postfix_ptr = &(*postfix_ptr)->next;
+            } else if (LA() == T_LBRACKET) {
+                ArrayAccessAST *ast = new (_pool) ArrayAccessAST;
+                ast->lbracket_token = consumeToken();
+                parseExpression(ast->expression);
+                match(T_RBRACKET, &ast->rbracket_token);
+                *postfix_ptr = new (_pool) PostfixListAST(ast);
+                postfix_ptr = &(*postfix_ptr)->next;
+            } else if (LA() == T_PLUS_PLUS || LA() == T_MINUS_MINUS) {
+                PostIncrDecrAST *ast = new (_pool) PostIncrDecrAST;
+                ast->incr_decr_token = consumeToken();
+                *postfix_ptr = new (_pool) PostfixListAST(ast);
+                postfix_ptr = &(*postfix_ptr)->next;
+            } else if (LA() == T_DOT || LA() == T_ARROW) {
+                MemberAccessAST *ast = new (_pool) MemberAccessAST;
+                ast->access_token = consumeToken();
+                if (LA() == T_TEMPLATE)
+                    ast->template_token = consumeToken();
+                if (! parseNameId(ast->member_name))
+                    _translationUnit->error(cursor(), "expected unqualified-id before token `%s'",
+                                            tok().spell());
+                *postfix_ptr = new (_pool) PostfixListAST(ast);
+                postfix_ptr = &(*postfix_ptr)->next;
+            } else break;
+        } // while
+
+        if (postfix_expressions) {
+            PostfixExpressionAST *ast = new (_pool) PostfixExpressionAST;
+            ast->base_expression = node;
+            ast->postfix_expression_list = postfix_expressions;
+            node = ast;
+        }
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseUnaryExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    switch (LA()) {
+    case T_PLUS_PLUS:
+    case T_MINUS_MINUS:
+    case T_STAR:
+    case T_AMPER:
+    case T_PLUS:
+    case T_MINUS:
+    case T_EXCLAIM: {
+        unsigned op = cursor();
+        UnaryExpressionAST *ast = new (_pool) UnaryExpressionAST;
+        ast->unary_op_token = consumeToken();
+        if (! parseCastExpression(ast->expression)) {
+            _translationUnit->error(op, "expected expression after token `%s'",
+                                    _translationUnit->spell(op));
+        }
+        node = ast;
+        return true;
+    }
+
+    case T_TILDE: {
+        if (LA(2) == T_IDENTIFIER && LA(3) == T_LPAREN)
+            break; // prefer destructor names
+
+        UnaryExpressionAST *ast = new (_pool) UnaryExpressionAST;
+        ast->unary_op_token = consumeToken();
+        parseCastExpression(ast->expression);
+        node = ast;
+        return true;
+    }
+
+    case T_SIZEOF: {
+        SizeofExpressionAST *ast = new (_pool) SizeofExpressionAST;
+        ast->sizeof_token = consumeToken();
+
+        if (LA() == T_LPAREN) {
+            unsigned lparen_token = consumeToken();
+            if (parseTypeId(ast->expression) && LA() == T_RPAREN) {
+                ast->lparen_token = lparen_token;
+                ast->rparen_token = consumeToken();
+                node = ast;
+                return true;
+            } else {
+                rewind(lparen_token);
+            }
+        }
+
+        parseUnaryExpression(ast->expression);
+        node = ast;
+        return true;
+    }
+
+    default:
+        break;
+    } // switch
+
+    if (LA() == T_NEW || (LA(1) == T_COLON_COLON &&
+                          LA(2) == T_NEW))
+        return parseNewExpression(node);
+    else if (LA() == T_DELETE || (LA(1) == T_COLON_COLON &&
+                                  LA(2) == T_DELETE))
+        return parseDeleteExpression(node);
+    else
+        return parsePostfixExpression(node);
+}
+
+// new-placement ::= T_LPAREN expression-list T_RPAREN
+bool Parser::parseNewPlacement(NewPlacementAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_LPAREN) {
+        unsigned lparen_token = consumeToken();
+        ExpressionListAST *expression_list = 0;
+        if (parseExpressionList(expression_list) && expression_list && LA() == T_RPAREN) {
+            unsigned rparen_token = consumeToken();
+            NewPlacementAST *ast = new (_pool) NewPlacementAST;
+            ast->lparen_token = lparen_token;
+            ast->expression_list = expression_list;
+            ast->rparen_token = rparen_token;
+            node = ast;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+// new-expression ::= T_COLON_COLON? T_NEW new-placement.opt
+//                    new-type-id new-initializer.opt
+// new-expression ::= T_COLON_COLON? T_NEW new-placement.opt
+//                    T_LPAREN type-id T_RPAREN new-initializer.opt
+bool Parser::parseNewExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (! (LA() == T_NEW || (LA() == T_COLON_COLON && LA(2) == T_NEW)))
+        return false;
+
+    NewExpressionAST *ast = new (_pool) NewExpressionAST;
+    if (LA() == T_COLON_COLON)
+        ast->scope_token = consumeToken();
+
+    ast->new_token = consumeToken();
+
+    NewPlacementAST *new_placement = 0;
+
+    if (parseNewPlacement(new_placement)) {
+        unsigned after_new_placement = cursor();
+
+        NewTypeIdAST *new_type_id = 0;
+        if (parseNewTypeId(new_type_id)) {
+            ast->new_placement = new_placement;
+            ast->new_type_id = new_type_id;
+            parseNewInitializer(ast->new_initializer);
+            // recognized new-placement.opt new-type-id new-initializer.opt
+            node = ast;
+            return true;
+        }
+
+        rewind(after_new_placement);
+        if (LA() == T_LPAREN) {
+            unsigned lparen_token = consumeToken();
+            ExpressionAST *type_id = 0;
+            if (parseTypeId(type_id) && LA() == T_RPAREN) {
+                ast->new_placement = new_placement;
+                ast->lparen_token = lparen_token;
+                ast->type_id = type_id;
+                ast->rparen_token = consumeToken();
+                parseNewInitializer(ast->new_initializer);
+                node = ast;
+                return true;
+            }
+        }
+    }
+
+    rewind(ast->new_token + 1);
+
+    if (LA() == T_LPAREN) {
+        unsigned lparen_token = consumeToken();
+        ExpressionAST *type_id = 0;
+        if (parseTypeId(type_id) && LA() == T_RPAREN) {
+            ast->lparen_token = lparen_token;
+            ast->type_id = type_id;
+            ast->rparen_token = consumeToken();
+            parseNewInitializer(ast->new_initializer);
+            node = ast;
+            return true;
+        }
+    }
+
+    parseNewTypeId(ast->new_type_id);
+    parseNewInitializer(ast->new_initializer);
+    node = ast;
+    return true;
+}
+
+bool Parser::parseNewTypeId(NewTypeIdAST *&node)
+{
+    DEBUG_THIS_RULE();
+    SpecifierListAST *typeSpec = 0;
+    if (! parseTypeSpecifier(typeSpec))
+        return false;
+
+    NewTypeIdAST *ast = new (_pool) NewTypeIdAST;
+    ast->type_specifier_list = typeSpec;
+
+    PtrOperatorListAST **ptrop_it = &ast->ptr_operator_list;
+    while (parsePtrOperator(*ptrop_it))
+        ptrop_it = &(*ptrop_it)->next;
+
+    NewArrayDeclaratorListAST **it = &ast->new_array_declarator_list;
+    while (parseNewArrayDeclarator(*it))
+        it = &(*it)->next;
+
+    node = ast;
+    return true;
+}
+
+
+bool Parser::parseNewArrayDeclarator(NewArrayDeclaratorListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_LBRACKET)
+        return false;
+
+    NewArrayDeclaratorAST *ast = new (_pool) NewArrayDeclaratorAST;
+    ast->lbracket_token = consumeToken();
+    parseExpression(ast->expression);
+    match(T_RBRACKET, &ast->rbracket_token);
+
+    node = new (_pool) NewArrayDeclaratorListAST;
+    node->value = ast;
+    return true;
+}
+
+bool Parser::parseNewInitializer(NewInitializerAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_LPAREN) {
+        unsigned lparen_token = consumeToken();
+        ExpressionAST *expression = 0;
+        if (LA() == T_RPAREN || parseExpression(expression)) {
+            NewInitializerAST *ast = new (_pool) NewInitializerAST;
+            ast->lparen_token = lparen_token;
+            ast->expression = expression;
+            match(T_RPAREN, &ast->rparen_token);
+            node = ast;
+            return true;
+        }
+    }
+    return false;
+}
+
+bool Parser::parseDeleteExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_DELETE || (LA() == T_COLON_COLON && LA(2) == T_DELETE)) {
+        DeleteExpressionAST *ast = new (_pool) DeleteExpressionAST;
+
+        if (LA() == T_COLON_COLON)
+            ast->scope_token = consumeToken();
+
+        ast->delete_token = consumeToken();
+
+        if (LA() == T_LBRACKET) {
+            ast->lbracket_token = consumeToken();
+            match(T_RBRACKET, &ast->rbracket_token);
+        }
+
+        parseCastExpression(ast->expression);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseCastExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_LPAREN) {
+        unsigned lparen_token = consumeToken();
+        ExpressionAST *type_id = 0;
+        if (parseTypeId(type_id) && LA() == T_RPAREN) {
+            unsigned rparen_token = consumeToken();
+            ExpressionAST *expression = 0;
+            if (parseCastExpression(expression)) {
+                CastExpressionAST *ast = new (_pool) CastExpressionAST;
+                ast->lparen_token = lparen_token;
+                ast->type_id = type_id;
+                ast->rparen_token = rparen_token;
+                ast->expression = expression;
+                node = ast;
+                return true;
+            }
+        }
+        rewind(lparen_token);
+    }
+    return parseUnaryExpression(node);
+}
+
+bool Parser::parsePmExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::PointerToMember)
+}
+
+bool Parser::parseMultiplicativeExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Multiplicative)
+}
+
+bool Parser::parseAdditiveExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Additive)
+}
+
+bool Parser::parseShiftExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Shift)
+}
+
+bool Parser::parseRelationalExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Relational)
+}
+
+bool Parser::parseEqualityExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Equality)
+}
+
+bool Parser::parseAndExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::And)
+}
+
+bool Parser::parseExclusiveOrExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::ExclusiveOr)
+}
+
+bool Parser::parseInclusiveOrExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::InclusiveOr)
+}
+
+bool Parser::parseLogicalAndExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::LogicalAnd)
+}
+
+bool Parser::parseLogicalOrExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::LogicalOr)
+}
+
+bool Parser::parseConditionalExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Conditional)
+}
+
+bool Parser::parseAssignmentExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_THROW)
+        return parseThrowExpression(node);
+    else
+        PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Assignment)
+}
+
+bool Parser::parseQtMethod(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_SIGNAL || LA() == T_SLOT) {
+        QtMethodAST *ast = new (_pool) QtMethodAST;
+        ast->method_token = consumeToken();
+        match(T_LPAREN, &ast->lparen_token);
+        if (! parseDeclarator(ast->declarator))
+            _translationUnit->error(cursor(), "expected a function declarator before token `%s'",
+                                    tok().spell());
+        match(T_RPAREN, &ast->rparen_token);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::parseConstantExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    return parseConditionalExpression(node);
+}
+
+bool Parser::parseExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+
+    if (_expressionDepth > MAX_EXPRESSION_DEPTH)
+        return false;
+
+    ++_expressionDepth;
+    bool success = parseCommaExpression(node);
+    --_expressionDepth;
+    return success;
+}
+
+void Parser::parseExpressionWithOperatorPrecedence(ExpressionAST *&lhs, int minPrecedence)
+{
+    DEBUG_THIS_RULE();
+
+    while (precedence(tok().kind(), _templateArguments) >= minPrecedence) {
+        const int operPrecedence = precedence(tok().kind(), _templateArguments);
+        const int oper = consumeToken();
+
+        ConditionalExpressionAST *condExpr = 0;
+        if (operPrecedence == Prec::Conditional) {
+            condExpr = new (_pool) ConditionalExpressionAST;
+            condExpr->question_token = oper;
+            if (oper == T_COLON) {
+                // GNU extension:
+                //   logical-or-expression '?' ':' conditional-expression
+                condExpr->left_expression = 0;
+            } else {
+                parseExpression(condExpr->left_expression);
+            }
+            match(T_COLON, &condExpr->colon_token);
+        }
+
+        ExpressionAST *rhs = 0;
+        const bool isCPlusPlus = true;
+        if (operPrecedence <= Prec::Conditional && isCPlusPlus) {
+            // in C++ you can put a throw in the right-most expression of a conditional expression,
+            // or an assignment, so some special handling:
+            if (!parseAssignmentExpression(rhs))
+                return;
+        } else {
+            // for C & all other expressions:
+            if (!parseCastExpression(rhs))
+                return;
+        }
+
+        for (int tokenKindAhead = tok().kind(), precedenceAhead = precedence(tokenKindAhead, _templateArguments);
+                precedenceAhead > operPrecedence && isBinaryOperator(tokenKindAhead)
+                        || precedenceAhead == operPrecedence && isRightAssociative(tokenKindAhead);
+                tokenKindAhead = tok().kind(), precedenceAhead = precedence(tokenKindAhead, _templateArguments)) {
+            parseExpressionWithOperatorPrecedence(rhs, precedenceAhead);
+        }
+
+        if (condExpr) { // we were parsing a ternairy conditional expression
+            condExpr->condition = lhs;
+            condExpr->right_expression = rhs;
+            lhs = condExpr;
+        } else {
+            BinaryExpressionAST *expr = new (_pool) BinaryExpressionAST;
+            expr->left_expression = lhs;
+            expr->binary_op_token = oper;
+            expr->right_expression = rhs;
+            lhs = expr;
+        }
+    }
+}
+
+bool Parser::parseCommaExpression(ExpressionAST *&node)
+{
+    PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Comma)
+}
+
+bool Parser::parseThrowExpression(ExpressionAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() == T_THROW) {
+        ThrowExpressionAST *ast = new (_pool) ThrowExpressionAST;
+        ast->throw_token = consumeToken();
+        parseAssignmentExpression(ast->expression);
+        node = ast;
+        return true;
+    }
+    return false;
+}
+
+bool Parser::lookAtObjCSelector() const
+{
+    switch (LA()) {
+    case T_IDENTIFIER:
+    case T_OR:
+    case T_AND:
+    case T_NOT:
+    case T_XOR:
+    case T_BITOR:
+    case T_COMPL:
+    case T_OR_EQ:
+    case T_AND_EQ:
+    case T_BITAND:
+    case T_NOT_EQ:
+    case T_XOR_EQ:
+        return true;
+
+    default:
+        if (tok().isKeyword())
+            return true;
+    } // switch
+
+    return false;
+}
+
+// objc-class-declaraton ::= T_AT_CLASS (T_IDENTIFIER @ T_COMMA) T_SEMICOLON
+//
+bool Parser::parseObjCClassForwardDeclaration(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_AT_CLASS)
+        return false;
+
+    ObjCClassForwardDeclarationAST *ast = new (_pool) ObjCClassForwardDeclarationAST;
+
+    ast->class_token = consumeToken();
+    unsigned identifier_token = 0;
+    match(T_IDENTIFIER, &identifier_token);
+
+    ast->identifier_list = new (_pool) ObjCIdentifierListAST;
+    SimpleNameAST *name = new (_pool) SimpleNameAST;
+    name->identifier_token = identifier_token;
+    ast->identifier_list->value = name;
+    ObjCIdentifierListAST **nextId = &ast->identifier_list->next;
+
+    while (LA() == T_COMMA) {
+        consumeToken(); // consume T_COMMA
+        match(T_IDENTIFIER, &identifier_token);
+
+        *nextId = new (_pool) ObjCIdentifierListAST;
+        name = new (_pool) SimpleNameAST;
+        name->identifier_token = identifier_token;
+        (*nextId)->value = name;
+        nextId = &(*nextId)->next;
+    }
+
+    match(T_SEMICOLON, &ast->semicolon_token);
+    node = ast;
+    return true;
+}
+
+// objc-interface ::= attribute-specifier-list-opt objc-class-interface
+// objc-interface ::= objc-category-interface
+//
+// objc-class-interface ::= T_AT_INTERFACE T_IDENTIFIER (T_COLON T_IDENTIFIER)?
+//                          objc-protocol-refs-opt
+//                          objc-class-instance-variables-opt
+//                          objc-interface-declaration-list
+//                          T_AT_END
+//
+// objc-category-interface ::= T_AT_INTERFACE T_IDENTIFIER
+//                             T_LPAREN T_IDENTIFIER? T_RPAREN
+//                             objc-protocol-refs-opt
+//                             objc-interface-declaration-list
+//                             T_AT_END
+//
+bool Parser::parseObjCInterface(DeclarationAST *&node,
+                                SpecifierListAST *attributes)
+{
+    DEBUG_THIS_RULE();
+    if (! attributes && LA() == T___ATTRIBUTE__) {
+        SpecifierListAST **attr = &attributes;
+        while (parseAttributeSpecifier(*attr))
+            attr = &(*attr)->next;
+    }
+
+    if (LA() != T_AT_INTERFACE)
+        return false;
+
+    unsigned objc_interface_token = consumeToken();
+    unsigned identifier_token = 0;
+    match(T_IDENTIFIER, &identifier_token);
+
+    if (LA() == T_LPAREN) {
+        // a category interface
+
+        if (attributes)
+            _translationUnit->error(attributes->firstToken(),
+                                    "invalid attributes for category interface declaration");
+
+        ObjCClassDeclarationAST *ast = new (_pool) ObjCClassDeclarationAST;
+        ast->attribute_list = attributes;
+        ast->interface_token = objc_interface_token;
+        SimpleNameAST *class_name = new (_pool) SimpleNameAST;
+        class_name->identifier_token= identifier_token;
+        ast->class_name = class_name;
+
+        match(T_LPAREN, &ast->lparen_token);
+        if (LA() == T_IDENTIFIER) {
+            SimpleNameAST *category_name = new (_pool) SimpleNameAST;
+            category_name->identifier_token = consumeToken();
+            ast->category_name = category_name;
+        }
+
+        match(T_RPAREN, &ast->rparen_token);
+
+        parseObjCProtocolRefs(ast->protocol_refs);
+
+        DeclarationListAST **nextMembers = &ast->member_declaration_list;
+        DeclarationAST *declaration = 0;
+        while (parseObjCInterfaceMemberDeclaration(declaration)) {
+            *nextMembers = new (_pool) DeclarationListAST;
+            (*nextMembers)->value = declaration;
+            nextMembers = &(*nextMembers)->next;
+        }
+
+        match(T_AT_END, &ast->end_token);
+
+        node = ast;
+        return true;
+    } else {
+        // a class interface declaration
+        ObjCClassDeclarationAST *ast = new (_pool) ObjCClassDeclarationAST;
+        ast->attribute_list = attributes;
+        ast->interface_token = objc_interface_token;
+        SimpleNameAST* class_name = new (_pool) SimpleNameAST;
+        class_name->identifier_token = identifier_token;
+        ast->class_name = class_name;
+
+        if (LA() == T_COLON) {
+            ast->colon_token = consumeToken();
+            SimpleNameAST *superclass = new (_pool) SimpleNameAST;
+            match(T_IDENTIFIER, &superclass->identifier_token);
+            ast->superclass = superclass;
+        }
+
+        parseObjCProtocolRefs(ast->protocol_refs);
+        parseObjClassInstanceVariables(ast->inst_vars_decl);
+
+        DeclarationListAST **nextMembers = &ast->member_declaration_list;
+        DeclarationAST *declaration = 0;
+        while (parseObjCInterfaceMemberDeclaration(declaration)) {
+            *nextMembers = new (_pool) DeclarationListAST;
+            (*nextMembers)->value = declaration;
+            nextMembers = &(*nextMembers)->next;
+        }
+
+        match(T_AT_END, &ast->end_token);
+
+        node = ast;
+        return true;
+    }
+}
+
+// objc-protocol ::= T_AT_PROTOCOL (T_IDENTIFIER @ T_COMMA) T_SEMICOLON
+//
+bool Parser::parseObjCProtocol(DeclarationAST *&node,
+                               SpecifierListAST *attributes)
+{
+    DEBUG_THIS_RULE();
+    if (! attributes && LA() == T___ATTRIBUTE__) {
+        SpecifierListAST **attr = &attributes;
+        while (parseAttributeSpecifier(*attr))
+            attr = &(*attr)->next;
+    }
+
+    if (LA() != T_AT_PROTOCOL)
+        return false;
+
+    unsigned protocol_token = consumeToken();
+    unsigned identifier_token = 0;
+    match(T_IDENTIFIER, &identifier_token);
+
+    if (LA() == T_COMMA || LA() == T_SEMICOLON) {
+        // a protocol forward declaration
+
+        ObjCProtocolForwardDeclarationAST *ast = new (_pool) ObjCProtocolForwardDeclarationAST;
+        ast->attribute_list = attributes;
+        ast->protocol_token = protocol_token;
+        ast->identifier_list = new (_pool) ObjCIdentifierListAST;
+        SimpleNameAST *name = new (_pool) SimpleNameAST;
+        name->identifier_token = identifier_token;
+        ast->identifier_list->value = name;
+        ObjCIdentifierListAST **nextId = &ast->identifier_list->next;
+
+        while (LA() == T_COMMA) {
+            consumeToken(); // consume T_COMMA
+            match(T_IDENTIFIER, &identifier_token);
+
+            *nextId = new (_pool) ObjCIdentifierListAST;
+            name = new (_pool) SimpleNameAST;
+            name->identifier_token = identifier_token;
+            (*nextId)->value = name;
+            nextId = &(*nextId)->next;
+        }
+
+        match(T_SEMICOLON, &ast->semicolon_token);
+        node = ast;
+        return true;
+    } else {
+        // a protocol definition
+        ObjCProtocolDeclarationAST *ast = new (_pool) ObjCProtocolDeclarationAST;
+        ast->attribute_list = attributes;
+        ast->protocol_token = protocol_token;
+        SimpleNameAST *name = new (_pool) SimpleNameAST;
+        name->identifier_token = identifier_token;
+        ast->name = name;
+
+        parseObjCProtocolRefs(ast->protocol_refs);
+
+        DeclarationListAST **nextMembers = &ast->member_declaration_list;
+        DeclarationAST *declaration = 0;
+        while (parseObjCInterfaceMemberDeclaration(declaration)) {
+            *nextMembers = new (_pool) DeclarationListAST;
+            (*nextMembers)->value = declaration;
+            nextMembers = &(*nextMembers)->next;
+        }
+
+        match(T_AT_END, &ast->end_token);
+
+        node = ast;
+        return true;
+    }
+}
+
+// objc-implementation ::= T_AT_IMPLEMENTAION T_IDENTIFIER (T_COLON T_IDENTIFIER)?
+//                         objc-class-instance-variables-opt
+// objc-implementation ::= T_AT_IMPLEMENTAION T_IDENTIFIER T_LPAREN T_IDENTIFIER T_RPAREN
+//
+bool Parser::parseObjCImplementation(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_AT_IMPLEMENTATION)
+        return false;
+
+    unsigned implementation_token = consumeToken();
+    unsigned identifier_token = 0;
+    match(T_IDENTIFIER, &identifier_token);
+
+    if (LA() == T_LPAREN) {
+        // a category implementation
+        ObjCClassDeclarationAST *ast = new (_pool) ObjCClassDeclarationAST;
+        ast->implementation_token = implementation_token;
+        SimpleNameAST *class_name = new (_pool) SimpleNameAST;
+        class_name->identifier_token = identifier_token;
+        ast->class_name = class_name;
+
+        match(T_LPAREN, &ast->lparen_token);
+        SimpleNameAST *category_name = new (_pool) SimpleNameAST;
+        match(T_IDENTIFIER, &category_name->identifier_token);
+        ast->category_name = category_name;
+        match(T_RPAREN, &ast->rparen_token);
+
+        parseObjCMethodDefinitionList(ast->member_declaration_list);
+        match(T_AT_END, &ast->end_token);
+
+        node = ast;
+    } else {
+        // a class implementation
+        ObjCClassDeclarationAST *ast = new (_pool) ObjCClassDeclarationAST;
+        ast->implementation_token = implementation_token;
+        SimpleNameAST *class_name = new (_pool) SimpleNameAST;
+        class_name->identifier_token = identifier_token;
+        ast->class_name = class_name;
+
+        if (LA() == T_COLON) {
+            ast->colon_token = consumeToken();
+            SimpleNameAST *superclass = new (_pool) SimpleNameAST;
+            match(T_IDENTIFIER, &superclass->identifier_token);
+            ast->superclass = superclass;
+        }
+
+        parseObjClassInstanceVariables(ast->inst_vars_decl);
+        parseObjCMethodDefinitionList(ast->member_declaration_list);
+        match(T_AT_END, &ast->end_token);
+
+        node = ast;
+    }
+
+    return true;
+}
+
+bool Parser::parseObjCMethodDefinitionList(DeclarationListAST *&node)
+{
+    DEBUG_THIS_RULE();
+    DeclarationListAST **next = &node;
+
+    while (LA() && LA() != T_AT_END) {
+        unsigned start = cursor();
+        DeclarationAST *declaration = 0;
+
+        switch (LA()) {
+        case T_PLUS:
+        case T_MINUS:
+            parseObjCMethodDefinition(declaration);
+
+            if (start == cursor())
+                consumeToken();
+            break;
+
+        case T_SEMICOLON:
+            consumeToken();
+            break;
+
+        case T_AT_SYNTHESIZE: {
+            ObjCSynthesizedPropertiesDeclarationAST *ast = new (_pool) ObjCSynthesizedPropertiesDeclarationAST;
+            ast->synthesized_token = consumeToken();
+            ObjCSynthesizedPropertyListAST *last = new (_pool) ObjCSynthesizedPropertyListAST;
+            ast->property_identifier_list = last;
+            last->value = new (_pool) ObjCSynthesizedPropertyAST;
+            match(T_IDENTIFIER, &last->value->property_identifier_token);
+
+            if (LA() == T_EQUAL) {
+                last->value->equals_token = consumeToken();
+
+                match(T_IDENTIFIER, &last->value->alias_identifier_token);
+            }
+
+            while (LA() == T_COMMA) {
+                consumeToken(); // consume T_COMMA
+
+                last->next = new (_pool) ObjCSynthesizedPropertyListAST;
+                last = last->next;
+
+                last->value = new (_pool) ObjCSynthesizedPropertyAST;
+                match(T_IDENTIFIER, &last->value->property_identifier_token);
+
+                if (LA() == T_EQUAL) {
+                    last->value->equals_token = consumeToken();
+
+                    match(T_IDENTIFIER, &last->value->alias_identifier_token);
+                }
+            }
+
+            match(T_SEMICOLON, &ast->semicolon_token);
+
+            declaration = ast;
+            break;
+        }
+
+        case T_AT_DYNAMIC: {
+            ObjCDynamicPropertiesDeclarationAST *ast = new (_pool) ObjCDynamicPropertiesDeclarationAST;
+            ast->dynamic_token = consumeToken();
+            ast->property_identifier_list = new (_pool) ObjCIdentifierListAST;
+            SimpleNameAST *name = new (_pool) SimpleNameAST;
+            match(T_IDENTIFIER, &name->identifier_token);
+            ast->property_identifier_list->value = name;
+
+            ObjCIdentifierListAST *last = ast->property_identifier_list;
+            while (LA() == T_COMMA) {
+                consumeToken(); // consume T_COMMA
+
+                last->next = new (_pool) ObjCIdentifierListAST;
+                last = last->next;
+                name = new (_pool) SimpleNameAST;
+                match(T_IDENTIFIER, &name->identifier_token);
+                last->value = name;
+            }
+
+            match(T_SEMICOLON, &ast->semicolon_token);
+
+            declaration = ast;
+            break;
+        }
+
+        default:
+            if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL) {
+                parseDeclaration(declaration);
+            } else {
+                if (! parseBlockDeclaration(declaration)) {
+                    rewind(start);
+                    _translationUnit->error(cursor(),
+                                            "skip token `%s'", tok().spell());
+
+                    consumeToken();
+                }
+            }
+            break;
+        } // switch
+
+        if (declaration) {
+            *next = new (_pool) DeclarationListAST;
+            (*next)->value = declaration;
+            next = &(*next)->next;
+        }
+    }
+
+    return true;
+}
+
+bool Parser::parseObjCMethodDefinition(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    ObjCMethodPrototypeAST *method_prototype = 0;
+    if (! parseObjCMethodPrototype(method_prototype))
+        return false;
+
+    ObjCMethodDeclarationAST *ast = new (_pool) ObjCMethodDeclarationAST;
+    ast->method_prototype = method_prototype;
+
+    // Objective-C allows you to write:
+    // - (void) foo; { body; }
+    // so a method is a forward declaration when it doesn't have a _body_.
+    // However, we still need to read the semicolon.
+    if (LA() == T_SEMICOLON) {
+        ast->semicolon_token = consumeToken();
+    }
+
+    parseFunctionBody(ast->function_body);
+
+    node = ast;
+    return true;
+}
+
+// objc-protocol-refs ::= T_LESS (T_IDENTIFIER @ T_COMMA) T_GREATER
+//
+bool Parser::parseObjCProtocolRefs(ObjCProtocolRefsAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_LESS)
+        return false;
+
+    ObjCProtocolRefsAST *ast = new (_pool) ObjCProtocolRefsAST;
+
+    match(T_LESS, &ast->less_token);
+
+    unsigned identifier_token = 0;
+    match(T_IDENTIFIER, &identifier_token);
+    ast->identifier_list = new (_pool) ObjCIdentifierListAST;
+    SimpleNameAST *name = new (_pool) SimpleNameAST;
+    name->identifier_token = identifier_token;
+    ast->identifier_list->value = name;
+    ObjCIdentifierListAST **nextId = &ast->identifier_list->next;
+
+    while (LA() == T_COMMA) {
+        consumeToken(); // consume T_COMMA
+        match(T_IDENTIFIER, &identifier_token);
+
+        *nextId = new (_pool) ObjCIdentifierListAST;
+        name = new (_pool) SimpleNameAST;
+        name->identifier_token = identifier_token;
+        (*nextId)->value = name;
+        nextId = &(*nextId)->next;
+    }
+
+    match(T_GREATER, &ast->greater_token);
+    node = ast;
+    return true;
+}
+
+// objc-class-instance-variables ::= T_LBRACE
+//                                   objc-instance-variable-decl-list-opt
+//                                   T_RBRACE
+//
+bool Parser::parseObjClassInstanceVariables(ObjCInstanceVariablesDeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_LBRACE)
+        return false;
+
+    ObjCInstanceVariablesDeclarationAST *ast = new (_pool) ObjCInstanceVariablesDeclarationAST;
+    match(T_LBRACE, &ast->lbrace_token);
+
+    for (DeclarationListAST **next = &ast->instance_variable_list; LA(); next = &(*next)->next) {
+        if (LA() == T_RBRACE)
+            break;
+
+        const unsigned start = cursor();
+
+        *next = new (_pool) DeclarationListAST;
+        parseObjCInstanceVariableDeclaration((*next)->value);
+
+        if (start == cursor()) {
+            // skip stray token.
+            _translationUnit->error(cursor(), "skip stray token `%s'", tok().spell());
+            consumeToken();
+        }
+    }
+
+    match(T_RBRACE, &ast->rbrace_token);
+
+    node = ast;
+    return true;
+}
+
+// objc-interface-declaration ::= T_AT_REQUIRED
+// objc-interface-declaration ::= T_AT_OPTIONAL
+// objc-interface-declaration ::= T_SEMICOLON
+// objc-interface-declaration ::= objc-property-declaration
+// objc-interface-declaration ::= objc-method-prototype
+bool Parser::parseObjCInterfaceMemberDeclaration(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    switch (LA()) {
+    case T_AT_END:
+        return false;
+
+    case T_AT_REQUIRED:
+    case T_AT_OPTIONAL:
+        consumeToken();
+        return true;
+
+    case T_SEMICOLON:
+        consumeToken();
+        return true;
+
+    case T_AT_PROPERTY: {
+        return parseObjCPropertyDeclaration(node);
+    }
+
+    case T_PLUS:
+    case T_MINUS: {
+        ObjCMethodDeclarationAST *ast = new (_pool) ObjCMethodDeclarationAST;
+        if (parseObjCMethodPrototype(ast->method_prototype)) {
+            match(T_SEMICOLON, &ast->semicolon_token);
+            node = ast;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    case T_ENUM:
+    case T_CLASS:
+    case T_STRUCT:
+    case T_UNION: {
+        return parseSimpleDeclaration(node, /*accept struct declarators */ true);
+    }
+
+    default: {
+        return parseSimpleDeclaration(node, /*accept struct declarators */ true);
+    } // default
+
+    } // switch
+}
+
+// objc-instance-variable-declaration ::= objc-visibility-specifier
+// objc-instance-variable-declaration ::= block-declaration
+//
+bool Parser::parseObjCInstanceVariableDeclaration(DeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    switch (LA()) {
+        case T_AT_PRIVATE:
+        case T_AT_PROTECTED:
+        case T_AT_PUBLIC:
+        case T_AT_PACKAGE: {
+            ObjCVisibilityDeclarationAST *ast = new (_pool) ObjCVisibilityDeclarationAST;
+            ast->visibility_token = consumeToken();
+            node = ast;
+            return true;
+        }
+
+        default:
+            return parseSimpleDeclaration(node, true);
+    }
+}
+
+// objc-property-declaration ::=
+//    T_AT_PROPERTY T_LPAREN (property-attribute @ T_COMMA) T_RPAREN simple-declaration
+//
+bool Parser::parseObjCPropertyDeclaration(DeclarationAST *&node, SpecifierListAST *attributes)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_AT_PROPERTY)
+        return false;
+
+    ObjCPropertyDeclarationAST *ast = new (_pool) ObjCPropertyDeclarationAST;
+    ast->attribute_list = attributes;
+    ast->property_token = consumeToken();
+
+    if (LA() == T_LPAREN) {
+        match(T_LPAREN, &ast->lparen_token);
+
+        ObjCPropertyAttributeAST *property_attribute = 0;
+        if (parseObjCPropertyAttribute(property_attribute)) {
+            ast->property_attribute_list = new (_pool) ObjCPropertyAttributeListAST;
+            ast->property_attribute_list->value = property_attribute;
+            ObjCPropertyAttributeListAST *last = ast->property_attribute_list;
+
+            while (LA() == T_COMMA) {
+                consumeToken(); // consume T_COMMA
+                last->next = new (_pool) ObjCPropertyAttributeListAST;
+                last = last->next;
+                if (!parseObjCPropertyAttribute(last->value)) {
+                    _translationUnit->error(_tokenIndex, "expected token `%s' got `%s'",
+                                            Token::name(T_IDENTIFIER), tok().spell());
+                    break;
+                }
+            }
+        }
+
+        match(T_RPAREN, &ast->rparen_token);
+    }
+
+    if (parseSimpleDeclaration(ast->simple_declaration, /*accept-struct-declarators = */ true))
+        node = ast;
+    else
+        _translationUnit->error(_tokenIndex, "expected a simple declaration");
+
+    return true;
+}
+
+// objc-method-prototype ::= (T_PLUS | T_MINUS) objc-method-decl objc-method-attrs-opt
+//
+// objc-method-decl ::= objc-type-name? objc-selector
+// objc-method-decl ::= objc-type-name? objc-keyword-decl-list objc-parmlist-opt
+//
+bool Parser::parseObjCMethodPrototype(ObjCMethodPrototypeAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_PLUS && LA() != T_MINUS)
+        return false;
+
+    ObjCMethodPrototypeAST *ast = new (_pool) ObjCMethodPrototypeAST;
+    ast->method_type_token = consumeToken();
+
+    parseObjCTypeName(ast->type_name);
+
+    if ((lookAtObjCSelector() && LA(2) == T_COLON) || LA() == T_COLON) {
+        ObjCSelectorArgumentAST *argument = 0;
+        ObjCMessageArgumentDeclarationAST *declaration = 0;
+        parseObjCKeywordDeclaration(argument, declaration);
+
+        ObjCSelectorWithArgumentsAST *sel = new (_pool) ObjCSelectorWithArgumentsAST;
+        ast->selector = sel;
+        ObjCSelectorArgumentListAST *lastSel = new (_pool) ObjCSelectorArgumentListAST;
+        sel->selector_argument_list = lastSel;
+        sel->selector_argument_list->value = argument;
+
+        ast->argument_list = new (_pool) ObjCMessageArgumentDeclarationListAST;
+        ast->argument_list->value = declaration;
+        ObjCMessageArgumentDeclarationListAST *lastArg = ast->argument_list;
+
+        while (parseObjCKeywordDeclaration(argument, declaration)) {
+            lastSel->next = new (_pool) ObjCSelectorArgumentListAST;
+            lastSel = lastSel->next;
+            lastSel->value = argument;
+
+            lastArg->next = new (_pool) ObjCMessageArgumentDeclarationListAST;
+            lastArg = lastArg->next;
+            lastArg->value = declaration;
+        }
+
+        while (LA() == T_COMMA) {
+            consumeToken();
+
+            if (LA() == T_DOT_DOT_DOT) {
+                ast->dot_dot_dot_token = consumeToken();
+                break;
+            }
+
+            // TODO: Is this still valid, and if so, should it be stored in the AST? (EV)
+            DeclarationAST *parameter_declaration = 0;
+            parseParameterDeclaration(parameter_declaration);
+        }
+    } else if (lookAtObjCSelector()) {
+        ObjCSelectorWithoutArgumentsAST *sel = new (_pool) ObjCSelectorWithoutArgumentsAST;
+        parseObjCSelector(sel->name_token);
+        ast->selector = sel;
+    } else {
+        _translationUnit->error(cursor(), "expected a selector");
+    }
+
+    SpecifierListAST **attr = &ast->attribute_list;
+    while (parseAttributeSpecifier(*attr))
+        attr = &(*attr)->next;
+
+    node = ast;
+    return true;
+}
+
+// objc-property-attribute ::= getter '=' identifier
+// objc-property-attribute ::= setter '=' identifier ':'
+// objc-property-attribute ::= readonly
+// objc-property-attribute ::= readwrite
+// objc-property-attribute ::= assign
+// objc-property-attribute ::= retain
+// objc-property-attribute ::= copy
+// objc-property-attribute ::= nonatomic
+bool Parser::parseObjCPropertyAttribute(ObjCPropertyAttributeAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_IDENTIFIER)
+        return false;
+
+    node = new (_pool) ObjCPropertyAttributeAST;
+
+    const Identifier *id = tok().identifier;
+    const int k = classifyObjectiveCTypeQualifiers(id->chars(), id->size());
+    switch (k) {
+    case Token_copy:
+    case Token_assign:
+    case Token_retain:
+    case Token_readonly:
+    case Token_readwrite:
+    case Token_nonatomic:
+        node->attribute_identifier_token = consumeToken();
+        return true;
+
+    case Token_getter: {
+        node->attribute_identifier_token = consumeToken();
+        match(T_EQUAL, &node->equals_token);
+        ObjCSelectorWithoutArgumentsAST *selector = new (_pool) ObjCSelectorWithoutArgumentsAST;
+        match(T_IDENTIFIER, &selector->name_token);
+        node->method_selector = selector;
+        return true;
+    }
+
+    case Token_setter: {
+        node->attribute_identifier_token = consumeToken();
+        match(T_EQUAL, &node->equals_token);
+        ObjCSelectorWithArgumentsAST *selector = new (_pool) ObjCSelectorWithArgumentsAST;
+        selector->selector_argument_list = new (_pool) ObjCSelectorArgumentListAST;
+        selector->selector_argument_list->value = new (_pool) ObjCSelectorArgumentAST;
+        match(T_IDENTIFIER, &selector->selector_argument_list->value->name_token);
+        match(T_COLON, &selector->selector_argument_list->value->colon_token);
+        node->method_selector = selector;
+        return true;
+    }
+
+    default:
+        return false;
+    }
+}
+
+// objc-type-name ::= T_LPAREN objc-type-qualifiers-opt type-id T_RPAREN
+//
+bool Parser::parseObjCTypeName(ObjCTypeNameAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_LPAREN)
+        return false;
+
+    ObjCTypeNameAST *ast = new (_pool) ObjCTypeNameAST;
+    match(T_LPAREN, &ast->lparen_token);
+    parseObjCTypeQualifiers(ast->type_qualifier_token);
+    parseTypeId(ast->type_id);
+    match(T_RPAREN, &ast->rparen_token);
+    node = ast;
+    return true;
+}
+
+// objc-selector ::= T_IDENTIFIER | keyword
+//
+bool Parser::parseObjCSelector(unsigned &selector_token)
+{
+    DEBUG_THIS_RULE();
+    if (! lookAtObjCSelector())
+        return false;
+
+    selector_token = consumeToken();
+    return true;
+}
+
+// objc-keyword-decl ::= objc-selector? T_COLON objc-type-name? objc-keyword-attributes-opt T_IDENTIFIER
+//
+bool Parser::parseObjCKeywordDeclaration(ObjCSelectorArgumentAST *&argument, ObjCMessageArgumentDeclarationAST *&node)
+{
+    DEBUG_THIS_RULE();
+    if (! (LA() == T_COLON || (lookAtObjCSelector() && LA(2) == T_COLON)))
+        return false;
+
+    node = new (_pool) ObjCMessageArgumentDeclarationAST;
+    argument = new (_pool) ObjCSelectorArgumentAST;
+
+    parseObjCSelector(argument->name_token);
+    match(T_COLON, &argument->colon_token);
+
+    parseObjCTypeName(node->type_name);
+
+    SpecifierListAST **attr = &node->attribute_list;
+    while (parseAttributeSpecifier(*attr))
+        attr = &(*attr)->next;
+
+    match(T_IDENTIFIER, &node->param_name_token);
+
+    return true;
+}
+
+bool Parser::parseObjCTypeQualifiers(unsigned &type_qualifier)
+{
+    DEBUG_THIS_RULE();
+    if (LA() != T_IDENTIFIER)
+        return false;
+
+    const Identifier *id = tok().identifier;
+    const int k = classifyObjectiveCTypeQualifiers(id->chars(), id->size());
+    if (k == Token_identifier)
+        return false;
+    type_qualifier = consumeToken();
+    return true;
+}
+
+bool Parser::peekAtObjCContextKeyword(int kind)
+{
+    if (LA() != T_IDENTIFIER)
+        return false;
+
+    const Identifier *id = tok().identifier;
+    const int k = classifyObjectiveCTypeQualifiers(id->chars(), id->size());
+    return k == kind;
+}
+
+bool Parser::parseObjCContextKeyword(int kind, unsigned &in_token)
+{
+    DEBUG_THIS_RULE();
+
+    if (peekAtObjCContextKeyword(kind)) {
+        in_token = consumeToken();
+        return true;
+    } else {
+        return false;
+    }
+}
+
+