[cfe-commits] r38824 - in /cfe/cfe/trunk: Parse/ParseDecl.cpp Parse/Parser.cpp include/clang/Basic/DiagnosticKinds.def include/clang/Parse/DeclSpec.h include/clang/Parse/Parser.h
sabre at cs.uiuc.edu
sabre at cs.uiuc.edu
Wed Jul 11 09:24:57 PDT 2007
Author: sabre
Date: Wed Jul 11 11:24:57 2007
New Revision: 38824
URL: http://llvm.org/viewvc/llvm-project?rev=38824&view=rev
Log:
Parse parenthesized and function declarators now, allowing us to parse things
like: "void (*signal(int, void (*)(int)))(int);"
Modified:
cfe/cfe/trunk/Parse/ParseDecl.cpp
cfe/cfe/trunk/Parse/Parser.cpp
cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/cfe/trunk/include/clang/Parse/DeclSpec.h
cfe/cfe/trunk/include/clang/Parse/Parser.h
Modified: cfe/cfe/trunk/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/ParseDecl.cpp?rev=38824&r1=38823&r2=38824&view=diff
==============================================================================
--- cfe/cfe/trunk/Parse/ParseDecl.cpp (original)
+++ cfe/cfe/trunk/Parse/ParseDecl.cpp Wed Jul 11 11:24:57 2007
@@ -160,6 +160,9 @@
//case tok::kw_union:
//case tok::kw_enum:
+ //case tok::identifier:
+ // TODO: handle typedef names.
+
// type-qualifier
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , PrevSpec, getLang())*2;
@@ -189,6 +192,56 @@
}
}
+/// isDeclarationSpecifier() - Return true if the current token is part of a
+/// declaration specifier.
+bool Parser::isDeclarationSpecifier() const {
+ switch (Tok.getKind()) {
+ default: return false;
+ // storage-class-specifier
+ case tok::kw_typedef:
+ case tok::kw_extern:
+ case tok::kw_static:
+ case tok::kw_auto:
+ case tok::kw_register:
+ case tok::kw___thread:
+
+ // type-specifiers
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw__Complex:
+ case tok::kw__Imaginary:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw__Bool:
+ case tok::kw__Decimal32:
+ case tok::kw__Decimal64:
+ case tok::kw__Decimal128:
+
+ // struct-or-union-specifier
+ case tok::kw_struct:
+ case tok::kw_union:
+ // enum-specifier
+ case tok::kw_enum:
+ // type-qualifier
+ case tok::kw_const:
+ case tok::kw_volatile:
+ case tok::kw_restrict:
+ // function-specifier
+ case tok::kw_inline:
+ return true;
+ // typedef-name
+ case tok::identifier:
+ // FIXME: if this is a typedef return true.
+ return false;
+ // TODO: Attributes.
+ }
+}
+
/// ParseDeclarator
/// declarator: [C99 6.7.5]
@@ -268,6 +321,55 @@
/// [GNU] direct-declarator '(' parameter-forward-declarations
/// parameter-type-list[opt] ')'
///
+void Parser::ParseDirectDeclarator(Declarator &D) {
+ // Parse the first direct-declarator seen.
+ if (Tok.getKind() == tok::identifier && D.mayHaveIdentifier()) {
+ assert(Tok.getIdentifierInfo() && "Not an identifier?");
+ D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+ ConsumeToken();
+ } else if (Tok.getKind() == tok::l_paren) {
+ // direct-declarator: '(' declarator ')'
+ // direct-declarator: '(' attributes declarator ')' [TODO]
+ // Example: 'char (*X)' or 'int (*XX)(void)'
+ ParseParenDeclarator(D);
+ } else if (Tok.getKind() == tok::l_square &&
+ D.mayOmitIdentifier()) {
+ // direct-abstract-declarator[opt] '[' assignment-expression[opt] ']'
+ // direct-abstract-declarator[opt] '[' '*' ']'
+
+ // direct-abstract-declarator was not specified. Remember that this is the
+ // place where the identifier would have been.
+ D.SetIdentifier(0, Tok.getLocation());
+ // Don't consume the '[', handle it below.
+ } else if (D.mayOmitIdentifier()) {
+ // This could be something simple like "int" (in which case the declarator
+ // portion is empty), if an abstract-declarator is allowed.
+ D.SetIdentifier(0, Tok.getLocation());
+ } else {
+ // expected identifier or '(' or '['.
+ assert(0 && "ERROR: should recover!");
+ }
+
+ assert(D.isPastIdentifier() &&
+ "Haven't past the location of the identifier yet?");
+
+ while (1) {
+ if (Tok.getKind() == tok::l_paren) {
+ ParseParenDeclarator(D);
+ } else if (Tok.getKind() == tok::l_square) {
+ assert(0 && "Unimp!");
+ } else {
+ break;
+ }
+ }
+}
+
+/// ParseParenDeclarator - We parsed the declarator D up to a paren. This may
+/// either be before the identifier (in which case these are just grouping
+/// parens for precedence) or it may be after the identifier, in which case
+/// these are function arguments.
+///
+/// This method also handles this portion of the grammar:
/// parameter-type-list: [C99 6.7.5]
/// parameter-list
/// parameter-list ',' '...'
@@ -278,33 +380,150 @@
///
/// parameter-declaration: [C99 6.7.5]
/// declaration-specifiers declarator
-/// [GNU] declaration-specifiers declarator attributes
+/// [GNU] declaration-specifiers declarator attributes [TODO]
/// declaration-specifiers abstract-declarator[opt]
-/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
+/// [GNU] declaration-specifiers abstract-declarator[opt] attributes [TODO]
///
/// identifier-list: [C99 6.7.5]
/// identifier
/// identifier-list ',' identifier
///
-void Parser::ParseDirectDeclarator(Declarator &D) {
- // Parse the first direct-declarator seen.
- if (Tok.getKind() == tok::identifier) {
- assert(Tok.getIdentifierInfo() && "Not an identifier?");
- D.SetIdentifier(Tok.getIdentifierInfo());
- ConsumeToken();
- } else if (0 && Tok.getKind() == tok::l_paren) {
- //char (*X);
- //int (*XX)(void);
- }
+void Parser::ParseParenDeclarator(Declarator &D) {
+ ConsumeParen();
- while (1) {
- if (Tok.getKind() == tok::l_paren) {
- assert(0 && "Unimp!");
- } else if (Tok.getKind() == tok::l_square) {
- assert(0 && "Unimp!");
+ // If we haven't past the identifier yet (or where the identifier would be
+ // stored, if this is an abstract declarator), then this is probably just
+ // grouping parens.
+ if (!D.isPastIdentifier()) {
+ // Okay, this is probably a grouping paren. However, if this could be an
+ // abstract-declarator, then this could also be the start of function
+ // arguments (consider 'void()').
+ bool isGrouping;
+
+ if (!D.mayOmitIdentifier()) {
+ // If this can't be an abstract-declarator, this *must* be a grouping
+ // paren, because we haven't seen the identifier yet.
+ isGrouping = true;
+ } else if (Tok.getKind() == tok::r_paren || // 'int()' is a function.
+ isDeclarationSpecifier()) { // 'int(int)' is a function.
+
+ isGrouping = false;
} else {
- break;
+ // Otherwise, 'int (*X)', this is a grouping paren.
+ isGrouping = true;
+ }
+
+ // If this is a grouping paren, handle:
+ // direct-declarator: '(' declarator ')'
+ // direct-declarator: '(' attributes declarator ')' [TODO]
+ if (isGrouping) {
+ ParseDeclarator(D);
+ // expected ')': skip until we find ')'.
+ if (Tok.getKind() != tok::r_paren)
+ assert(0 && "Recover!");
+ ConsumeParen();
+ return;
}
+
+ // Okay, if this wasn't a grouping paren, it must be the start of a function
+ // argument list. Recognize that this will never have an identifier (and
+ // where it would be), then fall through to the handling of argument lists.
+ D.SetIdentifier(0, Tok.getLocation());
}
+ // Okay, this is the parameter list of a function definition, or it is an
+ // identifier list of a K&R-style function.
+
+ // FIXME: enter function-declaration scope, limiting any declarators for
+ // arguments to the function scope.
+ // NOTE: better to only create a scope if not '()'
+ bool isVariadic;
+ bool HasPrototype;
+ if (Tok.getKind() == tok::r_paren) {
+ // int() -> no prototype, no '...'.
+ isVariadic = false;
+ HasPrototype = false;
+ } else if (Tok.getKind() == tok::identifier &&
+ 0/*TODO: !isatypedefname(Tok.getIdentifierInfo())*/) {
+ // 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!");
+
+ // If there was no identifier specified, either we are in an
+ // abstract-declarator, or we are in a parameter declarator which was found
+ // to be abstract. In abstract-declarators, identifier lists are not valid,
+ // diagnose this.
+ if (!D.getIdentifier())
+ Diag(Tok, diag::ext_ident_list_in_param);
+
+ // FIXME: Remember token.
+ ConsumeToken();
+ while (Tok.getKind() == tok::comma) {
+ // Eat the comma.
+ ConsumeToken();
+
+ // FIXME: if not identifier, consume until ')' then break.
+ assert(Tok.getKind() == tok::identifier);
+
+ // Eat the id.
+ // FIXME: remember it!
+ ConsumeToken();
+ }
+
+ // FIXME: if not identifier, consume until ')' then break.
+ assert(Tok.getKind() == tok::r_paren);
+
+ // K&R 'prototype'.
+ isVariadic = false;
+ HasPrototype = false;
+ } else {
+ isVariadic = false;
+ bool ReadArg = false;
+ // Finally, a normal, non-empty parameter type list.
+ while (1) {
+ if (Tok.getKind() == tok::ellipsis) {
+ isVariadic = true;
+
+ // Check to see if this is "void(...)" which is not allowed.
+ if (!ReadArg) {
+ // Otherwise, parse parameter type list. If it starts with an ellipsis,
+ // diagnose the malformed function.
+ Diag(Tok, diag::err_ellipsis_first_arg);
+ isVariadic = false; // Treat this like 'void()'.
+ }
+
+ // Consume the ellipsis.
+ ConsumeToken();
+ break;
+ }
+
+ ReadArg = true;
+
+ // Parse the declaration-specifiers.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+
+ // Parse the declarator. This is "PrototypeContext", because we must
+ // accept either 'declarator' or 'abstract-declarator' here.
+ Declarator DeclaratorInfo(DS, Declarator::PrototypeContext);
+ ParseDeclarator(DeclaratorInfo);
+
+ // TODO: do something with the declarator, if it is valid.
+
+ // If the next token is a comma, consume it and keep reading arguments.
+ if (Tok.getKind() != tok::comma) break;
+
+ // Consume the comma.
+ ConsumeToken();
+ }
+
+ HasPrototype = true;
+ }
+
+
+ // expected ')': skip until we find ')'.
+ if (Tok.getKind() != tok::r_paren)
+ assert(0 && "Recover!");
+ ConsumeParen();
}
+
Modified: cfe/cfe/trunk/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/Parser.cpp?rev=38824&r1=38823&r2=38824&view=diff
==============================================================================
--- cfe/cfe/trunk/Parse/Parser.cpp (original)
+++ cfe/cfe/trunk/Parse/Parser.cpp Wed Jul 11 11:24:57 2007
@@ -21,6 +21,7 @@
: PP(pp), Actions(actions), Diags(PP.getDiagnostics()) {
// Create the global scope, install it as the current scope.
CurScope = new Scope(0);
+ Tok.SetKind(tok::eof);
}
Parser::~Parser() {
@@ -109,7 +110,7 @@
// Parse the declarator.
{
- Declarator DeclaratorInfo(DS);
+ Declarator DeclaratorInfo(DS, Declarator::FileContext);
ParseDeclarator(DeclaratorInfo);
// If the declarator was a function type... handle it.
@@ -125,7 +126,7 @@
ConsumeToken();
// Parse the declarator.
- Declarator DeclaratorInfo(DS);
+ Declarator DeclaratorInfo(DS, Declarator::FileContext);
ParseDeclarator(DeclaratorInfo);
// declarator '=' initializer
Modified: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=38824&r1=38823&r2=38824&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:24:57 2007
@@ -250,6 +250,9 @@
DIAG(ext_thread_before, EXTENSION,
"'__thread' before 'static'")
+DIAG(ext_ident_list_in_param, EXTENSION,
+ "type-less parameter names in function declaration")
+
DIAG(err_parse_error, ERROR,
"parse error")
DIAG(err_invalid_decl_spec_combination, ERROR,
@@ -266,5 +269,7 @@
"'_Complex %s' is invalid")
DIAG(err_invalid_thread_spec, ERROR,
"'__thread %s' is invalid")
+DIAG(err_ellipsis_first_arg, ERROR,
+ "ISO C requires a named argument before '...'")
#undef DIAG
Modified: cfe/cfe/trunk/include/clang/Parse/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=38824&r1=38823&r2=38824&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/cfe/trunk/include/clang/Parse/DeclSpec.h Wed Jul 11 11:24:57 2007
@@ -15,11 +15,11 @@
#define LLVM_CLANG_PARSE_DECLARATIONS_H
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
namespace llvm {
namespace clang {
class LangOptions;
- class SourceLocation;
class IdentifierInfo;
/// DeclSpec - This class captures information about "declaration specifiers",
@@ -134,16 +134,58 @@
/// DeclaratorInfo - Information about one declarator, including the parsed type
/// information and the identifier. When the declarator is fully formed, this
/// is turned into the appropriate Decl object.
+///
+/// Declarators come in two types: normal declarators and abstract declarators.
+/// Abstract declarators are used when parsing types, and don't have an
+/// identifier. Normal declarators do have ID's. One strange case s
class Declarator {
const DeclSpec &DS;
IdentifierInfo *Identifier;
+ SourceLocation IdentifierLoc;
+
+public:
+ enum TheContext {
+ FileContext, // File scope declaration.
+ PrototypeContext, // Within a function prototype.
+ KNRTypeListContext, // K&R type definition list for formals.
+ TypeNameContext, // Abstract declarator for types.
+ MemberContext, // Struct/Union field.
+ BlockContext, // Declaration within a block in a function.
+ ForContext // Declaration within first part of a for loop.
+ };
+private:
+ /// Context - Where we are parsing this declarator.
+ ///
+ TheContext Context;
public:
- Declarator(const DeclSpec &ds) : DS(ds) {
- Identifier = 0;
+ Declarator(const DeclSpec &ds, TheContext C)
+ : DS(ds), Identifier(0), Context(C) {
}
+ /// mayOmitIdentifier - Return true if the identifier is either optional or
+ /// not allowed. This is true for typenames and prototypes.
+ bool mayOmitIdentifier() const {
+ return Context == TypeNameContext || Context == PrototypeContext;
+ }
+
+ /// mayHaveIdentifier - Return true if the identifier is either optional or
+ /// required. This is true for normal declarators and prototypes, but not
+ /// typenames.
+ bool mayHaveIdentifier() const {
+ return Context != TypeNameContext;
+ }
+
+ /// isPastIdentifier - Return true if we have parsed beyond the point where
+ /// the
+ bool isPastIdentifier() const { return IdentifierLoc.isValid(); }
+
IdentifierInfo *getIdentifier() const { return Identifier; }
- void SetIdentifier(IdentifierInfo *ID) { Identifier = ID; }
+ SourceLocation getIdentifierLoc() const { return IdentifierLoc; }
+
+ void SetIdentifier(IdentifierInfo *ID, SourceLocation Loc) {
+ Identifier = ID;
+ IdentifierLoc = Loc;
+ }
};
Modified: cfe/cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Parse/Parser.h?rev=38824&r1=38823&r2=38824&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/cfe/trunk/include/clang/Parse/Parser.h Wed Jul 11 11:24:57 2007
@@ -62,12 +62,24 @@
}
/// ConsumeToken - Consume the current 'peek token', lexing a new one and
- /// returning the token kind.
- tok::TokenKind ConsumeToken() {
+ /// returning the token kind. This does not work will all kinds of tokens,
+ /// strings and parens must be consumed with custom methods below.
+ void ConsumeToken() {
+ assert(Tok.getKind() != tok::string_literal &&
+ Tok.getKind() != tok::l_paren &&
+ Tok.getKind() != tok::r_paren &&
+ "Should consume special tokens with Consume*Token");
PP.Lex(Tok);
- return Tok.getKind();
}
+ /// ConsumeParen - This consume method keeps the paren count up-to-date.
+ ///
+ void ConsumeParen() {
+ assert((Tok.getKind() == tok::l_paren ||
+ Tok.getKind() == tok::r_paren) && "wrong consume method");
+ PP.Lex(Tok);
+ }
+
private:
//===--------------------------------------------------------------------===//
// C99 6.9: External Definitions.
@@ -78,10 +90,12 @@
//===--------------------------------------------------------------------===//
// C99 6.7: Declarations.
void ParseDeclarationSpecifiers(DeclSpec &DS);
+ bool isDeclarationSpecifier() const;
void ParseDeclarator(Declarator &D);
void ParseTypeQualifierListOpt(DeclSpec &DS);
void ParseDirectDeclarator(Declarator &D);
+ void ParseParenDeclarator(Declarator &D);
};
More information about the cfe-commits
mailing list