2006-07-31 05:13:43 +00:00
|
|
|
//===--- ParserDeclarations.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"
|
2006-08-04 04:39:53 +00:00
|
|
|
#include "clang/Parse/Declarations.h"
|
2006-07-31 05:13:43 +00:00
|
|
|
using namespace llvm;
|
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// C99 6.7: Declarations.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// ParseDeclarationSpecifiers
|
|
|
|
/// declaration-specifiers: [C99 6.7]
|
2006-08-04 05:25:55 +00:00
|
|
|
/// storage-class-specifier declaration-specifiers [opt]
|
2006-07-31 05:13:43 +00:00
|
|
|
/// type-specifier declaration-specifiers [opt]
|
2006-08-04 05:25:55 +00:00
|
|
|
/// type-qualifier declaration-specifiers [opt]
|
|
|
|
/// [C99] function-specifier declaration-specifiers [opt]
|
|
|
|
/// [GNU] attributes declaration-specifiers [opt] [TODO]
|
2006-07-31 05:13:43 +00:00
|
|
|
///
|
2006-08-05 03:28:50 +00:00
|
|
|
/// storage-class-specifier: [C99 6.7.1]
|
2006-08-04 05:25:55 +00:00
|
|
|
/// 'typedef'
|
|
|
|
/// 'extern'
|
|
|
|
/// 'static'
|
|
|
|
/// 'auto'
|
|
|
|
/// 'register'
|
|
|
|
/// [GNU] '__thread'
|
2006-07-31 05:13:43 +00:00
|
|
|
/// type-specifier: [C99 6.7.2]
|
|
|
|
/// 'void'
|
|
|
|
/// 'char'
|
|
|
|
/// 'short'
|
|
|
|
/// 'int'
|
|
|
|
/// 'long'
|
|
|
|
/// 'float'
|
|
|
|
/// 'double'
|
|
|
|
/// 'signed'
|
|
|
|
/// 'unsigned'
|
|
|
|
/// [C99] '_Bool'
|
|
|
|
/// [C99] '_Complex'
|
2006-08-04 05:25:55 +00:00
|
|
|
/// [C99] '_Imaginary' // Removed in TC2?
|
|
|
|
/// [GNU] '_Decimal32'
|
|
|
|
/// [GNU] '_Decimal64'
|
|
|
|
/// [GNU] '_Decimal128'
|
2006-08-05 03:28:50 +00:00
|
|
|
/// [GNU] typeof-specifier [TODO]
|
2006-08-04 05:25:55 +00:00
|
|
|
/// [OBJC] class-name objc-protocol-refs [opt] [TODO]
|
|
|
|
/// [OBJC] typedef-name objc-protocol-refs [TODO]
|
|
|
|
/// [OBJC] objc-protocol-refs [TODO]
|
|
|
|
/// struct-or-union-specifier [TODO]
|
|
|
|
/// enum-specifier [TODO]
|
|
|
|
/// typedef-name [TODO]
|
|
|
|
/// type-qualifier:
|
|
|
|
/// const
|
|
|
|
/// volatile
|
|
|
|
/// [C99] restrict
|
2006-08-04 04:39:53 +00:00
|
|
|
/// function-specifier: [C99 6.7.4]
|
|
|
|
/// [C99] inline
|
|
|
|
///
|
|
|
|
void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) {
|
|
|
|
SourceLocation StartLoc = Tok.getLocation();
|
2006-07-31 05:13:43 +00:00
|
|
|
while (1) {
|
2006-08-04 05:25:55 +00:00
|
|
|
int isInvalid = false;
|
2006-08-04 04:39:53 +00:00
|
|
|
const char *PrevSpec = 0;
|
2006-07-31 05:13:43 +00:00
|
|
|
switch (Tok.getKind()) {
|
2006-08-04 04:39:53 +00:00
|
|
|
default:
|
|
|
|
// If this is not a declaration specifier token, we're done reading decl
|
|
|
|
// specifiers. First verify that DeclSpec's are consistent.
|
2006-08-04 06:15:52 +00:00
|
|
|
DS.Finish(StartLoc, Diags, getLang());
|
2006-08-04 04:39:53 +00:00
|
|
|
return;
|
2006-08-05 03:28:50 +00:00
|
|
|
|
|
|
|
// storage-class-specifier
|
|
|
|
case tok::kw_typedef:
|
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_extern:
|
|
|
|
if (DS.SCS_thread_specified)
|
|
|
|
Diag(Tok, diag::ext_thread_before, "extern");
|
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_static:
|
|
|
|
if (DS.SCS_thread_specified)
|
|
|
|
Diag(Tok, diag::ext_thread_before, "static");
|
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_auto:
|
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_register:
|
|
|
|
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw___thread:
|
|
|
|
if (DS.SCS_thread_specified)
|
|
|
|
isInvalid = 2, PrevSpec = "__thread";
|
|
|
|
else
|
|
|
|
DS.SCS_thread_specified = true;
|
|
|
|
break;
|
|
|
|
|
2006-07-31 05:13:43 +00:00
|
|
|
// type-specifiers
|
2006-08-04 04:39:53 +00:00
|
|
|
case tok::kw_short:
|
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_long:
|
|
|
|
if (DS.TypeSpecWidth != DeclSpec::TSW_long) {
|
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, PrevSpec);
|
|
|
|
} else {
|
|
|
|
DS.TypeSpecWidth = DeclSpec::TSW_unspecified;
|
|
|
|
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, PrevSpec);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case tok::kw_signed:
|
|
|
|
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw__Complex:
|
|
|
|
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw__Imaginary:
|
|
|
|
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_void:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, PrevSpec);
|
|
|
|
break;
|
2006-07-31 05:13:43 +00:00
|
|
|
case tok::kw_char:
|
2006-08-04 04:39:53 +00:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, PrevSpec);
|
|
|
|
break;
|
2006-07-31 05:13:43 +00:00
|
|
|
case tok::kw_int:
|
2006-08-04 04:39:53 +00:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw_float:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, PrevSpec);
|
|
|
|
break;
|
2006-07-31 05:13:43 +00:00
|
|
|
case tok::kw_double:
|
2006-08-04 04:39:53 +00:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, PrevSpec);
|
|
|
|
break;
|
2006-07-31 05:13:43 +00:00
|
|
|
case tok::kw__Bool:
|
2006-08-04 04:39:53 +00:00
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw__Decimal32:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw__Decimal64:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, PrevSpec);
|
|
|
|
break;
|
|
|
|
case tok::kw__Decimal128:
|
|
|
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, PrevSpec);
|
2006-07-31 05:13:43 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
//case tok::kw_struct:
|
|
|
|
//case tok::kw_union:
|
|
|
|
//case tok::kw_enum:
|
2006-08-04 05:25:55 +00:00
|
|
|
|
|
|
|
// type-qualifier
|
|
|
|
case tok::kw_const:
|
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , PrevSpec, getLang())*2;
|
|
|
|
break;
|
|
|
|
case tok::kw_volatile:
|
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, PrevSpec, getLang())*2;
|
|
|
|
break;
|
|
|
|
case tok::kw_restrict:
|
|
|
|
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, PrevSpec, getLang())*2;
|
|
|
|
break;
|
2006-08-04 04:39:53 +00:00
|
|
|
|
|
|
|
// function-specifier
|
|
|
|
case tok::kw_inline:
|
2006-08-05 03:28:50 +00:00
|
|
|
// 'inline inline' is ok.
|
|
|
|
DS.FS_inline_specified = true;
|
2006-08-04 04:39:53 +00:00
|
|
|
break;
|
2006-07-31 05:13:43 +00:00
|
|
|
}
|
2006-08-04 04:39:53 +00:00
|
|
|
// If the specifier combination wasn't legal, issue a diagnostic.
|
|
|
|
if (isInvalid) {
|
|
|
|
assert(PrevSpec && "Method did not return previous specifier!");
|
2006-08-04 05:25:55 +00:00
|
|
|
if (isInvalid == 1) // Error.
|
|
|
|
Diag(Tok, diag::err_invalid_decl_spec_combination, PrevSpec);
|
|
|
|
else // extwarn.
|
|
|
|
Diag(Tok, diag::ext_duplicate_declspec, PrevSpec);
|
2006-08-04 04:39:53 +00:00
|
|
|
}
|
|
|
|
ConsumeToken();
|
2006-07-31 05:13:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-04 04:39:53 +00:00
|
|
|
|
2006-07-31 05:13:43 +00:00
|
|
|
/// ParseDeclarator
|
|
|
|
/// declarator: [C99 6.7.5]
|
|
|
|
/// pointer[opt] direct-declarator
|
|
|
|
///
|
|
|
|
/// pointer: [C99 6.7.5]
|
|
|
|
/// '*' type-qualifier-list[opt]
|
|
|
|
/// '*' type-qualifier-list[opt] pointer
|
|
|
|
///
|
|
|
|
void Parser::ParseDeclarator() {
|
|
|
|
while (Tok.getKind() == tok::star) { // '*' -> pointer.
|
|
|
|
ConsumeToken(); // Eat the *.
|
|
|
|
ParseTypeQualifierListOpt();
|
|
|
|
}
|
|
|
|
|
|
|
|
ParseDirectDeclarator();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseTypeQualifierListOpt
|
|
|
|
/// type-qualifier-list: [C99 6.7.5]
|
|
|
|
/// type-qualifier
|
|
|
|
/// [GNU] attributes [TODO]
|
|
|
|
/// type-qualifier-list type-qualifier
|
|
|
|
/// [GNU] type-qualifier-list attributes [TODO]
|
|
|
|
///
|
|
|
|
void Parser::ParseTypeQualifierListOpt() {
|
|
|
|
while (1) {
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default: break;
|
|
|
|
// TODO: attributes.
|
|
|
|
case tok::kw_const:
|
|
|
|
case tok::kw_volatile:
|
|
|
|
case tok::kw_restrict:
|
|
|
|
ConsumeToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// ParseDirectDeclarator
|
|
|
|
/// direct-declarator: [C99 6.7.5]
|
|
|
|
/// identifier
|
|
|
|
/// '(' declarator ')'
|
|
|
|
/// [GNU] '(' attributes declarator ')'
|
|
|
|
/// direct-declarator array-declarator
|
|
|
|
/// direct-declarator '(' parameter-type-list ')'
|
|
|
|
/// direct-declarator '(' identifier-list[opt] ')'
|
|
|
|
/// [GNU] direct-declarator '(' parameter-forward-declarations
|
|
|
|
/// parameter-type-list[opt] ')'
|
|
|
|
///
|
|
|
|
/// 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::ParseDirectDeclarator() {
|
|
|
|
if (Tok.getKind() == tok::identifier) {
|
|
|
|
ConsumeToken();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// FIXME: missing most stuff.
|
|
|
|
assert(0 && "Unknown token!");
|
|
|
|
}
|