- 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
This commit is contained in:
Steve Naroff 2006-10-27 23:18:49 +00:00
parent 21b691d573
commit b419d3a80e
6 changed files with 157 additions and 33 deletions

View File

@ -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<TypedefInfo>();
return TI != 0 && TI->isTypedef;
bool EmptyAction::isTypeName(const IdentifierInfo &II, Scope *S) const {
TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>();
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<TypeNameInfo>();
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<TypedefInfo>();
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<TypeNameInfo>());
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<IdentifierInfo*>(*I);
TypedefInfo *TI = II.getFETokenInfo<TypedefInfo>();
TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>();
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);
}
}
}

View File

@ -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!");

View File

@ -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;

View File

@ -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<IdentifierInfo *, 8> 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() {
}

View File

@ -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

View File

@ -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.