]> git.draconx.ca Git - cdecl99.git/blobdiff - src/typemap.c
Move typemap stuff into a separate file.
[cdecl99.git] / src / typemap.c
diff --git a/src/typemap.c b/src/typemap.c
new file mode 100644 (file)
index 0000000..0e5b41c
--- /dev/null
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include "cdecl.h"
+#include "typemap.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 CDECL_TYPE_LLONG 31
+
+static unsigned long add_typespec(unsigned long map, struct cdecl_declspec *s)
+{
+       if (s->type >= CDECL_TYPE_LLONG) {
+               fprintf(stderr, "invalid type specifier\n");
+               return -1;
+       }
+
+       if (s->type == CDECL_TYPE_LONG) {
+               if (map & (1ul<<CDECL_TYPE_LLONG)) {
+                       fprintf(stderr, "too many long specifiers\n");
+                       return -1;
+               } else if (map & (1ul<<CDECL_TYPE_LONG)) {
+                       return map | (1ul<<CDECL_TYPE_LLONG);
+               }
+       }
+
+       if (map & (1ul<<s->type)) {
+               fprintf(stderr, "duplicate type specifier\n");
+               return -1;
+       }
+
+       return map | (1ul<<s->type);
+}
+
+bool cdecl__typemap_is_valid(unsigned long map)
+{
+       switch (map) {
+#      include "validtypes.h"
+               return true;
+       }
+
+       return false;
+}
+
+unsigned long cdecl__build_typemap(struct cdecl_declspec *s)
+{
+       unsigned long map = 0;
+
+       for (struct cdecl_declspec *c = s; c; c = c->next) {
+               if (cdecl_spec_kind(c) != CDECL_SPEC_TYPE)
+                       continue;
+
+               map = add_typespec(map, c);
+               if (map == -1)
+                       break;
+       }
+
+       return map;
+}