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