From bc9fc82e7771a3b2dc55db36b8d654243eb2d187 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Mon, 20 Jul 2020 01:17:09 +0200 Subject: parse: rework handling of storage_class The handling of the storage class modifiers is done differently than the other modifiers: * they don't use MOD_... but their own enums * consequently they can't use modifier_string() and have their own string table to display them. * the attribute 'force' is considered as a kind of storage class. Fine, but it means that 'register' or '__tls' can't be used with 'force' (which is probably very fine but seems more as a side-effect than something really desired). The real justification for these difference seems to be that storage class modifiers *must* be treated differently than the other modifiers because they don't apply at the same level. For example, in a declaration like: static const int a[N]; 'static' applies to the array/the whole object, while 'const' only applies to the (type of the) elements of the array. Storage class specifiers must thus be parsed, stored aside and only be applied after the whole declarator have been parsed. But other modifiers are also in the same situation (for example, '__noreturn' or '__pure' for functions). So, use the generic keyword/attribute handling of modifiers for storage class specifiers but for simplicity, store them separately in decl_state to easily do duplication tests on them. Signed-off-by: Luc Van Oostenryck --- parse.c | 71 ++++++++++++++++++++-------------------------------------------- symbol.h | 4 +++- 2 files changed, 25 insertions(+), 50 deletions(-) diff --git a/parse.c b/parse.c index cc46f1a6..2711022a 100644 --- a/parse.c +++ b/parse.c @@ -116,10 +116,6 @@ enum { CInt = 0, CSInt, CUInt, CReal, }; -enum { - SNone = 0, STypedef, SAuto, SRegister, SExtern, SStatic, SForced, SMax, -}; - static void asm_modifier(struct token *token, unsigned long *mods, unsigned long mod) { if (*mods & mod) @@ -1389,85 +1385,67 @@ static struct token *attribute_specifier(struct token *token, struct decl_state return token; } -static const char *storage_class[] = -{ - [STypedef] = "typedef", - [SAuto] = "auto", - [SExtern] = "extern", - [SStatic] = "static", - [SRegister] = "register", - [SForced] = "[force]" -}; - static unsigned long decl_modifiers(struct decl_state *ctx) { - static unsigned long mod[SMax] = - { - [SAuto] = MOD_AUTO, - [SExtern] = MOD_EXTERN, - [SStatic] = MOD_STATIC, - [SRegister] = MOD_REGISTER - }; unsigned long mods = ctx->ctype.modifiers & MOD_DECLARE; ctx->ctype.modifiers &= ~MOD_DECLARE; - return mod[ctx->storage_class] | mods; + return ctx->storage_class | mods; } -static void set_storage_class(struct position *pos, struct decl_state *ctx, int class) +static void set_storage_class(struct position *pos, struct decl_state *ctx, unsigned long class) { int is_tls = ctx->ctype.modifiers & MOD_TLS; + const char *storage = modifier_string(class); + /* __thread can be used alone, or with extern or static */ - if (is_tls && (class != SStatic && class != SExtern)) { + if (is_tls && (class & ~(MOD_STATIC|MOD_EXTERN))) { sparse_error(*pos, "__thread can only be used alone, or with " "extern or static"); return; } - if (!ctx->storage_class) { + if (!ctx->storage_class) ctx->storage_class = class; - return; - } - if (ctx->storage_class == class) - sparse_error(*pos, "duplicate %s", storage_class[class]); + else if (ctx->storage_class == class) + sparse_error(*pos, "duplicate %s", storage); else sparse_error(*pos, "multiple storage classes"); } static struct token *typedef_specifier(struct token *next, struct decl_state *ctx) { - set_storage_class(&next->pos, ctx, STypedef); + set_storage_class(&next->pos, ctx, MOD_USERTYPE); return next; } static struct token *auto_specifier(struct token *next, struct decl_state *ctx) { - set_storage_class(&next->pos, ctx, SAuto); + set_storage_class(&next->pos, ctx, MOD_AUTO); return next; } static struct token *register_specifier(struct token *next, struct decl_state *ctx) { - set_storage_class(&next->pos, ctx, SRegister); + set_storage_class(&next->pos, ctx, MOD_REGISTER); return next; } static struct token *static_specifier(struct token *next, struct decl_state *ctx) { - set_storage_class(&next->pos, ctx, SStatic); + set_storage_class(&next->pos, ctx, MOD_STATIC); return next; } static struct token *extern_specifier(struct token *next, struct decl_state *ctx) { - set_storage_class(&next->pos, ctx, SExtern); + set_storage_class(&next->pos, ctx, MOD_EXTERN); return next; } static struct token *thread_specifier(struct token *next, struct decl_state *ctx) { /* This GCC extension can be used alone, or with extern or static */ - if (!ctx->storage_class || ctx->storage_class == SStatic - || ctx->storage_class == SExtern) { + if (!(ctx->storage_class & ~(MOD_STATIC|MOD_EXTERN))) { apply_qualifier(&next->pos, &ctx->ctype, MOD_TLS); } else { sparse_error(next->pos, "__thread can only be used alone, or " @@ -1479,7 +1457,7 @@ static struct token *thread_specifier(struct token *next, struct decl_state *ctx static struct token *attribute_force(struct token *token, struct symbol *attr, struct decl_state *ctx) { - set_storage_class(&token->pos, ctx, SForced); + ctx->forced = 1; return token; } @@ -2070,14 +2048,14 @@ static struct token *parameter_declaration(struct token *token, struct symbol *s sym->ctype = ctx.ctype; sym->ctype.modifiers |= decl_modifiers(&ctx); sym->endpos = token->pos; - sym->forced_arg = ctx.storage_class == SForced; + sym->forced_arg = ctx.forced; return token; } struct token *typename(struct token *token, struct symbol **p, int *forced) { struct decl_state ctx = {.prefer_abstract = 1}; - int class; + unsigned long class; struct symbol *sym = alloc_symbol(token->pos, SYM_NODE); *p = sym; token = declaration_specifiers(token, &ctx); @@ -2086,16 +2064,11 @@ struct token *typename(struct token *token, struct symbol **p, int *forced) sym->ctype = ctx.ctype; sym->endpos = token->pos; class = ctx.storage_class; - if (forced) { - *forced = 0; - if (class == SForced) { - *forced = 1; - class = 0; - } - } + if (forced) + *forced = ctx.forced; if (class) - warning(sym->pos, "storage class in typename (%s %s)", - storage_class[class], show_typename(sym)); + warning(sym->pos, "storage class in typename (%s%s)", + modifier_string(class), show_typename(sym)); return token; } @@ -3048,7 +3021,7 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis } /* type define declaration? */ - is_typedef = ctx.storage_class == STypedef; + is_typedef = ctx.storage_class == MOD_USERTYPE; /* Typedefs don't have meaningful storage */ if (is_typedef) diff --git a/symbol.h b/symbol.h index 4792b008..d2ca3d2d 100644 --- a/symbol.h +++ b/symbol.h @@ -108,8 +108,10 @@ struct decl_state { struct ident **ident; struct symbol_op *mode; unsigned long f_modifiers; // function attributes - unsigned char prefer_abstract, storage_class; + unsigned long storage_class; + unsigned char prefer_abstract; unsigned char autotype; + unsigned char forced; }; struct pseudo; -- cgit 1.2.3-korg