X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/bbfdea24b2b940031e86e990bc457785dd378b58..6d601969de9687819347cf27df8ddf6ab026e4b0:/src/parse-decl.c diff --git a/src/parse-decl.c b/src/parse-decl.c index 1ad3e8e..f25c4c4 100644 --- a/src/parse-decl.c +++ b/src/parse-decl.c @@ -26,6 +26,62 @@ #include "parse.h" #include "scan.h" +/* + * We can represent type specifiers as a bitmap, which gives us a finite + * list of acceptable bitmap values according to the C standard. However, + * the "long" specifier is allowed to occur more than once, but only at most + * 2 times. Treat it as a special case, assigning an unused bit to represent + * the second long. + */ +#define MAP_LLONG_BIT 31 +#define MAP_LONG_BIT (CDECL_TYPE_LONG-CDECL_SPEC_TYPE) +#define CDECL_TYPE_LLONG (CDECL_SPEC_TYPE+MAP_LLONG_BIT) + +#include "typemap.h" + +/* + * Convert the declaration specifiers to a bitmap with each bit + * corresponding to one specific type specifier. + */ +static int valid_typespec(struct cdecl_declspec *s) +{ + unsigned long map = 0; + + for (struct cdecl_declspec *c = s; c; c = c->next) { + unsigned long bit; + + if (cdecl_spec_kind(c) != CDECL_SPEC_TYPE) + continue; + + bit = c->type - CDECL_SPEC_TYPE; + assert(bit < MAP_LLONG_BIT); + bit = 1ul << bit; + + /* "long" special case */ + if ((map & bit) == 1ul << MAP_LONG_BIT) + bit = 1ul << MAP_LLONG_BIT; + + if (map & bit) { + if (bit == 1ul << MAP_LLONG_BIT) + fprintf(stderr, "too many long specifiers\n"); + else + fprintf(stderr, "duplicate type specifier\n"); + return false; + } + map |= bit; + } + + if (typemap_is_valid(map)) + return true; + + if (map == 0) + fprintf(stderr, "no type specified\n"); + else + fprintf(stderr, "invalid type specified\n"); + + return false; +} + /* * Verify the declaration specifiers of a declaration. If top is true, treat * this as a top-level declaration. Otherwise, treat this as a function @@ -37,10 +93,8 @@ static bool valid_declspecs(struct cdecl *decl, bool top) struct cdecl_declarator *d = decl->declarators; bool abstract = cdecl_is_abstract(d); unsigned num_storage = 0; - unsigned long typemap; - typemap = cdecl__build_typemap(specs); - if (typemap == -1) + if (!valid_typespec(specs)) return false; for (struct cdecl_declspec *c = specs; c; c = c->next) {