From b419d3a80ef4d48959478293a0cfb72297e08c5b Mon Sep 17 00:00:00 2001 From: Steve Naroff Date: Fri, 27 Oct 2006 23:18:49 +0000 Subject: [PATCH] - Added basic structure for parsing top level Objective-C forms. - Extended the typedef mechanism for classes, improved performance of the common case. - Implemented @class in the parser. llvm-svn: 39074 --- clang/Parse/MinimalAction.cpp | 73 ++++++++++++++++++++--------- clang/Parse/ParseDecl.cpp | 8 ++-- clang/Parse/ParseStmt.cpp | 2 +- clang/Parse/Parser.cpp | 75 ++++++++++++++++++++++++++++++ clang/include/clang/Parse/Action.h | 19 ++++++-- clang/include/clang/Parse/Parser.h | 13 +++++- 6 files changed, 157 insertions(+), 33 deletions(-) diff --git a/clang/Parse/MinimalAction.cpp b/clang/Parse/MinimalAction.cpp index be700f059a34..5ba684477147 100644 --- a/clang/Parse/MinimalAction.cpp +++ b/clang/Parse/MinimalAction.cpp @@ -17,18 +17,24 @@ using namespace llvm; using namespace clang; -/// TypedefInfo - A link exists here for each scope that an identifier is +/// TypeNameInfo - A link exists here for each scope that an identifier is /// defined. -struct TypedefInfo { - TypedefInfo *Prev; - bool isTypedef; +struct TypeNameInfo { + TypeNameInfo *Prev; + bool isTypeName; + + TypeNameInfo(bool istypename, TypeNameInfo *prev) { + isTypeName = istypename; + Prev = prev; + } + }; /// isTypedefName - This looks at the IdentifierInfo::FETokenInfo field to /// determine whether the name is a typedef or not in this scope. -bool EmptyAction::isTypedefName(const IdentifierInfo &II, Scope *S) const { - TypedefInfo *TI = II.getFETokenInfo(); - return TI != 0 && TI->isTypedef; +bool EmptyAction::isTypeName(const IdentifierInfo &II, Scope *S) const { + TypeNameInfo *TI = II.getFETokenInfo(); + return TI != 0 && TI->isTypeName; } /// ParseDeclarator - If this is a typedef declarator, we modify the @@ -37,20 +43,41 @@ bool EmptyAction::isTypedefName(const IdentifierInfo &II, Scope *S) const { Action::DeclTy * EmptyAction::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init, DeclTy *LastInGroup) { + IdentifierInfo *II = D.getIdentifier(); + // If there is no identifier associated with this declarator, bail out. - if (D.getIdentifier() == 0) return 0; + if (II == 0) return 0; - // Remember whether or not this declarator is a typedef. - TypedefInfo *TI = new TypedefInfo(); - TI->isTypedef = D.getDeclSpec().StorageClassSpec == DeclSpec::SCS_typedef; + TypeNameInfo *weCurrentlyHaveTypeInfo = II->getFETokenInfo(); + bool isTypeName = D.getDeclSpec().StorageClassSpec == DeclSpec::SCS_typedef; - // Add this to the linked-list hanging off the identifier. - IdentifierInfo &II = *D.getIdentifier(); - TI->Prev = II.getFETokenInfo(); - II.setFETokenInfo(TI); + // this check avoids creating TypeNameInfo objects for the common case. + // It does need to handle the uncommon case of shadowing a typedef name with a + // non-typedef name. e.g. { typedef int a; a xx; { int a; } } + if (weCurrentlyHaveTypeInfo || isTypeName) { + TypeNameInfo *TI = new TypeNameInfo(isTypeName, weCurrentlyHaveTypeInfo); + + II->setFETokenInfo(TI); - // Remember that this needs to be removed when the scope is popped. - S->AddDecl(&II); + // Remember that this needs to be removed when the scope is popped. + S->AddDecl(II); + } + return 0; +} + +// Scope will always be top level file scope. + +Action::DeclTy * +EmptyAction::ParsedClassDeclaration(Scope *S, + IdentifierInfo **identList, unsigned nElements) { + for (unsigned i = 0; i < nElements; i++) { + TypeNameInfo *TI = new TypeNameInfo(1, identList[i]->getFETokenInfo()); + + identList[i]->setFETokenInfo(TI); + + // Remember that this needs to be removed when the scope is popped. + S->AddDecl(identList[i]); + } return 0; } @@ -60,12 +87,14 @@ void EmptyAction::PopScope(SourceLocation Loc, Scope *S) { for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); I != E; ++I) { IdentifierInfo &II = *static_cast(*I); - TypedefInfo *TI = II.getFETokenInfo(); + TypeNameInfo *TI = II.getFETokenInfo(); assert(TI && "This decl didn't get pushed??"); - - TypedefInfo *Next = TI->Prev; - delete TI; - II.setFETokenInfo(Next); + if (TI) { + TypeNameInfo *Next = TI->Prev; + delete TI; + + II.setFETokenInfo(Next); + } } } diff --git a/clang/Parse/ParseDecl.cpp b/clang/Parse/ParseDecl.cpp index b1d3da0f3db7..709e50c9768c 100644 --- a/clang/Parse/ParseDecl.cpp +++ b/clang/Parse/ParseDecl.cpp @@ -262,7 +262,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { DS.TypeSpecComplex == DeclSpec::TSC_unspecified && DS.TypeSpecSign == DeclSpec::TSS_unspecified && // It has to be available as a typedef too! - Actions.isTypedefName(*Tok.getIdentifierInfo(), CurScope)) { + Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) { isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, PrevSpec); break; } @@ -645,7 +645,7 @@ bool Parser::isTypeSpecifierQualifier() const { // typedef-name case tok::identifier: - return Actions.isTypedefName(*Tok.getIdentifierInfo(), CurScope); + return Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope); // TODO: Attributes. } @@ -698,7 +698,7 @@ bool Parser::isDeclarationSpecifier() const { // typedef-name case tok::identifier: - return Actions.isTypedefName(*Tok.getIdentifierInfo(), CurScope); + return Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope); // TODO: Attributes. } } @@ -923,7 +923,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { HasPrototype = false; IsEmpty = true; } else if (Tok.getKind() == tok::identifier && - !Actions.isTypedefName(*Tok.getIdentifierInfo(), CurScope)) { + !Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) { // Identifier list. Note that '(' identifier-list ')' is only allowed for // normal declarators, not for abstract-declarators. assert(D.isPastIdentifier() && "Identifier (if present) must be passed!"); diff --git a/clang/Parse/ParseStmt.cpp b/clang/Parse/ParseStmt.cpp index 1c1c5dc0b043..e70c647502c8 100644 --- a/clang/Parse/ParseStmt.cpp +++ b/clang/Parse/ParseStmt.cpp @@ -205,7 +205,7 @@ Parser::StmtResult Parser::ParseIdentifierStatement(bool OnlyStatement) { // Check to see if this is a declaration. if (!OnlyStatement && - Actions.isTypedefName(*IdentTok.getIdentifierInfo(), CurScope)) { + Actions.isTypeName(*IdentTok.getIdentifierInfo(), CurScope)) { // Handle this. Warn/disable if in middle of block and !C99. DeclSpec DS; diff --git a/clang/Parse/Parser.cpp b/clang/Parse/Parser.cpp index b51316f890db..9d752a4668a3 100644 --- a/clang/Parse/Parser.cpp +++ b/clang/Parse/Parser.cpp @@ -287,6 +287,15 @@ Parser::DeclTy *Parser::ParseExternalDeclaration() { "top-level asm block"); // TODO: Invoke action for top-level asm. return 0; + case tok::at: + ObjCParseAtDirectives(); + return 0; + case tok::minus: + ObjCParseInstanceMethodDeclaration(); + return 0; + case tok::plus: + ObjCParseClassMethodDeclaration(); + return 0; default: // We can't tell whether this is a function-definition or declaration yet. return ParseDeclarationOrFunctionDefinition(); @@ -443,3 +452,69 @@ void Parser::ParseSimpleAsm() { MatchRHSPunctuation(tok::r_paren, Loc); } + +void Parser::ObjCParseAtDirectives() { + SourceLocation atLoc = ConsumeToken(); // the "@" + + IdentifierInfo *II = Tok.getIdentifierInfo(); + if (II == 0) return; // Not an identifier. + + switch (II->getObjCKeywordID()) { + case tok::objc_class: + ObjCParseClassDeclaration(atLoc); + case tok::objc_interface: + ObjCParseInterfaceDeclaration(); + case tok::objc_protocol: + ObjCParseProtocolDeclaration(); + case tok::objc_implementation: + ObjCParseImplementationDeclaration(); + case tok::objc_end: + ObjCParseEndDeclaration(); + case tok::objc_compatibility_alias: + ObjCParseAliasDeclaration(); + default: + ; // TODO: need to issue a diagnostic... + } +} + +/// +/// objc-class-declaration: +/// @class identifier-list ; +/// +void Parser::ObjCParseClassDeclaration(SourceLocation atLoc) { + ConsumeToken(); // the identifier "class" + SmallVector classNames; + + while (1) { + if (Tok.getKind() == tok::identifier) { + classNames.push_back(Tok.getIdentifierInfo()); + } else { + Diag(diag::err_expected_ident); + } + ConsumeToken(); + if (Tok.getKind() == tok::comma) + ConsumeToken(); + else + break; + } + if (Tok.getKind() == tok::semi) { + SourceLocation semiLoc = ConsumeToken(); + Actions.ParsedClassDeclaration(CurScope,&classNames[0],classNames.size()); + } +} +void Parser::ObjCParseInterfaceDeclaration() { +} +void Parser::ObjCParseProtocolDeclaration() { +} +void Parser::ObjCParseImplementationDeclaration() { +} +void Parser::ObjCParseEndDeclaration() { +} +void Parser::ObjCParseAliasDeclaration() { +} + +void Parser::ObjCParseInstanceMethodDeclaration() { +} + +void Parser::ObjCParseClassMethodDeclaration() { +} diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 5c633778d00d..87ead3b9193c 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -35,7 +35,7 @@ namespace clang { /// the parser has just done or is about to do when the method is called. They /// are not requests that the actions module do the specified action. /// -/// All of the methods here are optional except isTypedefName(), which must be +/// All of the methods here are optional except isTypeName(), which must be /// specified in order for the parse to complete accurately. The EmptyAction /// class does this bare-minimum of tracking to implement this functionality. class Action { @@ -78,9 +78,9 @@ public: // Symbol Table Tracking Callbacks. //===--------------------------------------------------------------------===// - /// isTypedefName - Return true if the specified identifier is a typedef name + /// isTypeName - Return true if the specified identifier is a typedef name /// in the current scope. - virtual bool isTypedefName(const IdentifierInfo &II, Scope *S) const = 0; + virtual bool isTypeName(const IdentifierInfo &II, Scope *S) const = 0; /// ParseDeclarator - This callback is invoked when a declarator is parsed and /// 'Init' specifies the initializer if any. This is for things like: @@ -111,6 +111,11 @@ public: // 'External Declaration' (Top Level) Parsing Callbacks. //===--------------------------------------------------------------------===// + virtual DeclTy *ParsedClassDeclaration(Scope *S, + IdentifierInfo **identList, unsigned nElements) { + return 0; + } + //===--------------------------------------------------------------------===// // Statement Parsing Callbacks. //===--------------------------------------------------------------------===// @@ -271,9 +276,9 @@ public: /// to reimplement all of the scoping rules. class EmptyAction : public Action { public: - /// isTypedefName - This looks at the IdentifierInfo::FETokenInfo field to + /// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to /// determine whether the name is a typedef or not in this scope. - virtual bool isTypedefName(const IdentifierInfo &II, Scope *S) const; + virtual bool isTypeName(const IdentifierInfo &II, Scope *S) const; /// ParseDeclarator - If this is a typedef declarator, we modify the /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is @@ -284,6 +289,10 @@ public: /// PopScope - When a scope is popped, if any typedefs are now out-of-scope, /// they are removed from the IdentifierInfo::FETokenInfo field. virtual void PopScope(SourceLocation Loc, Scope *S); + + virtual DeclTy *ParsedClassDeclaration(Scope *S, + IdentifierInfo **identList, unsigned nElements); + }; } // end namespace clang diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 354d01644033..b59112b73003 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -231,7 +231,18 @@ private: DeclTy *ParseFunctionDefinition(Declarator &D); void ParseSimpleAsm(); void ParseAsmStringLiteral(); - + + // Objective-C External Declarations + void ObjCParseAtDirectives(); + void ObjCParseClassDeclaration(SourceLocation atLoc); + void ObjCParseInterfaceDeclaration(); + void ObjCParseProtocolDeclaration(); + void ObjCParseImplementationDeclaration(); + void ObjCParseEndDeclaration(); + void ObjCParseAliasDeclaration(); + void ObjCParseInstanceMethodDeclaration(); + void ObjCParseClassMethodDeclaration(); + //===--------------------------------------------------------------------===// // C99 6.5: Expressions.