]> git.draconx.ca Git - cdecl99.git/blobdiff - src/parse-decl.c
Restructure the type specifier check.
[cdecl99.git] / src / parse-decl.c
index 694f4ab32c3875458b8293f98d619ce3b1be707c..f25c4c4d56f109d42452d969993a20855ad5c409 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Parse and validate C declarations.
- * Copyright © 2011-2012, 2020 Nick Bowler
+ * Copyright © 2011-2012, 2020-2021 Nick Bowler
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <stdbool.h>
 
 #include "cdecl.h"
-#include "typemap.h"
+#include "cdecl-internal.h"
 #include "parse.h"
 #include "scan.h"
-#include "i18n.h"
-#include "normalize.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
@@ -39,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) {
@@ -271,7 +323,6 @@ check_parameters(struct cdecl_declarator **p, struct cdecl_declarator *d)
 {
        struct cdecl_declspec *spec;
        struct cdecl *param;
-       bool has_void = false;
 
        if (d->type != CDECL_DECL_FUNCTION)
                return 0;