diff --git a/shared/cplusplus/AST.cpp b/shared/cplusplus/AST.cpp
index d112f9ab537ebd4d7c0264ab8dfc79147a207d8d..11be99ea48a1257371a3a584e5894b9669c55ca1 100644
--- a/shared/cplusplus/AST.cpp
+++ b/shared/cplusplus/AST.cpp
@@ -3898,6 +3898,8 @@ void IdentifierListAST::accept0(ASTVisitor *visitor)
 
 unsigned ObjCClassDeclarationAST::firstToken() const
 {
+    if (attributes)
+        return attributes->firstToken();
     return class_token;
 }
 
@@ -3911,12 +3913,19 @@ unsigned ObjCClassDeclarationAST::lastToken() const
             return it->identifier_token + 1;
     }
 
+    for (SpecifierAST *it = attributes; it; it = it->next) {
+        if (! it->next)
+            return it->lastToken();
+    }
+
     return class_token + 1;
 }
 
 ObjCClassDeclarationAST *ObjCClassDeclarationAST::clone(MemoryPool *pool) const
 {
     ObjCClassDeclarationAST *ast = new (pool) ObjCClassDeclarationAST;
+    if (attributes)
+        ast->attributes = attributes->clone(pool);
     ast->class_token = class_token;
     if (identifier_list)
         ast->identifier_list = identifier_list->clone(pool);
@@ -3927,6 +3936,9 @@ ObjCClassDeclarationAST *ObjCClassDeclarationAST::clone(MemoryPool *pool) const
 void ObjCClassDeclarationAST::accept0(ASTVisitor *visitor)
 {
     if (visitor->visit(this)) {
+        for (SpecifierAST *it = attributes; it; it = it->next) {
+            accept(it, visitor);
+        }
     }
 }
 
diff --git a/shared/cplusplus/AST.h b/shared/cplusplus/AST.h
index d03cd3ff82c6fc44aac09abbc9979ced259ff7bd..6607e76805b8072094d40bc4f43551d34ff57920 100644
--- a/shared/cplusplus/AST.h
+++ b/shared/cplusplus/AST.h
@@ -1949,6 +1949,7 @@ protected:
 class CPLUSPLUS_EXPORT ObjCClassDeclarationAST: public DeclarationAST
 {
 public:
+    SpecifierAST *attributes;
     unsigned class_token;
     IdentifierListAST *identifier_list;
     unsigned semicolon_token;
diff --git a/shared/cplusplus/Parser.cpp b/shared/cplusplus/Parser.cpp
index 8e15a220be538f5406fe351b8a7ae3977eb24904..6911fd4f9c049189110fc077078f9e921a4576aa 100644
--- a/shared/cplusplus/Parser.cpp
+++ b/shared/cplusplus/Parser.cpp
@@ -403,39 +403,45 @@ bool Parser::parseDeclaration(DeclarationAST *&node)
     case T_EXPORT:
         return parseTemplateDeclaration(node);
 
-    // objc++
-    case T_AT_IMPLEMENTATION:
-        return parseObjCClassImplementation(node);
-
+    // ObjcC++
     case T_AT_CLASS:
         return parseObjCClassDeclaration(node);
 
     case T_AT_INTERFACE:
-        return parseObjCInterfaceDeclaration(node);
+        return parseObjCInterface(node);
 
     case T_AT_PROTOCOL:
-        return parseObjCProtocolDeclaration(node);
+        return parseObjCProtocol(node);
 
     case T_AT_END:
-        return parseObjCEndDeclaration(node);
-
-    case T_AT_COMPATIBILITY_ALIAS:
-        return parseObjCAliasDeclaration(node);
-
-    case T_AT_SYNTHESIZE:
-        return parseObjCPropertySynthesize(node);
+        return parseObjCEnd(node);
 
-    case T_AT_DYNAMIC:
-        return parseObjCPropertyDynamic(node);
+    default: {
+        if (_objCEnabled && LA() == T___ATTRIBUTE__) {
+            const unsigned start = cursor();
+            SpecifierAST *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);
+        }
 
-    default:
         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)
@@ -2543,16 +2549,7 @@ bool Parser::parsePrimaryExpression(ExpressionAST *&node)
     case T_SLOT:
         return parseQtMethod(node);
 
-    case T_AT_ENCODE:
-    case T_AT_PROTOCOL:
-    case T_AT_SELECTOR:
-    case T_AT_STRING_LITERAL:
-        return parseObjCExpression(node);
-
     default: {
-        if (_objCEnabled && LA() == T_LBRACKET)
-            return parseObjCExpression(node);
-
         unsigned startOfName = cursor();
         NameAST *name = 0;
         if (parseName(name)) {
@@ -3303,513 +3300,417 @@ bool Parser::parseThrowExpression(ExpressionAST *&node)
     return false;
 }
 
-bool Parser::parseObjCClassImplementation(DeclarationAST *&)
+bool Parser::lookAtObjCSelector() const
 {
-    if (LA() != T_AT_IMPLEMENTATION)
-        return false;
-
-    /*unsigned implementation_token = */ consumeToken();
-    unsigned identifier_token = 0;
-    match(T_IDENTIFIER, &identifier_token);
+    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;
 
-    if (LA() == T_COLON) {
-        /*unsigned colon_token = */ consumeToken();
-        unsigned superclass_name_token = 0;
-        match(T_IDENTIFIER, &superclass_name_token);
-    } else if (LA() == T_LPAREN) {
-        /*unsigned lparen_token = */ consumeToken();
-        unsigned category_name_token = 0;
-        if (LA() == T_IDENTIFIER)
-            category_name_token = consumeToken();
-        unsigned rparen_token = 0;
-        match(T_RPAREN, &rparen_token);
-    }
+    default:
+        if (tok().isKeyword())
+            return true;
+    } // switch
 
-    _inObjCImplementationContext = true;
-    parseObjCMethodDefinitionList();
-    return true;
+    return false;
 }
 
+// objc-class-declaraton ::= T_AT_CLASS (T_IDENTIFIER @ T_COMMA) T_SEMICOLON
+//
 bool Parser::parseObjCClassDeclaration(DeclarationAST *&node)
 {
     if (LA() != T_AT_CLASS)
         return false;
 
-    ObjCClassDeclarationAST *ast = new (_pool) ObjCClassDeclarationAST;
-    ast->class_token = consumeToken();
-    parseObjCIdentifierList(ast->identifier_list);
-    match(T_SEMICOLON, &ast->semicolon_token);
-    node = ast;
+    unsigned objc_class_token = consumeToken();
+    unsigned identifier_token = 0;
+    match(T_IDENTIFIER, &identifier_token);
+    while (LA() == T_COMMA) {
+        consumeToken(); // skip T_COMMA
+        match(T_IDENTIFIER, &identifier_token);
+    }
+
+    unsigned semicolon_token = 0;
+    match(T_SEMICOLON, &semicolon_token);
     return true;
 }
 
-bool Parser::parseObjCInterfaceDeclaration(DeclarationAST *&)
+// 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,
+                                SpecifierAST *attributes)
 {
+    if (! attributes && LA() == T___ATTRIBUTE__) {
+        SpecifierAST **attr = &attributes;
+        while (parseAttributeSpecifier(*attr))
+            attr = &(*attr)->next;
+    }
+
     if (LA() != T_AT_INTERFACE)
         return false;
 
-    /*unsigned interface_token = */ consumeToken();
-    unsigned interface_name_token = 0;
-    match(T_IDENTIFIER, &interface_name_token);
+    unsigned objc_interface_token = consumeToken();
+    unsigned identifier_token = 0;
+    match(T_IDENTIFIER, &identifier_token);
+
     if (LA() == T_LPAREN) {
-        // category interface
-        /*unsigned lparen_token = */ consumeToken();
-        unsigned catagory_name_token = 0;
+        // a category interface
+
+        if (attributes)
+            _translationUnit->error(attributes->firstToken(),
+                                    "invalid attributes for category interface declaration");
+
+        unsigned lparen_token = 0, rparen_token = 0;
+        match(T_LPAREN, &lparen_token);
         if (LA() == T_IDENTIFIER)
-            catagory_name_token = consumeToken();
-        unsigned rparen_token = 0;
+            consumeToken();
+
         match(T_RPAREN, &rparen_token);
+
         parseObjCProtocolRefs();
-        parseObjCClassInstanceVariables();
-        parseObjCInterfaceDeclList();
-        unsigned end_token = 0;
-        match(T_AT_END, &end_token);
-        return true;
-    } else {
-        // class interface
-        unsigned colon_token = 0;
-        unsigned super_class_token = 0;
-        if (LA() == T_COLON) {
-            colon_token = consumeToken();
-            match(T_IDENTIFIER, &super_class_token);
+        while (parseObjCInterfaceMemberDeclaration()) {
         }
-        parseObjCProtocolRefs();
-        parseObjCInterfaceDeclList();
-        unsigned end_token = 0;
-        match(T_AT_END, &end_token);
+        unsigned objc_end_token = 0;
+        match(T_AT_END, &objc_end_token);
         return true;
     }
-    return false;
-}
-
-bool Parser::parseObjCProtocolDeclaration(DeclarationAST *&)
-{
-    return false;
-}
-
-bool Parser::parseObjCEndDeclaration(DeclarationAST *&)
-{
-    if (LA() != T_AT_END)
-        return false;
-
-    unsigned end_token = consumeToken();
 
-    if (! _inObjCImplementationContext) {
-        _translationUnit->warning(end_token,
-            "@end must appear in an @implementation context");
+    // a class interface declaration
+    if (LA() == T_COLON) {
+        consumeToken();
+        unsigned identifier_token = 0;
+        match(T_IDENTIFIER, &identifier_token);
     }
 
-    _inObjCImplementationContext = false;
+    parseObjCProtocolRefs();
+    parseObjClassInstanceVariables();
+    while (parseObjCInterfaceMemberDeclaration()) {
+    }
+    unsigned objc_end_token = 0;
+    match(T_AT_END, &objc_end_token);
     return true;
 }
 
-bool Parser::parseObjCAliasDeclaration(DeclarationAST *&)
+// objc-protocol ::= T_AT_PROTOCOL (T_IDENTIFIER @ T_COMMA) T_SEMICOLON
+//
+bool Parser::parseObjCProtocol(DeclarationAST *&node,
+                               SpecifierAST *attributes)
 {
-    return false;
-}
+    if (! attributes && LA() == T___ATTRIBUTE__) {
+        SpecifierAST **attr = &attributes;
+        while (parseAttributeSpecifier(*attr))
+            attr = &(*attr)->next;
+    }
 
-bool Parser::parseObjCPropertySynthesize(DeclarationAST *&)
-{
-    return false;
-}
+    if (LA() != T_AT_PROTOCOL)
+        return false;
 
-bool Parser::parseObjCPropertyDynamic(DeclarationAST *&)
-{
-    return false;
-}
+    unsigned objc_protocol_token = consumeToken();
+    unsigned identifier_token = 0;
+    match(T_IDENTIFIER, &identifier_token);
+
+    if (LA() == T_COMMA || LA() == T_SEMICOLON) {
+        // a protocol forward declaration
 
-bool Parser::parseObjCIdentifierList(IdentifierListAST *&node)
-{
-    if (LA() == T_IDENTIFIER) {
-        IdentifierListAST **it = &node;
-        IdentifierListAST *id = new (_pool) IdentifierListAST;
-        id->identifier_token = consumeToken();
-        *it = id;
         while (LA() == T_COMMA) {
             consumeToken();
-            if (LA() == T_IDENTIFIER) {
-                it = &(*it)->next;
-                IdentifierListAST *id = new (_pool) IdentifierListAST;
-                id->identifier_token = consumeToken();
-                *it = id;
-            }
+            match(T_IDENTIFIER, &identifier_token);
         }
+        unsigned semicolon_token = 0;
+        match(T_SEMICOLON, &semicolon_token);
         return true;
     }
-    return false;
-}
 
-bool Parser::parseObjCProtocolRefs()
-{
-    return false;
-}
+    // a protocol definition
+    parseObjCProtocolRefs();
 
-bool Parser::parseObjCClassInstanceVariables()
-{
-    return false;
-}
-
-bool Parser::parseObjCInterfaceDeclList()
-{
-    unsigned saved = cursor();
-    while (LA() != T_AT_END && parseObjCInterfaceMemberDeclaration()) {
-        if (saved == cursor())
-            consumeToken(); // skip a token
+    while (parseObjCInterfaceMemberDeclaration()) {
     }
-    return true;
-}
-
-bool Parser::parseObjCInterfaceMemberDeclaration()
-{
-    switch (LA()) {
-    case T_SEMICOLON:
-        consumeToken();
-        return true;
-
-    case T_AT_REQUIRED:
-    case T_AT_OPTIONAL:
-        consumeToken();
-        return true;
-
-    case T_PLUS:
-    case T_MINUS:
-        return parseObjCMethodPrototype();
-
-    default: {
-        DeclarationAST *declaration = 0;
-        if (parseDeclaration(declaration))
-            return true;
-    } // default
 
-    } // switch
+    unsigned objc_end_token = 0;
+    match(T_AT_END, &objc_end_token);
 
-    return false;
+    return true;
 }
 
-bool Parser::parseObjCPropertyDeclaration(DeclarationAST *&)
-{
-    return false;
-}
 
-bool Parser::parseObjCMethodPrototype()
+// objc-protocol-refs ::= T_LESS (T_IDENTIFIER @ T_COMMA) T_GREATER
+//
+bool Parser::parseObjCProtocolRefs()
 {
-    if (LA() != T_PLUS && LA() != T_MINUS)
+    if (LA() != T_LESS)
         return false;
-
-    // instance or class method?
-    /*unsigned method_type_token = */ consumeToken();
-
-    SpecifierAST *attributes = 0, **attr = &attributes;
-    while (parseAttributeSpecifier(*attr))
-        attr = &(*attr)->next;
-
-    return false;
+    unsigned less_token = 0, greater_token = 0;
+    unsigned identifier_token = 0;
+    match(T_LESS, &less_token);
+    match(T_IDENTIFIER, &identifier_token);
+    while (LA() == T_COMMA) {
+        consumeToken();
+        match(T_IDENTIFIER, &identifier_token);
+    }
+    match(T_GREATER, &greater_token);
+    return true;
 }
 
-bool Parser::parseObjCExpression(ExpressionAST *&node)
+// objc-class-instance-variables ::= T_LBRACE
+//                                   objc-instance-variable-decl-list-opt
+//                                   T_RBRACE
+//
+bool Parser::parseObjClassInstanceVariables()
 {
-    switch (LA()) {
-    case T_LBRACKET:
-        return parseObjCMessageExpression(node);
+    if (LA() != T_LBRACE)
+        return false;
 
-    case T_AT_STRING_LITERAL:
-        return parseObjCStringLiteral(node);
+    unsigned lbrace_token =  0, rbrace_token = 0;
 
-    case T_AT_ENCODE:
-        return parseObjCEncodeExpression(node);
+    match(T_LBRACE, &lbrace_token);
+    while (LA()) {
+        if (LA() == T_RBRACE)
+            break;
 
-    case T_AT_PROTOCOL:
-        return parseObjCProtocolExpression(node);
+        const unsigned start = cursor();
 
-    case T_AT_SELECTOR:
-        return parseObjCSelectorExpression(node);
-    }
-    return false;
-}
+        DeclarationAST *declaration = 0;
+        parseObjCInstanceVariableDeclaration(declaration);
 
-bool Parser::parseObjCMessageExpression(ExpressionAST *&)
-{
-    if (LA() != T_LBRACKET)
-        return false;
+        if (start == cursor()) {
+            // skip stray token.
+            _translationUnit->error(cursor(), "skip stray token `%s'", tok().spell());
+            consumeToken();
+        }
+    }
 
-    /*unsigned lbracket_token = */ consumeToken();
-    ExpressionAST *receiver = 0;
-    parseObjCMessageReceiver(receiver);
-    parseObjCMessageArguments();
-    unsigned rbracket_token = 0;
-    match(T_RBRACKET, &rbracket_token);
+    match(T_RBRACE, &rbrace_token);
     return true;
 }
 
-bool Parser::parseObjCStringLiteral(ExpressionAST *&)
+// 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()
 {
-    if (LA() != T_AT_STRING_LITERAL)
-        return false;
-
-    do {
+    switch (LA()) {
+    case T_AT_REQUIRED:
+    case T_AT_OPTIONAL:
         consumeToken();
-    } while (LA() == T_AT_STRING_LITERAL);
+        return true;
 
-    return true;
-}
+    case T_SEMICOLON:
+        consumeToken();
+        return true;
 
-bool Parser::parseObjCEncodeExpression(ExpressionAST *&)
-{
-    if (LA() != T_AT_ENCODE)
-        return false;
+    case T_AT_PROPERTY: {
+        DeclarationAST *declaration = 0;
+        return parseObjCPropertyDeclaration(declaration);
+    }
 
-    /*unsigned encode_token = */ consumeToken();
-    unsigned lparen_token = 0, rparen_token = 0;
-    match(T_LPAREN, &lparen_token);
-    SpecifierAST *type_specifier = 0;
-    parseSimpleTypeSpecifier(type_specifier);
-    match(T_RPAREN, &rparen_token);
-    return true;
-}
+    case T_PLUS:
+    case T_MINUS:
+        return parseObjCMethodPrototype();
 
-bool Parser::parseObjCProtocolExpression(ExpressionAST *&)
-{
-    if (LA() != T_AT_PROTOCOL)
+    default:
         return false;
-
-    /*unsigned protocol_token = */ consumeToken();
-    unsigned protocol_name_token = 0, lparen_token = 0, rparen_token = 0;
-    match(T_LPAREN, &lparen_token);
-    match(T_IDENTIFIER, &protocol_name_token);
-    match(T_RPAREN, &rparen_token);
-    return true;
+    }
 }
 
-bool Parser::parseObjCSelectorExpression(ExpressionAST *&)
+// objc-instance-variable-declaration ::= objc-visibility-specifier
+// objc-instance-variable-declaration ::= block-declaration
+//
+bool Parser::parseObjCInstanceVariableDeclaration(DeclarationAST *&node)
 {
-    if (LA() != T_AT_SELECTOR)
-        return false;
+    switch (LA()) {
+    case T_AT_PRIVATE:
+    case T_AT_PROTECTED:
+    case T_AT_PUBLIC:
+    case T_AT_PACKAGE:
+        consumeToken();
+        return true;
 
-    /*unsigned selector_token = */ consumeToken();
-    unsigned lparen_token = 0, rparen_token = 0;
-    match(T_LPAREN, &lparen_token);
-    while (LA(1) == T_IDENTIFIER && LA(2) == T_COLON) {
-        /*unsigned identifier_token = */ consumeToken();
-        /*unsigned colon_token = */ consumeToken();
+    default:
+        return parseBlockDeclaration(node);
     }
-    match(T_RPAREN, &rparen_token);
-    return true;
-}
-
-bool Parser::parseObjCMessageReceiver(ExpressionAST *&node)
-{
-    // ### expression or simple-type-specifier.
-    return parseExpression(node);
 }
 
-bool Parser::parseObjCMessageArguments()
+// objc-property-declaration ::=
+//    T_AT_PROPERTY T_LPAREN (property-attribute @ T_COMMA) T_RPAREN simple-declaration
+//
+bool Parser::parseObjCPropertyDeclaration(DeclarationAST *&, SpecifierAST *)
 {
-    if (LA() != T_IDENTIFIER && LA() != T_COLON)
+    if (LA() != T_AT_PROPERTY)
         return false;
 
-    unsigned selector_name_token = 0;
-
-    if (LA() == T_IDENTIFIER)
-        selector_name_token = consumeToken();
-
-    if (LA() == T_COLON) {
-        /*unsigned colon_token = */ consumeToken();
-
-        ExpressionAST *expr = 0;
-        parseAssignmentExpression(expr);
-
-        while ((LA() == T_IDENTIFIER && LA(2) == T_COLON) || LA() == T_COLON) {
-            if (LA() == T_IDENTIFIER)
-                consumeToken();
+    unsigned objc_property_token = consumeToken();
 
-            if (LA() == T_COLON)
-                consumeToken();
-
-            parseAssignmentExpression(expr);
-        }
-
-        while (LA() == T_COMMA) {
-            consumeToken();
-            parseAssignmentExpression(expr);
+    if (LA() == T_LPAREN) {
+        unsigned lparen_token = 0, rparen_token = 0;
+        match(T_LPAREN, &lparen_token);
+        while (parseObjCPropertyAttribute()) {
         }
+        match(T_RPAREN, &rparen_token);
     }
 
+    DeclarationAST *simple_declaration = 0;
+    parseSimpleDeclaration(simple_declaration, /*accept-struct-declarators = */ false);
     return true;
 }
 
-bool Parser::parseObjCMethodDefinitionList()
+// 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()
 {
-    bool done = false;
-    while (! done) {
-        switch (LA()) {
-        case T_EOF_SYMBOL:
-        case T_AT_END:
-            done = true;
-            break;
+    if (LA() != T_PLUS && LA() != T_MINUS)
+        return false;
 
-        case T_PLUS:
-        case T_MINUS:
-            parseObjCMethodSignature();
-            if (LA() == T_SEMICOLON)
-                consumeToken();
-            break;
+    unsigned method_type_token = consumeToken();
 
-        case T_AT_PROPERTY:
-            parseObjCAtProperty();
-            break;
-
-        case T_SEMICOLON:
-            consumeToken();
-            break;
+    parseObjCTypeName();
 
-        case T_AT_OPTIONAL:
-            consumeToken();
-            break;
+    if ((lookAtObjCSelector() && LA(2) == T_COLON) || LA() == T_COLON) {
+        while (parseObjCKeywordDeclaration()) {
+        }
 
-        case T_AT_REQUIRED:
+        while (LA() == T_COMMA) {
             consumeToken();
-            break;
 
-        case T_TEMPLATE:
-        case T_NAMESPACE: {
-            DeclarationAST *declaration = 0;
-            parseDeclaration(declaration);
-        }   break;
-
-        default: {
-            unsigned start = cursor();
-            DeclarationAST *declaration = 0;
-            if (LA(1) == T_EXTERN && LA(2) == T_STRING_LITERAL) {
-                parseLinkageSpecification(declaration);
-            } else if (parseBlockDeclaration(declaration)) {
-                // ### accept the declaration.
-            } else {
-                if (cursor() == start) {
-                    _translationUnit->error(cursor(),
-                            "stray `%s' between Objective-C++ methods",
-                            tok().spell());
-                    consumeToken();
-                }
+            if (LA() == T_DOT_DOT_DOT) {
+                consumeToken();
+                break;
             }
-        }   break; // default
 
-        } // switch
+            DeclarationAST *parameter_declaration = 0;
+            parseParameterDeclaration(parameter_declaration);
+        }
+    } else if (lookAtObjCSelector()) {
+        parseObjCSelector();
+    } else {
+        _translationUnit->error(cursor(), "expected a selector");
     }
 
+    SpecifierAST *attributes = 0, **attr = &attributes;
+    while (parseAttributeSpecifier(*attr))
+        attr = &(*attr)->next;
+
     return true;
 }
 
-bool Parser::parseObjCMethodSignature()
+// 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()
 {
-    if (LA() != T_PLUS && LA() != T_MINUS)
+    if (LA() != T_IDENTIFIER)
         return false;
 
-    /*unsigned method_type_token = */ consumeToken();
-    parseObjCTypeName();
-
-    bool first = true;
-
-    while (lookAtObjCSelector() || LA() == T_COLON) {
-        if (LA() != T_COLON)
-            /*selector_name_token = */ consumeToken();
-
-        SpecifierAST *attributes = 0, **attr = &attributes;
-        while (parseAttributeSpecifier(*attr))
-            attr = &(*attr)->next;
-
-        if (first) {
-            first = false;
-
-            if (LA() != T_COLON)
-                break;
-        }
-
-        unsigned colon_token = 0;
-        match(T_COLON, &colon_token);
-
-        parseObjCTypeName();
-
-        unsigned identifier_token = 0;
-        match(T_IDENTIFIER, &identifier_token);
-
-        while (parseAttributeSpecifier(*attr))
-            attr = &(*attr)->next;
-    }
-
-    // parse the method tail parameters.
-    while (LA() == T_COMMA) {
+    unsigned identifier_token = 0;
+    match(T_IDENTIFIER, &identifier_token);
+    if (LA() == T_EQUAL) {
         consumeToken();
-
-        if (LA() == T_DOT_DOT_DOT) {
+        match(T_IDENTIFIER, &identifier_token);
+        if (LA() == T_COLON)
             consumeToken();
-            break;
-        }
-
-        DeclarationAST *parameter_declaration = 0;
-        parseParameterDeclaration(parameter_declaration);
     }
 
     return true;
 }
 
+// objc-type-name ::= T_LPAREN objc-type-qualifiers-opt type-id T_RPAREN
+//
 bool Parser::parseObjCTypeName()
 {
     if (LA() != T_LPAREN)
         return false;
 
-    /*unsigned lparen_token = */ consumeToken();
-
-    parseObjCProtocolQualifiers();
-
+    unsigned lparen_token = 0, rparen_token = 0;
+    match(T_LPAREN, &lparen_token);
+    parseObjCTypeQualifiers();
     ExpressionAST *type_id = 0;
-    if (LA() != T_RPAREN)
-        parseTypeId(type_id);
+    parseTypeId(type_id);
+    match(T_RPAREN, &rparen_token);
+    return true;
+}
 
-    SpecifierAST *attributes = 0, **attr = &attributes;
-    while (parseAttributeSpecifier(*attr))
-        attr = &(*attr)->next;
+// objc-selector ::= T_IDENTIFIER | keyword
+//
+bool Parser::parseObjCSelector()
+{
+    if (! lookAtObjCSelector())
+        return false;
 
-    unsigned rparen_token = 0;
-    match(T_RPAREN, &rparen_token);
+    consumeToken();
     return true;
 }
 
-bool Parser::parseObjCAtProperty()
+// objc-keyword-decl ::= objc-selector? T_COLON objc-type-name? objc-keyword-attributes-opt T_IDENTIFIER
+//
+bool Parser::parseObjCKeywordDeclaration()
 {
-    if (LA() != T_AT_PROPERTY)
+    if (! (LA() == T_COLON || (lookAtObjCSelector() && LA(2) == T_COLON)))
         return false;
 
-    /*unsigned property_token = */ consumeToken();
+    parseObjCSelector();
+
+    unsigned colon_token = 0;
+    match(T_COLON, &colon_token);
+
+    parseObjCTypeName();
+
+    SpecifierAST *attributes = 0, **attr = &attributes;
+    while (parseAttributeSpecifier(*attr))
+        attr = &(*attr)->next;
+
+    unsigned identifier_token = 0;
+    match(T_IDENTIFIER, &identifier_token);
+
     return true;
 }
 
-bool Parser::parseObjCProtocolQualifiers()
+bool Parser::parseObjCTypeQualifiers()
 {
     return false;
 }
 
-bool Parser::lookAtObjCSelector() const
+// objc-end: T_AT_END
+bool Parser::parseObjCEnd(DeclarationAST *&)
 {
-    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
+    if (LA() != T_AT_END)
+        return false;
 
-    return false;
+    consumeToken();
+    return true;
 }
+
+
 CPLUSPLUS_END_NAMESPACE
diff --git a/shared/cplusplus/Parser.h b/shared/cplusplus/Parser.h
index c943664afe1b6428e511bce4e13f52ee146bb7c0..5132ec5732f58d97da94976a507571b5755bf29a 100644
--- a/shared/cplusplus/Parser.h
+++ b/shared/cplusplus/Parser.h
@@ -206,46 +206,32 @@ public:
     bool parseUsingDirective(DeclarationAST *&node);
     bool parseWhileStatement(StatementAST *&node);
 
+    // Qt MOC run
+    bool parseQtMethod(ExpressionAST *&node);
+
     // ObjC++
-    bool parseObjCClassImplementation(DeclarationAST *&node);
     bool parseObjCClassDeclaration(DeclarationAST *&node);
-    bool parseObjCInterfaceDeclaration(DeclarationAST *&node);
-    bool parseObjCProtocolDeclaration(DeclarationAST *&node);
-    bool parseObjCEndDeclaration(DeclarationAST *&node);
-    bool parseObjCAliasDeclaration(DeclarationAST *&node);
-    bool parseObjCPropertySynthesize(DeclarationAST *&node);
-    bool parseObjCPropertyDynamic(DeclarationAST *&node);
+    bool parseObjCInterface(DeclarationAST *&node,
+                            SpecifierAST *attributes = 0);
+    bool parseObjCProtocol(DeclarationAST *&node,
+                           SpecifierAST *attributes = 0);
 
-    bool parseObjCIdentifierList(IdentifierListAST *&node);
-
-    bool parseObjCPropertyDeclaration(DeclarationAST *&node);
     bool parseObjCProtocolRefs();
-    bool parseObjCClassInstanceVariables();
+    bool parseObjClassInstanceVariables();
     bool parseObjCInterfaceMemberDeclaration();
-    bool parseObjCInterfaceDeclList();
+    bool parseObjCInstanceVariableDeclaration(DeclarationAST *&node);
+    bool parseObjCPropertyDeclaration(DeclarationAST *&node,
+                                      SpecifierAST *attributes = 0);
     bool parseObjCMethodPrototype();
-
-    bool parseObjCExpression(ExpressionAST *&node);
-    bool parseObjCMessageExpression(ExpressionAST *&node);
-    bool parseObjCStringLiteral(ExpressionAST *&node);
-    bool parseObjCEncodeExpression(ExpressionAST *&node);
-    bool parseObjCProtocolExpression(ExpressionAST *&node);
-    bool parseObjCSelectorExpression(ExpressionAST *&node);
-
-    bool parseObjCMessageReceiver(ExpressionAST *&node);
-    bool parseObjCMessageArguments();
-
-    bool parseObjCMethodSignature();
-    bool parseObjCMethodDefinitionList();
-    bool parseObjCAtProperty();
+    bool parseObjCPropertyAttribute();
     bool parseObjCTypeName();
-    bool parseObjCProtocolQualifiers();
+    bool parseObjCSelector();
+    bool parseObjCKeywordDeclaration();
+    bool parseObjCTypeQualifiers();
+    bool parseObjCEnd(DeclarationAST *&node);
 
     bool lookAtObjCSelector() const;
 
-    // Qt MOC run
-    bool parseQtMethod(ExpressionAST *&node);
-
     bool skipUntil(int token);
     bool skipUntilDeclaration();
     bool skipUntilStatement();
diff --git a/shared/cplusplus/Token.h b/shared/cplusplus/Token.h
index d5b6f1a1c0eab08279942cd3bae67c78708ae394..fdc3298202f697f35604cebcb74ecc75ea36dbf5 100644
--- a/shared/cplusplus/Token.h
+++ b/shared/cplusplus/Token.h
@@ -201,9 +201,9 @@ enum Kind {
     T___TYPEOF__,
 
     // obj c++ @ keywords
-    T_FIRST_OBJC_KEYWORD,
+    T_FIRST_OBJC_AT_KEYWORD,
 
-    T_AT_CATCH = T_FIRST_OBJC_KEYWORD,
+    T_AT_CATCH = T_FIRST_OBJC_AT_KEYWORD,
     T_AT_CLASS,
     T_AT_COMPATIBILITY_ALIAS,
     T_AT_DEFS,
@@ -228,7 +228,9 @@ enum Kind {
     T_AT_THROW,
     T_AT_TRY,
 
-    T_FIRST_QT_KEYWORD,
+    T_LAST_OBJC_AT_KEYWORD,
+
+    T_FIRST_QT_KEYWORD = T_LAST_OBJC_AT_KEYWORD,
 
     // Qt keywords
     T_SIGNAL = T_FIRST_QT_KEYWORD,
@@ -295,6 +297,9 @@ public:
     inline bool isKeyword() const
     { return kind >= T_FIRST_KEYWORD && kind < T_FIRST_QT_KEYWORD; }
 
+    inline bool isObjCAtKeyword() const
+    { return kind >= T_FIRST_OBJC_AT_KEYWORD && kind < T_LAST_OBJC_AT_KEYWORD; }
+
     static const char *name(int kind);
 
 public:
diff --git a/tests/auto/cplusplus/ast/tst_ast.cpp b/tests/auto/cplusplus/ast/tst_ast.cpp
index 969f1ac5ae16453edd8be26484adf4e4aaaf0768..5756d2dd2245053c564ee73eea2f9dca11b70da0 100644
--- a/tests/auto/cplusplus/ast/tst_ast.cpp
+++ b/tests/auto/cplusplus/ast/tst_ast.cpp
@@ -20,11 +20,15 @@ public:
     {
         StringLiteral *fileId = control.findOrInsertFileName("<stdin>");
         TranslationUnit *unit = new TranslationUnit(&control, fileId);
+        unit->setObjCEnabled(true);
         unit->setSource(source.constData(), source.length());
         unit->parse(mode);
         return unit;
     }
 
+    TranslationUnit *parseDeclaration(const QByteArray &source)
+    { return parse(source, TranslationUnit::ParseDeclaration); }
+
     TranslationUnit *parseExpression(const QByteArray &source)
     { return parse(source, TranslationUnit::ParseExpression); }
 
@@ -43,6 +47,11 @@ private slots:
     void while_condition_statement();
     void for_statement();
     void cpp_initializer_or_function_declaration();
+
+    // objc++
+    void objc_attributes_followed_by_at_keyword();
+    void objc_protocol_forward_declaration_1();
+    void objc_protocol_definition_1();
 };
 
 void tst_AST::simple_name()
@@ -293,6 +302,31 @@ void tst_AST::cpp_initializer_or_function_declaration()
     QCOMPARE(param->type_specifier->asNamedTypeSpecifier()->name->asSimpleName()->identifier_token, 4U);
 }
 
+void tst_AST::objc_attributes_followed_by_at_keyword()
+{
+    QSharedPointer<TranslationUnit> unit(parseDeclaration("\n"
+"__attribute__((deprecated)) @interface foo <bar>\n"
+"{\n"
+" int a, b;\n"
+"}\n"
+"+ (id) init;\n"
+"- (id) init:(int)a foo:(int)b, c;\n"
+"@end\n"
+    ));
+    AST *ast = unit->ast();
+}
+
+void tst_AST::objc_protocol_forward_declaration_1()
+{
+    QSharedPointer<TranslationUnit> unit(parseDeclaration("\n@protocol foo;"));
+    AST *ast = unit->ast();
+}
+
+void tst_AST::objc_protocol_definition_1()
+{
+    QSharedPointer<TranslationUnit> unit(parseDeclaration("\n@protocol foo <ciao, bar> @end"));
+    AST *ast = unit->ast();
+}
 
 QTEST_APPLESS_MAIN(tst_AST)
 #include "tst_ast.moc"
diff --git a/tests/manual/cplusplus/main.cpp b/tests/manual/cplusplus/main.cpp
index c33bcbbeff7fc8accdb3e923f63e4ed7fb6867cc..4292fe929f62d933063ff6e13ef8bd7cf257c54f 100644
--- a/tests/manual/cplusplus/main.cpp
+++ b/tests/manual/cplusplus/main.cpp
@@ -248,6 +248,7 @@ int main(int argc, char *argv[])
     Control control;
     StringLiteral *fileId = control.findOrInsertFileName("<stdin>");
     TranslationUnit unit(&control, fileId);
+    unit.setObjCEnabled(true);
     unit.setSource(source.constData(), source.size());
     unit.parse();
     if (! unit.ast())