Stage two of getting CFE top correct.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@39734 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Parse/AttributeList.cpp b/Parse/AttributeList.cpp
new file mode 100644
index 0000000..385dc03
--- /dev/null
+++ b/Parse/AttributeList.cpp
@@ -0,0 +1,27 @@
+//===--- AttributeList.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Steve Naroff and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AttributeList class implementation
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/AttributeList.h"
+#include "clang/Lex/IdentifierTable.h"
+using namespace clang;
+
+AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
+ IdentifierInfo *pName, SourceLocation pLoc,
+ Action::ExprTy **elist, unsigned numargs,
+ AttributeList *n)
+ : AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc),
+ NumArgs(numargs), Next(n) {
+ Args = new Action::ExprTy*[numargs];
+ for (unsigned i = 0; i != numargs; ++i)
+ Args[i] = elist[i];
+}
diff --git a/Parse/DeclSpec.cpp b/Parse/DeclSpec.cpp
new file mode 100644
index 0000000..117ff12
--- /dev/null
+++ b/Parse/DeclSpec.cpp
@@ -0,0 +1,285 @@
+//===--- SemaDeclSpec.cpp - Declaration Specifier Semantic Analysis -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for declaration specifiers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+using namespace clang;
+
+/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
+///
+unsigned DeclSpec::getParsedSpecifiers() const {
+ unsigned Res = 0;
+ if (StorageClassSpec != SCS_unspecified ||
+ SCS_thread_specified)
+ Res |= PQ_StorageClassSpecifier;
+
+ if (TypeQualifiers != TQ_unspecified)
+ Res |= PQ_TypeQualifier;
+
+ if (hasTypeSpecifier())
+ Res |= PQ_TypeSpecifier;
+
+ if (FS_inline_specified)
+ Res |= PQ_FunctionSpecifier;
+ return Res;
+}
+
+const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) {
+ switch (S) {
+ default: assert(0 && "Unknown typespec!");
+ case DeclSpec::SCS_unspecified: return "unspecified";
+ case DeclSpec::SCS_typedef: return "typedef";
+ case DeclSpec::SCS_extern: return "extern";
+ case DeclSpec::SCS_static: return "static";
+ case DeclSpec::SCS_auto: return "auto";
+ case DeclSpec::SCS_register: return "register";
+ }
+}
+
+static bool BadSpecifier(DeclSpec::SCS S, const char *&PrevSpec) {
+ PrevSpec = DeclSpec::getSpecifierName(S);
+ return true;
+}
+
+static bool BadSpecifier(DeclSpec::TSW W, const char *&PrevSpec) {
+ switch (W) {
+ case DeclSpec::TSW_unspecified: PrevSpec = "unspecified"; break;
+ case DeclSpec::TSW_short: PrevSpec = "short"; break;
+ case DeclSpec::TSW_long: PrevSpec = "long"; break;
+ case DeclSpec::TSW_longlong: PrevSpec = "long long"; break;
+ }
+ return true;
+}
+
+static bool BadSpecifier(DeclSpec::TSC C, const char *&PrevSpec) {
+ switch (C) {
+ case DeclSpec::TSC_unspecified: PrevSpec = "unspecified"; break;
+ case DeclSpec::TSC_imaginary: PrevSpec = "imaginary"; break;
+ case DeclSpec::TSC_complex: PrevSpec = "complex"; break;
+ }
+ return true;
+}
+
+
+static bool BadSpecifier(DeclSpec::TSS S, const char *&PrevSpec) {
+ switch (S) {
+ case DeclSpec::TSS_unspecified: PrevSpec = "unspecified"; break;
+ case DeclSpec::TSS_signed: PrevSpec = "signed"; break;
+ case DeclSpec::TSS_unsigned: PrevSpec = "unsigned"; break;
+ }
+ return true;
+}
+
+const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
+ switch (T) {
+ default: assert(0 && "Unknown typespec!");
+ case DeclSpec::TST_unspecified: return "unspecified";
+ case DeclSpec::TST_void: return "void";
+ case DeclSpec::TST_char: return "char";
+ case DeclSpec::TST_int: return "int";
+ case DeclSpec::TST_float: return "float";
+ case DeclSpec::TST_double: return "double";
+ case DeclSpec::TST_bool: return "_Bool";
+ case DeclSpec::TST_decimal32: return "_Decimal32";
+ case DeclSpec::TST_decimal64: return "_Decimal64";
+ case DeclSpec::TST_decimal128: return "_Decimal128";
+ case DeclSpec::TST_enum: return "enum";
+ case DeclSpec::TST_union: return "union";
+ case DeclSpec::TST_struct: return "struct";
+ case DeclSpec::TST_typedef: return "typedef";
+ }
+}
+
+static bool BadSpecifier(DeclSpec::TST T, const char *&PrevSpec) {
+ PrevSpec = DeclSpec::getSpecifierName(T);
+ return true;
+}
+
+static bool BadSpecifier(DeclSpec::TQ T, const char *&PrevSpec) {
+ switch (T) {
+ case DeclSpec::TQ_unspecified: PrevSpec = "unspecified"; break;
+ case DeclSpec::TQ_const: PrevSpec = "const"; break;
+ case DeclSpec::TQ_restrict: PrevSpec = "restrict"; break;
+ case DeclSpec::TQ_volatile: PrevSpec = "volatile"; break;
+ }
+ return true;
+}
+
+bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (StorageClassSpec != SCS_unspecified)
+ return BadSpecifier(StorageClassSpec, PrevSpec);
+ StorageClassSpec = S;
+ StorageClassSpecLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (SCS_thread_specified) {
+ PrevSpec = "__thread";
+ return true;
+ }
+ SCS_thread_specified = true;
+ SCS_threadLoc = Loc;
+ return false;
+}
+
+
+/// These methods set the specified attribute of the DeclSpec, but return true
+/// and ignore the request if invalid (e.g. "extern" then "auto" is
+/// specified).
+bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (TypeSpecWidth != TSW_unspecified &&
+ // Allow turning long -> long long.
+ (W != TSW_longlong || TypeSpecWidth != TSW_long))
+ return BadSpecifier(TypeSpecWidth, PrevSpec);
+ TypeSpecWidth = W;
+ TSWLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (TypeSpecComplex != TSC_unspecified)
+ return BadSpecifier(TypeSpecComplex, PrevSpec);
+ TypeSpecComplex = C;
+ TSCLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (TypeSpecSign != TSS_unspecified)
+ return BadSpecifier(TypeSpecSign, PrevSpec);
+ TypeSpecSign = S;
+ TSSLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
+ const char *&PrevSpec, void *Rep) {
+ if (TypeSpecType != TST_unspecified)
+ return BadSpecifier(TypeSpecType, PrevSpec);
+ TypeSpecType = T;
+ TypeRep = Rep;
+ TSTLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
+ const LangOptions &Lang) {
+ // Duplicates turn into warnings pre-C99.
+ if ((TypeQualifiers & T) && !Lang.C99)
+ return BadSpecifier(T, PrevSpec);
+ TypeQualifiers |= T;
+
+ switch (T) {
+ default: assert(0 && "Unknown type qualifier!");
+ case TQ_const: TQ_constLoc = Loc; break;
+ case TQ_restrict: TQ_restrictLoc = Loc; break;
+ case TQ_volatile: TQ_volatileLoc = Loc; break;
+ }
+ return false;
+}
+
+bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec){
+ // 'inline inline' is ok.
+ FS_inline_specified = true;
+ FS_inlineLoc = Loc;
+ return false;
+}
+
+
+/// Finish - This does final analysis of the declspec, rejecting things like
+/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
+/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
+/// DeclSpec is guaranteed self-consistent, even if an error occurred.
+void DeclSpec::Finish(Diagnostic &D, const LangOptions &Lang) {
+ // Check the type specifier components first.
+
+ // signed/unsigned are only valid with int/char.
+ if (TypeSpecSign != TSS_unspecified) {
+ if (TypeSpecType == TST_unspecified)
+ TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int.
+ else if (TypeSpecType != TST_int && TypeSpecType != TST_char) {
+ Diag(D, TSSLoc, diag::err_invalid_sign_spec,
+ getSpecifierName(TypeSpecType));
+ // signed double -> double.
+ TypeSpecSign = TSS_unspecified;
+ }
+ }
+
+ // Validate the width of the type.
+ switch (TypeSpecWidth) {
+ case TSW_unspecified: break;
+ case TSW_short: // short int
+ case TSW_longlong: // long long int
+ if (TypeSpecType == TST_unspecified)
+ TypeSpecType = TST_int; // short -> short int, long long -> long long int.
+ else if (TypeSpecType != TST_int) {
+ Diag(D, TSWLoc,
+ TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec
+ : diag::err_invalid_longlong_spec,
+ getSpecifierName(TypeSpecType));
+ TypeSpecType = TST_int;
+ }
+ break;
+ case TSW_long: // long double, long int
+ if (TypeSpecType == TST_unspecified)
+ TypeSpecType = TST_int; // long -> long int.
+ else if (TypeSpecType != TST_int && TypeSpecType != TST_double) {
+ Diag(D, TSWLoc, diag::err_invalid_long_spec,
+ getSpecifierName(TypeSpecType));
+ TypeSpecType = TST_int;
+ }
+ break;
+ }
+
+ // TODO: if the implementation does not implement _Complex or _Imaginary,
+ // disallow their use. Need information about the backend.
+ if (TypeSpecComplex != TSC_unspecified) {
+ if (TypeSpecType == TST_unspecified) {
+ Diag(D, TSCLoc, diag::ext_plain_complex);
+ TypeSpecType = TST_double; // _Complex -> _Complex double.
+ } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) {
+ // Note that this intentionally doesn't include _Complex _Bool.
+ Diag(D, TSTLoc, diag::ext_integer_complex);
+ } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) {
+ Diag(D, TSCLoc, diag::err_invalid_complex_spec,
+ getSpecifierName(TypeSpecType));
+ TypeSpecComplex = TSC_unspecified;
+ }
+ }
+
+ // Verify __thread.
+ if (SCS_thread_specified) {
+ if (StorageClassSpec == SCS_unspecified) {
+ StorageClassSpec = SCS_extern; // '__thread int' -> 'extern __thread int'
+ } else if (StorageClassSpec != SCS_extern &&
+ StorageClassSpec != SCS_static) {
+ Diag(D, getStorageClassSpecLoc(), diag::err_invalid_thread_spec,
+ getSpecifierName(StorageClassSpec));
+ SCS_thread_specified = false;
+ }
+ }
+
+ // Okay, now we can infer the real type.
+ // TODO: infer real type.
+
+ // TODO: return "auto function" and other bad things based on the real type.
+
+ // 'data definition has no type or storage class'?
+}
diff --git a/Parse/Makefile b/Parse/Makefile
new file mode 100644
index 0000000..60e70f2
--- /dev/null
+++ b/Parse/Makefile
@@ -0,0 +1,22 @@
+##===- clang/Parse/Makefile --------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file was developed by Chris Lattner and is distributed under
+# the University of Illinois Open Source License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements the Parser library for the C-Language front-end.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../..
+LIBRARYNAME := clangParse
+BUILD_ARCHIVE = 1
+CXXFLAGS = -fno-rtti
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/Parse/MinimalAction.cpp b/Parse/MinimalAction.cpp
new file mode 100644
index 0000000..65bdca6
--- /dev/null
+++ b/Parse/MinimalAction.cpp
@@ -0,0 +1,105 @@
+//===--- MinimalAction.cpp - Implement the MinimalAction class ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the MinimalAction interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+using namespace clang;
+
+/// TypeNameInfo - A link exists here for each scope that an identifier is
+/// defined.
+struct TypeNameInfo {
+ TypeNameInfo *Prev;
+ bool isTypeName;
+
+ TypeNameInfo(bool istypename, TypeNameInfo *prev) {
+ isTypeName = istypename;
+ Prev = prev;
+ }
+};
+
+/// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to
+/// determine whether the name is a type name (objc class name or typedef) or
+/// not in this scope.
+Action::DeclTy *
+MinimalAction::isTypeName(const IdentifierInfo &II, Scope *S) const {
+ if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>())
+ if (TI->isTypeName)
+ return TI;
+ return 0;
+}
+
+/// ParseDeclarator - If this is a typedef declarator, we modify the
+/// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is
+/// popped.
+Action::DeclTy *
+MinimalAction::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 (II == 0) return 0;
+
+ TypeNameInfo *weCurrentlyHaveTypeInfo = II->getFETokenInfo<TypeNameInfo>();
+ bool isTypeName =
+ D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef;
+
+ // 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);
+ }
+ return 0;
+}
+
+/// ParsedObjcClassDeclaration -
+/// Scope will always be top level file scope.
+Action::DeclTy *
+MinimalAction::ParsedObjcClassDeclaration(Scope *S,
+ IdentifierInfo **IdentList,
+ unsigned NumElts) {
+ for (unsigned i = 0; i != NumElts; ++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;
+}
+
+/// PopScope - When a scope is popped, if any typedefs are now out-of-scope,
+/// they are removed from the IdentifierInfo::FETokenInfo field.
+void MinimalAction::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);
+ TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>();
+ assert(TI && "This decl didn't get pushed??");
+
+ if (TI) {
+ TypeNameInfo *Next = TI->Prev;
+ delete TI;
+
+ II.setFETokenInfo(Next);
+ }
+ }
+}
diff --git a/Parse/ParseDecl.cpp b/Parse/ParseDecl.cpp
new file mode 100644
index 0000000..02a79e6
--- /dev/null
+++ b/Parse/ParseDecl.cpp
@@ -0,0 +1,1396 @@
+//===--- ParseDecl.cpp - Declaration Parsing ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Declaration portions of the Parser interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/ADT/SmallSet.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// C99 6.7: Declarations.
+//===----------------------------------------------------------------------===//
+
+/// ParseTypeName
+/// type-name: [C99 6.7.6]
+/// specifier-qualifier-list abstract-declarator[opt]
+Parser::TypeTy *Parser::ParseTypeName() {
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseSpecifierQualifierList(DS);
+
+ // Parse the abstract-declarator, if present.
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ ParseDeclarator(DeclaratorInfo);
+
+ return Actions.ParseTypeName(CurScope, DeclaratorInfo).Val;
+}
+
+/// ParseAttributes - Parse a non-empty attributes list.
+///
+/// [GNU] attributes:
+/// attribute
+/// attributes attribute
+///
+/// [GNU] attribute:
+/// '__attribute__' '(' '(' attribute-list ')' ')'
+///
+/// [GNU] attribute-list:
+/// attrib
+/// attribute_list ',' attrib
+///
+/// [GNU] attrib:
+/// empty
+/// attrib-name
+/// attrib-name '(' identifier ')'
+/// attrib-name '(' identifier ',' nonempty-expr-list ')'
+/// attrib-name '(' argument-expression-list [C99 6.5.2] ')'
+///
+/// [GNU] attrib-name:
+/// identifier
+/// typespec
+/// typequal
+/// storageclass
+///
+/// FIXME: The GCC grammar/code for this construct implies we need two
+/// token lookahead. Comment from gcc: "If they start with an identifier
+/// which is followed by a comma or close parenthesis, then the arguments
+/// start with that identifier; otherwise they are an expression list."
+///
+/// At the moment, I am not doing 2 token lookahead. I am also unaware of
+/// any attributes that don't work (based on my limited testing). Most
+/// attributes are very simple in practice. Until we find a bug, I don't see
+/// a pressing need to implement the 2 token lookahead.
+
+AttributeList *Parser::ParseAttributes() {
+ assert(Tok.getKind() == tok::kw___attribute && "Not an attribute list!");
+
+ AttributeList *CurrAttr = 0;
+
+ while (Tok.getKind() == tok::kw___attribute) {
+ ConsumeToken();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+ "attribute")) {
+ SkipUntil(tok::r_paren, true); // skip until ) or ;
+ return CurrAttr;
+ }
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) {
+ SkipUntil(tok::r_paren, true); // skip until ) or ;
+ return CurrAttr;
+ }
+ // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") ))
+ while (Tok.getKind() == tok::identifier || isDeclarationSpecifier() ||
+ Tok.getKind() == tok::comma) {
+
+ if (Tok.getKind() == tok::comma) {
+ // allows for empty/non-empty attributes. ((__vector_size__(16),,,,))
+ ConsumeToken();
+ continue;
+ }
+ // we have an identifier or declaration specifier (const, int, etc.)
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = ConsumeToken();
+
+ // check if we have a "paramterized" attribute
+ if (Tok.getKind() == tok::l_paren) {
+ ConsumeParen(); // ignore the left paren loc for now
+
+ if (Tok.getKind() == tok::identifier) {
+ IdentifierInfo *ParmName = Tok.getIdentifierInfo();
+ SourceLocation ParmLoc = ConsumeToken();
+
+ if (Tok.getKind() == tok::r_paren) {
+ // __attribute__(( mode(byte) ))
+ ConsumeParen(); // ignore the right paren loc for now
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ ParmName, ParmLoc, 0, 0, CurrAttr);
+ } else if (Tok.getKind() == tok::comma) {
+ ConsumeToken();
+ // __attribute__(( format(printf, 1, 2) ))
+ llvm::SmallVector<ExprTy*, 8> ArgExprs;
+ bool ArgExprsOk = true;
+
+ // now parse the non-empty comma separated list of expressions
+ while (1) {
+ ExprResult ArgExpr = ParseAssignmentExpression();
+ if (ArgExpr.isInvalid) {
+ ArgExprsOk = false;
+ SkipUntil(tok::r_paren);
+ break;
+ } else {
+ ArgExprs.push_back(ArgExpr.Val);
+ }
+ if (Tok.getKind() != tok::comma)
+ break;
+ ConsumeToken(); // Eat the comma, move to the next argument
+ }
+ if (ArgExprsOk && Tok.getKind() == tok::r_paren) {
+ ConsumeParen(); // ignore the right paren loc for now
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName,
+ ParmLoc, &ArgExprs[0], ArgExprs.size(), CurrAttr);
+ }
+ }
+ } else { // not an identifier
+ // parse a possibly empty comma separated list of expressions
+ if (Tok.getKind() == tok::r_paren) {
+ // __attribute__(( nonnull() ))
+ ConsumeParen(); // ignore the right paren loc for now
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ 0, SourceLocation(), 0, 0, CurrAttr);
+ } else {
+ // __attribute__(( aligned(16) ))
+ llvm::SmallVector<ExprTy*, 8> ArgExprs;
+ bool ArgExprsOk = true;
+
+ // now parse the list of expressions
+ while (1) {
+ ExprResult ArgExpr = ParseAssignmentExpression();
+ if (ArgExpr.isInvalid) {
+ ArgExprsOk = false;
+ SkipUntil(tok::r_paren);
+ break;
+ } else {
+ ArgExprs.push_back(ArgExpr.Val);
+ }
+ if (Tok.getKind() != tok::comma)
+ break;
+ ConsumeToken(); // Eat the comma, move to the next argument
+ }
+ // Match the ')'.
+ if (ArgExprsOk && Tok.getKind() == tok::r_paren) {
+ ConsumeParen(); // ignore the right paren loc for now
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+ SourceLocation(), &ArgExprs[0], ArgExprs.size(),
+ CurrAttr);
+ }
+ }
+ }
+ } else {
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ 0, SourceLocation(), 0, 0, CurrAttr);
+ }
+ }
+ if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
+ SkipUntil(tok::r_paren, false);
+ if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
+ SkipUntil(tok::r_paren, false);
+ }
+ return CurrAttr;
+}
+
+/// ParseDeclaration - Parse a full 'declaration', which consists of
+/// declaration-specifiers, some number of declarators, and a semicolon.
+/// 'Context' should be a Declarator::TheContext value.
+Parser::DeclTy *Parser::ParseDeclaration(unsigned Context) {
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+
+ // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
+ // declaration-specifiers init-declarator-list[opt] ';'
+ if (Tok.getKind() == tok::semi) {
+ ConsumeToken();
+ return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ }
+
+ Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context);
+ ParseDeclarator(DeclaratorInfo);
+
+ return ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
+}
+
+/// ParseInitDeclaratorListAfterFirstDeclarator - Parse 'declaration' after
+/// parsing 'declaration-specifiers declarator'. This method is split out this
+/// way to handle the ambiguity between top-level function-definitions and
+/// declarations.
+///
+/// declaration: [C99 6.7]
+/// declaration-specifiers init-declarator-list[opt] ';' [TODO]
+/// [!C99] init-declarator-list ';' [TODO]
+/// [OMP] threadprivate-directive [TODO]
+///
+/// init-declarator-list: [C99 6.7]
+/// init-declarator
+/// init-declarator-list ',' init-declarator
+/// init-declarator: [C99 6.7]
+/// declarator
+/// declarator '=' initializer
+/// [GNU] declarator simple-asm-expr[opt] attributes[opt]
+/// [GNU] declarator simple-asm-expr[opt] attributes[opt] '=' initializer
+///
+Parser::DeclTy *Parser::
+ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
+
+ // Declarators may be grouped together ("int X, *Y, Z();"). Provide info so
+ // that they can be chained properly if the actions want this.
+ Parser::DeclTy *LastDeclInGroup = 0;
+
+ // At this point, we know that it is not a function definition. Parse the
+ // rest of the init-declarator-list.
+ while (1) {
+ // If a simple-asm-expr is present, parse it.
+ if (Tok.getKind() == tok::kw_asm)
+ ParseSimpleAsm();
+
+ // If attributes are present, parse them.
+ if (Tok.getKind() == tok::kw___attribute)
+ D.AddAttributes(ParseAttributes());
+
+ // Parse declarator '=' initializer.
+ ExprResult Init;
+ if (Tok.getKind() == tok::equal) {
+ ConsumeToken();
+ Init = ParseInitializer();
+ if (Init.isInvalid) {
+ SkipUntil(tok::semi);
+ return 0;
+ }
+ }
+
+ // Inform the current actions module that we just parsed this declarator.
+ // FIXME: pass asm & attributes.
+ LastDeclInGroup = Actions.ParseDeclarator(CurScope, D, Init.Val,
+ LastDeclInGroup);
+
+ // If we don't have a comma, it is either the end of the list (a ';') or an
+ // error, bail out.
+ if (Tok.getKind() != tok::comma)
+ break;
+
+ // Consume the comma.
+ ConsumeToken();
+
+ // Parse the next declarator.
+ D.clear();
+ ParseDeclarator(D);
+ }
+
+ if (Tok.getKind() == tok::semi) {
+ ConsumeToken();
+ return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup);
+ }
+
+ Diag(Tok, diag::err_parse_error);
+ // Skip to end of block or statement
+ SkipUntil(tok::r_brace, true);
+ if (Tok.getKind() == tok::semi)
+ ConsumeToken();
+ return 0;
+}
+
+/// ParseSpecifierQualifierList
+/// specifier-qualifier-list:
+/// type-specifier specifier-qualifier-list[opt]
+/// type-qualifier specifier-qualifier-list[opt]
+/// [GNU] attributes specifier-qualifier-list[opt]
+///
+void Parser::ParseSpecifierQualifierList(DeclSpec &DS) {
+ /// specifier-qualifier-list is a subset of declaration-specifiers. Just
+ /// parse declaration-specifiers and complain about extra stuff.
+ SourceLocation Loc = Tok.getLocation();
+ ParseDeclarationSpecifiers(DS);
+
+ // Validate declspec for type-name.
+ unsigned Specs = DS.getParsedSpecifiers();
+ if (Specs == DeclSpec::PQ_None)
+ Diag(Tok, diag::err_typename_requires_specqual);
+
+ // Issue diagnostic and remove storage class if present.
+ if (Specs & DeclSpec::PQ_StorageClassSpecifier) {
+ if (DS.getStorageClassSpecLoc().isValid())
+ Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass);
+ else
+ Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass);
+ DS.ClearStorageClassSpecs();
+ }
+
+ // Issue diagnostic and remove function specfier if present.
+ if (Specs & DeclSpec::PQ_FunctionSpecifier) {
+ Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec);
+ DS.ClearFunctionSpecs();
+ }
+}
+
+/// ParseDeclarationSpecifiers
+/// declaration-specifiers: [C99 6.7]
+/// storage-class-specifier declaration-specifiers[opt]
+/// type-specifier declaration-specifiers[opt]
+/// type-qualifier declaration-specifiers[opt]
+/// [C99] function-specifier declaration-specifiers[opt]
+/// [GNU] attributes declaration-specifiers[opt]
+///
+/// storage-class-specifier: [C99 6.7.1]
+/// 'typedef'
+/// 'extern'
+/// 'static'
+/// 'auto'
+/// 'register'
+/// [GNU] '__thread'
+/// type-specifier: [C99 6.7.2]
+/// 'void'
+/// 'char'
+/// 'short'
+/// 'int'
+/// 'long'
+/// 'float'
+/// 'double'
+/// 'signed'
+/// 'unsigned'
+/// struct-or-union-specifier
+/// enum-specifier
+/// typedef-name
+/// [C++] 'bool'
+/// [C99] '_Bool'
+/// [C99] '_Complex'
+/// [C99] '_Imaginary' // Removed in TC2?
+/// [GNU] '_Decimal32'
+/// [GNU] '_Decimal64'
+/// [GNU] '_Decimal128'
+/// [GNU] typeof-specifier [TODO]
+/// [OBJC] class-name objc-protocol-refs[opt] [TODO]
+/// [OBJC] typedef-name objc-protocol-refs [TODO]
+/// [OBJC] objc-protocol-refs [TODO]
+/// type-qualifier:
+/// 'const'
+/// 'volatile'
+/// [C99] 'restrict'
+/// function-specifier: [C99 6.7.4]
+/// [C99] 'inline'
+///
+void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) {
+ while (1) {
+ int isInvalid = false;
+ const char *PrevSpec = 0;
+ SourceLocation Loc = Tok.getLocation();
+
+ switch (Tok.getKind()) {
+ // typedef-name
+ case tok::identifier:
+ // This identifier can only be a typedef name if we haven't already seen
+ // a type-specifier. Without this check we misparse:
+ // typedef int X; struct Y { short X; }; as 'short int'.
+ if (!DS.hasTypeSpecifier()) {
+ // It has to be available as a typedef too!
+ if (void *TypeRep = Actions.isTypeName(*Tok.getIdentifierInfo(),
+ CurScope)) {
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec,
+ TypeRep);
+ break;
+ }
+ }
+ // FALL THROUGH.
+ default:
+ // If this is not a declaration specifier token, we're done reading decl
+ // specifiers. First verify that DeclSpec's are consistent.
+ DS.Finish(Diags, getLang());
+ return;
+
+ // GNU attributes support.
+ case tok::kw___attribute:
+ DS.AddAttributes(ParseAttributes());
+ continue;
+
+ // storage-class-specifier
+ case tok::kw_typedef:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec);
+ break;
+ case tok::kw_extern:
+ if (DS.isThreadSpecified())
+ Diag(Tok, diag::ext_thread_before, "extern");
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec);
+ break;
+ case tok::kw_static:
+ if (DS.isThreadSpecified())
+ Diag(Tok, diag::ext_thread_before, "static");
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec);
+ break;
+ case tok::kw_auto:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec);
+ break;
+ case tok::kw_register:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec);
+ break;
+ case tok::kw___thread:
+ isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2;
+ break;
+
+ // type-specifiers
+ case tok::kw_short:
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
+ break;
+ case tok::kw_long:
+ if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
+ else
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec);
+ break;
+ case tok::kw_signed:
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
+ break;
+ case tok::kw_unsigned:
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
+ break;
+ case tok::kw__Complex:
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec);
+ break;
+ case tok::kw__Imaginary:
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec);
+ break;
+ case tok::kw_void:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
+ break;
+ case tok::kw_char:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
+ break;
+ case tok::kw_int:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
+ break;
+ case tok::kw_float:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
+ break;
+ case tok::kw_double:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
+ break;
+ case tok::kw_bool: // [C++ 2.11p1]
+ case tok::kw__Bool:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal32:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal64:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal128:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec);
+ break;
+
+ case tok::kw_struct:
+ case tok::kw_union:
+ ParseStructUnionSpecifier(DS);
+ continue;
+ case tok::kw_enum:
+ ParseEnumSpecifier(DS);
+ continue;
+
+ // type-qualifier
+ case tok::kw_const:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_volatile:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_restrict:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
+ getLang())*2;
+ break;
+
+ // function-specifier
+ case tok::kw_inline:
+ isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec);
+ break;
+ }
+ // If the specifier combination wasn't legal, issue a diagnostic.
+ if (isInvalid) {
+ assert(PrevSpec && "Method did not return previous specifier!");
+ if (isInvalid == 1) // Error.
+ Diag(Tok, diag::err_invalid_decl_spec_combination, PrevSpec);
+ else // extwarn.
+ Diag(Tok, diag::ext_duplicate_declspec, PrevSpec);
+ }
+ ConsumeToken();
+ }
+}
+
+/// ParseTag - Parse "struct-or-union-or-class-or-enum identifier[opt]", where
+/// the first token has already been read and has been turned into an instance
+/// of DeclSpec::TST (TagType). This returns true if there is an error parsing,
+/// otherwise it returns false and fills in Decl.
+bool Parser::ParseTag(DeclTy *&Decl, unsigned TagType, SourceLocation StartLoc){
+ AttributeList *Attr = 0;
+ // If attributes exist after tag, parse them.
+ if (Tok.getKind() == tok::kw___attribute)
+ Attr = ParseAttributes();
+
+ // Must have either 'struct name' or 'struct {...}'.
+ if (Tok.getKind() != tok::identifier &&
+ Tok.getKind() != tok::l_brace) {
+ Diag(Tok, diag::err_expected_ident_lbrace);
+ // TODO: better error recovery here.
+ return true;
+ }
+
+ // If an identifier is present, consume and remember it.
+ IdentifierInfo *Name = 0;
+ SourceLocation NameLoc;
+ if (Tok.getKind() == tok::identifier) {
+ Name = Tok.getIdentifierInfo();
+ NameLoc = ConsumeToken();
+ }
+
+ // There are three options here. If we have 'struct foo;', then this is a
+ // forward declaration. If we have 'struct foo {...' then this is a
+ // definition. Otherwise we have something like 'struct foo xyz', a reference.
+ //
+ // This is needed to handle stuff like this right (C99 6.7.2.3p11):
+ // struct foo {..}; void bar() { struct foo; } <- new foo in bar.
+ // struct foo {..}; void bar() { struct foo x; } <- use of old foo.
+ //
+ Action::TagKind TK;
+ if (Tok.getKind() == tok::l_brace)
+ TK = Action::TK_Definition;
+ else if (Tok.getKind() == tok::semi)
+ TK = Action::TK_Declaration;
+ else
+ TK = Action::TK_Reference;
+ Decl = Actions.ParseTag(CurScope, TagType, TK, StartLoc, Name, NameLoc, Attr);
+ return false;
+}
+
+
+/// ParseStructUnionSpecifier
+/// struct-or-union-specifier: [C99 6.7.2.1]
+/// struct-or-union identifier[opt] '{' struct-contents '}'
+/// struct-or-union identifier
+/// [GNU] struct-or-union attributes[opt] identifier[opt] '{' struct-contents
+/// '}' attributes[opt]
+/// [GNU] struct-or-union attributes[opt] identifier
+/// struct-or-union:
+/// 'struct'
+/// 'union'
+///
+void Parser::ParseStructUnionSpecifier(DeclSpec &DS) {
+ assert((Tok.getKind() == tok::kw_struct ||
+ Tok.getKind() == tok::kw_union) && "Not a struct/union specifier");
+ DeclSpec::TST TagType =
+ Tok.getKind() == tok::kw_union ? DeclSpec::TST_union : DeclSpec::TST_struct;
+ SourceLocation StartLoc = ConsumeToken();
+
+ // Parse the tag portion of this.
+ DeclTy *TagDecl;
+ if (ParseTag(TagDecl, TagType, StartLoc))
+ return;
+
+ // If there is a body, parse it and inform the actions module.
+ if (Tok.getKind() == tok::l_brace)
+ ParseStructUnionBody(StartLoc, TagType, TagDecl);
+
+ const char *PrevSpec = 0;
+ if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, TagDecl))
+ Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec);
+}
+
+
+/// ParseStructUnionBody
+/// struct-contents:
+/// struct-declaration-list
+/// [EXT] empty
+/// [GNU] "struct-declaration-list" without terminatoring ';'
+/// struct-declaration-list:
+/// struct-declaration
+/// struct-declaration-list struct-declaration
+/// [OBC] '@' 'defs' '(' class-name ')' [TODO]
+/// struct-declaration:
+/// specifier-qualifier-list struct-declarator-list ';'
+/// [GNU] __extension__ struct-declaration
+/// [GNU] specifier-qualifier-list ';'
+/// struct-declarator-list:
+/// struct-declarator
+/// struct-declarator-list ',' struct-declarator
+/// [GNU] struct-declarator-list ',' attributes[opt] struct-declarator
+/// struct-declarator:
+/// declarator
+/// [GNU] declarator attributes[opt]
+/// declarator[opt] ':' constant-expression
+/// [GNU] declarator[opt] ':' constant-expression attributes[opt]
+///
+void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
+ unsigned TagType, DeclTy *TagDecl) {
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in
+ // C++.
+ if (Tok.getKind() == tok::r_brace)
+ Diag(Tok, diag::ext_empty_struct_union_enum,
+ DeclSpec::getSpecifierName((DeclSpec::TST)TagType));
+
+ llvm::SmallVector<DeclTy*, 32> FieldDecls;
+
+ // While we still have something to read, read the declarations in the struct.
+ while (Tok.getKind() != tok::r_brace &&
+ Tok.getKind() != tok::eof) {
+ // Each iteration of this loop reads one struct-declaration.
+
+ // Check for extraneous top-level semicolon.
+ if (Tok.getKind() == tok::semi) {
+ Diag(Tok, diag::ext_extra_struct_semi);
+ ConsumeToken();
+ continue;
+ }
+
+ // FIXME: When __extension__ is specified, disable extension diagnostics.
+ if (Tok.getKind() == tok::kw___extension__)
+ ConsumeToken();
+
+ // Parse the common specifier-qualifiers-list piece.
+ DeclSpec DS;
+ SourceLocation SpecQualLoc = Tok.getLocation();
+ ParseSpecifierQualifierList(DS);
+ // TODO: Does specifier-qualifier list correctly check that *something* is
+ // specified?
+
+ // If there are no declarators, issue a warning.
+ if (Tok.getKind() == tok::semi) {
+ Diag(SpecQualLoc, diag::w_no_declarators);
+ ConsumeToken();
+ continue;
+ }
+
+ // Read struct-declarators until we find the semicolon.
+ Declarator DeclaratorInfo(DS, Declarator::MemberContext);
+
+ while (1) {
+ /// struct-declarator: declarator
+ /// struct-declarator: declarator[opt] ':' constant-expression
+ if (Tok.getKind() != tok::colon)
+ ParseDeclarator(DeclaratorInfo);
+
+ ExprTy *BitfieldSize = 0;
+ if (Tok.getKind() == tok::colon) {
+ ConsumeToken();
+ ExprResult Res = ParseConstantExpression();
+ if (Res.isInvalid) {
+ SkipUntil(tok::semi, true, true);
+ } else {
+ BitfieldSize = Res.Val;
+ }
+ }
+
+ // If attributes exist after the declarator, parse them.
+ if (Tok.getKind() == tok::kw___attribute)
+ DeclaratorInfo.AddAttributes(ParseAttributes());
+
+ // Install the declarator into the current TagDecl.
+ DeclTy *Field = Actions.ParseField(CurScope, TagDecl, SpecQualLoc,
+ DeclaratorInfo, BitfieldSize);
+ FieldDecls.push_back(Field);
+
+ // If we don't have a comma, it is either the end of the list (a ';')
+ // or an error, bail out.
+ if (Tok.getKind() != tok::comma)
+ break;
+
+ // Consume the comma.
+ ConsumeToken();
+
+ // Parse the next declarator.
+ DeclaratorInfo.clear();
+
+ // Attributes are only allowed on the second declarator.
+ if (Tok.getKind() == tok::kw___attribute)
+ DeclaratorInfo.AddAttributes(ParseAttributes());
+ }
+
+ if (Tok.getKind() == tok::semi) {
+ ConsumeToken();
+ } else if (Tok.getKind() == tok::r_brace) {
+ Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list);
+ break;
+ } else {
+ Diag(Tok, diag::err_expected_semi_decl_list);
+ // Skip to end of block or statement
+ SkipUntil(tok::r_brace, true, true);
+ }
+ }
+
+ MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+
+ Actions.ParseRecordBody(RecordLoc, TagDecl, &FieldDecls[0],FieldDecls.size());
+
+ AttributeList *AttrList = 0;
+ // If attributes exist after struct contents, parse them.
+ if (Tok.getKind() == tok::kw___attribute)
+ AttrList = ParseAttributes(); // FIXME: where should I put them?
+}
+
+
+/// ParseEnumSpecifier
+/// enum-specifier: [C99 6.7.2.2]
+/// 'enum' identifier[opt] '{' enumerator-list '}'
+/// [C99] 'enum' identifier[opt] '{' enumerator-list ',' '}'
+/// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt]
+/// '}' attributes[opt]
+/// 'enum' identifier
+/// [GNU] 'enum' attributes[opt] identifier
+void Parser::ParseEnumSpecifier(DeclSpec &DS) {
+ assert(Tok.getKind() == tok::kw_enum && "Not an enum specifier");
+ SourceLocation StartLoc = ConsumeToken();
+
+ // Parse the tag portion of this.
+ DeclTy *TagDecl;
+ if (ParseTag(TagDecl, DeclSpec::TST_enum, StartLoc))
+ return;
+
+ if (Tok.getKind() == tok::l_brace)
+ ParseEnumBody(StartLoc, TagDecl);
+
+ // TODO: semantic analysis on the declspec for enums.
+ const char *PrevSpec = 0;
+ if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, TagDecl))
+ Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec);
+}
+
+/// ParseEnumBody - Parse a {} enclosed enumerator-list.
+/// enumerator-list:
+/// enumerator
+/// enumerator-list ',' enumerator
+/// enumerator:
+/// enumeration-constant
+/// enumeration-constant '=' constant-expression
+/// enumeration-constant:
+/// identifier
+///
+void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) {
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ if (Tok.getKind() == tok::r_brace)
+ Diag(Tok, diag::ext_empty_struct_union_enum, "enum");
+
+ llvm::SmallVector<DeclTy*, 32> EnumConstantDecls;
+
+ DeclTy *LastEnumConstDecl = 0;
+
+ // Parse the enumerator-list.
+ while (Tok.getKind() == tok::identifier) {
+ IdentifierInfo *Ident = Tok.getIdentifierInfo();
+ SourceLocation IdentLoc = ConsumeToken();
+
+ SourceLocation EqualLoc;
+ ExprTy *AssignedVal = 0;
+ if (Tok.getKind() == tok::equal) {
+ EqualLoc = ConsumeToken();
+ ExprResult Res = ParseConstantExpression();
+ if (Res.isInvalid)
+ SkipUntil(tok::comma, tok::r_brace, true, true);
+ else
+ AssignedVal = Res.Val;
+ }
+
+ // Install the enumerator constant into EnumDecl.
+ DeclTy *EnumConstDecl = Actions.ParseEnumConstant(CurScope, EnumDecl,
+ LastEnumConstDecl,
+ IdentLoc, Ident,
+ EqualLoc, AssignedVal);
+ EnumConstantDecls.push_back(EnumConstDecl);
+ LastEnumConstDecl = EnumConstDecl;
+
+ if (Tok.getKind() != tok::comma)
+ break;
+ SourceLocation CommaLoc = ConsumeToken();
+
+ if (Tok.getKind() != tok::identifier && !getLang().C99)
+ Diag(CommaLoc, diag::ext_c99_enumerator_list_comma);
+ }
+
+ // Eat the }.
+ MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+
+ Actions.ParseEnumBody(StartLoc, EnumDecl, &EnumConstantDecls[0],
+ EnumConstantDecls.size());
+
+ DeclTy *AttrList = 0;
+ // If attributes exist after the identifier list, parse them.
+ if (Tok.getKind() == tok::kw___attribute)
+ AttrList = ParseAttributes(); // FIXME: where do they do?
+}
+
+/// isTypeSpecifierQualifier - Return true if the current token could be the
+/// start of a specifier-qualifier-list.
+bool Parser::isTypeSpecifierQualifier() const {
+ switch (Tok.getKind()) {
+ default: return false;
+ // GNU attributes support.
+ case tok::kw___attribute:
+ // 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:
+ return true;
+
+ // typedef-name
+ case tok::identifier:
+ return Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope) != 0;
+
+ // TODO: Attributes.
+ }
+}
+
+/// 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:
+ return Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope) != 0;
+ // TODO: Attributes.
+ }
+}
+
+
+/// ParseTypeQualifierListOpt
+/// type-qualifier-list: [C99 6.7.5]
+/// type-qualifier
+/// [GNU] attributes
+/// type-qualifier-list type-qualifier
+/// [GNU] type-qualifier-list attributes
+///
+void Parser::ParseTypeQualifierListOpt(DeclSpec &DS) {
+ while (1) {
+ int isInvalid = false;
+ const char *PrevSpec = 0;
+ SourceLocation Loc = Tok.getLocation();
+
+ switch (Tok.getKind()) {
+ default:
+ // If this is not a type-qualifier token, we're done reading type
+ // qualifiers. First verify that DeclSpec's are consistent.
+ DS.Finish(Diags, getLang());
+ return;
+ case tok::kw_const:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_volatile:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_restrict:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw___attribute:
+ DS.AddAttributes(ParseAttributes());
+ continue; // do *not* consume the next token!
+ }
+
+ // If the specifier combination wasn't legal, issue a diagnostic.
+ if (isInvalid) {
+ assert(PrevSpec && "Method did not return previous specifier!");
+ if (isInvalid == 1) // Error.
+ Diag(Tok, diag::err_invalid_decl_spec_combination, PrevSpec);
+ else // extwarn.
+ Diag(Tok, diag::ext_duplicate_declspec, PrevSpec);
+ }
+ ConsumeToken();
+ }
+}
+
+
+/// ParseDeclarator - Parse and verify a newly-initialized declarator.
+///
+void Parser::ParseDeclarator(Declarator &D) {
+ /// This implements the 'declarator' production in the C grammar, then checks
+ /// for well-formedness and issues diagnostics.
+ ParseDeclaratorInternal(D);
+
+ // TODO: validate D.
+
+}
+
+/// ParseDeclaratorInternal
+/// declarator: [C99 6.7.5]
+/// pointer[opt] direct-declarator
+/// [C++] '&' declarator [C++ 8p4, dcl.decl]
+/// [GNU] '&' restrict[opt] attributes[opt] declarator
+///
+/// pointer: [C99 6.7.5]
+/// '*' type-qualifier-list[opt]
+/// '*' type-qualifier-list[opt] pointer
+///
+void Parser::ParseDeclaratorInternal(Declarator &D) {
+ tok::TokenKind Kind = Tok.getKind();
+
+ // Not a pointer or C++ reference.
+ if (Kind != tok::star && !(Kind == tok::amp && getLang().CPlusPlus))
+ return ParseDirectDeclarator(D);
+
+ // Otherwise, '*' -> pointer or '&' -> reference.
+ SourceLocation Loc = ConsumeToken(); // Eat the * or &.
+
+ if (Kind == tok::star) {
+ // Is a pointer
+ DeclSpec DS;
+
+ ParseTypeQualifierListOpt(DS);
+
+ // Recursively parse the declarator.
+ ParseDeclaratorInternal(D);
+
+ // Remember that we parsed a pointer type, and remember the type-quals.
+ D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc));
+ } else {
+ // Is a reference
+ DeclSpec DS;
+
+ // C++ 8.3.2p1: cv-qualified references are ill-formed except when the
+ // cv-qualifiers are introduced through the use of a typedef or of a
+ // template type argument, in which case the cv-qualifiers are ignored.
+ //
+ // [GNU] Retricted references are allowed.
+ // [GNU] Attributes on references are allowed.
+ ParseTypeQualifierListOpt(DS);
+
+ if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+ Diag(DS.getConstSpecLoc(),
+ diag::err_invalid_reference_qualifier_application,
+ "const");
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
+ Diag(DS.getVolatileSpecLoc(),
+ diag::err_invalid_reference_qualifier_application,
+ "volatile");
+ }
+
+ // Recursively parse the declarator.
+ ParseDeclaratorInternal(D);
+
+ // Remember that we parsed a reference type. It doesn't have type-quals.
+ D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc));
+ }
+}
+
+/// ParseDirectDeclarator
+/// direct-declarator: [C99 6.7.5]
+/// identifier
+/// '(' declarator ')'
+/// [GNU] '(' attributes declarator ')'
+/// [C90] direct-declarator '[' constant-expression[opt] ']'
+/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']'
+/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
+/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
+/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
+/// direct-declarator '(' parameter-type-list ')'
+/// direct-declarator '(' identifier-list[opt] ')'
+/// [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 ')'
+ // Example: 'char (*X)' or 'int (*XX)(void)'
+ ParseParenDeclarator(D);
+ } 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 '('.
+ Diag(Tok, diag::err_expected_ident_lparen);
+ D.SetIdentifier(0, Tok.getLocation());
+ }
+
+ 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) {
+ ParseBracketDeclarator(D);
+ } 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 ',' '...'
+///
+/// parameter-list: [C99 6.7.5]
+/// parameter-declaration
+/// parameter-list ',' parameter-declaration
+///
+/// parameter-declaration: [C99 6.7.5]
+/// declaration-specifiers declarator
+/// [GNU] declaration-specifiers declarator attributes
+/// declaration-specifiers abstract-declarator[opt]
+/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
+///
+/// identifier-list: [C99 6.7.5]
+/// identifier
+/// identifier-list ',' identifier
+///
+void Parser::ParseParenDeclarator(Declarator &D) {
+ SourceLocation StartLoc = ConsumeParen();
+
+ // 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.
+ // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is
+ // considered to be a type, not a K&R identifier-list.
+ isGrouping = false;
+ } else {
+ // Otherwise, this is a grouping paren, e.g. 'int (*X)' or 'int(X)'.
+ isGrouping = true;
+ }
+
+ // If this is a grouping paren, handle:
+ // direct-declarator: '(' declarator ')'
+ // direct-declarator: '(' attributes declarator ')'
+ if (isGrouping) {
+ if (Tok.getKind() == tok::kw___attribute)
+ D.AddAttributes(ParseAttributes());
+
+ ParseDeclaratorInternal(D);
+ // Match the ')'.
+ MatchRHSPunctuation(tok::r_paren, StartLoc);
+ return;
+ }
+
+ // Okay, if this wasn't a grouping paren, it must be the start of a function
+ // argument list. Recognize that this declarator will never have an
+ // identifier (and remember where it would have been), 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.
+ bool IsVariadic;
+ bool HasPrototype;
+ bool ErrorEmitted = false;
+
+ // Build up an array of information about the parsed arguments.
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+ llvm::SmallSet<const IdentifierInfo*, 16> ParamsSoFar;
+
+ if (Tok.getKind() == tok::r_paren) {
+ // int() -> no prototype, no '...'.
+ IsVariadic = false;
+ HasPrototype = false;
+ } else if (Tok.getKind() == tok::identifier &&
+ // K&R identifier lists can't have typedefs as identifiers, per
+ // C99 6.7.5.3p11.
+ !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!");
+
+ // 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);
+
+ // Remember this identifier in ParamInfo.
+ ParamInfo.push_back(DeclaratorChunk::ParamInfo(Tok.getIdentifierInfo(),
+ Tok.getLocation(), 0));
+
+ ConsumeToken();
+ while (Tok.getKind() == tok::comma) {
+ // Eat the comma.
+ ConsumeToken();
+
+ if (Tok.getKind() != tok::identifier) {
+ Diag(Tok, diag::err_expected_ident);
+ ErrorEmitted = true;
+ break;
+ }
+
+ IdentifierInfo *ParmII = Tok.getIdentifierInfo();
+
+ // Verify that the argument identifier has not already been mentioned.
+ if (!ParamsSoFar.insert(ParmII)) {
+ Diag(Tok.getLocation(), diag::err_param_redefinition,ParmII->getName());
+ ParmII = 0;
+ }
+
+ // Remember this identifier in ParamInfo.
+ if (ParmII)
+ ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
+ Tok.getLocation(), 0));
+
+ // Eat the identifier.
+ ConsumeToken();
+ }
+
+ // K&R 'prototype'.
+ IsVariadic = false;
+ HasPrototype = false;
+ } else {
+ // Finally, a normal, non-empty parameter type list.
+
+ // Enter function-declaration scope, limiting any declarators for struct
+ // tags to the function prototype scope.
+ // FIXME: is this needed?
+ EnterScope(0);
+
+ IsVariadic = false;
+ while (1) {
+ if (Tok.getKind() == tok::ellipsis) {
+ IsVariadic = true;
+
+ // Check to see if this is "void(...)" which is not allowed.
+ if (ParamInfo.empty()) {
+ // 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;
+ }
+
+ // 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 ParmDecl(DS, Declarator::PrototypeContext);
+ ParseDeclarator(ParmDecl);
+
+ // Parse GNU attributes, if present.
+ if (Tok.getKind() == tok::kw___attribute)
+ ParmDecl.AddAttributes(ParseAttributes());
+
+ // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
+ // NOTE: we could trivially allow 'int foo(auto int X)' if we wanted.
+ if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
+ DS.getStorageClassSpec() != DeclSpec::SCS_register) {
+ Diag(DS.getStorageClassSpecLoc(),
+ diag::err_invalid_storage_class_in_func_decl);
+ DS.ClearStorageClassSpecs();
+ }
+ if (DS.isThreadSpecified()) {
+ Diag(DS.getThreadSpecLoc(),
+ diag::err_invalid_storage_class_in_func_decl);
+ DS.ClearStorageClassSpecs();
+ }
+
+ // Inform the actions module about the parameter declarator, so it gets
+ // added to the current scope.
+ Action::TypeResult ParamTy =
+ Actions.ParseParamDeclaratorType(CurScope, ParmDecl);
+
+ // Remember this parsed parameter in ParamInfo.
+ IdentifierInfo *ParmII = ParmDecl.getIdentifier();
+
+ // Verify that the argument identifier has not already been mentioned.
+ if (ParmII && !ParamsSoFar.insert(ParmII)) {
+ Diag(ParmDecl.getIdentifierLoc(), diag::err_param_redefinition,
+ ParmII->getName());
+ ParmII = 0;
+ }
+
+ ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
+ ParmDecl.getIdentifierLoc(),
+ ParamTy.Val));
+
+ // 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;
+
+ // Leave prototype scope.
+ ExitScope();
+ }
+
+ // Remember that we parsed a function type, and remember the attributes.
+ if (!ErrorEmitted)
+ D.AddTypeInfo(DeclaratorChunk::getFunction(HasPrototype, IsVariadic,
+ &ParamInfo[0], ParamInfo.size(),
+ StartLoc));
+
+ // If we have the closing ')', eat it and we're done.
+ if (Tok.getKind() == tok::r_paren) {
+ ConsumeParen();
+ } else {
+ // If an error happened earlier parsing something else in the proto, don't
+ // issue another error.
+ if (!ErrorEmitted)
+ Diag(Tok, diag::err_expected_rparen);
+ SkipUntil(tok::r_paren);
+ }
+}
+
+
+/// [C90] direct-declarator '[' constant-expression[opt] ']'
+/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']'
+/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
+/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
+/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
+void Parser::ParseBracketDeclarator(Declarator &D) {
+ SourceLocation StartLoc = ConsumeBracket();
+
+ // If valid, this location is the position where we read the 'static' keyword.
+ SourceLocation StaticLoc;
+ if (Tok.getKind() == tok::kw_static)
+ StaticLoc = ConsumeToken();
+
+ // If there is a type-qualifier-list, read it now.
+ DeclSpec DS;
+ ParseTypeQualifierListOpt(DS);
+
+ // If we haven't already read 'static', check to see if there is one after the
+ // type-qualifier-list.
+ if (!StaticLoc.isValid() && Tok.getKind() == tok::kw_static)
+ StaticLoc = ConsumeToken();
+
+ // Handle "direct-declarator [ type-qual-list[opt] * ]".
+ bool isStar = false;
+ ExprResult NumElements(false);
+ if (Tok.getKind() == tok::star) {
+ // Remember the '*' token, in case we have to un-get it.
+ LexerToken StarTok = Tok;
+ ConsumeToken();
+
+ // Check that the ']' token is present to avoid incorrectly parsing
+ // expressions starting with '*' as [*].
+ if (Tok.getKind() == tok::r_square) {
+ if (StaticLoc.isValid())
+ Diag(StaticLoc, diag::err_unspecified_vla_size_with_static);
+ StaticLoc = SourceLocation(); // Drop the static.
+ isStar = true;
+ } else {
+ // Otherwise, the * must have been some expression (such as '*ptr') that
+ // started an assignment-expr. We already consumed the token, but now we
+ // need to reparse it. This handles cases like 'X[*p + 4]'
+ NumElements = ParseAssignmentExpressionWithLeadingStar(StarTok);
+ }
+ } else if (Tok.getKind() != tok::r_square) {
+ // Parse the assignment-expression now.
+ NumElements = ParseAssignmentExpression();
+ }
+
+ // If there was an error parsing the assignment-expression, recover.
+ if (NumElements.isInvalid) {
+ // If the expression was invalid, skip it.
+ SkipUntil(tok::r_square);
+ return;
+ }
+
+ MatchRHSPunctuation(tok::r_square, StartLoc);
+
+ // If C99 isn't enabled, emit an ext-warn if the arg list wasn't empty and if
+ // it was not a constant expression.
+ if (!getLang().C99) {
+ // TODO: check C90 array constant exprness.
+ if (isStar || StaticLoc.isValid() ||
+ 0/*TODO: NumElts is not a C90 constantexpr */)
+ Diag(StartLoc, diag::ext_c99_array_usage);
+ }
+
+ // Remember that we parsed a pointer type, and remember the type-quals.
+ D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
+ StaticLoc.isValid(), isStar,
+ NumElements.Val, StartLoc));
+}
+
diff --git a/Parse/ParseExpr.cpp b/Parse/ParseExpr.cpp
new file mode 100644
index 0000000..41f347f
--- /dev/null
+++ b/Parse/ParseExpr.cpp
@@ -0,0 +1,935 @@
+//===--- ParseExpr.cpp - Expression Parsing -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Expression parsing implementation. Expressions in
+// C99 basically consist of a bunch of binary operators with unary operators and
+// other random stuff at the leaves.
+//
+// In the C99 grammar, these unary operators bind tightest and are represented
+// as the 'cast-expression' production. Everything else is either a binary
+// operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are
+// handled by ParseCastExpression, the higher level pieces are handled by
+// ParseBinaryExpression.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallString.h"
+using namespace clang;
+
+/// PrecedenceLevels - These are precedences for the binary/ternary operators in
+/// the C99 grammar. These have been named to relate with the C99 grammar
+/// productions. Low precedences numbers bind more weakly than high numbers.
+namespace prec {
+ enum Level {
+ Unknown = 0, // Not binary operator.
+ Comma = 1, // ,
+ Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
+ Conditional = 3, // ?
+ LogicalOr = 4, // ||
+ LogicalAnd = 5, // &&
+ InclusiveOr = 6, // |
+ ExclusiveOr = 7, // ^
+ And = 8, // &
+ Equality = 9, // ==, !=
+ Relational = 10, // >=, <=, >, <
+ Shift = 11, // <<, >>
+ Additive = 12, // -, +
+ Multiplicative = 13 // *, /, %
+ };
+}
+
+
+/// getBinOpPrecedence - Return the precedence of the specified binary operator
+/// token. This returns:
+///
+static prec::Level getBinOpPrecedence(tok::TokenKind Kind) {
+ switch (Kind) {
+ default: return prec::Unknown;
+ case tok::comma: return prec::Comma;
+ case tok::equal:
+ case tok::starequal:
+ case tok::slashequal:
+ case tok::percentequal:
+ case tok::plusequal:
+ case tok::minusequal:
+ case tok::lesslessequal:
+ case tok::greatergreaterequal:
+ case tok::ampequal:
+ case tok::caretequal:
+ case tok::pipeequal: return prec::Assignment;
+ case tok::question: return prec::Conditional;
+ case tok::pipepipe: return prec::LogicalOr;
+ case tok::ampamp: return prec::LogicalAnd;
+ case tok::pipe: return prec::InclusiveOr;
+ case tok::caret: return prec::ExclusiveOr;
+ case tok::amp: return prec::And;
+ case tok::exclaimequal:
+ case tok::equalequal: return prec::Equality;
+ case tok::lessequal:
+ case tok::less:
+ case tok::greaterequal:
+ case tok::greater: return prec::Relational;
+ case tok::lessless:
+ case tok::greatergreater: return prec::Shift;
+ case tok::plus:
+ case tok::minus: return prec::Additive;
+ case tok::percent:
+ case tok::slash:
+ case tok::star: return prec::Multiplicative;
+ }
+}
+
+
+/// ParseExpression - Simple precedence-based parser for binary/ternary
+/// operators.
+///
+/// Note: we diverge from the C99 grammar when parsing the assignment-expression
+/// production. C99 specifies that the LHS of an assignment operator should be
+/// parsed as a unary-expression, but consistency dictates that it be a
+/// conditional-expession. In practice, the important thing here is that the
+/// LHS of an assignment has to be an l-value, which productions between
+/// unary-expression and conditional-expression don't produce. Because we want
+/// consistency, we parse the LHS as a conditional-expression, then check for
+/// l-value-ness in semantic analysis stages.
+///
+/// multiplicative-expression: [C99 6.5.5]
+/// cast-expression
+/// multiplicative-expression '*' cast-expression
+/// multiplicative-expression '/' cast-expression
+/// multiplicative-expression '%' cast-expression
+///
+/// additive-expression: [C99 6.5.6]
+/// multiplicative-expression
+/// additive-expression '+' multiplicative-expression
+/// additive-expression '-' multiplicative-expression
+///
+/// shift-expression: [C99 6.5.7]
+/// additive-expression
+/// shift-expression '<<' additive-expression
+/// shift-expression '>>' additive-expression
+///
+/// relational-expression: [C99 6.5.8]
+/// shift-expression
+/// relational-expression '<' shift-expression
+/// relational-expression '>' shift-expression
+/// relational-expression '<=' shift-expression
+/// relational-expression '>=' shift-expression
+///
+/// equality-expression: [C99 6.5.9]
+/// relational-expression
+/// equality-expression '==' relational-expression
+/// equality-expression '!=' relational-expression
+///
+/// AND-expression: [C99 6.5.10]
+/// equality-expression
+/// AND-expression '&' equality-expression
+///
+/// exclusive-OR-expression: [C99 6.5.11]
+/// AND-expression
+/// exclusive-OR-expression '^' AND-expression
+///
+/// inclusive-OR-expression: [C99 6.5.12]
+/// exclusive-OR-expression
+/// inclusive-OR-expression '|' exclusive-OR-expression
+///
+/// logical-AND-expression: [C99 6.5.13]
+/// inclusive-OR-expression
+/// logical-AND-expression '&&' inclusive-OR-expression
+///
+/// logical-OR-expression: [C99 6.5.14]
+/// logical-AND-expression
+/// logical-OR-expression '||' logical-AND-expression
+///
+/// conditional-expression: [C99 6.5.15]
+/// logical-OR-expression
+/// logical-OR-expression '?' expression ':' conditional-expression
+/// [GNU] logical-OR-expression '?' ':' conditional-expression
+///
+/// assignment-expression: [C99 6.5.16]
+/// conditional-expression
+/// unary-expression assignment-operator assignment-expression
+///
+/// assignment-operator: one of
+/// = *= /= %= += -= <<= >>= &= ^= |=
+///
+/// expression: [C99 6.5.17]
+/// assignment-expression
+/// expression ',' assignment-expression
+///
+Parser::ExprResult Parser::ParseExpression() {
+ ExprResult LHS = ParseCastExpression(false);
+ if (LHS.isInvalid) return LHS;
+
+ return ParseRHSOfBinaryExpression(LHS, prec::Comma);
+}
+
+/// ParseAssignmentExpression - Parse an expr that doesn't include commas.
+///
+Parser::ExprResult Parser::ParseAssignmentExpression() {
+ ExprResult LHS = ParseCastExpression(false);
+ if (LHS.isInvalid) return LHS;
+
+ return ParseRHSOfBinaryExpression(LHS, prec::Assignment);
+}
+
+Parser::ExprResult Parser::ParseConstantExpression() {
+ ExprResult LHS = ParseCastExpression(false);
+ if (LHS.isInvalid) return LHS;
+
+ // TODO: Validate that this is a constant expr!
+ return ParseRHSOfBinaryExpression(LHS, prec::Conditional);
+}
+
+/// ParseExpressionWithLeadingIdentifier - This special purpose method is used
+/// in contexts where we have already consumed an identifier (which we saved in
+/// 'IdTok'), then discovered that the identifier was really the leading token
+/// of part of an expression. For example, in "A[1]+B", we consumed "A" (which
+/// is now in 'IdTok') and the current token is "[".
+Parser::ExprResult Parser::
+ParseExpressionWithLeadingIdentifier(const LexerToken &IdTok) {
+ // We know that 'IdTok' must correspond to this production:
+ // primary-expression: identifier
+
+ // Let the actions module handle the identifier.
+ ExprResult Res = Actions.ParseIdentifierExpr(CurScope, IdTok.getLocation(),
+ *IdTok.getIdentifierInfo(),
+ Tok.getKind() == tok::l_paren);
+
+ // Because we have to parse an entire cast-expression before starting the
+ // ParseRHSOfBinaryExpression method (which parses any trailing binops), we
+ // need to handle the 'postfix-expression' rules. We do this by invoking
+ // ParsePostfixExpressionSuffix to consume any postfix-expression suffixes:
+ Res = ParsePostfixExpressionSuffix(Res);
+ if (Res.isInvalid) return Res;
+
+ // At this point, the "A[1]" part of "A[1]+B" has been consumed. Once this is
+ // done, we know we don't have to do anything for cast-expression, because the
+ // only non-postfix-expression production starts with a '(' token, and we know
+ // we have an identifier. As such, we can invoke ParseRHSOfBinaryExpression
+ // to consume any trailing operators (e.g. "+" in this example) and connected
+ // chunks of the expression.
+ return ParseRHSOfBinaryExpression(Res, prec::Comma);
+}
+
+/// ParseExpressionWithLeadingIdentifier - This special purpose method is used
+/// in contexts where we have already consumed an identifier (which we saved in
+/// 'IdTok'), then discovered that the identifier was really the leading token
+/// of part of an assignment-expression. For example, in "A[1]+B", we consumed
+/// "A" (which is now in 'IdTok') and the current token is "[".
+Parser::ExprResult Parser::
+ParseAssignmentExprWithLeadingIdentifier(const LexerToken &IdTok) {
+ // We know that 'IdTok' must correspond to this production:
+ // primary-expression: identifier
+
+ // Let the actions module handle the identifier.
+ ExprResult Res = Actions.ParseIdentifierExpr(CurScope, IdTok.getLocation(),
+ *IdTok.getIdentifierInfo(),
+ Tok.getKind() == tok::l_paren);
+
+ // Because we have to parse an entire cast-expression before starting the
+ // ParseRHSOfBinaryExpression method (which parses any trailing binops), we
+ // need to handle the 'postfix-expression' rules. We do this by invoking
+ // ParsePostfixExpressionSuffix to consume any postfix-expression suffixes:
+ Res = ParsePostfixExpressionSuffix(Res);
+ if (Res.isInvalid) return Res;
+
+ // At this point, the "A[1]" part of "A[1]+B" has been consumed. Once this is
+ // done, we know we don't have to do anything for cast-expression, because the
+ // only non-postfix-expression production starts with a '(' token, and we know
+ // we have an identifier. As such, we can invoke ParseRHSOfBinaryExpression
+ // to consume any trailing operators (e.g. "+" in this example) and connected
+ // chunks of the expression.
+ return ParseRHSOfBinaryExpression(Res, prec::Assignment);
+}
+
+
+/// ParseAssignmentExpressionWithLeadingStar - This special purpose method is
+/// used in contexts where we have already consumed a '*' (which we saved in
+/// 'StarTok'), then discovered that the '*' was really the leading token of an
+/// expression. For example, in "*(int*)P+B", we consumed "*" (which is
+/// now in 'StarTok') and the current token is "(".
+Parser::ExprResult Parser::
+ParseAssignmentExpressionWithLeadingStar(const LexerToken &StarTok) {
+ // We know that 'StarTok' must correspond to this production:
+ // unary-expression: unary-operator cast-expression
+ // where 'unary-operator' is '*'.
+
+ // Parse the cast-expression that follows the '*'. This will parse the
+ // "*(int*)P" part of "*(int*)P+B".
+ ExprResult Res = ParseCastExpression(false);
+ if (Res.isInvalid) return Res;
+
+ // Combine StarTok + Res to get the new AST for the combined expression..
+ Res = Actions.ParseUnaryOp(StarTok.getLocation(), tok::star, Res.Val);
+ if (Res.isInvalid) return Res;
+
+
+ // We have to parse an entire cast-expression before starting the
+ // ParseRHSOfBinaryExpression method (which parses any trailing binops). Since
+ // we know that the only production above us is the cast-expression
+ // production, and because the only alternative productions start with a '('
+ // token (we know we had a '*'), there is no work to do to get a whole
+ // cast-expression.
+
+ // At this point, the "*(int*)P" part of "*(int*)P+B" has been consumed. Once
+ // this is done, we can invoke ParseRHSOfBinaryExpression to consume any
+ // trailing operators (e.g. "+" in this example) and connected chunks of the
+ // assignment-expression.
+ return ParseRHSOfBinaryExpression(Res, prec::Assignment);
+}
+
+
+/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with
+/// LHS and has a precedence of at least MinPrec.
+Parser::ExprResult
+Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
+ unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind());
+ SourceLocation ColonLoc;
+
+ while (1) {
+ // If this token has a lower precedence than we are allowed to parse (e.g.
+ // because we are called recursively, or because the token is not a binop),
+ // then we are done!
+ if (NextTokPrec < MinPrec)
+ return LHS;
+
+ // Consume the operator, saving the operator token for error reporting.
+ LexerToken OpToken = Tok;
+ ConsumeToken();
+
+ // Special case handling for the ternary operator.
+ ExprResult TernaryMiddle(true);
+ if (NextTokPrec == prec::Conditional) {
+ if (Tok.getKind() != tok::colon) {
+ // Handle this production specially:
+ // logical-OR-expression '?' expression ':' conditional-expression
+ // In particular, the RHS of the '?' is 'expression', not
+ // 'logical-OR-expression' as we might expect.
+ TernaryMiddle = ParseExpression();
+ if (TernaryMiddle.isInvalid) return TernaryMiddle;
+ } else {
+ // Special case handling of "X ? Y : Z" where Y is empty:
+ // logical-OR-expression '?' ':' conditional-expression [GNU]
+ TernaryMiddle = ExprResult(false);
+ Diag(Tok, diag::ext_gnu_conditional_expr);
+ }
+
+ if (Tok.getKind() != tok::colon) {
+ Diag(Tok, diag::err_expected_colon);
+ Diag(OpToken, diag::err_matching, "?");
+ return ExprResult(true);
+ }
+
+ // Eat the colon.
+ ColonLoc = ConsumeToken();
+ }
+
+ // Parse another leaf here for the RHS of the operator.
+ ExprResult RHS = ParseCastExpression(false);
+ if (RHS.isInvalid) return RHS;
+
+ // Remember the precedence of this operator and get the precedence of the
+ // operator immediately to the right of the RHS.
+ unsigned ThisPrec = NextTokPrec;
+ NextTokPrec = getBinOpPrecedence(Tok.getKind());
+
+ // Assignment and conditional expressions are right-associative.
+ bool isRightAssoc = NextTokPrec == prec::Conditional ||
+ NextTokPrec == prec::Assignment;
+
+ // Get the precedence of the operator to the right of the RHS. If it binds
+ // more tightly with RHS than we do, evaluate it completely first.
+ if (ThisPrec < NextTokPrec ||
+ (ThisPrec == NextTokPrec && isRightAssoc)) {
+ // If this is left-associative, only parse things on the RHS that bind
+ // more tightly than the current operator. If it is left-associative, it
+ // is okay, to bind exactly as tightly. For example, compile A=B=C=D as
+ // A=(B=(C=D)), where each paren is a level of recursion here.
+ RHS = ParseRHSOfBinaryExpression(RHS, ThisPrec + !isRightAssoc);
+ if (RHS.isInvalid) return RHS;
+
+ NextTokPrec = getBinOpPrecedence(Tok.getKind());
+ }
+ assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
+
+ // Combine the LHS and RHS into the LHS (e.g. build AST).
+ if (TernaryMiddle.isInvalid)
+ LHS = Actions.ParseBinOp(OpToken.getLocation(), OpToken.getKind(),
+ LHS.Val, RHS.Val);
+ else
+ LHS = Actions.ParseConditionalOp(OpToken.getLocation(), ColonLoc,
+ LHS.Val, TernaryMiddle.Val, RHS.Val);
+ }
+}
+
+/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
+/// true, parse a unary-expression.
+///
+/// cast-expression: [C99 6.5.4]
+/// unary-expression
+/// '(' type-name ')' cast-expression
+///
+/// unary-expression: [C99 6.5.3]
+/// postfix-expression
+/// '++' unary-expression
+/// '--' unary-expression
+/// unary-operator cast-expression
+/// 'sizeof' unary-expression
+/// 'sizeof' '(' type-name ')'
+/// [GNU] '__alignof' unary-expression
+/// [GNU] '__alignof' '(' type-name ')'
+/// [GNU] '&&' identifier
+///
+/// unary-operator: one of
+/// '&' '*' '+' '-' '~' '!'
+/// [GNU] '__extension__' '__real' '__imag'
+///
+/// primary-expression: [C99 6.5.1]
+/// identifier
+/// constant
+/// string-literal
+/// [C++] boolean-literal [C++ 2.13.5]
+/// '(' expression ')'
+/// '__func__' [C99 6.4.2.2]
+/// [GNU] '__FUNCTION__'
+/// [GNU] '__PRETTY_FUNCTION__'
+/// [GNU] '(' compound-statement ')'
+/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
+/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
+/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
+/// assign-expr ')'
+/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
+/// [OBC] '[' objc-receiver objc-message-args ']' [TODO]
+/// [OBC] '@selector' '(' objc-selector-arg ')' [TODO]
+/// [OBC] '@protocol' '(' identifier ')' [TODO]
+/// [OBC] '@encode' '(' type-name ')' [TODO]
+/// [OBC] objc-string-literal [TODO]
+/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
+///
+/// constant: [C99 6.4.4]
+/// integer-constant
+/// floating-constant
+/// enumeration-constant -> identifier
+/// character-constant
+///
+Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
+ ExprResult Res;
+ tok::TokenKind SavedKind = Tok.getKind();
+
+ // This handles all of cast-expression, unary-expression, postfix-expression,
+ // and primary-expression. We handle them together like this for efficiency
+ // and to simplify handling of an expression starting with a '(' token: which
+ // may be one of a parenthesized expression, cast-expression, compound literal
+ // expression, or statement expression.
+ //
+ // If the parsed tokens consist of a primary-expression, the cases below
+ // call ParsePostfixExpressionSuffix to handle the postfix expression
+ // suffixes. Cases that cannot be followed by postfix exprs should
+ // return without invoking ParsePostfixExpressionSuffix.
+ switch (SavedKind) {
+ case tok::l_paren: {
+ // If this expression is limited to being a unary-expression, the parent can
+ // not start a cast expression.
+ ParenParseOption ParenExprType =
+ isUnaryExpression ? CompoundLiteral : CastExpr;
+ TypeTy *CastTy;
+ SourceLocation LParenLoc = Tok.getLocation();
+ SourceLocation RParenLoc;
+ Res = ParseParenExpression(ParenExprType, CastTy, RParenLoc);
+ if (Res.isInvalid) return Res;
+
+ switch (ParenExprType) {
+ case SimpleExpr: break; // Nothing else to do.
+ case CompoundStmt: break; // Nothing else to do.
+ case CompoundLiteral:
+ // We parsed '(' type-name ')' '{' ... '}'. If any suffixes of
+ // postfix-expression exist, parse them now.
+ break;
+ case CastExpr:
+ // We parsed '(' type-name ')' and the thing after it wasn't a '{'. Parse
+ // the cast-expression that follows it next.
+ // TODO: For cast expression with CastTy.
+ Res = ParseCastExpression(false);
+ if (!Res.isInvalid)
+ Res = Actions.ParseCastExpr(LParenLoc, CastTy, RParenLoc, Res.Val);
+ return Res;
+ }
+
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(Res);
+ }
+
+ // primary-expression
+ case tok::numeric_constant:
+ // constant: integer-constant
+ // constant: floating-constant
+
+ Res = Actions.ParseNumericConstant(Tok);
+ ConsumeToken();
+
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(Res);
+
+ case tok::kw_true:
+ case tok::kw_false:
+ return ParseCXXBoolLiteral();
+
+ case tok::identifier: { // primary-expression: identifier
+ // constant: enumeration-constant
+ // Consume the identifier so that we can see if it is followed by a '('.
+ // Function designators are allowed to be undeclared (C99 6.5.1p2), so we
+ // need to know whether or not this identifier is a function designator or
+ // not.
+ IdentifierInfo &II = *Tok.getIdentifierInfo();
+ SourceLocation L = ConsumeToken();
+ Res = Actions.ParseIdentifierExpr(CurScope, L, II,
+ Tok.getKind() == tok::l_paren);
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(Res);
+ }
+ case tok::char_constant: // constant: character-constant
+ Res = Actions.ParseCharacterConstant(Tok);
+ ConsumeToken();
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(Res);
+ case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
+ case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]
+ case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU]
+ Res = Actions.ParseSimplePrimaryExpr(Tok.getLocation(), SavedKind);
+ ConsumeToken();
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(Res);
+ case tok::string_literal: // primary-expression: string-literal
+ case tok::wide_string_literal:
+ Res = ParseStringLiteralExpression();
+ if (Res.isInvalid) return Res;
+ // This can be followed by postfix-expr pieces (e.g. "foo"[1]).
+ return ParsePostfixExpressionSuffix(Res);
+ case tok::kw___builtin_va_arg:
+ case tok::kw___builtin_offsetof:
+ case tok::kw___builtin_choose_expr:
+ case tok::kw___builtin_types_compatible_p:
+ return ParseBuiltinPrimaryExpression();
+ case tok::plusplus: // unary-expression: '++' unary-expression
+ case tok::minusminus: { // unary-expression: '--' unary-expression
+ SourceLocation SavedLoc = ConsumeToken();
+ Res = ParseCastExpression(true);
+ if (!Res.isInvalid)
+ Res = Actions.ParseUnaryOp(SavedLoc, SavedKind, Res.Val);
+ return Res;
+ }
+ case tok::amp: // unary-expression: '&' cast-expression
+ case tok::star: // unary-expression: '*' cast-expression
+ case tok::plus: // unary-expression: '+' cast-expression
+ case tok::minus: // unary-expression: '-' cast-expression
+ case tok::tilde: // unary-expression: '~' cast-expression
+ case tok::exclaim: // unary-expression: '!' cast-expression
+ case tok::kw___real: // unary-expression: '__real' cast-expression [GNU]
+ case tok::kw___imag: // unary-expression: '__imag' cast-expression [GNU]
+ case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU]
+ // FIXME: Extension not handled correctly here!
+ SourceLocation SavedLoc = ConsumeToken();
+ Res = ParseCastExpression(false);
+ if (!Res.isInvalid)
+ Res = Actions.ParseUnaryOp(SavedLoc, SavedKind, Res.Val);
+ return Res;
+ }
+ case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression
+ // unary-expression: 'sizeof' '(' type-name ')'
+ case tok::kw___alignof: // unary-expression: '__alignof' unary-expression
+ // unary-expression: '__alignof' '(' type-name ')'
+ return ParseSizeofAlignofExpression();
+ case tok::ampamp: { // unary-expression: '&&' identifier
+ SourceLocation AmpAmpLoc = ConsumeToken();
+ if (Tok.getKind() != tok::identifier) {
+ Diag(Tok, diag::err_expected_ident);
+ return ExprResult(true);
+ }
+
+ Diag(AmpAmpLoc, diag::ext_gnu_address_of_label);
+ Res = Actions.ParseAddrLabel(AmpAmpLoc, Tok.getLocation(),
+ Tok.getIdentifierInfo());
+ ConsumeToken();
+ return Res;
+ }
+ case tok::kw_const_cast:
+ case tok::kw_dynamic_cast:
+ case tok::kw_reinterpret_cast:
+ case tok::kw_static_cast:
+ return ParseCXXCasts();
+ default:
+ Diag(Tok, diag::err_expected_expression);
+ return ExprResult(true);
+ }
+
+ // unreachable.
+ abort();
+}
+
+/// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression
+/// is parsed, this method parses any suffixes that apply.
+///
+/// postfix-expression: [C99 6.5.2]
+/// primary-expression
+/// postfix-expression '[' expression ']'
+/// postfix-expression '(' argument-expression-list[opt] ')'
+/// postfix-expression '.' identifier
+/// postfix-expression '->' identifier
+/// postfix-expression '++'
+/// postfix-expression '--'
+/// '(' type-name ')' '{' initializer-list '}'
+/// '(' type-name ')' '{' initializer-list ',' '}'
+///
+/// argument-expression-list: [C99 6.5.2]
+/// argument-expression
+/// argument-expression-list ',' assignment-expression
+///
+Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
+
+ // Now that the primary-expression piece of the postfix-expression has been
+ // parsed, see if there are any postfix-expression pieces here.
+ SourceLocation Loc;
+ while (1) {
+ switch (Tok.getKind()) {
+ default: // Not a postfix-expression suffix.
+ return LHS;
+ case tok::l_square: { // postfix-expression: p-e '[' expression ']'
+ Loc = ConsumeBracket();
+ ExprResult Idx = ParseExpression();
+
+ SourceLocation RLoc = Tok.getLocation();
+
+ if (!LHS.isInvalid && !Idx.isInvalid && Tok.getKind() == tok::r_square)
+ LHS = Actions.ParseArraySubscriptExpr(LHS.Val, Loc, Idx.Val, RLoc);
+ else
+ LHS = ExprResult(true);
+
+ // Match the ']'.
+ MatchRHSPunctuation(tok::r_square, Loc);
+ break;
+ }
+
+ case tok::l_paren: { // p-e: p-e '(' argument-expression-list[opt] ')'
+ llvm::SmallVector<ExprTy*, 8> ArgExprs;
+ llvm::SmallVector<SourceLocation, 8> CommaLocs;
+ bool ArgExprsOk = true;
+
+ Loc = ConsumeParen();
+
+ if (Tok.getKind() != tok::r_paren) {
+ while (1) {
+ ExprResult ArgExpr = ParseAssignmentExpression();
+ if (ArgExpr.isInvalid) {
+ ArgExprsOk = false;
+ SkipUntil(tok::r_paren);
+ break;
+ } else
+ ArgExprs.push_back(ArgExpr.Val);
+
+ if (Tok.getKind() != tok::comma)
+ break;
+ // Move to the next argument, remember where the comma was.
+ CommaLocs.push_back(ConsumeToken());
+ }
+ }
+
+ // Match the ')'.
+ if (!LHS.isInvalid && ArgExprsOk && Tok.getKind() == tok::r_paren) {
+ assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&&
+ "Unexpected number of commas!");
+ LHS = Actions.ParseCallExpr(LHS.Val, Loc, &ArgExprs[0], ArgExprs.size(),
+ &CommaLocs[0], Tok.getLocation());
+ }
+
+ if (ArgExprsOk)
+ MatchRHSPunctuation(tok::r_paren, Loc);
+ break;
+ }
+ case tok::arrow: // postfix-expression: p-e '->' identifier
+ case tok::period: { // postfix-expression: p-e '.' identifier
+ tok::TokenKind OpKind = Tok.getKind();
+ SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token.
+
+ if (Tok.getKind() != tok::identifier) {
+ Diag(Tok, diag::err_expected_ident);
+ return ExprResult(true);
+ }
+
+ if (!LHS.isInvalid)
+ LHS = Actions.ParseMemberReferenceExpr(LHS.Val, OpLoc, OpKind,
+ Tok.getLocation(),
+ *Tok.getIdentifierInfo());
+ ConsumeToken();
+ break;
+ }
+ case tok::plusplus: // postfix-expression: postfix-expression '++'
+ case tok::minusminus: // postfix-expression: postfix-expression '--'
+ if (!LHS.isInvalid)
+ LHS = Actions.ParsePostfixUnaryOp(Tok.getLocation(), Tok.getKind(),
+ LHS.Val);
+ ConsumeToken();
+ break;
+ }
+ }
+}
+
+
+/// ParseSizeofAlignofExpression - Parse a sizeof or alignof expression.
+/// unary-expression: [C99 6.5.3]
+/// 'sizeof' unary-expression
+/// 'sizeof' '(' type-name ')'
+/// [GNU] '__alignof' unary-expression
+/// [GNU] '__alignof' '(' type-name ')'
+Parser::ExprResult Parser::ParseSizeofAlignofExpression() {
+ assert((Tok.getKind() == tok::kw_sizeof ||
+ Tok.getKind() == tok::kw___alignof) &&
+ "Not a sizeof/alignof expression!");
+ LexerToken OpTok = Tok;
+ ConsumeToken();
+
+ // If the operand doesn't start with an '(', it must be an expression.
+ ExprResult Operand;
+ if (Tok.getKind() != tok::l_paren) {
+ Operand = ParseCastExpression(true);
+ } else {
+ // If it starts with a '(', we know that it is either a parenthesized
+ // type-name, or it is a unary-expression that starts with a compound
+ // literal, or starts with a primary-expression that is a parenthesized
+ // expression.
+ ParenParseOption ExprType = CastExpr;
+ TypeTy *CastTy;
+ SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
+ Operand = ParseParenExpression(ExprType, CastTy, RParenLoc);
+
+ // If ParseParenExpression parsed a '(typename)' sequence only, the this is
+ // sizeof/alignof a type. Otherwise, it is sizeof/alignof an expression.
+ if (ExprType == CastExpr) {
+ return Actions.ParseSizeOfAlignOfTypeExpr(OpTok.getLocation(),
+ OpTok.getKind() == tok::kw_sizeof,
+ LParenLoc, CastTy, RParenLoc);
+ }
+ }
+
+ // If we get here, the operand to the sizeof/alignof was an expresion.
+ if (!Operand.isInvalid)
+ Operand = Actions.ParseUnaryOp(OpTok.getLocation(), OpTok.getKind(),
+ Operand.Val);
+ return Operand;
+}
+
+/// ParseBuiltinPrimaryExpression
+///
+/// primary-expression: [C99 6.5.1]
+/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
+/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
+/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
+/// assign-expr ')'
+/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
+///
+/// [GNU] offsetof-member-designator:
+/// [GNU] identifier
+/// [GNU] offsetof-member-designator '.' identifier
+/// [GNU] offsetof-member-designator '[' expression ']'
+///
+Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
+ ExprResult Res(false);
+ const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo();
+
+ tok::TokenKind T = Tok.getKind();
+ SourceLocation StartLoc = ConsumeToken(); // Eat the builtin identifier.
+
+ // All of these start with an open paren.
+ if (Tok.getKind() != tok::l_paren) {
+ Diag(Tok, diag::err_expected_lparen_after, BuiltinII->getName());
+ return ExprResult(true);
+ }
+
+ SourceLocation LParenLoc = ConsumeParen();
+ // TODO: Build AST.
+
+ switch (T) {
+ default: assert(0 && "Not a builtin primary expression!");
+ case tok::kw___builtin_va_arg:
+ Res = ParseAssignmentExpression();
+ if (Res.isInvalid) {
+ SkipUntil(tok::r_paren);
+ return Res;
+ }
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprResult(true);
+
+ ParseTypeName();
+ break;
+
+ case tok::kw___builtin_offsetof:
+ ParseTypeName();
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprResult(true);
+
+ // We must have at least one identifier here.
+ if (ExpectAndConsume(tok::identifier, diag::err_expected_ident, "",
+ tok::r_paren))
+ return ExprResult(true);
+
+ while (1) {
+ if (Tok.getKind() == tok::period) {
+ // offsetof-member-designator: offsetof-member-designator '.' identifier
+ ConsumeToken();
+
+ if (ExpectAndConsume(tok::identifier, diag::err_expected_ident, "",
+ tok::r_paren))
+ return ExprResult(true);
+ } else if (Tok.getKind() == tok::l_square) {
+ // offsetof-member-designator: offsetof-member-design '[' expression ']'
+ SourceLocation LSquareLoc = ConsumeBracket();
+ Res = ParseExpression();
+ if (Res.isInvalid) {
+ SkipUntil(tok::r_paren);
+ return Res;
+ }
+
+ MatchRHSPunctuation(tok::r_square, LSquareLoc);
+ } else {
+ break;
+ }
+ }
+ break;
+ case tok::kw___builtin_choose_expr:
+ Res = ParseAssignmentExpression();
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprResult(true);
+
+ Res = ParseAssignmentExpression();
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprResult(true);
+
+ Res = ParseAssignmentExpression();
+ break;
+ case tok::kw___builtin_types_compatible_p:
+ ParseTypeName();
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprResult(true);
+
+ ParseTypeName();
+ break;
+ }
+
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ // These can be followed by postfix-expr pieces because they are
+ // primary-expressions.
+ return ParsePostfixExpressionSuffix(Res);
+}
+
+/// ParseParenExpression - This parses the unit that starts with a '(' token,
+/// based on what is allowed by ExprType. The actual thing parsed is returned
+/// in ExprType.
+///
+/// primary-expression: [C99 6.5.1]
+/// '(' expression ')'
+/// [GNU] '(' compound-statement ')' (if !ParenExprOnly)
+/// postfix-expression: [C99 6.5.2]
+/// '(' type-name ')' '{' initializer-list '}'
+/// '(' type-name ')' '{' initializer-list ',' '}'
+/// cast-expression: [C99 6.5.4]
+/// '(' type-name ')' cast-expression
+///
+Parser::ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType,
+ TypeTy *&CastTy,
+ SourceLocation &RParenLoc) {
+ assert(Tok.getKind() == tok::l_paren && "Not a paren expr!");
+ SourceLocation OpenLoc = ConsumeParen();
+ ExprResult Result(false);
+ CastTy = 0;
+
+ if (ExprType >= CompoundStmt && Tok.getKind() == tok::l_brace &&
+ !getLang().NoExtensions) {
+ Diag(Tok, diag::ext_gnu_statement_expr);
+ ParseCompoundStatement();
+ ExprType = CompoundStmt;
+ // TODO: Build AST for GNU compound stmt.
+ } else if (ExprType >= CompoundLiteral && isTypeSpecifierQualifier()) {
+ // Otherwise, this is a compound literal expression or cast expression.
+ TypeTy *Ty = ParseTypeName();
+
+ // Match the ')'.
+ if (Tok.getKind() == tok::r_paren)
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, OpenLoc);
+
+ if (Tok.getKind() == tok::l_brace) {
+ if (!getLang().C99) // Compound literals don't exist in C90.
+ Diag(OpenLoc, diag::ext_c99_compound_literal);
+ Result = ParseInitializer();
+ ExprType = CompoundLiteral;
+ // TODO: Build AST for compound literal.
+ } else if (ExprType == CastExpr) {
+ // Note that this doesn't parse the subsequence cast-expression, it just
+ // returns the parsed type to the callee.
+ ExprType = CastExpr;
+ CastTy = Ty;
+ return ExprResult(false);
+ } else {
+ Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
+ return ExprResult(true);
+ }
+ return Result;
+ } else {
+ Result = ParseExpression();
+ ExprType = SimpleExpr;
+ if (!Result.isInvalid && Tok.getKind() == tok::r_paren)
+ Result = Actions.ParseParenExpr(OpenLoc, Tok.getLocation(), Result.Val);
+ }
+
+ // Match the ')'.
+ if (Result.isInvalid)
+ SkipUntil(tok::r_paren);
+ else {
+ if (Tok.getKind() == tok::r_paren)
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, OpenLoc);
+ }
+
+ return Result;
+}
+
+/// ParseStringLiteralExpression - This handles the various token types that
+/// form string literals, and also handles string concatenation [C99 5.1.1.2,
+/// translation phase #6].
+///
+/// primary-expression: [C99 6.5.1]
+/// string-literal
+Parser::ExprResult Parser::ParseStringLiteralExpression() {
+ assert(isTokenStringLiteral() && "Not a string literal!");
+
+ // String concat. Note that keywords like __func__ and __FUNCTION__ are not
+ // considered to be strings for concatenation purposes.
+ llvm::SmallVector<LexerToken, 4> StringToks;
+
+ do {
+ StringToks.push_back(Tok);
+ ConsumeStringToken();
+ } while (isTokenStringLiteral());
+
+ // Pass the set of string tokens, ready for concatenation, to the actions.
+ return Actions.ParseStringLiteral(&StringToks[0], StringToks.size());
+}
diff --git a/Parse/ParseExprCXX.cpp b/Parse/ParseExprCXX.cpp
new file mode 100644
index 0000000..7048660
--- /dev/null
+++ b/Parse/ParseExprCXX.cpp
@@ -0,0 +1,78 @@
+//===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Bill Wendling and is distributed under the
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Expression parsing implementation for C++.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Parse/Parser.h"
+using namespace clang;
+
+/// ParseCXXCasts - This handles the various ways to cast expressions to another
+/// type.
+///
+/// postfix-expression: [C++ 5.2p1]
+/// 'dynamic_cast' '<' type-name '>' '(' expression ')'
+/// 'static_cast' '<' type-name '>' '(' expression ')'
+/// 'reinterpret_cast' '<' type-name '>' '(' expression ')'
+/// 'const_cast' '<' type-name '>' '(' expression ')'
+///
+Parser::ExprResult Parser::ParseCXXCasts() {
+ tok::TokenKind Kind = Tok.getKind();
+ const char *CastName = 0; // For error messages
+
+ switch (Kind) {
+ default: assert(0 && "Unknown C++ cast!"); abort();
+ case tok::kw_const_cast: CastName = "const_cast"; break;
+ case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break;
+ case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break;
+ case tok::kw_static_cast: CastName = "static_cast"; break;
+ }
+
+ SourceLocation OpLoc = ConsumeToken();
+ SourceLocation LAngleBracketLoc = Tok.getLocation();
+
+ if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
+ return ExprResult(true);
+
+ TypeTy *CastTy = ParseTypeName();
+ SourceLocation RAngleBracketLoc = Tok.getLocation();
+
+ if (ExpectAndConsume(tok::greater, diag::err_expected_greater)) {
+ Diag(LAngleBracketLoc, diag::err_matching, "<");
+ return ExprResult(true);
+ }
+
+ SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
+
+ if (Tok.getKind() != tok::l_paren) {
+ Diag(Tok, diag::err_expected_lparen_after, CastName);
+ return ExprResult(true);
+ }
+
+ ExprResult Result = ParseSimpleParenExpression(RParenLoc);
+
+ if (!Result.isInvalid)
+ Result = Actions.ParseCXXCasts(OpLoc, Kind,
+ LAngleBracketLoc, CastTy, RAngleBracketLoc,
+ LParenLoc, Result.Val, RParenLoc);
+
+ return Result;
+}
+
+/// ParseCXXBoolLiteral - This handles the C++ Boolean literals.
+///
+/// boolean-literal: [C++ 2.13.5]
+/// 'true'
+/// 'false'
+Parser::ExprResult Parser::ParseCXXBoolLiteral() {
+ tok::TokenKind Kind = Tok.getKind();
+ return Actions.ParseCXXBoolLiteral(ConsumeToken(), Kind);
+}
diff --git a/Parse/ParseInit.cpp b/Parse/ParseInit.cpp
new file mode 100644
index 0000000..01169d8
--- /dev/null
+++ b/Parse/ParseInit.cpp
@@ -0,0 +1,188 @@
+//===--- ParseInit.cpp - Initializer Parsing ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements initializer parsing as specified by C99 6.7.8.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Basic/Diagnostic.h"
+using namespace clang;
+
+
+/// MayBeDesignationStart - Return true if this token might be the start of a
+/// designator.
+static bool MayBeDesignationStart(tok::TokenKind K) {
+ switch (K) {
+ default: return false;
+ case tok::period: // designator: '.' identifier
+ case tok::l_square: // designator: array-designator
+ case tok::identifier: // designation: identifier ':'
+ return true;
+ }
+}
+
+/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
+/// checking to see if the token stream starts with a designator.
+///
+/// designation:
+/// designator-list '='
+/// [GNU] array-designator
+/// [GNU] identifier ':'
+///
+/// designator-list:
+/// designator
+/// designator-list designator
+///
+/// designator:
+/// array-designator
+/// '.' identifier
+///
+/// array-designator:
+/// '[' constant-expression ']'
+/// [GNU] '[' constant-expression '...' constant-expression ']'
+///
+/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an
+/// initializer. We need to consider this case when parsing array designators.
+///
+Parser::ExprResult Parser::ParseInitializerWithPotentialDesignator() {
+ // Parse each designator in the designator list until we find an initializer.
+ while (1) {
+ switch (Tok.getKind()) {
+ case tok::equal:
+ // We read some number (at least one due to the grammar we implemented)
+ // of designators and found an '=' sign. The following tokens must be
+ // the initializer.
+ ConsumeToken();
+ return ParseInitializer();
+
+ default: {
+ // We read some number (at least one due to the grammar we implemented)
+ // of designators and found something that isn't an = or an initializer.
+ // If we have exactly one array designator [TODO CHECK], this is the GNU
+ // 'designation: array-designator' extension. Otherwise, it is a parse
+ // error.
+ SourceLocation Loc = Tok.getLocation();
+ ExprResult Init = ParseInitializer();
+ if (Init.isInvalid) return Init;
+
+ Diag(Tok, diag::ext_gnu_missing_equal_designator);
+ return Init;
+ }
+ case tok::period:
+ // designator: '.' identifier
+ ConsumeToken();
+ if (ExpectAndConsume(tok::identifier, diag::err_expected_ident))
+ return ExprResult(true);
+ break;
+
+ case tok::l_square: {
+ // array-designator: '[' constant-expression ']'
+ // array-designator: '[' constant-expression '...' constant-expression ']'
+ SourceLocation StartLoc = ConsumeBracket();
+
+ ExprResult Idx = ParseConstantExpression();
+ if (Idx.isInvalid) {
+ SkipUntil(tok::r_square);
+ return Idx;
+ }
+
+ // Handle the gnu array range extension.
+ if (Tok.getKind() == tok::ellipsis) {
+ Diag(Tok, diag::ext_gnu_array_range);
+ ConsumeToken();
+
+ ExprResult RHS = ParseConstantExpression();
+ if (RHS.isInvalid) {
+ SkipUntil(tok::r_square);
+ return RHS;
+ }
+ }
+
+ MatchRHSPunctuation(tok::r_square, StartLoc);
+ break;
+ }
+ case tok::identifier: {
+ // Due to the GNU "designation: identifier ':'" extension, we don't know
+ // whether something starting with an identifier is an
+ // assignment-expression or if it is an old-style structure field
+ // designator.
+ // TODO: Check that this is the first designator.
+ LexerToken Ident = Tok;
+ ConsumeToken();
+
+ // If this is the gross GNU extension, handle it now.
+ if (Tok.getKind() == tok::colon) {
+ Diag(Ident, diag::ext_gnu_old_style_field_designator);
+ ConsumeToken();
+ return ParseInitializer();
+ }
+
+ // Otherwise, we just consumed the first token of an expression. Parse
+ // the rest of it now.
+ return ParseAssignmentExprWithLeadingIdentifier(Ident);
+ }
+ }
+ }
+}
+
+
+/// ParseInitializer
+/// initializer: [C99 6.7.8]
+/// assignment-expression
+/// '{' initializer-list '}'
+/// '{' initializer-list ',' '}'
+/// [GNU] '{' '}'
+///
+/// initializer-list:
+/// designation[opt] initializer
+/// initializer-list ',' designation[opt] initializer
+///
+Parser::ExprResult Parser::ParseInitializer() {
+ if (Tok.getKind() != tok::l_brace)
+ return ParseAssignmentExpression();
+
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ // We support empty initializers, but tell the user that they aren't using
+ // C99-clean code.
+ if (Tok.getKind() == tok::r_brace)
+ Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
+ else {
+ while (1) {
+ // Parse: designation[opt] initializer
+
+ // If we know that this cannot be a designation, just parse the nested
+ // initializer directly.
+ ExprResult SubElt;
+ if (!MayBeDesignationStart(Tok.getKind()))
+ SubElt = ParseInitializer();
+ else
+ SubElt = ParseInitializerWithPotentialDesignator();
+
+ // If we couldn't parse the subelement, bail out.
+ if (SubElt.isInvalid) {
+ SkipUntil(tok::r_brace);
+ return SubElt;
+ }
+
+ // If we don't have a comma continued list, we're done.
+ if (Tok.getKind() != tok::comma) break;
+ ConsumeToken();
+
+ // Handle trailing comma.
+ if (Tok.getKind() == tok::r_brace) break;
+ }
+ }
+
+ // Match the '}'.
+ MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+ return ExprResult(false);
+}
+
diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp
new file mode 100644
index 0000000..00b606a
--- /dev/null
+++ b/Parse/ParseObjc.cpp
@@ -0,0 +1,105 @@
+//===--- ParseObjc.cpp - Objective C Parsing ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Steve Naroff and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Objective-C portions of the Parser interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/SmallVector.h"
+using namespace clang;
+
+
+/// ParseExternalDeclaration:
+/// external-declaration: [C99 6.9]
+/// [OBJC] objc-class-definition
+/// [OBJC] objc-class-declaration [TODO]
+/// [OBJC] objc-alias-declaration [TODO]
+/// [OBJC] objc-protocol-definition [TODO]
+/// [OBJC] objc-method-definition [TODO]
+/// [OBJC] '@' 'end' [TODO]
+void Parser::ParseObjCAtDirectives() {
+ SourceLocation AtLoc = ConsumeToken(); // the "@"
+
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ switch (II ? II->getObjCKeywordID() : tok::objc_not_keyword) {
+ case tok::objc_class:
+ return ParseObjCAtClassDeclaration(AtLoc);
+ case tok::objc_interface:
+ return ParseObjCAtInterfaceDeclaration();
+ case tok::objc_protocol:
+ return ParseObjCAtProtocolDeclaration();
+ case tok::objc_implementation:
+ return ParseObjCAtImplementationDeclaration();
+ case tok::objc_end:
+ return ParseObjCAtEndDeclaration();
+ case tok::objc_compatibility_alias:
+ return ParseObjCAtAliasDeclaration();
+ default:
+ Diag(AtLoc, diag::err_unexpected_at);
+ SkipUntil(tok::semi);
+ }
+}
+
+///
+/// objc-class-declaration:
+/// '@' 'class' identifier-list ';'
+///
+void Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
+ ConsumeToken(); // the identifier "class"
+ llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
+
+ while (1) {
+ if (Tok.getKind() != tok::identifier) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::semi);
+ return;
+ }
+
+ ClassNames.push_back(Tok.getIdentifierInfo());
+ ConsumeToken();
+
+ if (Tok.getKind() != tok::comma)
+ break;
+
+ ConsumeToken();
+ }
+
+ // Consume the ';'.
+ if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
+ return;
+
+ Actions.ParsedObjcClassDeclaration(CurScope,
+ &ClassNames[0], ClassNames.size());
+}
+
+void Parser::ParseObjCAtInterfaceDeclaration() {
+ assert(0 && "Unimp");
+}
+void Parser::ParseObjCAtProtocolDeclaration() {
+ assert(0 && "Unimp");
+}
+void Parser::ParseObjCAtImplementationDeclaration() {
+ assert(0 && "Unimp");
+}
+void Parser::ParseObjCAtEndDeclaration() {
+ assert(0 && "Unimp");
+}
+void Parser::ParseObjCAtAliasDeclaration() {
+ assert(0 && "Unimp");
+}
+
+void Parser::ParseObjCInstanceMethodDeclaration() {
+ assert(0 && "Unimp");
+}
+
+void Parser::ParseObjCClassMethodDeclaration() {
+ assert(0 && "Unimp");
+}
diff --git a/Parse/ParseStmt.cpp b/Parse/ParseStmt.cpp
new file mode 100644
index 0000000..7bc7a9c
--- /dev/null
+++ b/Parse/ParseStmt.cpp
@@ -0,0 +1,848 @@
+//===--- ParseStmt.cpp - Statement and Block Parser -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Statement and Block portions of the Parser
+// interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// C99 6.8: Statements and Blocks.
+//===----------------------------------------------------------------------===//
+
+/// ParseStatementOrDeclaration - Read 'statement' or 'declaration'.
+/// StatementOrDeclaration:
+/// statement
+/// declaration
+///
+/// statement:
+/// labeled-statement
+/// compound-statement
+/// expression-statement
+/// selection-statement
+/// iteration-statement
+/// jump-statement
+/// [OBC] objc-throw-statement [TODO]
+/// [OBC] objc-try-catch-statement [TODO]
+/// [OBC] objc-synchronized-statement [TODO]
+/// [GNU] asm-statement
+/// [OMP] openmp-construct [TODO]
+///
+/// labeled-statement:
+/// identifier ':' statement
+/// 'case' constant-expression ':' statement
+/// 'default' ':' statement
+///
+/// selection-statement:
+/// if-statement
+/// switch-statement
+///
+/// iteration-statement:
+/// while-statement
+/// do-statement
+/// for-statement
+///
+/// expression-statement:
+/// expression[opt] ';'
+///
+/// jump-statement:
+/// 'goto' identifier ';'
+/// 'continue' ';'
+/// 'break' ';'
+/// 'return' expression[opt] ';'
+/// [GNU] 'goto' '*' expression ';'
+///
+/// [OBC] objc-throw-statement: [TODO]
+/// [OBC] '@' 'throw' expression ';' [TODO]
+/// [OBC] '@' 'throw' ';' [TODO]
+///
+Parser::StmtResult Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
+ const char *SemiError = 0;
+ Parser::StmtResult Res;
+
+ // Cases in this switch statement should fall through if the parser expects
+ // the token to end in a semicolon (in which case SemiError should be set),
+ // or they directly 'return;' if not.
+ switch (Tok.getKind()) {
+ case tok::identifier: // C99 6.8.1: labeled-statement
+ // identifier ':' statement
+ // declaration (if !OnlyStatement)
+ // expression[opt] ';'
+ return ParseIdentifierStatement(OnlyStatement);
+
+ default:
+ if (!OnlyStatement && isDeclarationSpecifier()) {
+ // TODO: warn/disable if declaration is in the middle of a block and !C99.
+ return Actions.ParseDeclStmt(ParseDeclaration(Declarator::BlockContext));
+ } else if (Tok.getKind() == tok::r_brace) {
+ Diag(Tok, diag::err_expected_statement);
+ return true;
+ } else {
+ // expression[opt] ';'
+ ExprResult Res = ParseExpression();
+ if (Res.isInvalid) {
+ // If the expression is invalid, skip ahead to the next semicolon. Not
+ // doing this opens us up to the possibility of infinite loops if
+ // ParseExpression does not consume any tokens.
+ SkipUntil(tok::semi);
+ return true;
+ }
+ // Otherwise, eat the semicolon.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
+ return Actions.ParseExprStmt(Res.Val);
+ }
+
+ case tok::kw_case: // C99 6.8.1: labeled-statement
+ return ParseCaseStatement();
+ case tok::kw_default: // C99 6.8.1: labeled-statement
+ return ParseDefaultStatement();
+
+ case tok::l_brace: // C99 6.8.2: compound-statement
+ return ParseCompoundStatement();
+ case tok::semi: // C99 6.8.3p3: expression[opt] ';'
+ return Actions.ParseNullStmt(ConsumeToken());
+
+ case tok::kw_if: // C99 6.8.4.1: if-statement
+ return ParseIfStatement();
+ case tok::kw_switch: // C99 6.8.4.2: switch-statement
+ return ParseSwitchStatement();
+
+ case tok::kw_while: // C99 6.8.5.1: while-statement
+ return ParseWhileStatement();
+ case tok::kw_do: // C99 6.8.5.2: do-statement
+ Res = ParseDoStatement();
+ SemiError = "do/while loop";
+ break;
+ case tok::kw_for: // C99 6.8.5.3: for-statement
+ return ParseForStatement();
+
+ case tok::kw_goto: // C99 6.8.6.1: goto-statement
+ Res = ParseGotoStatement();
+ SemiError = "goto statement";
+ break;
+ case tok::kw_continue: // C99 6.8.6.2: continue-statement
+ Res = ParseContinueStatement();
+ SemiError = "continue statement";
+ break;
+ case tok::kw_break: // C99 6.8.6.3: break-statement
+ Res = ParseBreakStatement();
+ SemiError = "break statement";
+ break;
+ case tok::kw_return: // C99 6.8.6.4: return-statement
+ Res = ParseReturnStatement();
+ SemiError = "return statement";
+ break;
+
+ case tok::kw_asm:
+ Res = ParseAsmStatement();
+ SemiError = "asm statement";
+ break;
+ }
+
+ // If we reached this code, the statement must end in a semicolon.
+ if (Tok.getKind() == tok::semi) {
+ ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_expected_semi_after, SemiError);
+ SkipUntil(tok::semi);
+ }
+ return Res;
+}
+
+/// ParseIdentifierStatement - Because we don't have two-token lookahead, we
+/// have a bit of a quandry here. Reading the identifier is necessary to see if
+/// there is a ':' after it. If there is, this is a label, regardless of what
+/// else the identifier can mean. If not, this is either part of a declaration
+/// (if the identifier is a type-name) or part of an expression.
+///
+/// labeled-statement:
+/// identifier ':' statement
+/// [GNU] identifier ':' attributes[opt] statement
+/// declaration (if !OnlyStatement)
+/// expression[opt] ';'
+///
+Parser::StmtResult Parser::ParseIdentifierStatement(bool OnlyStatement) {
+ assert(Tok.getKind() == tok::identifier && Tok.getIdentifierInfo() &&
+ "Not an identifier!");
+
+ LexerToken IdentTok = Tok; // Save the whole token.
+ ConsumeToken(); // eat the identifier.
+
+ // identifier ':' statement
+ if (Tok.getKind() == tok::colon) {
+ SourceLocation ColonLoc = ConsumeToken();
+
+ // Read label attributes, if present.
+ DeclTy *AttrList = 0;
+ if (Tok.getKind() == tok::kw___attribute)
+ // TODO: save these somewhere.
+ AttrList = ParseAttributes();
+
+ StmtResult SubStmt = ParseStatement();
+
+ // Broken substmt shouldn't prevent the label from being added to the AST.
+ if (SubStmt.isInvalid)
+ SubStmt = Actions.ParseNullStmt(ColonLoc);
+
+ return Actions.ParseLabelStmt(IdentTok.getLocation(),
+ IdentTok.getIdentifierInfo(),
+ ColonLoc, SubStmt.Val);
+ }
+
+ // Check to see if this is a declaration.
+ void *TypeRep;
+ if (!OnlyStatement &&
+ (TypeRep = Actions.isTypeName(*IdentTok.getIdentifierInfo(), CurScope))) {
+ // Handle this. Warn/disable if in middle of block and !C99.
+ DeclSpec DS;
+
+ // Add the typedef name to the start of the decl-specs.
+ const char *PrevSpec = 0;
+ int isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef,
+ IdentTok.getLocation(), PrevSpec,
+ TypeRep);
+ assert(!isInvalid && "First declspec can't be invalid!");
+
+ // ParseDeclarationSpecifiers will continue from there.
+ ParseDeclarationSpecifiers(DS);
+
+ // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
+ // declaration-specifiers init-declarator-list[opt] ';'
+ if (Tok.getKind() == tok::semi) {
+ // TODO: emit error on 'int;' or 'const enum foo;'.
+ // if (!DS.isMissingDeclaratorOk()) Diag(...);
+
+ ConsumeToken();
+ // FIXME: Return this as a type decl.
+ return 0;
+ }
+
+ // Parse all the declarators.
+ Declarator DeclaratorInfo(DS, Declarator::BlockContext);
+ ParseDeclarator(DeclaratorInfo);
+
+ DeclTy *Decl = ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
+ return Decl ? Actions.ParseDeclStmt(Decl) : 0;
+ }
+
+ // Otherwise, this is an expression. Seed it with II and parse it.
+ ExprResult Res = ParseExpressionWithLeadingIdentifier(IdentTok);
+ if (Res.isInvalid) {
+ SkipUntil(tok::semi);
+ return true;
+ } else if (Tok.getKind() != tok::semi) {
+ Diag(Tok, diag::err_expected_semi_after, "expression");
+ SkipUntil(tok::semi);
+ return true;
+ } else {
+ ConsumeToken();
+ // Convert expr to a stmt.
+ return Actions.ParseExprStmt(Res.Val);
+ }
+}
+
+/// ParseCaseStatement
+/// labeled-statement:
+/// 'case' constant-expression ':' statement
+/// [GNU] 'case' constant-expression '...' constant-expression ':' statement
+///
+/// Note that this does not parse the 'statement' at the end.
+///
+Parser::StmtResult Parser::ParseCaseStatement() {
+ assert(Tok.getKind() == tok::kw_case && "Not a case stmt!");
+ SourceLocation CaseLoc = ConsumeToken(); // eat the 'case'.
+
+ ExprResult LHS = ParseConstantExpression();
+ if (LHS.isInvalid) {
+ SkipUntil(tok::colon);
+ return true;
+ }
+
+ // GNU case range extension.
+ SourceLocation DotDotDotLoc;
+ ExprTy *RHSVal = 0;
+ if (Tok.getKind() == tok::ellipsis) {
+ Diag(Tok, diag::ext_gnu_case_range);
+ DotDotDotLoc = ConsumeToken();
+
+ ExprResult RHS = ParseConstantExpression();
+ if (RHS.isInvalid) {
+ SkipUntil(tok::colon);
+ return true;
+ }
+ RHSVal = RHS.Val;
+ }
+
+ if (Tok.getKind() != tok::colon) {
+ Diag(Tok, diag::err_expected_colon_after, "'case'");
+ SkipUntil(tok::colon);
+ return true;
+ }
+
+ SourceLocation ColonLoc = ConsumeToken();
+
+ // Diagnose the common error "switch (X) { case 4: }", which is not valid.
+ if (Tok.getKind() == tok::r_brace) {
+ Diag(Tok, diag::err_label_end_of_compound_statement);
+ return true;
+ }
+
+ StmtResult SubStmt = ParseStatement();
+
+ // Broken substmt shouldn't prevent the case from being added to the AST.
+ if (SubStmt.isInvalid)
+ SubStmt = Actions.ParseNullStmt(ColonLoc);
+
+ // TODO: look up enclosing switch stmt.
+ return Actions.ParseCaseStmt(CaseLoc, LHS.Val, DotDotDotLoc, RHSVal, ColonLoc,
+ SubStmt.Val);
+}
+
+/// ParseDefaultStatement
+/// labeled-statement:
+/// 'default' ':' statement
+/// Note that this does not parse the 'statement' at the end.
+///
+Parser::StmtResult Parser::ParseDefaultStatement() {
+ assert(Tok.getKind() == tok::kw_default && "Not a default stmt!");
+ SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
+
+ if (Tok.getKind() != tok::colon) {
+ Diag(Tok, diag::err_expected_colon_after, "'default'");
+ SkipUntil(tok::colon);
+ return true;
+ }
+
+ SourceLocation ColonLoc = ConsumeToken();
+
+ // Diagnose the common error "switch (X) {... default: }", which is not valid.
+ if (Tok.getKind() == tok::r_brace) {
+ Diag(Tok, diag::err_label_end_of_compound_statement);
+ return true;
+ }
+
+ StmtResult SubStmt = ParseStatement();
+ if (SubStmt.isInvalid)
+ return true;
+
+ // TODO: look up enclosing switch stmt.
+ return Actions.ParseDefaultStmt(DefaultLoc, ColonLoc, SubStmt.Val);
+}
+
+
+/// ParseCompoundStatement - Parse a "{}" block.
+///
+/// compound-statement: [C99 6.8.2]
+/// { block-item-list[opt] }
+/// [GNU] { label-declarations block-item-list } [TODO]
+///
+/// block-item-list:
+/// block-item
+/// block-item-list block-item
+///
+/// block-item:
+/// declaration
+/// [GNU] '__extension__' declaration [TODO]
+/// statement
+/// [OMP] openmp-directive [TODO]
+///
+/// [GNU] label-declarations:
+/// [GNU] label-declaration
+/// [GNU] label-declarations label-declaration
+///
+/// [GNU] label-declaration:
+/// [GNU] '__label__' identifier-list ';'
+///
+/// [OMP] openmp-directive: [TODO]
+/// [OMP] barrier-directive
+/// [OMP] flush-directive
+///
+Parser::StmtResult Parser::ParseCompoundStatement() {
+ assert(Tok.getKind() == tok::l_brace && "Not a compount stmt!");
+
+ // Enter a scope to hold everything within the compound stmt.
+ EnterScope(0);
+
+ // Parse the statements in the body.
+ StmtResult Body = ParseCompoundStatementBody();
+
+ ExitScope();
+ return Body;
+}
+
+
+/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the
+/// ParseCompoundStmt action. This expects the '{' to be the current token, and
+/// consume the '}' at the end of the block. It does not manipulate the scope
+/// stack.
+Parser::StmtResult Parser::ParseCompoundStatementBody() {
+ SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'.
+
+ // TODO: "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are
+ // only allowed at the start of a compound stmt.
+
+ llvm::SmallVector<StmtTy*, 32> Stmts;
+ while (Tok.getKind() != tok::r_brace && Tok.getKind() != tok::eof) {
+ StmtResult R = ParseStatementOrDeclaration(false);
+ if (!R.isInvalid && R.Val)
+ Stmts.push_back(R.Val);
+ }
+
+ // We broke out of the while loop because we found a '}' or EOF.
+ if (Tok.getKind() != tok::r_brace) {
+ Diag(Tok, diag::err_expected_rbrace);
+ return 0;
+ }
+
+ SourceLocation RBraceLoc = ConsumeBrace();
+ return Actions.ParseCompoundStmt(LBraceLoc, RBraceLoc,
+ &Stmts[0], Stmts.size());
+}
+
+/// ParseIfStatement
+/// if-statement: [C99 6.8.4.1]
+/// 'if' '(' expression ')' statement
+/// 'if' '(' expression ')' statement 'else' statement
+///
+Parser::StmtResult Parser::ParseIfStatement() {
+ assert(Tok.getKind() == tok::kw_if && "Not an if stmt!");
+ SourceLocation IfLoc = ConsumeToken(); // eat the 'if'.
+
+ if (Tok.getKind() != tok::l_paren) {
+ Diag(Tok, diag::err_expected_lparen_after, "if");
+ SkipUntil(tok::semi);
+ return true;
+ }
+
+ // Parse the condition.
+ ExprResult CondExp = ParseSimpleParenExpression();
+ if (CondExp.isInvalid) {
+ SkipUntil(tok::semi);
+ return true;
+ }
+
+ // Read the if condition.
+ StmtResult CondStmt = ParseStatement();
+
+ // Broken substmt shouldn't prevent the label from being added to the AST.
+ if (CondStmt.isInvalid)
+ CondStmt = Actions.ParseNullStmt(Tok.getLocation());
+
+
+ // If it has an else, parse it.
+ SourceLocation ElseLoc;
+ StmtResult ElseStmt(false);
+ if (Tok.getKind() == tok::kw_else) {
+ ElseLoc = ConsumeToken();
+ ElseStmt = ParseStatement();
+
+ if (ElseStmt.isInvalid)
+ ElseStmt = Actions.ParseNullStmt(ElseLoc);
+ }
+
+ return Actions.ParseIfStmt(IfLoc, CondExp.Val, CondStmt.Val,
+ ElseLoc, ElseStmt.Val);
+}
+
+/// ParseSwitchStatement
+/// switch-statement:
+/// 'switch' '(' expression ')' statement
+Parser::StmtResult Parser::ParseSwitchStatement() {
+ assert(Tok.getKind() == tok::kw_switch && "Not a switch stmt!");
+ SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'.
+
+ if (Tok.getKind() != tok::l_paren) {
+ Diag(Tok, diag::err_expected_lparen_after, "switch");
+ SkipUntil(tok::semi);
+ return true;
+ }
+
+ // Start the switch scope.
+ EnterScope(Scope::BreakScope);
+
+ // Parse the condition.
+ ExprResult Cond = ParseSimpleParenExpression();
+
+ // Read the body statement.
+ StmtResult Body = ParseStatement();
+
+ ExitScope();
+
+ if (Cond.isInvalid || Body.isInvalid) return true;
+
+ return Actions.ParseSwitchStmt(SwitchLoc, Cond.Val, Body.Val);
+}
+
+/// ParseWhileStatement
+/// while-statement: [C99 6.8.5.1]
+/// 'while' '(' expression ')' statement
+Parser::StmtResult Parser::ParseWhileStatement() {
+ assert(Tok.getKind() == tok::kw_while && "Not a while stmt!");
+ SourceLocation WhileLoc = Tok.getLocation();
+ ConsumeToken(); // eat the 'while'.
+
+ if (Tok.getKind() != tok::l_paren) {
+ Diag(Tok, diag::err_expected_lparen_after, "while");
+ SkipUntil(tok::semi);
+ return true;
+ }
+
+ // Start the loop scope.
+ EnterScope(Scope::BreakScope | Scope::ContinueScope);
+
+ // Parse the condition.
+ ExprResult Cond = ParseSimpleParenExpression();
+
+ // Read the body statement.
+ StmtResult Body = ParseStatement();
+
+ ExitScope();
+
+ if (Cond.isInvalid || Body.isInvalid) return true;
+
+ return Actions.ParseWhileStmt(WhileLoc, Cond.Val, Body.Val);
+}
+
+/// ParseDoStatement
+/// do-statement: [C99 6.8.5.2]
+/// 'do' statement 'while' '(' expression ')' ';'
+/// Note: this lets the caller parse the end ';'.
+Parser::StmtResult Parser::ParseDoStatement() {
+ assert(Tok.getKind() == tok::kw_do && "Not a do stmt!");
+ SourceLocation DoLoc = ConsumeToken(); // eat the 'do'.
+
+ // Start the loop scope.
+ EnterScope(Scope::BreakScope | Scope::ContinueScope);
+
+ // Read the body statement.
+ StmtResult Body = ParseStatement();
+
+ if (Tok.getKind() != tok::kw_while) {
+ ExitScope();
+ Diag(Tok, diag::err_expected_while);
+ Diag(DoLoc, diag::err_matching, "do");
+ SkipUntil(tok::semi);
+ return true;
+ }
+ SourceLocation WhileLoc = ConsumeToken();
+
+ if (Tok.getKind() != tok::l_paren) {
+ ExitScope();
+ Diag(Tok, diag::err_expected_lparen_after, "do/while");
+ SkipUntil(tok::semi);
+ return true;
+ }
+
+ // Parse the condition.
+ ExprResult Cond = ParseSimpleParenExpression();
+
+ ExitScope();
+
+ if (Cond.isInvalid || Body.isInvalid) return true;
+
+ return Actions.ParseDoStmt(DoLoc, Body.Val, WhileLoc, Cond.Val);
+}
+
+/// ParseForStatement
+/// for-statement: [C99 6.8.5.3]
+/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
+/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
+Parser::StmtResult Parser::ParseForStatement() {
+ assert(Tok.getKind() == tok::kw_for && "Not a for stmt!");
+ SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
+
+ if (Tok.getKind() != tok::l_paren) {
+ Diag(Tok, diag::err_expected_lparen_after, "for");
+ SkipUntil(tok::semi);
+ return true;
+ }
+
+ EnterScope(Scope::BreakScope | Scope::ContinueScope);
+
+ SourceLocation LParenLoc = ConsumeParen();
+ ExprResult Value;
+
+ StmtTy *FirstPart = 0;
+ ExprTy *SecondPart = 0;
+ StmtTy *ThirdPart = 0;
+
+ // Parse the first part of the for specifier.
+ if (Tok.getKind() == tok::semi) { // for (;
+ // no first part, eat the ';'.
+ ConsumeToken();
+ } else if (isDeclarationSpecifier()) { // for (int X = 4;
+ // Parse declaration, which eats the ';'.
+ if (!getLang().C99) // Use of C99-style for loops in C90 mode?
+ Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
+ DeclTy *aBlockVarDecl = ParseDeclaration(Declarator::ForContext);
+ StmtResult stmtResult = Actions.ParseDeclStmt(aBlockVarDecl);
+ FirstPart = stmtResult.isInvalid ? 0 : stmtResult.Val;
+ } else {
+ Value = ParseExpression();
+
+ // Turn the expression into a stmt.
+ if (!Value.isInvalid) {
+ StmtResult R = Actions.ParseExprStmt(Value.Val);
+ if (!R.isInvalid)
+ FirstPart = R.Val;
+ }
+
+ if (Tok.getKind() == tok::semi) {
+ ConsumeToken();
+ } else {
+ if (!Value.isInvalid) Diag(Tok, diag::err_expected_semi_for);
+ SkipUntil(tok::semi);
+ }
+ }
+
+ // Parse the second part of the for specifier.
+ if (Tok.getKind() == tok::semi) { // for (...;;
+ // no second part.
+ Value = ExprResult();
+ } else {
+ Value = ParseExpression();
+ if (!Value.isInvalid)
+ SecondPart = Value.Val;
+ }
+
+ if (Tok.getKind() == tok::semi) {
+ ConsumeToken();
+ } else {
+ if (!Value.isInvalid) Diag(Tok, diag::err_expected_semi_for);
+ SkipUntil(tok::semi);
+ }
+
+ // Parse the third part of the for specifier.
+ if (Tok.getKind() == tok::r_paren) { // for (...;...;)
+ // no third part.
+ Value = ExprResult();
+ } else {
+ Value = ParseExpression();
+ if (!Value.isInvalid) {
+ // Turn the expression into a stmt.
+ StmtResult R = Actions.ParseExprStmt(Value.Val);
+ if (!R.isInvalid)
+ ThirdPart = R.Val;
+ }
+ }
+
+ // Match the ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ // Read the body statement.
+ StmtResult Body = ParseStatement();
+
+ // Leave the for-scope.
+ ExitScope();
+
+ if (Body.isInvalid)
+ return Body;
+
+ return Actions.ParseForStmt(ForLoc, LParenLoc, FirstPart, SecondPart,
+ ThirdPart, RParenLoc, Body.Val);
+}
+
+/// ParseGotoStatement
+/// jump-statement:
+/// 'goto' identifier ';'
+/// [GNU] 'goto' '*' expression ';'
+///
+/// Note: this lets the caller parse the end ';'.
+///
+Parser::StmtResult Parser::ParseGotoStatement() {
+ assert(Tok.getKind() == tok::kw_goto && "Not a goto stmt!");
+ SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'.
+
+ StmtResult Res;
+ if (Tok.getKind() == tok::identifier) {
+ Res = Actions.ParseGotoStmt(GotoLoc, Tok.getLocation(),
+ Tok.getIdentifierInfo());
+ ConsumeToken();
+ } else if (Tok.getKind() == tok::star && !getLang().NoExtensions) {
+ // GNU indirect goto extension.
+ Diag(Tok, diag::ext_gnu_indirect_goto);
+ SourceLocation StarLoc = ConsumeToken();
+ ExprResult R = ParseExpression();
+ if (R.isInvalid) { // Skip to the semicolon, but don't consume it.
+ SkipUntil(tok::semi, false, true);
+ return true;
+ }
+ Res = Actions.ParseIndirectGotoStmt(GotoLoc, StarLoc, R.Val);
+ }
+ return Res;
+}
+
+/// ParseContinueStatement
+/// jump-statement:
+/// 'continue' ';'
+///
+/// Note: this lets the caller parse the end ';'.
+///
+Parser::StmtResult Parser::ParseContinueStatement() {
+ SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'.
+ return Actions.ParseContinueStmt(ContinueLoc, CurScope);
+}
+
+/// ParseBreakStatement
+/// jump-statement:
+/// 'break' ';'
+///
+/// Note: this lets the caller parse the end ';'.
+///
+Parser::StmtResult Parser::ParseBreakStatement() {
+ SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'.
+ return Actions.ParseBreakStmt(BreakLoc, CurScope);
+}
+
+/// ParseReturnStatement
+/// jump-statement:
+/// 'return' expression[opt] ';'
+Parser::StmtResult Parser::ParseReturnStatement() {
+ assert(Tok.getKind() == tok::kw_return && "Not a return stmt!");
+ SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'.
+
+ ExprResult R(0);
+ if (Tok.getKind() != tok::semi) {
+ R = ParseExpression();
+ if (R.isInvalid) { // Skip to the semicolon, but don't consume it.
+ SkipUntil(tok::semi, false, true);
+ return true;
+ }
+ }
+ return Actions.ParseReturnStmt(ReturnLoc, R.Val);
+}
+
+/// ParseAsmStatement - Parse a GNU extended asm statement.
+/// [GNU] asm-statement:
+/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';'
+///
+/// [GNU] asm-argument:
+/// asm-string-literal
+/// asm-string-literal ':' asm-operands[opt]
+/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
+/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
+/// ':' asm-clobbers
+///
+/// [GNU] asm-clobbers:
+/// asm-string-literal
+/// asm-clobbers ',' asm-string-literal
+///
+Parser::StmtResult Parser::ParseAsmStatement() {
+ assert(Tok.getKind() == tok::kw_asm && "Not an asm stmt");
+ ConsumeToken();
+
+ DeclSpec DS;
+ SourceLocation Loc = Tok.getLocation();
+ ParseTypeQualifierListOpt(DS);
+
+ // GNU asms accept, but warn, about type-qualifiers other than volatile.
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+ Diag(Loc, diag::w_asm_qualifier_ignored, "const");
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
+ Diag(Loc, diag::w_asm_qualifier_ignored, "restrict");
+
+ // Remember if this was a volatile asm.
+ //bool isVolatile = DS.TypeQualifiers & DeclSpec::TQ_volatile;
+
+ if (Tok.getKind() != tok::l_paren) {
+ Diag(Tok, diag::err_expected_lparen_after, "asm");
+ SkipUntil(tok::r_paren);
+ return true;
+ }
+ Loc = ConsumeParen();
+
+ ParseAsmStringLiteral();
+
+ // Parse Outputs, if present.
+ ParseAsmOperandsOpt();
+
+ // Parse Inputs, if present.
+ ParseAsmOperandsOpt();
+
+ // Parse the clobbers, if present.
+ if (Tok.getKind() == tok::colon) {
+ ConsumeToken();
+
+ if (isTokenStringLiteral()) {
+ // Parse the asm-string list for clobbers.
+ while (1) {
+ ParseAsmStringLiteral();
+
+ if (Tok.getKind() != tok::comma) break;
+ ConsumeToken();
+ }
+ }
+ }
+
+ MatchRHSPunctuation(tok::r_paren, Loc);
+
+ // FIXME: Implement action for asm parsing.
+ return false;
+}
+
+/// ParseAsmOperands - Parse the asm-operands production as used by
+/// asm-statement. We also parse a leading ':' token. If the leading colon is
+/// not present, we do not parse anything.
+///
+/// [GNU] asm-operands:
+/// asm-operand
+/// asm-operands ',' asm-operand
+///
+/// [GNU] asm-operand:
+/// asm-string-literal '(' expression ')'
+/// '[' identifier ']' asm-string-literal '(' expression ')'
+///
+void Parser::ParseAsmOperandsOpt() {
+ // Only do anything if this operand is present.
+ if (Tok.getKind() != tok::colon) return;
+ ConsumeToken();
+
+ // 'asm-operands' isn't present?
+ if (!isTokenStringLiteral() && Tok.getKind() != tok::l_square)
+ return;
+
+ while (1) {
+ // Read the [id] if present.
+ if (Tok.getKind() == tok::l_square) {
+ SourceLocation Loc = ConsumeBracket();
+
+ if (Tok.getKind() != tok::identifier) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::r_paren);
+ return;
+ }
+ MatchRHSPunctuation(tok::r_square, Loc);
+ }
+
+ ParseAsmStringLiteral();
+
+ if (Tok.getKind() != tok::l_paren) {
+ Diag(Tok, diag::err_expected_lparen_after, "asm operand");
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ // Read the parenthesized expression.
+ ExprResult Res = ParseSimpleParenExpression();
+ if (Res.isInvalid) {
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ // Eat the comma and continue parsing if it exists.
+ if (Tok.getKind() != tok::comma) return;
+ ConsumeToken();
+ }
+}
diff --git a/Parse/Parser.cpp b/Parse/Parser.cpp
new file mode 100644
index 0000000..251febb
--- /dev/null
+++ b/Parse/Parser.cpp
@@ -0,0 +1,615 @@
+//===--- Parser.cpp - C Language Family Parser ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Parser interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+using namespace clang;
+
+Parser::Parser(Preprocessor &pp, Action &actions)
+ : PP(pp), Actions(actions), Diags(PP.getDiagnostics()) {
+ Tok.setKind(tok::eof);
+ CurScope = 0;
+
+ ParenCount = BracketCount = BraceCount = 0;
+}
+
+/// Out-of-line virtual destructor to provide home for Action class.
+Action::~Action() {}
+
+
+void Parser::Diag(SourceLocation Loc, unsigned DiagID,
+ const std::string &Msg) {
+ Diags.Report(Loc, DiagID, &Msg, 1);
+}
+
+/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'),
+/// this helper function matches and consumes the specified RHS token if
+/// present. If not present, it emits the specified diagnostic indicating
+/// that the parser failed to match the RHS of the token at LHSLoc. LHSName
+/// should be the name of the unmatched LHS token.
+SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok,
+ SourceLocation LHSLoc) {
+
+ if (Tok.getKind() == RHSTok)
+ return ConsumeAnyToken();
+
+ SourceLocation R = Tok.getLocation();
+ const char *LHSName = "unknown";
+ diag::kind DID = diag::err_parse_error;
+ switch (RHSTok) {
+ default: break;
+ case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break;
+ case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break;
+ case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break;
+ case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break;
+ }
+ Diag(Tok, DID);
+ Diag(LHSLoc, diag::err_matching, LHSName);
+ SkipUntil(RHSTok);
+ return R;
+}
+
+/// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the
+/// input. If so, it is consumed and false is returned.
+///
+/// If the input is malformed, this emits the specified diagnostic. Next, if
+/// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is
+/// returned.
+bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
+ const char *Msg, tok::TokenKind SkipToTok) {
+ if (Tok.getKind() == ExpectedTok) {
+ ConsumeAnyToken();
+ return false;
+ }
+
+ Diag(Tok, DiagID, Msg);
+ if (SkipToTok != tok::unknown)
+ SkipUntil(SkipToTok);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Error recovery.
+//===----------------------------------------------------------------------===//
+
+/// SkipUntil - Read tokens until we get to the specified token, then consume
+/// it (unless DontConsume is false). Because we cannot guarantee that the
+/// token will ever occur, this skips to the next token, or to some likely
+/// good stopping point. If StopAtSemi is true, skipping will stop at a ';'
+/// character.
+///
+/// If SkipUntil finds the specified token, it returns true, otherwise it
+/// returns false.
+bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
+ bool StopAtSemi, bool DontConsume) {
+ // We always want this function to skip at least one token if the first token
+ // isn't T and if not at EOF.
+ bool isFirstTokenSkipped = true;
+ while (1) {
+ // If we found one of the tokens, stop and return true.
+ for (unsigned i = 0; i != NumToks; ++i) {
+ if (Tok.getKind() == Toks[i]) {
+ if (DontConsume) {
+ // Noop, don't consume the token.
+ } else {
+ ConsumeAnyToken();
+ }
+ return true;
+ }
+ }
+
+ switch (Tok.getKind()) {
+ case tok::eof:
+ // Ran out of tokens.
+ return false;
+
+ case tok::l_paren:
+ // Recursively skip properly-nested parens.
+ ConsumeParen();
+ SkipUntil(tok::r_paren, false);
+ break;
+ case tok::l_square:
+ // Recursively skip properly-nested square brackets.
+ ConsumeBracket();
+ SkipUntil(tok::r_square, false);
+ break;
+ case tok::l_brace:
+ // Recursively skip properly-nested braces.
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, false);
+ break;
+
+ // Okay, we found a ']' or '}' or ')', which we think should be balanced.
+ // Since the user wasn't looking for this token (if they were, it would
+ // already be handled), this isn't balanced. If there is a LHS token at a
+ // higher level, we will assume that this matches the unbalanced token
+ // and return it. Otherwise, this is a spurious RHS token, which we skip.
+ case tok::r_paren:
+ if (ParenCount && !isFirstTokenSkipped)
+ return false; // Matches something.
+ ConsumeParen();
+ break;
+ case tok::r_square:
+ if (BracketCount && !isFirstTokenSkipped)
+ return false; // Matches something.
+ ConsumeBracket();
+ break;
+ case tok::r_brace:
+ if (BraceCount && !isFirstTokenSkipped)
+ return false; // Matches something.
+ ConsumeBrace();
+ break;
+
+ case tok::string_literal:
+ case tok::wide_string_literal:
+ ConsumeStringToken();
+ break;
+ case tok::semi:
+ if (StopAtSemi)
+ return false;
+ // FALL THROUGH.
+ default:
+ // Skip this token.
+ ConsumeToken();
+ break;
+ }
+ isFirstTokenSkipped = false;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Scope manipulation
+//===----------------------------------------------------------------------===//
+
+/// ScopeCache - Cache scopes to avoid malloc traffic.
+/// FIXME: eliminate this static ctor
+static llvm::SmallVector<Scope*, 16> ScopeCache;
+
+/// EnterScope - Start a new scope.
+void Parser::EnterScope(unsigned ScopeFlags) {
+ if (!ScopeCache.empty()) {
+ Scope *N = ScopeCache.back();
+ ScopeCache.pop_back();
+ N->Init(CurScope, ScopeFlags);
+ CurScope = N;
+ } else {
+ CurScope = new Scope(CurScope, ScopeFlags);
+ }
+}
+
+/// ExitScope - Pop a scope off the scope stack.
+void Parser::ExitScope() {
+ assert(CurScope && "Scope imbalance!");
+
+ // Inform the actions module that this scope is going away.
+ Actions.PopScope(Tok.getLocation(), CurScope);
+
+ Scope *Old = CurScope;
+ CurScope = Old->getParent();
+
+ if (ScopeCache.size() == 16)
+ delete Old;
+ else
+ ScopeCache.push_back(Old);
+}
+
+
+
+
+//===----------------------------------------------------------------------===//
+// C99 6.9: External Definitions.
+//===----------------------------------------------------------------------===//
+
+Parser::~Parser() {
+ // If we still have scopes active, delete the scope tree.
+ delete CurScope;
+
+ // Free the scope cache.
+ while (!ScopeCache.empty()) {
+ delete ScopeCache.back();
+ ScopeCache.pop_back();
+ }
+}
+
+/// Initialize - Warm up the parser.
+///
+void Parser::Initialize() {
+ // Prime the lexer look-ahead.
+ ConsumeToken();
+
+ // Create the global scope, install it as the current scope.
+ assert(CurScope == 0 && "A scope is already active?");
+ EnterScope(0);
+
+
+ // Install builtin types.
+ // TODO: Move this someplace more useful.
+ {
+ const char *Dummy;
+
+ //__builtin_va_list
+ DeclSpec DS;
+ bool Error = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, SourceLocation(),
+ Dummy);
+
+ // TODO: add a 'TST_builtin' type?
+ Error |= DS.SetTypeSpecType(DeclSpec::TST_int, SourceLocation(), Dummy);
+ assert(!Error && "Error setting up __builtin_va_list!");
+
+ Declarator D(DS, Declarator::FileContext);
+ D.SetIdentifier(PP.getIdentifierInfo("__builtin_va_list"),SourceLocation());
+ Actions.ParseDeclarator(CurScope, D, 0, 0);
+ }
+
+ if (Tok.getKind() == tok::eof) // Empty source file is an extension.
+ Diag(Tok, diag::ext_empty_source_file);
+}
+
+/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
+/// action tells us to. This returns true if the EOF was encountered.
+bool Parser::ParseTopLevelDecl(DeclTy*& Result) {
+ Result = 0;
+ if (Tok.getKind() == tok::eof) return true;
+
+ Result = ParseExternalDeclaration();
+ return false;
+}
+
+/// Finalize - Shut down the parser.
+///
+void Parser::Finalize() {
+ ExitScope();
+ assert(CurScope == 0 && "Scope imbalance!");
+}
+
+/// ParseTranslationUnit:
+/// translation-unit: [C99 6.9]
+/// external-declaration
+/// translation-unit external-declaration
+void Parser::ParseTranslationUnit() {
+ Initialize();
+
+ DeclTy *Res;
+ while (!ParseTopLevelDecl(Res))
+ /*parse them all*/;
+
+ Finalize();
+}
+
+/// ParseExternalDeclaration:
+/// external-declaration: [C99 6.9]
+/// function-definition [TODO]
+/// declaration [TODO]
+/// [EXT] ';'
+/// [GNU] asm-definition
+/// [GNU] __extension__ external-declaration [TODO]
+/// [OBJC] objc-class-definition
+/// [OBJC] objc-class-declaration
+/// [OBJC] objc-alias-declaration
+/// [OBJC] objc-protocol-definition
+/// [OBJC] objc-method-definition
+/// [OBJC] @end
+///
+/// [GNU] asm-definition:
+/// simple-asm-expr ';'
+///
+Parser::DeclTy *Parser::ParseExternalDeclaration() {
+ switch (Tok.getKind()) {
+ case tok::semi:
+ Diag(Tok, diag::ext_top_level_semi);
+ ConsumeToken();
+ // TODO: Invoke action for top-level semicolon.
+ return 0;
+ case tok::kw_asm:
+ ParseSimpleAsm();
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ "top-level asm block");
+ // TODO: Invoke action for top-level asm.
+ return 0;
+ case tok::at:
+ // @ is not a legal token unless objc is enabled, no need to check.
+ ParseObjCAtDirectives();
+ return 0;
+ case tok::minus:
+ if (getLang().ObjC1) {
+ ParseObjCInstanceMethodDeclaration();
+ } else {
+ Diag(Tok, diag::err_expected_external_declaration);
+ ConsumeToken();
+ }
+ return 0;
+ case tok::plus:
+ if (getLang().ObjC1) {
+ ParseObjCClassMethodDeclaration();
+ } else {
+ Diag(Tok, diag::err_expected_external_declaration);
+ ConsumeToken();
+ }
+ return 0;
+ case tok::kw_typedef:
+ // A function definition cannot start with a 'typedef' keyword.
+ return ParseDeclaration(Declarator::FileContext);
+ default:
+ // We can't tell whether this is a function-definition or declaration yet.
+ return ParseDeclarationOrFunctionDefinition();
+ }
+}
+
+/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or
+/// a declaration. We can't tell which we have until we read up to the
+/// compound-statement in function-definition.
+///
+/// function-definition: [C99 6.9.1]
+/// declaration-specifiers[opt] declarator declaration-list[opt]
+/// compound-statement [TODO]
+/// declaration: [C99 6.7]
+/// declaration-specifiers init-declarator-list[opt] ';' [TODO]
+/// [!C99] init-declarator-list ';' [TODO]
+/// [OMP] threadprivate-directive [TODO]
+///
+Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() {
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+
+ // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
+ // declaration-specifiers init-declarator-list[opt] ';'
+ if (Tok.getKind() == tok::semi) {
+ ConsumeToken();
+ return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ }
+
+ // Parse the first declarator.
+ Declarator DeclaratorInfo(DS, Declarator::FileContext);
+ ParseDeclarator(DeclaratorInfo);
+ // Error parsing the declarator?
+ if (DeclaratorInfo.getIdentifier() == 0) {
+ // If so, skip until the semi-colon or a }.
+ SkipUntil(tok::r_brace, true);
+ if (Tok.getKind() == tok::semi)
+ ConsumeToken();
+ return 0;
+ }
+
+ // If the declarator is the start of a function definition, handle it.
+ if (Tok.getKind() == tok::equal || // int X()= -> not a function def
+ Tok.getKind() == tok::comma || // int X(), -> not a function def
+ Tok.getKind() == tok::semi || // int X(); -> not a function def
+ Tok.getKind() == tok::kw_asm || // int X() __asm__ -> not a fn def
+ Tok.getKind() == tok::kw___attribute) {// int X() __attr__ -> not a fn def
+ // FALL THROUGH.
+ } else if (DeclaratorInfo.isFunctionDeclarator() &&
+ (Tok.getKind() == tok::l_brace || // int X() {}
+ isDeclarationSpecifier())) { // int X(f) int f; {}
+ return ParseFunctionDefinition(DeclaratorInfo);
+ } else {
+ if (DeclaratorInfo.isFunctionDeclarator())
+ Diag(Tok, diag::err_expected_fn_body);
+ else
+ Diag(Tok, diag::err_expected_after_declarator);
+ SkipUntil(tok::semi);
+ return 0;
+ }
+
+ // Parse the init-declarator-list for a normal declaration.
+ return ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
+}
+
+/// ParseFunctionDefinition - We parsed and verified that the specified
+/// Declarator is well formed. If this is a K&R-style function, read the
+/// parameters declaration-list, then start the compound-statement.
+///
+/// declaration-specifiers[opt] declarator declaration-list[opt]
+/// compound-statement [TODO]
+///
+Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) {
+ const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0);
+ assert(FnTypeInfo.Kind == DeclaratorChunk::Function &&
+ "This isn't a function declarator!");
+ const DeclaratorChunk::FunctionTypeInfo &FTI = FnTypeInfo.Fun;
+
+ // If this declaration was formed with a K&R-style identifier list for the
+ // arguments, parse declarations for all of the args next.
+ // int foo(a,b) int a; float b; {}
+ if (!FTI.hasPrototype && FTI.NumArgs != 0)
+ ParseKNRParamDeclarations(D);
+
+ // Enter a scope for the function body.
+ EnterScope(Scope::FnScope);
+
+ // Tell the actions module that we have entered a function definition with the
+ // specified Declarator for the function.
+ DeclTy *Res = Actions.ParseStartOfFunctionDef(CurScope, D);
+
+
+ // We should have an opening brace now.
+ if (Tok.getKind() != tok::l_brace) {
+ Diag(Tok, diag::err_expected_fn_body);
+
+ // Skip over garbage, until we get to '{'. Don't eat the '{'.
+ SkipUntil(tok::l_brace, true, true);
+
+ // If we didn't find the '{', bail out.
+ if (Tok.getKind() != tok::l_brace) {
+ ExitScope();
+ return 0;
+ }
+ }
+
+ // Do not enter a scope for the brace, as the arguments are in the same scope
+ // (the function body) as the body itself. Instead, just read the statement
+ // list and put it into a CompoundStmt for safe keeping.
+ StmtResult FnBody = ParseCompoundStatementBody();
+ if (FnBody.isInvalid) {
+ ExitScope();
+ return 0;
+ }
+
+ // Leave the function body scope.
+ ExitScope();
+
+ // TODO: Pass argument information.
+ return Actions.ParseFunctionDefBody(Res, FnBody.Val);
+}
+
+/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides
+/// types for a function with a K&R-style identifier list for arguments.
+void Parser::ParseKNRParamDeclarations(Declarator &D) {
+ // We know that the top-level of this declarator is a function.
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+
+ // Read all the argument declarations.
+ while (isDeclarationSpecifier()) {
+ SourceLocation DSStart = Tok.getLocation();
+
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+
+ // C99 6.9.1p6: 'each declaration in the declaration list shall have at
+ // least one declarator'.
+ // NOTE: GCC just makes this an ext-warn. It's not clear what it does with
+ // the declarations though. It's trivial to ignore them, really hard to do
+ // anything else with them.
+ if (Tok.getKind() == tok::semi) {
+ Diag(DSStart, diag::err_declaration_does_not_declare_param);
+ ConsumeToken();
+ continue;
+ }
+
+ // C99 6.9.1p6: Declarations shall contain no storage-class specifiers other
+ // than register.
+ if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
+ DS.getStorageClassSpec() != DeclSpec::SCS_register) {
+ Diag(DS.getStorageClassSpecLoc(),
+ diag::err_invalid_storage_class_in_func_decl);
+ DS.ClearStorageClassSpecs();
+ }
+ if (DS.isThreadSpecified()) {
+ Diag(DS.getThreadSpecLoc(),
+ diag::err_invalid_storage_class_in_func_decl);
+ DS.ClearStorageClassSpecs();
+ }
+
+ // Parse the first declarator attached to this declspec.
+ Declarator ParmDeclarator(DS, Declarator::KNRTypeListContext);
+ ParseDeclarator(ParmDeclarator);
+
+ // Handle the full declarator list.
+ while (1) {
+ DeclTy *AttrList;
+ // If attributes are present, parse them.
+ if (Tok.getKind() == tok::kw___attribute)
+ // FIXME: attach attributes too.
+ AttrList = ParseAttributes();
+
+ // Ask the actions module to compute the type for this declarator.
+ Action::TypeResult TR =
+ Actions.ParseParamDeclaratorType(CurScope, ParmDeclarator);
+ if (!TR.isInvalid &&
+ // A missing identifier has already been diagnosed.
+ ParmDeclarator.getIdentifier()) {
+
+ // Scan the argument list looking for the correct param to apply this
+ // type.
+ for (unsigned i = 0; ; ++i) {
+ // C99 6.9.1p6: those declarators shall declare only identifiers from
+ // the identifier list.
+ if (i == FTI.NumArgs) {
+ Diag(ParmDeclarator.getIdentifierLoc(), diag::err_no_matching_param,
+ ParmDeclarator.getIdentifier()->getName());
+ break;
+ }
+
+ if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) {
+ // Reject redefinitions of parameters.
+ if (FTI.ArgInfo[i].TypeInfo) {
+ Diag(ParmDeclarator.getIdentifierLoc(),
+ diag::err_param_redefinition,
+ ParmDeclarator.getIdentifier()->getName());
+ } else {
+ FTI.ArgInfo[i].TypeInfo = TR.Val;
+ }
+ break;
+ }
+ }
+ }
+
+ // If we don't have a comma, it is either the end of the list (a ';') or
+ // an error, bail out.
+ if (Tok.getKind() != tok::comma)
+ break;
+
+ // Consume the comma.
+ ConsumeToken();
+
+ // Parse the next declarator.
+ ParmDeclarator.clear();
+ ParseDeclarator(ParmDeclarator);
+ }
+
+ if (Tok.getKind() == tok::semi) {
+ ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_parse_error);
+ // Skip to end of block or statement
+ SkipUntil(tok::semi, true);
+ if (Tok.getKind() == tok::semi)
+ ConsumeToken();
+ }
+ }
+
+ // The actions module must verify that all arguments were declared.
+}
+
+
+/// ParseAsmStringLiteral - This is just a normal string-literal, but is not
+/// allowed to be a wide string, and is not subject to character translation.
+///
+/// [GNU] asm-string-literal:
+/// string-literal
+///
+void Parser::ParseAsmStringLiteral() {
+ if (!isTokenStringLiteral()) {
+ Diag(Tok, diag::err_expected_string_literal);
+ return;
+ }
+
+ ExprResult Res = ParseStringLiteralExpression();
+ if (Res.isInvalid) return;
+
+ // TODO: Diagnose: wide string literal in 'asm'
+}
+
+/// ParseSimpleAsm
+///
+/// [GNU] simple-asm-expr:
+/// 'asm' '(' asm-string-literal ')'
+///
+void Parser::ParseSimpleAsm() {
+ assert(Tok.getKind() == tok::kw_asm && "Not an asm!");
+ ConsumeToken();
+
+ if (Tok.getKind() != tok::l_paren) {
+ Diag(Tok, diag::err_expected_lparen_after, "asm");
+ return;
+ }
+
+ SourceLocation Loc = ConsumeParen();
+
+ ParseAsmStringLiteral();
+
+ MatchRHSPunctuation(tok::r_paren, Loc);
+}
+