]> git.draconx.ca Git - cdecl99.git/blobdiff - src/parse-decl.c
Restructure the type specifier check.
[cdecl99.git] / src / parse-decl.c
index 1ad3e8e175006f320cc86a49809a6f9e2608ba8e..f25c4c4d56f109d42452d969993a20855ad5c409 100644 (file)
 #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) {