diff --git a/src/libs/cplusplus/SimpleLexer.cpp b/src/libs/cplusplus/SimpleLexer.cpp
index 1af3bdb9366e73a1f986e95e8b90854822569052..de5dca135ed2bbfc2b01dfd01302f4c602652b59 100644
--- a/src/libs/cplusplus/SimpleLexer.cpp
+++ b/src/libs/cplusplus/SimpleLexer.cpp
@@ -71,7 +71,7 @@ bool SimpleToken::isComment() const
 
 bool SimpleToken::isObjCAtKeyword() const
 {
-    return _kind >= T_FIRST_OBJC_AT_KEYWORD && _kind <= T_LAST_OBJC_AT_KEYWORD;
+    return _kind >= T_FIRST_OBJC_KEYWORD && _kind <= T_LAST_OBJC_KEYWORD;
 }
 
 const char *SimpleToken::name() const
diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp
index 61c1312df3ad05fbd14c38fca3aabbb303599318..aa55de8d65f9c4890b87e13a0e03ce97730346ee 100644
--- a/src/plugins/cppeditor/cpphighlighter.cpp
+++ b/src/plugins/cppeditor/cpphighlighter.cpp
@@ -127,8 +127,7 @@ void CppHighlighter::highlightBlock(const QString &text)
         else if (tk.is(T_NUMERIC_LITERAL))
             setFormat(tk.position(), tk.length(), m_formats[CppNumberFormat]);
 
-        else if (tk.is(T_STRING_LITERAL) || tk.is(T_CHAR_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL) ||
-                 tk.is(T_AT_STRING_LITERAL))
+        else if (tk.is(T_STRING_LITERAL) || tk.is(T_CHAR_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL))
             highightLine(text, tk.position(), tk.length(), m_formats[CppStringFormat]);
 
         else if (tk.is(T_WIDE_STRING_LITERAL) || tk.is(T_WIDE_CHAR_LITERAL))
diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp
index 3d7cbebf9d944e31e682b0e6cc5c6ed71bd42b89..85a7666970d2ba5f3fd7a492058210005fb663d3 100644
--- a/src/plugins/cpptools/cppcodecompletion.cpp
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -1197,18 +1197,35 @@ bool CppCodeCompletion::completeScope(const QList<LookupItem> &results,
     return ! m_completions.isEmpty();
 }
 
-void CppCodeCompletion::addKeywords()
+void CppCodeCompletion::addKeyword(const QString &text)
 {
-    int keywordLimit = T_FIRST_OBJC_AT_KEYWORD;
-    if (objcKeywordsWanted())
-        keywordLimit = T_LAST_OBJC_AT_KEYWORD + 1;
+    TextEditor::CompletionItem item(this);
+    item.text = text;
+    item.icon = m_icons.keywordIcon();
+    m_completions.append(item);
+}
 
+void CppCodeCompletion::addKeywords()
+{
     // keyword completion items.
-    for (int i = T_FIRST_KEYWORD; i < keywordLimit; ++i) {
-        TextEditor::CompletionItem item(this);
-        item.text = QLatin1String(Token::name(i));
-        item.icon = m_icons.keywordIcon();
-        m_completions.append(item);
+    for (int i = T_FIRST_KEYWORD; i < T_FIRST_OBJC_KEYWORD; ++i) {
+        addKeyword(QLatin1String(Token::name(i)));
+    }
+
+    if (objcKeywordsWanted()) {
+        // unique Objective-C keywords:
+        for (int i = T_FIRST_OBJC_KEYWORD; i <= T_LAST_OBJC_KEYWORD; ++i) {
+            addKeyword(QLatin1Char('@') + QLatin1String(Token::name(i)));
+        }
+
+        // overlapping keywords:
+        addKeyword(QLatin1Char('@') + QLatin1String(Token::name(T_CATCH)));
+        addKeyword(QLatin1Char('@') + QLatin1String(Token::name(T_CLASS)));
+        addKeyword(QLatin1Char('@') + QLatin1String(Token::name(T_PRIVATE)));
+        addKeyword(QLatin1Char('@') + QLatin1String(Token::name(T_PROTECTED)));
+        addKeyword(QLatin1Char('@') + QLatin1String(Token::name(T_PUBLIC)));
+        addKeyword(QLatin1Char('@') + QLatin1String(Token::name(T_THROW)));
+        addKeyword(QLatin1Char('@') + QLatin1String(Token::name(T_TRY)));
     }
 }
 
diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h
index d4160ee3c1da220a5873513d237d0ad321617492..0d98dfdf95857b0a276ff16a17836e473ef34605 100644
--- a/src/plugins/cpptools/cppcodecompletion.h
+++ b/src/plugins/cpptools/cppcodecompletion.h
@@ -89,6 +89,7 @@ public:
     void setPartialCompletionEnabled(bool partialCompletionEnabled);
 
 private:
+    void addKeyword(const QString &text);
     void addKeywords();
     void addMacros(const QString &fileName, const CPlusPlus::Snapshot &snapshot);
     void addMacros_helper(const CPlusPlus::Snapshot &snapshot,
diff --git a/src/shared/cplusplus/AST.cpp b/src/shared/cplusplus/AST.cpp
index 9a8312eabaa5573788af11e3d798d5ea68d65184..51f5ce0a5fcbcac1029d248b8bb28b81fc937be2 100644
--- a/src/shared/cplusplus/AST.cpp
+++ b/src/shared/cplusplus/AST.cpp
@@ -1561,14 +1561,16 @@ unsigned SizeofExpressionAST::lastToken() const
 
 unsigned StringLiteralAST::firstToken() const
 {
-    return literal_token;
+    return at_token;
 }
 
 unsigned StringLiteralAST::lastToken() const
 {
     if (next)
         return next->lastToken();
-    return literal_token + 1;
+    if (literal_token)
+        return literal_token + 1;
+    return at_token + 1;
 }
 
 
@@ -1910,7 +1912,7 @@ unsigned ObjCClassForwardDeclarationAST::firstToken() const
     if (attribute_list)
         return attribute_list->firstToken();
 
-    return class_token;
+    return at_token;
 }
 
 unsigned ObjCClassForwardDeclarationAST::lastToken() const
@@ -1921,7 +1923,10 @@ unsigned ObjCClassForwardDeclarationAST::lastToken() const
     else if (identifier_list)
         return identifier_list->lastToken();
 
-    return class_token + 1;
+    else if (class_token)
+        return class_token + 1;
+    else
+        return at_token + 1;
 }
 
 unsigned ObjCProtocolForwardDeclarationAST::firstToken() const
@@ -1929,7 +1934,7 @@ unsigned ObjCProtocolForwardDeclarationAST::firstToken() const
     if (attribute_list)
         return attribute_list->firstToken();
 
-    return protocol_token;
+    return at_token;
 }
 
 unsigned ObjCProtocolForwardDeclarationAST::lastToken() const
@@ -1940,7 +1945,10 @@ unsigned ObjCProtocolForwardDeclarationAST::lastToken() const
     else if (identifier_list)
         return identifier_list->lastToken();
 
-    return protocol_token + 1;
+    else if (protocol_token)
+        return protocol_token + 1;
+    else
+        return at_token + 1;
 }
 
 unsigned ObjCClassDeclarationAST::firstToken() const
@@ -1948,15 +1956,14 @@ unsigned ObjCClassDeclarationAST::firstToken() const
     if (attribute_list)
         return attribute_list->firstToken();
 
-    if (interface_token)
-        return interface_token;
-    else
-        return implementation_token;
+    return at_token;
 }
 
 unsigned ObjCClassDeclarationAST::lastToken() const
 {
     if (end_token)                   return end_token + 1;
+    if (ending_at_token)
+        return ending_at_token + 1;
     if (member_declaration_list)         return member_declaration_list->lastToken();
     if (inst_vars_decl)              return inst_vars_decl->lastToken();
     if (protocol_refs)
@@ -1974,21 +1981,25 @@ unsigned ObjCClassDeclarationAST::lastToken() const
 
     if (interface_token)
         return interface_token + 1;
-    else
+    else if (implementation_token)
         return implementation_token + 1;
+    else
+        return at_token + 1;
 }
 
 unsigned ObjCProtocolDeclarationAST::firstToken() const
 {
     if (attribute_list)
         return attribute_list->firstToken();
-    return protocol_token;
+    return at_token;
 }
 
 unsigned ObjCProtocolDeclarationAST::lastToken() const
 {
     if (end_token)
         return end_token + 1;
+    else if (ending_at_token)
+        return ending_at_token + 1;
 
     else if (member_declaration_list)
         return member_declaration_list->lastToken();
@@ -2001,8 +2012,10 @@ unsigned ObjCProtocolDeclarationAST::lastToken() const
 
     else if (attribute_list)
         return attribute_list->lastToken();
-
-    return protocol_token + 1;
+    else if (protocol_token)
+        return protocol_token + 1;
+    else
+        return at_token + 1;
 }
 
 unsigned ObjCProtocolRefsAST::firstToken() const
@@ -2063,7 +2076,7 @@ unsigned ObjCMessageArgumentAST::lastToken() const
 
 unsigned ObjCProtocolExpressionAST::firstToken() const
 {
-    return protocol_token;
+    return at_token;
 }
 
 unsigned ObjCProtocolExpressionAST::lastToken() const
@@ -2077,7 +2090,10 @@ unsigned ObjCProtocolExpressionAST::lastToken() const
     if (lparen_token)
         return lparen_token + 1;
 
-    return protocol_token + 1;
+    if (protocol_token)
+        return protocol_token + 1;
+
+    return at_token + 1;
 }
 
 unsigned ObjCTypeNameAST::firstToken() const
@@ -2101,7 +2117,7 @@ unsigned ObjCTypeNameAST::lastToken() const
 
 unsigned ObjCEncodeExpressionAST::firstToken() const
 {
-    return encode_token;
+    return at_token;
 }
 
 unsigned ObjCEncodeExpressionAST::lastToken() const
@@ -2109,7 +2125,10 @@ unsigned ObjCEncodeExpressionAST::lastToken() const
     if (type_name)
         return type_name->lastToken();
 
-    return encode_token + 1;
+    if (encode_token)
+        return encode_token + 1;
+
+    return at_token + 1;
 }
 
 unsigned ObjCSelectorWithoutArgumentsAST::firstToken() const
@@ -2147,7 +2166,7 @@ unsigned ObjCSelectorWithArgumentsAST::lastToken() const
 
 unsigned ObjCSelectorExpressionAST::firstToken() const
 {
-    return selector_token;
+    return at_token;
 }
 
 unsigned ObjCSelectorExpressionAST::lastToken() const
@@ -2158,7 +2177,9 @@ unsigned ObjCSelectorExpressionAST::lastToken() const
         return selector->lastToken();
     if (lparen_token)
         return rparen_token + 1;
-    return selector_token + 1;
+    if (selector_token)
+        return selector_token + 1;
+    return at_token + 1;
 }
 
 unsigned ObjCInstanceVariablesDeclarationAST::firstToken() const
@@ -2179,12 +2200,15 @@ unsigned ObjCInstanceVariablesDeclarationAST::lastToken() const
 
 unsigned ObjCVisibilityDeclarationAST::firstToken() const
 {
-    return visibility_token;
+    return at_token;
 }
 
 unsigned ObjCVisibilityDeclarationAST::lastToken() const
 {
-    return visibility_token + 1;
+    if (visibility_token)
+        return visibility_token + 1;
+    else
+        return at_token + 1;
 }
 
 unsigned ObjCPropertyAttributeAST::firstToken() const
@@ -2207,7 +2231,7 @@ unsigned ObjCPropertyDeclarationAST::firstToken() const
     if (attribute_list)
         return attribute_list->firstToken();
 
-    return property_token;
+    return at_token;
 }
 
 unsigned ObjCPropertyDeclarationAST::lastToken() const
@@ -2220,8 +2244,10 @@ unsigned ObjCPropertyDeclarationAST::lastToken() const
         return property_attribute_list->lastToken();
     else if (lparen_token)
         return lparen_token + 1;
-
-    return property_token + 1;
+    else if (property_token)
+        return property_token + 1;
+    else
+        return at_token + 1;
 }
 
 unsigned ObjCMessageArgumentDeclarationAST::firstToken() const
@@ -2354,7 +2380,7 @@ unsigned ObjCFastEnumerationAST::lastToken() const
 
 unsigned ObjCSynchronizedStatementAST::firstToken() const
 {
-    return synchronized_token;
+    return at_token;
 }
 
 unsigned ObjCSynchronizedStatementAST::lastToken() const
@@ -2363,5 +2389,6 @@ unsigned ObjCSynchronizedStatementAST::lastToken() const
     if (rparen_token) return rparen_token + 1;
     if (synchronized_object) return synchronized_object->lastToken();
     if (lparen_token) return lparen_token + 1;
-    return synchronized_token + 1;
+    if (synchronized_token) return synchronized_token + 1;
+    return at_token + 1;
 }
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
index 4b0c149357f1dc819b62ece6b35ebc8d33eea761..76ec773226ef7f619cf148b2a85421c072a839bb 100644
--- a/src/shared/cplusplus/AST.h
+++ b/src/shared/cplusplus/AST.h
@@ -2275,6 +2275,7 @@ protected:
 class CPLUSPLUS_EXPORT StringLiteralAST: public ExpressionAST
 {
 public:
+    unsigned at_token;
     unsigned literal_token;
     StringLiteralAST *next;
 
@@ -2588,6 +2589,7 @@ class CPLUSPLUS_EXPORT ObjCClassForwardDeclarationAST: public DeclarationAST
 {
 public:
     SpecifierListAST *attribute_list;
+    unsigned at_token;
     unsigned class_token;
     NameListAST *identifier_list;
     unsigned semicolon_token;
@@ -2612,6 +2614,7 @@ class CPLUSPLUS_EXPORT ObjCClassDeclarationAST: public DeclarationAST
 {
 public:
     SpecifierListAST *attribute_list;
+    unsigned at_token;
     unsigned interface_token;
     unsigned implementation_token;
     NameAST *class_name;
@@ -2623,6 +2626,7 @@ public:
     ObjCProtocolRefsAST *protocol_refs;
     ObjCInstanceVariablesDeclarationAST *inst_vars_decl;
     DeclarationListAST *member_declaration_list;
+    unsigned ending_at_token;
     unsigned end_token;
 
 public: // annotations
@@ -2645,6 +2649,7 @@ class CPLUSPLUS_EXPORT ObjCProtocolForwardDeclarationAST: public DeclarationAST
 {
 public:
     SpecifierListAST *attribute_list;
+    unsigned at_token;
     unsigned protocol_token;
     NameListAST *identifier_list;
     unsigned semicolon_token;
@@ -2669,10 +2674,12 @@ class CPLUSPLUS_EXPORT ObjCProtocolDeclarationAST: public DeclarationAST
 {
 public:
     SpecifierListAST *attribute_list;
+    unsigned at_token;
     unsigned protocol_token;
     NameAST *name;
     ObjCProtocolRefsAST *protocol_refs;
     DeclarationListAST *member_declaration_list;
+    unsigned ending_at_token;
     unsigned end_token;
 
 public: // annotations
@@ -2754,6 +2761,7 @@ protected:
 class CPLUSPLUS_EXPORT ObjCProtocolExpressionAST: public ExpressionAST
 {
 public:
+    unsigned at_token;
     unsigned protocol_token;
     unsigned lparen_token;
     unsigned identifier_token;
@@ -2796,6 +2804,7 @@ protected:
 class CPLUSPLUS_EXPORT ObjCEncodeExpressionAST: public ExpressionAST
 {
 public:
+    unsigned at_token;
     unsigned encode_token;
     ObjCTypeNameAST *type_name;
 
@@ -2870,6 +2879,7 @@ protected:
 class CPLUSPLUS_EXPORT ObjCSelectorExpressionAST: public ExpressionAST
 {
 public:
+    unsigned at_token;
     unsigned selector_token;
     unsigned lparen_token;
     ObjCSelectorAST *selector;
@@ -2911,6 +2921,7 @@ protected:
 class CPLUSPLUS_EXPORT ObjCVisibilityDeclarationAST: public DeclarationAST
 {
 public:
+    unsigned at_token;
     unsigned visibility_token;
 
 public:
@@ -2950,6 +2961,7 @@ class CPLUSPLUS_EXPORT ObjCPropertyDeclarationAST: public DeclarationAST
 {
 public:
     SpecifierListAST *attribute_list;
+    unsigned at_token;
     unsigned property_token;
     unsigned lparen_token;
     ObjCPropertyAttributeListAST *property_attribute_list;
@@ -3137,6 +3149,7 @@ protected:
 class CPLUSPLUS_EXPORT ObjCSynchronizedStatementAST: public StatementAST
 {
 public:
+    unsigned at_token;
     unsigned synchronized_token;
     unsigned lparen_token;
     ExpressionAST *synchronized_object;
diff --git a/src/shared/cplusplus/ASTClone.cpp b/src/shared/cplusplus/ASTClone.cpp
index 87ee91558b14208778705c4cc192a26ce216cff1..d4247ad1160e8a61879cd3ce3f230717bde16ae3 100644
--- a/src/shared/cplusplus/ASTClone.cpp
+++ b/src/shared/cplusplus/ASTClone.cpp
@@ -1064,6 +1064,7 @@ NestedExpressionAST *NestedExpressionAST::clone(MemoryPool *pool) const
 StringLiteralAST *StringLiteralAST::clone(MemoryPool *pool) const
 {
     StringLiteralAST *ast = new (pool) StringLiteralAST;
+    ast->at_token = at_token;
     ast->literal_token = literal_token;
     if (next)
         ast->next = next->clone(pool);
@@ -1232,6 +1233,7 @@ ObjCClassForwardDeclarationAST *ObjCClassForwardDeclarationAST::clone(MemoryPool
     for (SpecifierListAST *iter = attribute_list, **ast_iter = &ast->attribute_list;
          iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
         *ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : 0);
+    ast->at_token = at_token;
     ast->class_token = class_token;
     for (NameListAST *iter = identifier_list, **ast_iter = &ast->identifier_list;
          iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
@@ -1246,6 +1248,7 @@ ObjCClassDeclarationAST *ObjCClassDeclarationAST::clone(MemoryPool *pool) const
     for (SpecifierListAST *iter = attribute_list, **ast_iter = &ast->attribute_list;
          iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
         *ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : 0);
+    ast->at_token = at_token;
     ast->interface_token = interface_token;
     ast->implementation_token = implementation_token;
     if (class_name)
@@ -1264,6 +1267,7 @@ ObjCClassDeclarationAST *ObjCClassDeclarationAST::clone(MemoryPool *pool) const
     for (DeclarationListAST *iter = member_declaration_list, **ast_iter = &ast->member_declaration_list;
          iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
         *ast_iter = new (pool) DeclarationListAST((iter->value) ? iter->value->clone(pool) : 0);
+    ast->ending_at_token = ending_at_token;
     ast->end_token = end_token;
     return ast;
 }
@@ -1274,6 +1278,7 @@ ObjCProtocolForwardDeclarationAST *ObjCProtocolForwardDeclarationAST::clone(Memo
     for (SpecifierListAST *iter = attribute_list, **ast_iter = &ast->attribute_list;
          iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
         *ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : 0);
+    ast->at_token = at_token;
     ast->protocol_token = protocol_token;
     for (NameListAST *iter = identifier_list, **ast_iter = &ast->identifier_list;
          iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
@@ -1288,6 +1293,7 @@ ObjCProtocolDeclarationAST *ObjCProtocolDeclarationAST::clone(MemoryPool *pool)
     for (SpecifierListAST *iter = attribute_list, **ast_iter = &ast->attribute_list;
          iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
         *ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : 0);
+    ast->at_token = at_token;
     ast->protocol_token = protocol_token;
     if (name)
         ast->name = name->clone(pool);
@@ -1296,6 +1302,7 @@ ObjCProtocolDeclarationAST *ObjCProtocolDeclarationAST::clone(MemoryPool *pool)
     for (DeclarationListAST *iter = member_declaration_list, **ast_iter = &ast->member_declaration_list;
          iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
         *ast_iter = new (pool) DeclarationListAST((iter->value) ? iter->value->clone(pool) : 0);
+    ast->ending_at_token = ending_at_token;
     ast->end_token = end_token;
     return ast;
 }
@@ -1337,6 +1344,7 @@ ObjCMessageExpressionAST *ObjCMessageExpressionAST::clone(MemoryPool *pool) cons
 ObjCProtocolExpressionAST *ObjCProtocolExpressionAST::clone(MemoryPool *pool) const
 {
     ObjCProtocolExpressionAST *ast = new (pool) ObjCProtocolExpressionAST;
+    ast->at_token = at_token;
     ast->protocol_token = protocol_token;
     ast->lparen_token = lparen_token;
     ast->identifier_token = identifier_token;
@@ -1358,6 +1366,7 @@ ObjCTypeNameAST *ObjCTypeNameAST::clone(MemoryPool *pool) const
 ObjCEncodeExpressionAST *ObjCEncodeExpressionAST::clone(MemoryPool *pool) const
 {
     ObjCEncodeExpressionAST *ast = new (pool) ObjCEncodeExpressionAST;
+    ast->at_token = at_token;
     ast->encode_token = encode_token;
     if (type_name)
         ast->type_name = type_name->clone(pool);
@@ -1391,6 +1400,7 @@ ObjCSelectorWithArgumentsAST *ObjCSelectorWithArgumentsAST::clone(MemoryPool *po
 ObjCSelectorExpressionAST *ObjCSelectorExpressionAST::clone(MemoryPool *pool) const
 {
     ObjCSelectorExpressionAST *ast = new (pool) ObjCSelectorExpressionAST;
+    ast->at_token = at_token;
     ast->selector_token = selector_token;
     ast->lparen_token = lparen_token;
     if (selector)
@@ -1413,6 +1423,7 @@ ObjCInstanceVariablesDeclarationAST *ObjCInstanceVariablesDeclarationAST::clone(
 ObjCVisibilityDeclarationAST *ObjCVisibilityDeclarationAST::clone(MemoryPool *pool) const
 {
     ObjCVisibilityDeclarationAST *ast = new (pool) ObjCVisibilityDeclarationAST;
+    ast->at_token = at_token;
     ast->visibility_token = visibility_token;
     return ast;
 }
@@ -1433,6 +1444,7 @@ ObjCPropertyDeclarationAST *ObjCPropertyDeclarationAST::clone(MemoryPool *pool)
     for (SpecifierListAST *iter = attribute_list, **ast_iter = &ast->attribute_list;
          iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
         *ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : 0);
+    ast->at_token = at_token;
     ast->property_token = property_token;
     ast->lparen_token = lparen_token;
     for (ObjCPropertyAttributeListAST *iter = property_attribute_list, **ast_iter = &ast->property_attribute_list;
@@ -1541,6 +1553,7 @@ ObjCFastEnumerationAST *ObjCFastEnumerationAST::clone(MemoryPool *pool) const
 ObjCSynchronizedStatementAST *ObjCSynchronizedStatementAST::clone(MemoryPool *pool) const
 {
     ObjCSynchronizedStatementAST *ast = new (pool) ObjCSynchronizedStatementAST;
+    ast->at_token = at_token;
     ast->synchronized_token = synchronized_token;
     ast->lparen_token = lparen_token;
     if (synchronized_object)
diff --git a/src/shared/cplusplus/ASTMatcher.cpp b/src/shared/cplusplus/ASTMatcher.cpp
index c3e04a0d4e3525175bfd1fe7cd9a9db72cba4aed..627fe3abf85a5f7f3551ec8830cff0a80c95ca94 100644
--- a/src/shared/cplusplus/ASTMatcher.cpp
+++ b/src/shared/cplusplus/ASTMatcher.cpp
@@ -1771,6 +1771,8 @@ bool ASTMatcher::match(StringLiteralAST *node, StringLiteralAST *pattern)
     (void) node;
     (void) pattern;
 
+    pattern->at_token = node->at_token;
+
     pattern->literal_token = node->literal_token;
 
     if (! pattern->next)
@@ -2063,6 +2065,8 @@ bool ASTMatcher::match(ObjCClassForwardDeclarationAST *node, ObjCClassForwardDec
     else if (! AST::match(node->attribute_list, pattern->attribute_list, this))
         return false;
 
+    pattern->at_token = node->at_token;
+
     pattern->class_token = node->class_token;
 
     if (! pattern->identifier_list)
@@ -2085,6 +2089,8 @@ bool ASTMatcher::match(ObjCClassDeclarationAST *node, ObjCClassDeclarationAST *p
     else if (! AST::match(node->attribute_list, pattern->attribute_list, this))
         return false;
 
+    pattern->at_token = node->at_token;
+
     pattern->interface_token = node->interface_token;
 
     pattern->implementation_token = node->implementation_token;
@@ -2125,6 +2131,8 @@ bool ASTMatcher::match(ObjCClassDeclarationAST *node, ObjCClassDeclarationAST *p
     else if (! AST::match(node->member_declaration_list, pattern->member_declaration_list, this))
         return false;
 
+    pattern->ending_at_token = node->ending_at_token;
+
     pattern->end_token = node->end_token;
 
     return true;
@@ -2140,6 +2148,8 @@ bool ASTMatcher::match(ObjCProtocolForwardDeclarationAST *node, ObjCProtocolForw
     else if (! AST::match(node->attribute_list, pattern->attribute_list, this))
         return false;
 
+    pattern->at_token = node->at_token;
+
     pattern->protocol_token = node->protocol_token;
 
     if (! pattern->identifier_list)
@@ -2162,6 +2172,8 @@ bool ASTMatcher::match(ObjCProtocolDeclarationAST *node, ObjCProtocolDeclaration
     else if (! AST::match(node->attribute_list, pattern->attribute_list, this))
         return false;
 
+    pattern->at_token = node->at_token;
+
     pattern->protocol_token = node->protocol_token;
 
     if (! pattern->name)
@@ -2179,6 +2191,8 @@ bool ASTMatcher::match(ObjCProtocolDeclarationAST *node, ObjCProtocolDeclaration
     else if (! AST::match(node->member_declaration_list, pattern->member_declaration_list, this))
         return false;
 
+    pattern->ending_at_token = node->ending_at_token;
+
     pattern->end_token = node->end_token;
 
     return true;
@@ -2246,6 +2260,8 @@ bool ASTMatcher::match(ObjCProtocolExpressionAST *node, ObjCProtocolExpressionAS
     (void) node;
     (void) pattern;
 
+    pattern->at_token = node->at_token;
+
     pattern->protocol_token = node->protocol_token;
 
     pattern->lparen_token = node->lparen_token;
@@ -2281,6 +2297,8 @@ bool ASTMatcher::match(ObjCEncodeExpressionAST *node, ObjCEncodeExpressionAST *p
     (void) node;
     (void) pattern;
 
+    pattern->at_token = node->at_token;
+
     pattern->encode_token = node->encode_token;
 
     if (! pattern->type_name)
@@ -2331,6 +2349,8 @@ bool ASTMatcher::match(ObjCSelectorExpressionAST *node, ObjCSelectorExpressionAS
     (void) node;
     (void) pattern;
 
+    pattern->at_token = node->at_token;
+
     pattern->selector_token = node->selector_token;
 
     pattern->lparen_token = node->lparen_token;
@@ -2367,6 +2387,8 @@ bool ASTMatcher::match(ObjCVisibilityDeclarationAST *node, ObjCVisibilityDeclara
     (void) node;
     (void) pattern;
 
+    pattern->at_token = node->at_token;
+
     pattern->visibility_token = node->visibility_token;
 
     return true;
@@ -2399,6 +2421,8 @@ bool ASTMatcher::match(ObjCPropertyDeclarationAST *node, ObjCPropertyDeclaration
     else if (! AST::match(node->attribute_list, pattern->attribute_list, this))
         return false;
 
+    pattern->at_token = node->at_token;
+
     pattern->property_token = node->property_token;
 
     pattern->lparen_token = node->lparen_token;
@@ -2587,6 +2611,8 @@ bool ASTMatcher::match(ObjCSynchronizedStatementAST *node, ObjCSynchronizedState
     (void) node;
     (void) pattern;
 
+    pattern->at_token = node->at_token;
+
     pattern->synchronized_token = node->synchronized_token;
 
     pattern->lparen_token = node->lparen_token;
diff --git a/src/shared/cplusplus/Lexer.cpp b/src/shared/cplusplus/Lexer.cpp
index 9a71ccfa7e77100193a8b4815f7ce74c93259877..f8cc188238fde58493eb97c8e70b14e27f4fc183 100644
--- a/src/shared/cplusplus/Lexer.cpp
+++ b/src/shared/cplusplus/Lexer.cpp
@@ -596,52 +596,11 @@ void Lexer::scan_helper(Token *tok)
         tok->f.kind = T_COMMA;
         break;
 
-    default: {
-        if (f._objCEnabled) {
-            if (ch == '@' && _yychar >= 'a' && _yychar <= 'z') {
-                const char *yytext = _currentChar;
-
-                do {
-                    yyinp();
-                    if (! (isalnum(_yychar) || _yychar == '_' || _yychar == '$'))
-                        break;
-                } while (_yychar);
-
-                const int yylen = _currentChar - yytext;
-                tok->f.kind = classifyObjCAtKeyword(yytext, yylen);
-                break;
-            } else if (ch == '@' && _yychar == '"') {
-                // objc @string literals
-                ch = _yychar;
-                yyinp();
-                tok->f.kind = T_AT_STRING_LITERAL;
-
-                const char *yytext = _currentChar;
-
-                while (_yychar && _yychar != '"') {
-                    if (_yychar != '\\')
-                        yyinp();
-                    else {
-                        yyinp(); // skip `\\'
-
-                        if (_yychar)
-                            yyinp();
-                    }
-                }
-                // assert(_yychar == '"');
-
-                int yylen = _currentChar - yytext;
-
-                if (_yychar == '"')
-                    yyinp();
-
-                if (control())
-                    tok->string = control()->findOrInsertStringLiteral(yytext, yylen);
-
-                break;
-            }
-        }
+    case '@':
+        tok->f.kind = T_AT;
+        break;
 
+    default: {
         if (ch == 'L' && (_yychar == '"' || _yychar == '\'')) {
             // wide char/string literals
             ch = _yychar;
@@ -679,11 +638,18 @@ void Lexer::scan_helper(Token *tok)
             while (std::isalnum(_yychar) || _yychar == '_' || _yychar == '$')
                 yyinp();
             int yylen = _currentChar - yytext;
-            if (f._scanKeywords)
+            if (f._scanKeywords) {
                 tok->f.kind = classify(yytext, yylen, f._qtMocRunEnabled);
-            else
+            } else {
                 tok->f.kind = T_IDENTIFIER;
-
+            }
+            // ### is this correct w.r.t. the _scanKeywords?
+            if (f._objCEnabled && tok->f.kind == T_IDENTIFIER) {
+                tok->f.kind = classifyObjCAtKeyword(yytext, yylen);
+                if (tok->f.kind == T_ERROR)
+                    tok->f.kind = T_IDENTIFIER;
+            }
+            // ### is this correct w.r.t. the _scanKeywords?
             if (tok->f.kind == T_IDENTIFIER) {
                 tok->f.kind = classifyOperator(yytext, yylen);
 
diff --git a/src/shared/cplusplus/ObjectiveCAtKeywords.cpp b/src/shared/cplusplus/ObjectiveCAtKeywords.cpp
index 78b0cf94a41f317371f8ef389d3888db53dd2274..cdadbc46f853ffcfb3568696b5c31bd63f917d7e 100644
--- a/src/shared/cplusplus/ObjectiveCAtKeywords.cpp
+++ b/src/shared/cplusplus/ObjectiveCAtKeywords.cpp
@@ -36,14 +36,7 @@ static inline int classify3(const char *s) {
   if (s[0] == 'e') {
     if (s[1] == 'n') {
       if (s[2] == 'd') {
-        return T_AT_END;
-      }
-    }
-  }
-  else if (s[0] == 't') {
-    if (s[1] == 'r') {
-      if (s[2] == 'y') {
-        return T_AT_TRY;
+        return T_END;
       }
     }
   }
@@ -55,42 +48,7 @@ static inline int classify4(const char *s) {
     if (s[1] == 'e') {
       if (s[2] == 'f') {
         if (s[3] == 's') {
-          return T_AT_DEFS;
-        }
-      }
-    }
-  }
-  return T_ERROR;
-}
-
-static inline int classify5(const char *s) {
-  if (s[0] == 'c') {
-    if (s[1] == 'a') {
-      if (s[2] == 't') {
-        if (s[3] == 'c') {
-          if (s[4] == 'h') {
-            return T_AT_CATCH;
-          }
-        }
-      }
-    }
-    else if (s[1] == 'l') {
-      if (s[2] == 'a') {
-        if (s[3] == 's') {
-          if (s[4] == 's') {
-            return T_AT_CLASS;
-          }
-        }
-      }
-    }
-  }
-  else if (s[0] == 't') {
-    if (s[1] == 'h') {
-      if (s[2] == 'r') {
-        if (s[3] == 'o') {
-          if (s[4] == 'w') {
-            return T_AT_THROW;
-          }
+          return T_DEFS;
         }
       }
     }
@@ -105,20 +63,7 @@ static inline int classify6(const char *s) {
         if (s[3] == 'o') {
           if (s[4] == 'd') {
             if (s[5] == 'e') {
-              return T_AT_ENCODE;
-            }
-          }
-        }
-      }
-    }
-  }
-  else if (s[0] == 'p') {
-    if (s[1] == 'u') {
-      if (s[2] == 'b') {
-        if (s[3] == 'l') {
-          if (s[4] == 'i') {
-            if (s[5] == 'c') {
-              return T_AT_PUBLIC;
+              return T_ENCODE;
             }
           }
         }
@@ -136,7 +81,7 @@ static inline int classify7(const char *s) {
           if (s[4] == 'm') {
             if (s[5] == 'i') {
               if (s[6] == 'c') {
-                return T_AT_DYNAMIC;
+                return T_DYNAMIC;
               }
             }
           }
@@ -151,7 +96,7 @@ static inline int classify7(const char *s) {
           if (s[4] == 'l') {
             if (s[5] == 'l') {
               if (s[6] == 'y') {
-                return T_AT_FINALLY;
+                return T_FINALLY;
               }
             }
           }
@@ -166,7 +111,7 @@ static inline int classify7(const char *s) {
           if (s[4] == 'a') {
             if (s[5] == 'g') {
               if (s[6] == 'e') {
-                return T_AT_PACKAGE;
+                return T_PACKAGE;
               }
             }
           }
@@ -179,7 +124,7 @@ static inline int classify7(const char *s) {
           if (s[4] == 'a') {
             if (s[5] == 't') {
               if (s[6] == 'e') {
-                return T_AT_PRIVATE;
+                return T_PRIVATE;
               }
             }
           }
@@ -199,7 +144,7 @@ static inline int classify8(const char *s) {
             if (s[5] == 'n') {
               if (s[6] == 'a') {
                 if (s[7] == 'l') {
-                  return T_AT_OPTIONAL;
+                  return T_OPTIONAL;
                 }
               }
             }
@@ -216,7 +161,7 @@ static inline int classify8(const char *s) {
             if (s[5] == 'r') {
               if (s[6] == 't') {
                 if (s[7] == 'y') {
-                  return T_AT_PROPERTY;
+                  return T_PROPERTY;
                 }
               }
             }
@@ -227,7 +172,7 @@ static inline int classify8(const char *s) {
             if (s[5] == 'c') {
               if (s[6] == 'o') {
                 if (s[7] == 'l') {
-                  return T_AT_PROTOCOL;
+                  return T_PROTOCOL;
                 }
               }
             }
@@ -244,7 +189,7 @@ static inline int classify8(const char *s) {
             if (s[5] == 'r') {
               if (s[6] == 'e') {
                 if (s[7] == 'd') {
-                  return T_AT_REQUIRED;
+                  return T_REQUIRED;
                 }
               }
             }
@@ -261,7 +206,7 @@ static inline int classify8(const char *s) {
             if (s[5] == 't') {
               if (s[6] == 'o') {
                 if (s[7] == 'r') {
-                  return T_AT_SELECTOR;
+                  return T_SELECTOR;
                 }
               }
             }
@@ -283,26 +228,7 @@ static inline int classify9(const char *s) {
               if (s[6] == 'a') {
                 if (s[7] == 'c') {
                   if (s[8] == 'e') {
-                    return T_AT_INTERFACE;
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-  else if (s[0] == 'p') {
-    if (s[1] == 'r') {
-      if (s[2] == 'o') {
-        if (s[3] == 't') {
-          if (s[4] == 'e') {
-            if (s[5] == 'c') {
-              if (s[6] == 't') {
-                if (s[7] == 'e') {
-                  if (s[8] == 'd') {
-                    return T_AT_PROTECTED;
+                    return T_INTERFACE;
                   }
                 }
               }
@@ -326,7 +252,7 @@ static inline int classify10(const char *s) {
                 if (s[7] == 'i') {
                   if (s[8] == 'z') {
                     if (s[9] == 'e') {
-                      return T_AT_SYNTHESIZE;
+                      return T_SYNTHESIZE;
                     }
                   }
                 }
@@ -352,7 +278,7 @@ static inline int classify11(const char *s) {
                   if (s[8] == 'o') {
                     if (s[9] == 'r') {
                       if (s[10] == 'd') {
-                        return T_AT_NOT_KEYWORD;
+                        return T_NOT_KEYWORD;
                       }
                     }
                   }
@@ -380,7 +306,7 @@ static inline int classify12(const char *s) {
                     if (s[9] == 'z') {
                       if (s[10] == 'e') {
                         if (s[11] == 'd') {
-                          return T_AT_SYNCHRONIZED;
+                          return T_SYNCHRONIZED;
                         }
                       }
                     }
@@ -411,7 +337,7 @@ static inline int classify14(const char *s) {
                         if (s[11] == 'i') {
                           if (s[12] == 'o') {
                             if (s[13] == 'n') {
-                              return T_AT_IMPLEMENTATION;
+                              return T_IMPLEMENTATION;
                             }
                           }
                         }
@@ -449,7 +375,7 @@ static inline int classify19(const char *s) {
                                   if (s[16] == 'i') {
                                     if (s[17] == 'a') {
                                       if (s[18] == 's') {
-                                        return T_AT_COMPATIBILITY_ALIAS;
+                                        return T_COMPATIBILITY_ALIAS;
                                       }
                                     }
                                   }
@@ -476,7 +402,6 @@ int Lexer::classifyObjCAtKeyword(const char *s, int n) {
   switch (n) {
     case 3: return classify3(s);
     case 4: return classify4(s);
-    case 5: return classify5(s);
     case 6: return classify6(s);
     case 7: return classify7(s);
     case 8: return classify8(s);
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp
index 7bc832ffa6abf9c25d1e9eb54b3b47d23a1919dc..a6b6e0b1c8190f490f5aa5f6c9aac05ecebda360 100644
--- a/src/shared/cplusplus/Parser.cpp
+++ b/src/shared/cplusplus/Parser.cpp
@@ -293,13 +293,22 @@ void Parser::skipUntilDeclaration()
         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;
 
+        // ObjC declarations:
+        case T_AT:
+            switch (LA(2)) {
+            case T_CLASS:
+            case T_INTERFACE:
+            case T_PROTOCOL:
+            case T_IMPLEMENTATION:
+            case T_END:
+                return;
+            default: {
+                // INTENTIONAL FALL-THROUGH!
+            }
+            }
+
         default:
             if (lookAtBuiltinTypeSpecifier() || lookAtClassKey() ||
                 lookAtFunctionSpecifier() || lookAtStorageClassSpecifier())
@@ -352,8 +361,8 @@ bool Parser::skipUntilStatement()
             case T_USING:
                 return true;
 
-            case T_AT_SYNCHRONIZED:
-                if (objCEnabled())
+            case T_AT:
+                if (objCEnabled() && LA(2) == T_SYNCHRONIZED)
                     return true;
 
             default:
@@ -585,23 +594,28 @@ bool Parser::parseDeclaration(DeclarationAST *&node)
         return parseTemplateDeclaration(node);
 
     // ObjcC++
-    case T_AT_CLASS:
-        return parseObjCClassForwardDeclaration(node);
+    case T_AT:
+        if (objCEnabled()) {
+            switch (LA(2)) {
+            case T_CLASS:
+                return parseObjCClassForwardDeclaration(node);
 
-    case T_AT_INTERFACE:
-        return parseObjCInterface(node);
+            case T_INTERFACE:
+                return parseObjCInterface(node);
 
-    case T_AT_PROTOCOL:
-        return parseObjCProtocol(node);
+            case T_PROTOCOL:
+                return parseObjCProtocol(node);
 
-    case T_AT_IMPLEMENTATION:
-        return parseObjCImplementation(node);
+            case T_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;
+            case T_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__) {
@@ -609,12 +623,14 @@ bool Parser::parseDeclaration(DeclarationAST *&node)
             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);
+            if (LA() == T_AT) {
+                if (LA(2) == T_INTERFACE)
+                    return parseObjCInterface(node, attributes);
+                else if (LA(2) == T_PROTOCOL)
+                    return parseObjCProtocol(node, attributes);
+                else if (LA(2) == T_PROPERTY)
+                    return parseObjCPropertyDeclaration(node, attributes);
+            }
             rewind(start);
         }
 
@@ -2415,9 +2431,6 @@ bool Parser::parseStatement(StatementAST *&node)
         return true;
     }
 
-    case T_AT_SYNCHRONIZED:
-        return objCEnabled() && parseObjCSynchronizedStatement(node);
-
     case T_Q_D:
     case T_Q_Q: {
         QtMemberDeclarationAST *ast = new (_pool) QtMemberDeclarationAST;
@@ -2428,6 +2441,10 @@ bool Parser::parseStatement(StatementAST *&node)
         node = ast;
     } return true;
 
+    case T_AT:
+        return objCEnabled() && LA(2) == T_SYNCHRONIZED
+                && parseObjCSynchronizedStatement(node);
+
     default:
         if (LA() == T_IDENTIFIER && LA(2) == T_COLON)
             return parseLabeledStatement(node);
@@ -3470,10 +3487,7 @@ bool Parser::parsePrimaryExpression(ExpressionAST *&node)
         return parseQtMethod(node);
 
     case T_LBRACKET:
-    case T_AT_STRING_LITERAL:
-    case T_AT_ENCODE:
-    case T_AT_PROTOCOL:
-    case T_AT_SELECTOR:
+    case T_AT:
         return parseObjCExpression(node);
 
     default: {
@@ -3493,20 +3507,22 @@ bool Parser::parsePrimaryExpression(ExpressionAST *&node)
 bool Parser::parseObjCExpression(ExpressionAST *&node)
 {
     DEBUG_THIS_RULE();
-    switch (LA()) {
-    case T_AT_ENCODE:
+    if (LA() == T_LBRACKET)
+        return parseObjCMessageExpression(node);
+    if (LA() != T_AT)
+        return false;
+
+    switch (LA(2)) {
+    case T_ENCODE:
         return parseObjCEncodeExpression(node);
 
-    case T_AT_PROTOCOL:
+    case T_PROTOCOL:
         return parseObjCProtocolExpression(node);
 
-    case T_AT_SELECTOR:
+    case T_SELECTOR:
         return parseObjCSelectorExpression(node);
 
-    case T_LBRACKET:
-        return parseObjCMessageExpression(node);
-
-    case T_AT_STRING_LITERAL:
+    case T_STRING_LITERAL:
         return parseObjCStringLiteral(node);
 
     default:
@@ -3515,30 +3531,54 @@ bool Parser::parseObjCExpression(ExpressionAST *&node)
     return false;
 }
 
+// We allow for the same kind of Objective-C string literals as clang, NOT as
+// GCC. So, we/clang allow(s):
+//   NSLog(@"foo");
+//   NSLog(@
+//          "foo");
+//   NSLog(@"foo"
+//          "bar");
+//   NSLog(@"foo"
+//         @"bar');
+//
+// What we don't grok, but GCC also allows:
+//   NSLog(@"foo"
+//        @@"bar");
+//   NSLog(@"foo"
+//          "bar"@@);
 bool Parser::parseObjCStringLiteral(ExpressionAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT_STRING_LITERAL)
+    if (LA() != T_AT || LA(2) != T_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;
+    StringLiteralAST **ast = 0;
+    while (LA()) {
+        if (LA() == T_AT && LA(2) == T_STRING_LITERAL) {
+            *ast = new (_pool) StringLiteralAST;
+            (*ast)->at_token = consumeToken();
+            (*ast)->literal_token = consumeToken();
+            ast = &(*ast)->next;
+        } else if (LA() == T_STRING_LITERAL) {
+            *ast = new (_pool) StringLiteralAST;
+            (*ast)->literal_token = consumeToken();
+            ast = &(*ast)->next;
+        } else {
+            break;
+        }
     }
+    node = *ast;
     return true;
 }
 
 bool Parser::parseObjCSynchronizedStatement(StatementAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT_SYNCHRONIZED)
+    if (LA() == T_AT || LA(2) != T_SYNCHRONIZED)
         return false;
 
     ObjCSynchronizedStatementAST *ast = new (_pool) ObjCSynchronizedStatementAST;
-
+    ast->at_token = consumeToken();
     ast->synchronized_token = consumeToken();
     match(T_LPAREN, &ast->lparen_token);
     parseExpression(ast->synchronized_object);
@@ -3552,10 +3592,11 @@ bool Parser::parseObjCSynchronizedStatement(StatementAST *&node)
 bool Parser::parseObjCEncodeExpression(ExpressionAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT_ENCODE)
+    if (LA() != T_AT || LA(2) != T_ENCODE)
         return false;
 
     ObjCEncodeExpressionAST *ast = new (_pool) ObjCEncodeExpressionAST;
+    ast->at_token = consumeToken();
     ast->encode_token = consumeToken();
     parseObjCTypeName(ast->type_name);
     node = ast;
@@ -3565,10 +3606,11 @@ bool Parser::parseObjCEncodeExpression(ExpressionAST *&node)
 bool Parser::parseObjCProtocolExpression(ExpressionAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT_PROTOCOL)
+    if (LA() != T_AT || LA(2) != T_PROTOCOL)
         return false;
 
     ObjCProtocolExpressionAST *ast = new (_pool) ObjCProtocolExpressionAST;
+    ast->at_token = consumeToken();
     ast->protocol_token = consumeToken();
     match(T_LPAREN, &ast->lparen_token);
     match(T_IDENTIFIER, &ast->identifier_token);
@@ -3580,10 +3622,11 @@ bool Parser::parseObjCProtocolExpression(ExpressionAST *&node)
 bool Parser::parseObjCSelectorExpression(ExpressionAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT_SELECTOR)
+    if (LA() != T_AT || LA(2) != T_SELECTOR)
         return false;
 
     ObjCSelectorExpressionAST *ast = new (_pool) ObjCSelectorExpressionAST;
+    ast->at_token = consumeToken();
     ast->selector_token = consumeToken();
     match(T_LPAREN, &ast->lparen_token);
 
@@ -4493,11 +4536,11 @@ bool Parser::lookAtObjCSelector() const
 bool Parser::parseObjCClassForwardDeclaration(DeclarationAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT_CLASS)
+    if (LA() != T_AT || LA(2) != T_CLASS)
         return false;
 
     ObjCClassForwardDeclarationAST *ast = new (_pool) ObjCClassForwardDeclarationAST;
-
+    ast->at_token = consumeToken();
     ast->class_token = consumeToken();
     unsigned identifier_token = 0;
     match(T_IDENTIFIER, &identifier_token);
@@ -4549,9 +4592,10 @@ bool Parser::parseObjCInterface(DeclarationAST *&node,
             attr = &(*attr)->next;
     }
 
-    if (LA() != T_AT_INTERFACE)
+    if (LA() != T_AT || LA(2) != T_INTERFACE)
         return false;
 
+    unsigned at_token = consumeToken();
     unsigned objc_interface_token = consumeToken();
     unsigned identifier_token = 0;
     match(T_IDENTIFIER, &identifier_token);
@@ -4565,6 +4609,7 @@ bool Parser::parseObjCInterface(DeclarationAST *&node,
 
         ObjCClassDeclarationAST *ast = new (_pool) ObjCClassDeclarationAST;
         ast->attribute_list = attributes;
+        ast->at_token = at_token;
         ast->interface_token = objc_interface_token;
         SimpleNameAST *class_name = new (_pool) SimpleNameAST;
         class_name->identifier_token= identifier_token;
@@ -4589,7 +4634,8 @@ bool Parser::parseObjCInterface(DeclarationAST *&node,
             nextMembers = &(*nextMembers)->next;
         }
 
-        match(T_AT_END, &ast->end_token);
+        match(T_AT, &ast->ending_at_token);
+        match(T_END, &ast->end_token);
 
         node = ast;
         return true;
@@ -4597,6 +4643,7 @@ bool Parser::parseObjCInterface(DeclarationAST *&node,
         // a class interface declaration
         ObjCClassDeclarationAST *ast = new (_pool) ObjCClassDeclarationAST;
         ast->attribute_list = attributes;
+        ast->at_token = at_token;
         ast->interface_token = objc_interface_token;
         SimpleNameAST* class_name = new (_pool) SimpleNameAST;
         class_name->identifier_token = identifier_token;
@@ -4620,7 +4667,8 @@ bool Parser::parseObjCInterface(DeclarationAST *&node,
             nextMembers = &(*nextMembers)->next;
         }
 
-        match(T_AT_END, &ast->end_token);
+        match(T_AT, &ast->ending_at_token);
+        match(T_END, &ast->end_token);
 
         node = ast;
         return true;
@@ -4639,9 +4687,10 @@ bool Parser::parseObjCProtocol(DeclarationAST *&node,
             attr = &(*attr)->next;
     }
 
-    if (LA() != T_AT_PROTOCOL)
+    if (LA() != T_AT || LA(2) != T_PROTOCOL)
         return false;
 
+    unsigned at_token = consumeToken();
     unsigned protocol_token = consumeToken();
     unsigned identifier_token = 0;
     match(T_IDENTIFIER, &identifier_token);
@@ -4651,6 +4700,7 @@ bool Parser::parseObjCProtocol(DeclarationAST *&node,
 
         ObjCProtocolForwardDeclarationAST *ast = new (_pool) ObjCProtocolForwardDeclarationAST;
         ast->attribute_list = attributes;
+        ast->at_token = at_token;
         ast->protocol_token = protocol_token;
         ast->identifier_list = new (_pool) NameListAST;
         SimpleNameAST *name = new (_pool) SimpleNameAST;
@@ -4676,6 +4726,7 @@ bool Parser::parseObjCProtocol(DeclarationAST *&node,
         // a protocol definition
         ObjCProtocolDeclarationAST *ast = new (_pool) ObjCProtocolDeclarationAST;
         ast->attribute_list = attributes;
+        ast->at_token = at_token;
         ast->protocol_token = protocol_token;
         SimpleNameAST *name = new (_pool) SimpleNameAST;
         name->identifier_token = identifier_token;
@@ -4691,7 +4742,8 @@ bool Parser::parseObjCProtocol(DeclarationAST *&node,
             nextMembers = &(*nextMembers)->next;
         }
 
-        match(T_AT_END, &ast->end_token);
+        match(T_AT, &ast->ending_at_token);
+        match(T_END, &ast->end_token);
 
         node = ast;
         return true;
@@ -4705,9 +4757,10 @@ bool Parser::parseObjCProtocol(DeclarationAST *&node,
 bool Parser::parseObjCImplementation(DeclarationAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT_IMPLEMENTATION)
+    if (LA() != T_AT || LA(2) != T_IMPLEMENTATION)
         return false;
 
+    unsigned at_token = consumeToken();
     unsigned implementation_token = consumeToken();
     unsigned identifier_token = 0;
     match(T_IDENTIFIER, &identifier_token);
@@ -4715,6 +4768,7 @@ bool Parser::parseObjCImplementation(DeclarationAST *&node)
     if (LA() == T_LPAREN) {
         // a category implementation
         ObjCClassDeclarationAST *ast = new (_pool) ObjCClassDeclarationAST;
+        ast->at_token = at_token;
         ast->implementation_token = implementation_token;
         SimpleNameAST *class_name = new (_pool) SimpleNameAST;
         class_name->identifier_token = identifier_token;
@@ -4727,12 +4781,14 @@ bool Parser::parseObjCImplementation(DeclarationAST *&node)
         match(T_RPAREN, &ast->rparen_token);
 
         parseObjCMethodDefinitionList(ast->member_declaration_list);
-        match(T_AT_END, &ast->end_token);
+        match(T_AT, &ast->ending_at_token);
+        match(T_END, &ast->end_token);
 
         node = ast;
     } else {
         // a class implementation
         ObjCClassDeclarationAST *ast = new (_pool) ObjCClassDeclarationAST;
+        ast->at_token = at_token;
         ast->implementation_token = implementation_token;
         SimpleNameAST *class_name = new (_pool) SimpleNameAST;
         class_name->identifier_token = identifier_token;
@@ -4747,7 +4803,8 @@ bool Parser::parseObjCImplementation(DeclarationAST *&node)
 
         parseObjClassInstanceVariables(ast->inst_vars_decl);
         parseObjCMethodDefinitionList(ast->member_declaration_list);
-        match(T_AT_END, &ast->end_token);
+        match(T_AT, &ast->ending_at_token);
+        match(T_END, &ast->end_token);
 
         node = ast;
     }
@@ -4760,7 +4817,7 @@ bool Parser::parseObjCMethodDefinitionList(DeclarationListAST *&node)
     DEBUG_THIS_RULE();
     DeclarationListAST **next = &node;
 
-    while (LA() && LA() != T_AT_END) {
+    while (LA() && !(LA() == T_AT && LA(2) == T_END)) {
         unsigned start = cursor();
         DeclarationAST *declaration = 0;
 
@@ -4777,26 +4834,12 @@ bool Parser::parseObjCMethodDefinitionList(DeclarationListAST *&node)
             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;
-
+        case T_AT:
+            if (LA(2) == T_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);
 
@@ -4805,38 +4848,51 @@ bool Parser::parseObjCMethodDefinitionList(DeclarationListAST *&node)
 
                     match(T_IDENTIFIER, &last->value->alias_identifier_token);
                 }
-            }
 
-            match(T_SEMICOLON, &ast->semicolon_token);
+                while (LA() == T_COMMA) {
+                    consumeToken(); // consume T_COMMA
 
-            declaration = ast;
-            break;
-        }
+                    last->next = new (_pool) ObjCSynthesizedPropertyListAST;
+                    last = last->next;
 
-        case T_AT_DYNAMIC: {
-            ObjCDynamicPropertiesDeclarationAST *ast = new (_pool) ObjCDynamicPropertiesDeclarationAST;
-            ast->dynamic_token = consumeToken();
-            ast->property_identifier_list = new (_pool) NameListAST;
-            SimpleNameAST *name = new (_pool) SimpleNameAST;
-            match(T_IDENTIFIER, &name->identifier_token);
-            ast->property_identifier_list->value = name;
+                    last->value = new (_pool) ObjCSynthesizedPropertyAST;
+                    match(T_IDENTIFIER, &last->value->property_identifier_token);
 
-            NameListAST *last = ast->property_identifier_list;
-            while (LA() == T_COMMA) {
-                consumeToken(); // consume T_COMMA
+                    if (LA() == T_EQUAL) {
+                        last->value->equals_token = consumeToken();
 
-                last->next = new (_pool) NameListAST;
-                last = last->next;
-                name = new (_pool) SimpleNameAST;
+                        match(T_IDENTIFIER, &last->value->alias_identifier_token);
+                    }
+                }
+
+                match(T_SEMICOLON, &ast->semicolon_token);
+
+                declaration = ast;
+                break;
+            } else if (LA(2) == T_DYNAMIC) {
+                ObjCDynamicPropertiesDeclarationAST *ast = new (_pool) ObjCDynamicPropertiesDeclarationAST;
+                ast->dynamic_token = consumeToken();
+                ast->property_identifier_list = new (_pool) NameListAST;
+                SimpleNameAST *name = new (_pool) SimpleNameAST;
                 match(T_IDENTIFIER, &name->identifier_token);
-                last->value = name;
-            }
+                ast->property_identifier_list->value = name;
 
-            match(T_SEMICOLON, &ast->semicolon_token);
+                NameListAST *last = ast->property_identifier_list;
+                while (LA() == T_COMMA) {
+                    consumeToken(); // consume T_COMMA
 
-            declaration = ast;
-            break;
-        }
+                    last->next = new (_pool) NameListAST;
+                    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) {
@@ -4967,22 +5023,6 @@ 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;
@@ -5002,6 +5042,30 @@ bool Parser::parseObjCInterfaceMemberDeclaration(DeclarationAST *&node)
         return parseSimpleDeclaration(node, /*accept struct declarators */ true);
     }
 
+    case T_AT:
+        switch (LA(2)) {
+        case T_END:
+            return false;
+
+        case T_REQUIRED:
+        case T_OPTIONAL:
+            // ### FIXME
+            consumeToken();
+            return true;
+
+        case T_SEMICOLON:
+            consumeToken();
+            return true;
+
+        case T_PROPERTY: {
+            return parseObjCPropertyDeclaration(node);
+
+        default: {
+            // INTENTIONAL FALL-THROUGH!
+        }
+        }
+    }
+
     default: {
         return parseSimpleDeclaration(node, /*accept struct declarators */ true);
     } // default
@@ -5015,20 +5079,23 @@ bool Parser::parseObjCInterfaceMemberDeclaration(DeclarationAST *&node)
 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;
+    if (LA() == T_AT) {
+        switch (LA(2)) {
+            case T_PRIVATE:
+            case T_PROTECTED:
+            case T_PUBLIC:
+            case T_PACKAGE: {
+                ObjCVisibilityDeclarationAST *ast =
+                        new (_pool) ObjCVisibilityDeclarationAST;
+                ast->at_token = consumeToken();
+                ast->visibility_token = consumeToken();
+                node = ast;
+                return true;
+            }
         }
-
-        default:
-            return parseSimpleDeclaration(node, true);
     }
+
+    return parseSimpleDeclaration(node, true);
 }
 
 // objc-property-declaration ::=
@@ -5037,11 +5104,12 @@ bool Parser::parseObjCInstanceVariableDeclaration(DeclarationAST *&node)
 bool Parser::parseObjCPropertyDeclaration(DeclarationAST *&node, SpecifierListAST *attributes)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT_PROPERTY)
+    if (LA() != T_AT || LA(2) != T_PROPERTY)
         return false;
 
     ObjCPropertyDeclarationAST *ast = new (_pool) ObjCPropertyDeclarationAST;
     ast->attribute_list = attributes;
+    ast->at_token = consumeToken();
     ast->property_token = consumeToken();
 
     if (LA() == T_LPAREN) {
diff --git a/src/shared/cplusplus/Semantic.cpp b/src/shared/cplusplus/Semantic.cpp
index d8d6d6617e9a33d370de11ee822bf84fe2347c4f..98dfa35e291d4f264222697e3ac13634d94a723f 100644
--- a/src/shared/cplusplus/Semantic.cpp
+++ b/src/shared/cplusplus/Semantic.cpp
@@ -218,13 +218,13 @@ int Semantic::visibilityForAccessSpecifier(int tokenKind) const
 int Semantic::visibilityForObjCAccessSpecifier(int tokenKind) const
 {
     switch (tokenKind) {
-    case T_AT_PUBLIC:
+    case T_PUBLIC:
         return Symbol::Public;
-    case T_AT_PROTECTED:
+    case T_PROTECTED:
         return Symbol::Protected;
-    case T_AT_PRIVATE:
+    case T_PRIVATE:
         return Symbol::Private;
-    case T_AT_PACKAGE:
+    case T_PACKAGE:
         return Symbol::Package;
     default:
         return Symbol::Protected;
diff --git a/src/shared/cplusplus/Token.cpp b/src/shared/cplusplus/Token.cpp
index e86038271fa1eed95d0f18f59eac5e4d8bafd4ce..e4f2baba4d4359cf7031bf560ba574b1c9d0ad46 100644
--- a/src/shared/cplusplus/Token.cpp
+++ b/src/shared/cplusplus/Token.cpp
@@ -59,14 +59,14 @@ static const char *token_names[] = {
 
     ("<identifier>"), ("<numeric literal>"), ("<char literal>"),
     ("<wide char literal>"), ("<string literal>"), ("<wide char literal>"),
-    ("<@string literal>"), ("<angle string literal>"),
+    ("<angle string literal>"),
 
-    ("&"), ("&&"), ("&="), ("->"), ("->*"), ("^"), ("^="), (":"), ("::"),
-    (","), ("/"), ("/="), ("."), ("..."), (".*"), ("="), ("=="), ("!"),
-    ("!="), (">"), (">="), (">>"), (">>="), ("{"), ("["), ("<"), ("<="),
-    ("<<"), ("<<="), ("("), ("-"), ("-="), ("--"), ("%"), ("%="), ("|"),
-    ("|="), ("||"), ("+"), ("+="), ("++"), ("#"), ("##"), ("?"), ("}"),
-    ("]"), (")"), (";"), ("*"), ("*="), ("~"), ("~="),
+    ("&"), ("&&"), ("&="), ("->"), ("->*"), ("@"), ("^"), ("^="), (":"),
+    ("::"), (","), ("/"), ("/="), ("."), ("..."), (".*"), ("="), ("=="),
+    ("!"), ("!="), (">"), (">="), (">>"), (">>="), ("{"), ("["), ("<"),
+    ("<="), ("<<"), ("<<="), ("("), ("-"), ("-="), ("--"), ("%"), ("%="),
+    ("|"), ("|="), ("||"), ("+"), ("+="), ("++"), ("#"), ("##"), ("?"),
+    ("}"), ("]"), (")"), (";"), ("*"), ("*="), ("~"), ("~="),
 
     ("asm"), ("auto"), ("bool"), ("break"), ("case"), ("catch"), ("char"),
     ("class"), ("const"), ("const_cast"), ("continue"), ("default"),
@@ -84,12 +84,11 @@ static const char *token_names[] = {
     // gnu
     ("__attribute__"), ("__typeof__"),
 
-    // objc @keywords
-    ("@catch"), ("@class"), ("@compatibility_alias"), ("@defs"), ("@dynamic"),
-    ("@encode"), ("@end"), ("@finally"), ("@implementation"), ("@interface"),
-    ("@not_keyword"), ("@optional"), ("@package"), ("@private"), ("@property"),
-    ("@protected"), ("@protocol"), ("@public"), ("@required"), ("@selector"),
-    ("@synchronized"), ("@synthesize"), ("@throw"), ("@try"),
+    // objc keywords
+    ("@compatibility_alias"), ("@defs"), ("@dynamic"), ("@encode"), ("@end"),
+    ("@finally"), ("@implementation"), ("@interface"), ("@not_keyword"),
+    ("@optional"), ("@package"), ("@property"), ("@protocol"), ("@required"),
+    ("@selector"), ("@synchronized"), ("@synthesize"),
 
     ("SIGNAL"), ("SLOT"), ("Q_SIGNAL"), ("Q_SLOT"), ("signals"), ("slots"),
     ("Q_FOREACH"), ("Q_D"), ("Q_Q"),
@@ -124,7 +123,6 @@ const char *Token::spell() const
     case T_NUMERIC_LITERAL:
     case T_CHAR_LITERAL:
     case T_STRING_LITERAL:
-    case T_AT_STRING_LITERAL:
     case T_ANGLE_STRING_LITERAL:
     case T_WIDE_CHAR_LITERAL:
     case T_WIDE_STRING_LITERAL:
diff --git a/src/shared/cplusplus/Token.h b/src/shared/cplusplus/Token.h
index d139584bddbc116474808e77aec38aeda7ce4032..05505b94e417d5a0bd077232568ec783fdd95204 100644
--- a/src/shared/cplusplus/Token.h
+++ b/src/shared/cplusplus/Token.h
@@ -69,7 +69,6 @@ enum Kind {
     T_WIDE_CHAR_LITERAL,
     T_STRING_LITERAL,
     T_WIDE_STRING_LITERAL,
-    T_AT_STRING_LITERAL,
     T_ANGLE_STRING_LITERAL,
     T_LAST_LITERAL = T_ANGLE_STRING_LITERAL,
 
@@ -79,6 +78,7 @@ enum Kind {
     T_AMPER_EQUAL,
     T_ARROW,
     T_ARROW_STAR,
+    T_AT,
     T_CARET,
     T_CARET_EQUAL,
     T_COLON,
@@ -196,35 +196,28 @@ enum Kind {
     T___ATTRIBUTE__,
     T___TYPEOF__,
 
-    // obj c++ @ keywords
-    T_FIRST_OBJC_AT_KEYWORD,
-
-    T_AT_CATCH = T_FIRST_OBJC_AT_KEYWORD,
-    T_AT_CLASS,
-    T_AT_COMPATIBILITY_ALIAS,
-    T_AT_DEFS,
-    T_AT_DYNAMIC,
-    T_AT_ENCODE,
-    T_AT_END,
-    T_AT_FINALLY,
-    T_AT_IMPLEMENTATION,
-    T_AT_INTERFACE,
-    T_AT_NOT_KEYWORD,
-    T_AT_OPTIONAL,
-    T_AT_PACKAGE,
-    T_AT_PRIVATE,
-    T_AT_PROPERTY,
-    T_AT_PROTECTED,
-    T_AT_PROTOCOL,
-    T_AT_PUBLIC,
-    T_AT_REQUIRED,
-    T_AT_SELECTOR,
-    T_AT_SYNCHRONIZED,
-    T_AT_SYNTHESIZE,
-    T_AT_THROW,
-    T_AT_TRY,
-
-    T_LAST_OBJC_AT_KEYWORD = T_AT_TRY,
+    // obj c keywords
+    T_FIRST_OBJC_KEYWORD,
+
+    T_COMPATIBILITY_ALIAS = T_FIRST_OBJC_KEYWORD,
+    T_DEFS,
+    T_DYNAMIC,
+    T_ENCODE,
+    T_END,
+    T_FINALLY,
+    T_IMPLEMENTATION,
+    T_INTERFACE,
+    T_NOT_KEYWORD,
+    T_OPTIONAL,
+    T_PACKAGE,
+    T_PROPERTY,
+    T_PROTOCOL,
+    T_REQUIRED,
+    T_SELECTOR,
+    T_SYNCHRONIZED,
+    T_SYNTHESIZE,
+
+    T_LAST_OBJC_KEYWORD = T_SYNTHESIZE,
 
     T_FIRST_QT_KEYWORD,
 
@@ -313,9 +306,6 @@ public:
     { return f.kind == T_COMMENT || f.kind == T_DOXY_COMMENT ||
       f.kind == T_CPP_COMMENT || f.kind == T_CPP_DOXY_COMMENT; }
 
-    inline bool isObjCAtKeyword() const
-    { return f.kind >= T_FIRST_OBJC_AT_KEYWORD && f.kind <= T_LAST_OBJC_AT_KEYWORD; }
-
     static const char *name(int kind);
 
 public: