[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