forked from OSchip/llvm-project
- 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:
parent
21b691d573
commit
b419d3a80e
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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!");
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in New Issue