diff --git a/src/libs/cplusplus/SimpleLexer.cpp b/src/libs/cplusplus/SimpleLexer.cpp
index de5dca135ed2bbfc2b01dfd01302f4c602652b59..1af3bdb9366e73a1f986e95e8b90854822569052 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_KEYWORD && _kind <= T_LAST_OBJC_KEYWORD;
+    return _kind >= T_FIRST_OBJC_AT_KEYWORD && _kind <= T_LAST_OBJC_AT_KEYWORD;
 }
 
 const char *SimpleToken::name() const
diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp
index aa55de8d65f9c4890b87e13a0e03ce97730346ee..61c1312df3ad05fbd14c38fca3aabbb303599318 100644
--- a/src/plugins/cppeditor/cpphighlighter.cpp
+++ b/src/plugins/cppeditor/cpphighlighter.cpp
@@ -127,7 +127,8 @@ 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))
+        else if (tk.is(T_STRING_LITERAL) || tk.is(T_CHAR_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL) ||
+                 tk.is(T_AT_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 85a7666970d2ba5f3fd7a492058210005fb663d3..3d7cbebf9d944e31e682b0e6cc5c6ed71bd42b89 100644
--- a/src/plugins/cpptools/cppcodecompletion.cpp
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -1197,35 +1197,18 @@ bool CppCodeCompletion::completeScope(const QList<LookupItem> &results,
     return ! m_completions.isEmpty();
 }
 
-void CppCodeCompletion::addKeyword(const QString &text)
-{
-    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 < T_FIRST_OBJC_KEYWORD; ++i) {
-        addKeyword(QLatin1String(Token::name(i)));
-    }
+    int keywordLimit = T_FIRST_OBJC_AT_KEYWORD;
+    if (objcKeywordsWanted())
+        keywordLimit = T_LAST_OBJC_AT_KEYWORD + 1;
 
-    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)));
+    // 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);
     }
 }
 
diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h
index 0d98dfdf95857b0a276ff16a17836e473ef34605..d4160ee3c1da220a5873513d237d0ad321617492 100644
--- a/src/plugins/cpptools/cppcodecompletion.h
+++ b/src/plugins/cpptools/cppcodecompletion.h
@@ -89,7 +89,6 @@ 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 51f5ce0a5fcbcac1029d248b8bb28b81fc937be2..9a8312eabaa5573788af11e3d798d5ea68d65184 100644
--- a/src/shared/cplusplus/AST.cpp
+++ b/src/shared/cplusplus/AST.cpp
@@ -1561,16 +1561,14 @@ unsigned SizeofExpressionAST::lastToken() const
 
 unsigned StringLiteralAST::firstToken() const
 {
-    return at_token;
+    return literal_token;
 }
 
 unsigned StringLiteralAST::lastToken() const
 {
     if (next)
         return next->lastToken();
-    if (literal_token)
-        return literal_token + 1;
-    return at_token + 1;
+    return literal_token + 1;
 }
 
 
@@ -1912,7 +1910,7 @@ unsigned ObjCClassForwardDeclarationAST::firstToken() const
     if (attribute_list)
         return attribute_list->firstToken();
 
-    return at_token;
+    return class_token;
 }
 
 unsigned ObjCClassForwardDeclarationAST::lastToken() const
@@ -1923,10 +1921,7 @@ unsigned ObjCClassForwardDeclarationAST::lastToken() const
     else if (identifier_list)
         return identifier_list->lastToken();
 
-    else if (class_token)
-        return class_token + 1;
-    else
-        return at_token + 1;
+    return class_token + 1;
 }
 
 unsigned ObjCProtocolForwardDeclarationAST::firstToken() const
@@ -1934,7 +1929,7 @@ unsigned ObjCProtocolForwardDeclarationAST::firstToken() const
     if (attribute_list)
         return attribute_list->firstToken();
 
-    return at_token;
+    return protocol_token;
 }
 
 unsigned ObjCProtocolForwardDeclarationAST::lastToken() const
@@ -1945,10 +1940,7 @@ unsigned ObjCProtocolForwardDeclarationAST::lastToken() const
     else if (identifier_list)
         return identifier_list->lastToken();
 
-    else if (protocol_token)
-        return protocol_token + 1;
-    else
-        return at_token + 1;
+    return protocol_token + 1;
 }
 
 unsigned ObjCClassDeclarationAST::firstToken() const
@@ -1956,14 +1948,15 @@ unsigned ObjCClassDeclarationAST::firstToken() const
     if (attribute_list)
         return attribute_list->firstToken();
 
-    return at_token;
+    if (interface_token)
+        return interface_token;
+    else
+        return implementation_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)
@@ -1981,25 +1974,21 @@ unsigned ObjCClassDeclarationAST::lastToken() const
 
     if (interface_token)
         return interface_token + 1;
-    else if (implementation_token)
-        return implementation_token + 1;
     else
-        return at_token + 1;
+        return implementation_token + 1;
 }
 
 unsigned ObjCProtocolDeclarationAST::firstToken() const
 {
     if (attribute_list)
         return attribute_list->firstToken();
-    return at_token;
+    return protocol_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();
@@ -2012,10 +2001,8 @@ unsigned ObjCProtocolDeclarationAST::lastToken() const
 
     else if (attribute_list)
         return attribute_list->lastToken();
-    else if (protocol_token)
-        return protocol_token + 1;
-    else
-        return at_token + 1;
+
+    return protocol_token + 1;
 }
 
 unsigned ObjCProtocolRefsAST::firstToken() const
@@ -2076,7 +2063,7 @@ unsigned ObjCMessageArgumentAST::lastToken() const
 
 unsigned ObjCProtocolExpressionAST::firstToken() const
 {
-    return at_token;
+    return protocol_token;
 }
 
 unsigned ObjCProtocolExpressionAST::lastToken() const
@@ -2090,10 +2077,7 @@ unsigned ObjCProtocolExpressionAST::lastToken() const
     if (lparen_token)
         return lparen_token + 1;
 
-    if (protocol_token)
-        return protocol_token + 1;
-
-    return at_token + 1;
+    return protocol_token + 1;
 }
 
 unsigned ObjCTypeNameAST::firstToken() const
@@ -2117,7 +2101,7 @@ unsigned ObjCTypeNameAST::lastToken() const
 
 unsigned ObjCEncodeExpressionAST::firstToken() const
 {
-    return at_token;
+    return encode_token;
 }
 
 unsigned ObjCEncodeExpressionAST::lastToken() const
@@ -2125,10 +2109,7 @@ unsigned ObjCEncodeExpressionAST::lastToken() const
     if (type_name)
         return type_name->lastToken();
 
-    if (encode_token)
-        return encode_token + 1;
-
-    return at_token + 1;
+    return encode_token + 1;
 }
 
 unsigned ObjCSelectorWithoutArgumentsAST::firstToken() const
@@ -2166,7 +2147,7 @@ unsigned ObjCSelectorWithArgumentsAST::lastToken() const
 
 unsigned ObjCSelectorExpressionAST::firstToken() const
 {
-    return at_token;
+    return selector_token;
 }
 
 unsigned ObjCSelectorExpressionAST::lastToken() const
@@ -2177,9 +2158,7 @@ unsigned ObjCSelectorExpressionAST::lastToken() const
         return selector->lastToken();
     if (lparen_token)
         return rparen_token + 1;
-    if (selector_token)
-        return selector_token + 1;
-    return at_token + 1;
+    return selector_token + 1;
 }
 
 unsigned ObjCInstanceVariablesDeclarationAST::firstToken() const
@@ -2200,15 +2179,12 @@ unsigned ObjCInstanceVariablesDeclarationAST::lastToken() const
 
 unsigned ObjCVisibilityDeclarationAST::firstToken() const
 {
-    return at_token;
+    return visibility_token;
 }
 
 unsigned ObjCVisibilityDeclarationAST::lastToken() const
 {
-    if (visibility_token)
-        return visibility_token + 1;
-    else
-        return at_token + 1;
+    return visibility_token + 1;
 }
 
 unsigned ObjCPropertyAttributeAST::firstToken() const
@@ -2231,7 +2207,7 @@ unsigned ObjCPropertyDeclarationAST::firstToken() const
     if (attribute_list)
         return attribute_list->firstToken();
 
-    return at_token;
+    return property_token;
 }
 
 unsigned ObjCPropertyDeclarationAST::lastToken() const
@@ -2244,10 +2220,8 @@ unsigned ObjCPropertyDeclarationAST::lastToken() const
         return property_attribute_list->lastToken();
     else if (lparen_token)
         return lparen_token + 1;
-    else if (property_token)
-        return property_token + 1;
-    else
-        return at_token + 1;
+
+    return property_token + 1;
 }
 
 unsigned ObjCMessageArgumentDeclarationAST::firstToken() const
@@ -2380,7 +2354,7 @@ unsigned ObjCFastEnumerationAST::lastToken() const
 
 unsigned ObjCSynchronizedStatementAST::firstToken() const
 {
-    return at_token;
+    return synchronized_token;
 }
 
 unsigned ObjCSynchronizedStatementAST::lastToken() const
@@ -2389,6 +2363,5 @@ 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;
-    if (synchronized_token) return synchronized_token + 1;
-    return at_token + 1;
+    return synchronized_token + 1;
 }
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
index 76ec773226ef7f619cf148b2a85421c072a839bb..4b0c149357f1dc819b62ece6b35ebc8d33eea761 100644
--- a/src/shared/cplusplus/AST.h
+++ b/src/shared/cplusplus/AST.h
@@ -2275,7 +2275,6 @@ protected:
 class CPLUSPLUS_EXPORT StringLiteralAST: public ExpressionAST
 {
 public:
-    unsigned at_token;
     unsigned literal_token;
     StringLiteralAST *next;
 
@@ -2589,7 +2588,6 @@ class CPLUSPLUS_EXPORT ObjCClassForwardDeclarationAST: public DeclarationAST
 {
 public:
     SpecifierListAST *attribute_list;
-    unsigned at_token;
     unsigned class_token;
     NameListAST *identifier_list;
     unsigned semicolon_token;
@@ -2614,7 +2612,6 @@ class CPLUSPLUS_EXPORT ObjCClassDeclarationAST: public DeclarationAST
 {
 public:
     SpecifierListAST *attribute_list;
-    unsigned at_token;
     unsigned interface_token;
     unsigned implementation_token;
     NameAST *class_name;
@@ -2626,7 +2623,6 @@ public:
     ObjCProtocolRefsAST *protocol_refs;
     ObjCInstanceVariablesDeclarationAST *inst_vars_decl;
     DeclarationListAST *member_declaration_list;
-    unsigned ending_at_token;
     unsigned end_token;
 
 public: // annotations
@@ -2649,7 +2645,6 @@ class CPLUSPLUS_EXPORT ObjCProtocolForwardDeclarationAST: public DeclarationAST
 {
 public:
     SpecifierListAST *attribute_list;
-    unsigned at_token;
     unsigned protocol_token;
     NameListAST *identifier_list;
     unsigned semicolon_token;
@@ -2674,12 +2669,10 @@ 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
@@ -2761,7 +2754,6 @@ protected:
 class CPLUSPLUS_EXPORT ObjCProtocolExpressionAST: public ExpressionAST
 {
 public:
-    unsigned at_token;
     unsigned protocol_token;
     unsigned lparen_token;
     unsigned identifier_token;
@@ -2804,7 +2796,6 @@ protected:
 class CPLUSPLUS_EXPORT ObjCEncodeExpressionAST: public ExpressionAST
 {
 public:
-    unsigned at_token;
     unsigned encode_token;
     ObjCTypeNameAST *type_name;
 
@@ -2879,7 +2870,6 @@ protected:
 class CPLUSPLUS_EXPORT ObjCSelectorExpressionAST: public ExpressionAST
 {
 public:
-    unsigned at_token;
     unsigned selector_token;
     unsigned lparen_token;
     ObjCSelectorAST *selector;
@@ -2921,7 +2911,6 @@ protected:
 class CPLUSPLUS_EXPORT ObjCVisibilityDeclarationAST: public DeclarationAST
 {
 public:
-    unsigned at_token;
     unsigned visibility_token;
 
 public:
@@ -2961,7 +2950,6 @@ class CPLUSPLUS_EXPORT ObjCPropertyDeclarationAST: public DeclarationAST
 {
 public:
     SpecifierListAST *attribute_list;
-    unsigned at_token;
     unsigned property_token;
     unsigned lparen_token;
     ObjCPropertyAttributeListAST *property_attribute_list;
@@ -3149,7 +3137,6 @@ 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 d4247ad1160e8a61879cd3ce3f230717bde16ae3..87ee91558b14208778705c4cc192a26ce216cff1 100644
--- a/src/shared/cplusplus/ASTClone.cpp
+++ b/src/shared/cplusplus/ASTClone.cpp
@@ -1064,7 +1064,6 @@ 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);
@@ -1233,7 +1232,6 @@ 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)
@@ -1248,7 +1246,6 @@ 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)
@@ -1267,7 +1264,6 @@ 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;
 }
@@ -1278,7 +1274,6 @@ 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)
@@ -1293,7 +1288,6 @@ 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);
@@ -1302,7 +1296,6 @@ 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;
 }
@@ -1344,7 +1337,6 @@ 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;
@@ -1366,7 +1358,6 @@ 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);
@@ -1400,7 +1391,6 @@ 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)
@@ -1423,7 +1413,6 @@ 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;
 }
@@ -1444,7 +1433,6 @@ 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;
@@ -1553,7 +1541,6 @@ 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 627fe3abf85a5f7f3551ec8830cff0a80c95ca94..c3e04a0d4e3525175bfd1fe7cd9a9db72cba4aed 100644
--- a/src/shared/cplusplus/ASTMatcher.cpp
+++ b/src/shared/cplusplus/ASTMatcher.cpp
@@ -1771,8 +1771,6 @@ 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)
@@ -2065,8 +2063,6 @@ 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)
@@ -2089,8 +2085,6 @@ 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;
@@ -2131,8 +2125,6 @@ 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;
@@ -2148,8 +2140,6 @@ 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)
@@ -2172,8 +2162,6 @@ 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)
@@ -2191,8 +2179,6 @@ 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;
@@ -2260,8 +2246,6 @@ 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;
@@ -2297,8 +2281,6 @@ 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)
@@ -2349,8 +2331,6 @@ 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;
@@ -2387,8 +2367,6 @@ bool ASTMatcher::match(ObjCVisibilityDeclarationAST *node, ObjCVisibilityDeclara
     (void) node;
     (void) pattern;
 
-    pattern->at_token = node->at_token;
-
     pattern->visibility_token = node->visibility_token;
 
     return true;
@@ -2421,8 +2399,6 @@ 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;
@@ -2611,8 +2587,6 @@ 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 f8cc188238fde58493eb97c8e70b14e27f4fc183..9a71ccfa7e77100193a8b4815f7ce74c93259877 100644
--- a/src/shared/cplusplus/Lexer.cpp
+++ b/src/shared/cplusplus/Lexer.cpp
@@ -596,11 +596,52 @@ void Lexer::scan_helper(Token *tok)
         tok->f.kind = T_COMMA;
         break;
 
-    case '@':
-        tok->f.kind = T_AT;
-        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;
+            }
+        }
+
         if (ch == 'L' && (_yychar == '"' || _yychar == '\'')) {
             // wide char/string literals
             ch = _yychar;
@@ -638,18 +679,11 @@ 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 cdadbc46f853ffcfb3568696b5c31bd63f917d7e..78b0cf94a41f317371f8ef389d3888db53dd2274 100644
--- a/src/shared/cplusplus/ObjectiveCAtKeywords.cpp
+++ b/src/shared/cplusplus/ObjectiveCAtKeywords.cpp
@@ -36,7 +36,14 @@ static inline int classify3(const char *s) {
   if (s[0] == 'e') {
     if (s[1] == 'n') {
       if (s[2] == 'd') {
-        return T_END;
+        return T_AT_END;
+      }
+    }
+  }
+  else if (s[0] == 't') {
+    if (s[1] == 'r') {
+      if (s[2] == 'y') {
+        return T_AT_TRY;
       }
     }
   }
@@ -48,7 +55,42 @@ static inline int classify4(const char *s) {
     if (s[1] == 'e') {
       if (s[2] == 'f') {
         if (s[3] == 's') {
-          return T_DEFS;
+          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;
+          }
         }
       }
     }
@@ -63,7 +105,20 @@ static inline int classify6(const char *s) {
         if (s[3] == 'o') {
           if (s[4] == 'd') {
             if (s[5] == 'e') {
-              return T_ENCODE;
+              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;
             }
           }
         }
@@ -81,7 +136,7 @@ static inline int classify7(const char *s) {
           if (s[4] == 'm') {
             if (s[5] == 'i') {
               if (s[6] == 'c') {
-                return T_DYNAMIC;
+                return T_AT_DYNAMIC;
               }
             }
           }
@@ -96,7 +151,7 @@ static inline int classify7(const char *s) {
           if (s[4] == 'l') {
             if (s[5] == 'l') {
               if (s[6] == 'y') {
-                return T_FINALLY;
+                return T_AT_FINALLY;
               }
             }
           }
@@ -111,7 +166,7 @@ static inline int classify7(const char *s) {
           if (s[4] == 'a') {
             if (s[5] == 'g') {
               if (s[6] == 'e') {
-                return T_PACKAGE;
+                return T_AT_PACKAGE;
               }
             }
           }
@@ -124,7 +179,7 @@ static inline int classify7(const char *s) {
           if (s[4] == 'a') {
             if (s[5] == 't') {
               if (s[6] == 'e') {
-                return T_PRIVATE;
+                return T_AT_PRIVATE;
               }
             }
           }
@@ -144,7 +199,7 @@ static inline int classify8(const char *s) {
             if (s[5] == 'n') {
               if (s[6] == 'a') {
                 if (s[7] == 'l') {
-                  return T_OPTIONAL;
+                  return T_AT_OPTIONAL;
                 }
               }
             }
@@ -161,7 +216,7 @@ static inline int classify8(const char *s) {
             if (s[5] == 'r') {
               if (s[6] == 't') {
                 if (s[7] == 'y') {
-                  return T_PROPERTY;
+                  return T_AT_PROPERTY;
                 }
               }
             }
@@ -172,7 +227,7 @@ static inline int classify8(const char *s) {
             if (s[5] == 'c') {
               if (s[6] == 'o') {
                 if (s[7] == 'l') {
-                  return T_PROTOCOL;
+                  return T_AT_PROTOCOL;
                 }
               }
             }
@@ -189,7 +244,7 @@ static inline int classify8(const char *s) {
             if (s[5] == 'r') {
               if (s[6] == 'e') {
                 if (s[7] == 'd') {
-                  return T_REQUIRED;
+                  return T_AT_REQUIRED;
                 }
               }
             }
@@ -206,7 +261,7 @@ static inline int classify8(const char *s) {
             if (s[5] == 't') {
               if (s[6] == 'o') {
                 if (s[7] == 'r') {
-                  return T_SELECTOR;
+                  return T_AT_SELECTOR;
                 }
               }
             }
@@ -228,7 +283,26 @@ static inline int classify9(const char *s) {
               if (s[6] == 'a') {
                 if (s[7] == 'c') {
                   if (s[8] == 'e') {
-                    return T_INTERFACE;
+                    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;
                   }
                 }
               }
@@ -252,7 +326,7 @@ static inline int classify10(const char *s) {
                 if (s[7] == 'i') {
                   if (s[8] == 'z') {
                     if (s[9] == 'e') {
-                      return T_SYNTHESIZE;
+                      return T_AT_SYNTHESIZE;
                     }
                   }
                 }
@@ -278,7 +352,7 @@ static inline int classify11(const char *s) {
                   if (s[8] == 'o') {
                     if (s[9] == 'r') {
                       if (s[10] == 'd') {
-                        return T_NOT_KEYWORD;
+                        return T_AT_NOT_KEYWORD;
                       }
                     }
                   }
@@ -306,7 +380,7 @@ static inline int classify12(const char *s) {
                     if (s[9] == 'z') {
                       if (s[10] == 'e') {
                         if (s[11] == 'd') {
-                          return T_SYNCHRONIZED;
+                          return T_AT_SYNCHRONIZED;
                         }
                       }
                     }
@@ -337,7 +411,7 @@ static inline int classify14(const char *s) {
                         if (s[11] == 'i') {
                           if (s[12] == 'o') {
                             if (s[13] == 'n') {
-                              return T_IMPLEMENTATION;
+                              return T_AT_IMPLEMENTATION;
                             }
                           }
                         }
@@ -375,7 +449,7 @@ static inline int classify19(const char *s) {
                                   if (s[16] == 'i') {
                                     if (s[17] == 'a') {
                                       if (s[18] == 's') {
-                                        return T_COMPATIBILITY_ALIAS;
+                                        return T_AT_COMPATIBILITY_ALIAS;
                                       }
                                     }
                                   }
@@ -402,6 +476,7 @@ 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 a6b6e0b1c8190f490f5aa5f6c9aac05ecebda360..7bc832ffa6abf9c25d1e9eb54b3b47d23a1919dc 100644
--- a/src/shared/cplusplus/Parser.cpp
+++ b/src/shared/cplusplus/Parser.cpp
@@ -293,22 +293,13 @@ 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())
@@ -361,8 +352,8 @@ bool Parser::skipUntilStatement()
             case T_USING:
                 return true;
 
-            case T_AT:
-                if (objCEnabled() && LA(2) == T_SYNCHRONIZED)
+            case T_AT_SYNCHRONIZED:
+                if (objCEnabled())
                     return true;
 
             default:
@@ -594,28 +585,23 @@ bool Parser::parseDeclaration(DeclarationAST *&node)
         return parseTemplateDeclaration(node);
 
     // ObjcC++
-    case T_AT:
-        if (objCEnabled()) {
-            switch (LA(2)) {
-            case T_CLASS:
-                return parseObjCClassForwardDeclaration(node);
+    case T_AT_CLASS:
+        return parseObjCClassForwardDeclaration(node);
 
-            case T_INTERFACE:
-                return parseObjCInterface(node);
+    case T_AT_INTERFACE:
+        return parseObjCInterface(node);
 
-            case T_PROTOCOL:
-                return parseObjCProtocol(node);
+    case T_AT_PROTOCOL:
+        return parseObjCProtocol(node);
 
-            case T_IMPLEMENTATION:
-                return parseObjCImplementation(node);
+    case T_AT_IMPLEMENTATION:
+        return parseObjCImplementation(node);
 
-            case T_END:
-                // TODO: should this be done here, or higher-up?
-                _translationUnit->error(cursor(), "skip stray token `%s'", tok().spell());
-                consumeToken();
-                break;
-            }
-        }
+    case T_AT_END:
+        // TODO: should this be done here, or higher-up?
+        _translationUnit->error(cursor(), "skip stray token `%s'", tok().spell());
+        consumeToken();
+        break;
 
     default: {
         if (_objCEnabled && LA() == T___ATTRIBUTE__) {
@@ -623,14 +609,12 @@ bool Parser::parseDeclaration(DeclarationAST *&node)
             SpecifierListAST *attributes = 0, **attr = &attributes;
             while (parseAttributeSpecifier(*attr))
                 attr = &(*attr)->next;
-            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);
-            }
+            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);
         }
 
@@ -2431,6 +2415,9 @@ 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;
@@ -2441,10 +2428,6 @@ 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);
@@ -3487,7 +3470,10 @@ bool Parser::parsePrimaryExpression(ExpressionAST *&node)
         return parseQtMethod(node);
 
     case T_LBRACKET:
-    case T_AT:
+    case T_AT_STRING_LITERAL:
+    case T_AT_ENCODE:
+    case T_AT_PROTOCOL:
+    case T_AT_SELECTOR:
         return parseObjCExpression(node);
 
     default: {
@@ -3507,22 +3493,20 @@ bool Parser::parsePrimaryExpression(ExpressionAST *&node)
 bool Parser::parseObjCExpression(ExpressionAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() == T_LBRACKET)
-        return parseObjCMessageExpression(node);
-    if (LA() != T_AT)
-        return false;
-
-    switch (LA(2)) {
-    case T_ENCODE:
+    switch (LA()) {
+    case T_AT_ENCODE:
         return parseObjCEncodeExpression(node);
 
-    case T_PROTOCOL:
+    case T_AT_PROTOCOL:
         return parseObjCProtocolExpression(node);
 
-    case T_SELECTOR:
+    case T_AT_SELECTOR:
         return parseObjCSelectorExpression(node);
 
-    case T_STRING_LITERAL:
+    case T_LBRACKET:
+        return parseObjCMessageExpression(node);
+
+    case T_AT_STRING_LITERAL:
         return parseObjCStringLiteral(node);
 
     default:
@@ -3531,54 +3515,30 @@ 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 || LA(2) != T_STRING_LITERAL)
+    if (LA() != T_AT_STRING_LITERAL)
         return false;
 
-    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;
-        }
+    StringLiteralAST **ast = reinterpret_cast<StringLiteralAST **> (&node);
+
+    while (LA() == T_AT_STRING_LITERAL) {
+        *ast = new (_pool) StringLiteralAST;
+        (*ast)->literal_token = consumeToken();
+        ast = &(*ast)->next;
     }
-    node = *ast;
     return true;
 }
 
 bool Parser::parseObjCSynchronizedStatement(StatementAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() == T_AT || LA(2) != T_SYNCHRONIZED)
+    if (LA() != T_AT_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);
@@ -3592,11 +3552,10 @@ bool Parser::parseObjCSynchronizedStatement(StatementAST *&node)
 bool Parser::parseObjCEncodeExpression(ExpressionAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT || LA(2) != T_ENCODE)
+    if (LA() != T_AT_ENCODE)
         return false;
 
     ObjCEncodeExpressionAST *ast = new (_pool) ObjCEncodeExpressionAST;
-    ast->at_token = consumeToken();
     ast->encode_token = consumeToken();
     parseObjCTypeName(ast->type_name);
     node = ast;
@@ -3606,11 +3565,10 @@ bool Parser::parseObjCEncodeExpression(ExpressionAST *&node)
 bool Parser::parseObjCProtocolExpression(ExpressionAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT || LA(2) != T_PROTOCOL)
+    if (LA() != T_AT_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);
@@ -3622,11 +3580,10 @@ bool Parser::parseObjCProtocolExpression(ExpressionAST *&node)
 bool Parser::parseObjCSelectorExpression(ExpressionAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT || LA(2) != T_SELECTOR)
+    if (LA() != T_AT_SELECTOR)
         return false;
 
     ObjCSelectorExpressionAST *ast = new (_pool) ObjCSelectorExpressionAST;
-    ast->at_token = consumeToken();
     ast->selector_token = consumeToken();
     match(T_LPAREN, &ast->lparen_token);
 
@@ -4536,11 +4493,11 @@ bool Parser::lookAtObjCSelector() const
 bool Parser::parseObjCClassForwardDeclaration(DeclarationAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT || LA(2) != T_CLASS)
+    if (LA() != T_AT_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);
@@ -4592,10 +4549,9 @@ bool Parser::parseObjCInterface(DeclarationAST *&node,
             attr = &(*attr)->next;
     }
 
-    if (LA() != T_AT || LA(2) != T_INTERFACE)
+    if (LA() != T_AT_INTERFACE)
         return false;
 
-    unsigned at_token = consumeToken();
     unsigned objc_interface_token = consumeToken();
     unsigned identifier_token = 0;
     match(T_IDENTIFIER, &identifier_token);
@@ -4609,7 +4565,6 @@ 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;
@@ -4634,8 +4589,7 @@ bool Parser::parseObjCInterface(DeclarationAST *&node,
             nextMembers = &(*nextMembers)->next;
         }
 
-        match(T_AT, &ast->ending_at_token);
-        match(T_END, &ast->end_token);
+        match(T_AT_END, &ast->end_token);
 
         node = ast;
         return true;
@@ -4643,7 +4597,6 @@ 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;
@@ -4667,8 +4620,7 @@ bool Parser::parseObjCInterface(DeclarationAST *&node,
             nextMembers = &(*nextMembers)->next;
         }
 
-        match(T_AT, &ast->ending_at_token);
-        match(T_END, &ast->end_token);
+        match(T_AT_END, &ast->end_token);
 
         node = ast;
         return true;
@@ -4687,10 +4639,9 @@ bool Parser::parseObjCProtocol(DeclarationAST *&node,
             attr = &(*attr)->next;
     }
 
-    if (LA() != T_AT || LA(2) != T_PROTOCOL)
+    if (LA() != T_AT_PROTOCOL)
         return false;
 
-    unsigned at_token = consumeToken();
     unsigned protocol_token = consumeToken();
     unsigned identifier_token = 0;
     match(T_IDENTIFIER, &identifier_token);
@@ -4700,7 +4651,6 @@ 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;
@@ -4726,7 +4676,6 @@ 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;
@@ -4742,8 +4691,7 @@ bool Parser::parseObjCProtocol(DeclarationAST *&node,
             nextMembers = &(*nextMembers)->next;
         }
 
-        match(T_AT, &ast->ending_at_token);
-        match(T_END, &ast->end_token);
+        match(T_AT_END, &ast->end_token);
 
         node = ast;
         return true;
@@ -4757,10 +4705,9 @@ bool Parser::parseObjCProtocol(DeclarationAST *&node,
 bool Parser::parseObjCImplementation(DeclarationAST *&node)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT || LA(2) != T_IMPLEMENTATION)
+    if (LA() != T_AT_IMPLEMENTATION)
         return false;
 
-    unsigned at_token = consumeToken();
     unsigned implementation_token = consumeToken();
     unsigned identifier_token = 0;
     match(T_IDENTIFIER, &identifier_token);
@@ -4768,7 +4715,6 @@ 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;
@@ -4781,14 +4727,12 @@ bool Parser::parseObjCImplementation(DeclarationAST *&node)
         match(T_RPAREN, &ast->rparen_token);
 
         parseObjCMethodDefinitionList(ast->member_declaration_list);
-        match(T_AT, &ast->ending_at_token);
-        match(T_END, &ast->end_token);
+        match(T_AT_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;
@@ -4803,8 +4747,7 @@ bool Parser::parseObjCImplementation(DeclarationAST *&node)
 
         parseObjClassInstanceVariables(ast->inst_vars_decl);
         parseObjCMethodDefinitionList(ast->member_declaration_list);
-        match(T_AT, &ast->ending_at_token);
-        match(T_END, &ast->end_token);
+        match(T_AT_END, &ast->end_token);
 
         node = ast;
     }
@@ -4817,7 +4760,7 @@ bool Parser::parseObjCMethodDefinitionList(DeclarationListAST *&node)
     DEBUG_THIS_RULE();
     DeclarationListAST **next = &node;
 
-    while (LA() && !(LA() == T_AT && LA(2) == T_END)) {
+    while (LA() && LA() != T_AT_END) {
         unsigned start = cursor();
         DeclarationAST *declaration = 0;
 
@@ -4834,12 +4777,26 @@ bool Parser::parseObjCMethodDefinitionList(DeclarationListAST *&node)
             consumeToken();
             break;
 
-        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;
+        case T_AT_SYNTHESIZE: {
+            ObjCSynthesizedPropertiesDeclarationAST *ast = new (_pool) ObjCSynthesizedPropertiesDeclarationAST;
+            ast->synthesized_token = consumeToken();
+            ObjCSynthesizedPropertyListAST *last = new (_pool) ObjCSynthesizedPropertyListAST;
+            ast->property_identifier_list = last;
+            last->value = new (_pool) ObjCSynthesizedPropertyAST;
+            match(T_IDENTIFIER, &last->value->property_identifier_token);
+
+            if (LA() == T_EQUAL) {
+                last->value->equals_token = consumeToken();
+
+                match(T_IDENTIFIER, &last->value->alias_identifier_token);
+            }
+
+            while (LA() == T_COMMA) {
+                consumeToken(); // consume T_COMMA
+
+                last->next = new (_pool) ObjCSynthesizedPropertyListAST;
+                last = last->next;
+
                 last->value = new (_pool) ObjCSynthesizedPropertyAST;
                 match(T_IDENTIFIER, &last->value->property_identifier_token);
 
@@ -4848,51 +4805,38 @@ bool Parser::parseObjCMethodDefinitionList(DeclarationListAST *&node)
 
                     match(T_IDENTIFIER, &last->value->alias_identifier_token);
                 }
+            }
 
-                while (LA() == T_COMMA) {
-                    consumeToken(); // consume T_COMMA
-
-                    last->next = new (_pool) ObjCSynthesizedPropertyListAST;
-                    last = last->next;
-
-                    last->value = new (_pool) ObjCSynthesizedPropertyAST;
-                    match(T_IDENTIFIER, &last->value->property_identifier_token);
+            match(T_SEMICOLON, &ast->semicolon_token);
 
-                    if (LA() == T_EQUAL) {
-                        last->value->equals_token = consumeToken();
+            declaration = ast;
+            break;
+        }
 
-                        match(T_IDENTIFIER, &last->value->alias_identifier_token);
-                    }
-                }
+        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;
 
-                match(T_SEMICOLON, &ast->semicolon_token);
+            NameListAST *last = ast->property_identifier_list;
+            while (LA() == T_COMMA) {
+                consumeToken(); // consume T_COMMA
 
-                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;
+                last->next = new (_pool) NameListAST;
+                last = last->next;
+                name = new (_pool) SimpleNameAST;
                 match(T_IDENTIFIER, &name->identifier_token);
-                ast->property_identifier_list->value = name;
-
-                NameListAST *last = ast->property_identifier_list;
-                while (LA() == T_COMMA) {
-                    consumeToken(); // consume T_COMMA
-
-                    last->next = new (_pool) NameListAST;
-                    last = last->next;
-                    name = new (_pool) SimpleNameAST;
-                    match(T_IDENTIFIER, &name->identifier_token);
-                    last->value = name;
-                }
+                last->value = name;
+            }
 
-                match(T_SEMICOLON, &ast->semicolon_token);
+            match(T_SEMICOLON, &ast->semicolon_token);
 
-                declaration = ast;
-                break;
-            }
+            declaration = ast;
+            break;
+        }
 
         default:
             if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL) {
@@ -5023,6 +4967,22 @@ 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;
@@ -5042,30 +5002,6 @@ 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
@@ -5079,23 +5015,20 @@ bool Parser::parseObjCInterfaceMemberDeclaration(DeclarationAST *&node)
 bool Parser::parseObjCInstanceVariableDeclaration(DeclarationAST *&node)
 {
     DEBUG_THIS_RULE();
-    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;
-            }
+    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;
         }
-    }
 
-    return parseSimpleDeclaration(node, true);
+        default:
+            return parseSimpleDeclaration(node, true);
+    }
 }
 
 // objc-property-declaration ::=
@@ -5104,12 +5037,11 @@ bool Parser::parseObjCInstanceVariableDeclaration(DeclarationAST *&node)
 bool Parser::parseObjCPropertyDeclaration(DeclarationAST *&node, SpecifierListAST *attributes)
 {
     DEBUG_THIS_RULE();
-    if (LA() != T_AT || LA(2) != T_PROPERTY)
+    if (LA() != T_AT_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 98dfa35e291d4f264222697e3ac13634d94a723f..d8d6d6617e9a33d370de11ee822bf84fe2347c4f 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_PUBLIC:
+    case T_AT_PUBLIC:
         return Symbol::Public;
-    case T_PROTECTED:
+    case T_AT_PROTECTED:
         return Symbol::Protected;
-    case T_PRIVATE:
+    case T_AT_PRIVATE:
         return Symbol::Private;
-    case T_PACKAGE:
+    case T_AT_PACKAGE:
         return Symbol::Package;
     default:
         return Symbol::Protected;
diff --git a/src/shared/cplusplus/Token.cpp b/src/shared/cplusplus/Token.cpp
index e4f2baba4d4359cf7031bf560ba574b1c9d0ad46..e86038271fa1eed95d0f18f59eac5e4d8bafd4ce 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>"),
-    ("<angle string literal>"),
+    ("<@string literal>"), ("<angle string literal>"),
 
-    ("&"), ("&&"), ("&="), ("->"), ("->*"), ("@"), ("^"), ("^="), (":"),
-    ("::"), (","), ("/"), ("/="), ("."), ("..."), (".*"), ("="), ("=="),
-    ("!"), ("!="), (">"), (">="), (">>"), (">>="), ("{"), ("["), ("<"),
-    ("<="), ("<<"), ("<<="), ("("), ("-"), ("-="), ("--"), ("%"), ("%="),
-    ("|"), ("|="), ("||"), ("+"), ("+="), ("++"), ("#"), ("##"), ("?"),
-    ("}"), ("]"), (")"), (";"), ("*"), ("*="), ("~"), ("~="),
+    ("&"), ("&&"), ("&="), ("->"), ("->*"), ("^"), ("^="), (":"), ("::"),
+    (","), ("/"), ("/="), ("."), ("..."), (".*"), ("="), ("=="), ("!"),
+    ("!="), (">"), (">="), (">>"), (">>="), ("{"), ("["), ("<"), ("<="),
+    ("<<"), ("<<="), ("("), ("-"), ("-="), ("--"), ("%"), ("%="), ("|"),
+    ("|="), ("||"), ("+"), ("+="), ("++"), ("#"), ("##"), ("?"), ("}"),
+    ("]"), (")"), (";"), ("*"), ("*="), ("~"), ("~="),
 
     ("asm"), ("auto"), ("bool"), ("break"), ("case"), ("catch"), ("char"),
     ("class"), ("const"), ("const_cast"), ("continue"), ("default"),
@@ -84,11 +84,12 @@ static const char *token_names[] = {
     // gnu
     ("__attribute__"), ("__typeof__"),
 
-    // objc keywords
-    ("@compatibility_alias"), ("@defs"), ("@dynamic"), ("@encode"), ("@end"),
-    ("@finally"), ("@implementation"), ("@interface"), ("@not_keyword"),
-    ("@optional"), ("@package"), ("@property"), ("@protocol"), ("@required"),
-    ("@selector"), ("@synchronized"), ("@synthesize"),
+    // 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"),
 
     ("SIGNAL"), ("SLOT"), ("Q_SIGNAL"), ("Q_SLOT"), ("signals"), ("slots"),
     ("Q_FOREACH"), ("Q_D"), ("Q_Q"),
@@ -123,6 +124,7 @@ 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 05505b94e417d5a0bd077232568ec783fdd95204..d139584bddbc116474808e77aec38aeda7ce4032 100644
--- a/src/shared/cplusplus/Token.h
+++ b/src/shared/cplusplus/Token.h
@@ -69,6 +69,7 @@ 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,
 
@@ -78,7 +79,6 @@ enum Kind {
     T_AMPER_EQUAL,
     T_ARROW,
     T_ARROW_STAR,
-    T_AT,
     T_CARET,
     T_CARET_EQUAL,
     T_COLON,
@@ -196,28 +196,35 @@ enum Kind {
     T___ATTRIBUTE__,
     T___TYPEOF__,
 
-    // 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,
+    // 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,
 
     T_FIRST_QT_KEYWORD,
 
@@ -306,6 +313,9 @@ 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: