]> git.draconx.ca Git - cdecl99.git/commitdiff
Restructure the type specifier check.
authorNick Bowler <nbowler@draconx.ca>
Fri, 12 Mar 2021 04:54:24 +0000 (23:54 -0500)
committerNick Bowler <nbowler@draconx.ca>
Fri, 12 Mar 2021 05:04:45 +0000 (00:04 -0500)
As the typemap.c functionality is only used for one thing and is quite
simple, let's integrate that more closely with the declaration specifier
checks.  This further reduces the code size of the library somewhat.

The old sed line noise is replaced by a similar awk script which should
be much easier to adjust as needed.

Makefile.am
src/.gitignore
src/gen-typemap.awk [new file with mode: 0755]
src/parse-decl.c
src/typemap.c [deleted file]
src/validtypes.sed [deleted file]

index 9698512190b33e6f42221ea86b9675fda4f725a0..36bba03d9834692c0fa5e78352879ae2e52cd101 100644 (file)
@@ -23,11 +23,11 @@ MAINTAINERCLEANFILES = src/scan.c src/scan.h src/scan.stamp \
 
 DISTCLEANFILES =
 
-CLEANFILES = src/validtypes.h src/namespecs.h $(EXTRA_LTLIBRARIES)
+CLEANFILES = src/namespecs.h $(EXTRA_LTLIBRARIES)
 
 EXTRA_DIST = bootstrap $(DX_BASEDIR)/scripts/fix-gnulib.pl m4/gnulib-cache.m4 \
-             src/types.lst src/validtypes.sed src/specs.lst src/namespecs.sed \
-             src/parse.y src/parse.stamp src/scan.l src/scan.stamp \
+             src/types.lst src/specs.lst src/namespecs.sed src/parse.y \
+             src/parse.stamp src/scan.l src/scan.stamp \
              COPYING.WTFPL2 README.md INSTALL
 
 dist_man_MANS = doc/cdecl99.1 doc/libcdecl.3
@@ -41,10 +41,9 @@ noinst_DATA = $(MOFILES)
 lib_LTLIBRARIES = libcdecl.la
 libcdecl_la_LDFLAGS = -export-symbols-regex '^cdecl_[[:lower:]]' \
                       -no-undefined
-libcdecl_la_SOURCES = src/scan.c src/parse.c src/parse-decl.c src/typemap.c \
-                      src/output.c src/explain.c src/declare.c src/i18n.c \
-                      src/error.c src/normalize.c src/cdecl-internal.h \
-                      src/errtab.h
+libcdecl_la_SOURCES = src/scan.c src/parse.c src/parse-decl.c src/output.c \
+                      src/explain.c src/declare.c src/i18n.c src/error.c \
+                      src/normalize.c src/cdecl-internal.h src/errtab.h
 libcdecl_la_LIBADD = libgnu.la $(LTLIBINTL) $(LTLIBTHREAD)
 $(libcdecl_la_OBJECTS): $(gnulib_headers)
 
@@ -86,17 +85,11 @@ $(test_normalize_OBJECTS): $(gnulib_headers)
 
 src/parse.lo: src/scan.h
 src/scan.lo: src/parse.h
-src/parse-decl.lo: src/scan.h src/parse.h
-src/typemap.lo: src/validtypes.h
+src/parse-decl.lo: src/scan.h src/parse.h src/typemap.h
 src/error.lo: src/errtab.h
 src/output.lo: src/namespecs.h
 test/declgen.lo: test/typegen.h
 
-src/validtypes.h: $(srcdir)/src/types.lst $(srcdir)/src/validtypes.sed
-       $(AM_V_GEN)sed -f $(srcdir)/src/validtypes.sed \
-               < $(srcdir)/src/types.lst > $@.tmp
-       $(AM_V_at)mv -f $@.tmp $@
-
 src/namespecs.h: $(srcdir)/src/specs.lst $(srcdir)/src/namespecs.sed
        $(AM_V_GEN) sed -f $(srcdir)/src/namespecs.sed \
                < $(srcdir)/src/specs.lst > $@.tmp
@@ -210,6 +203,13 @@ src/cmdlist.h: src/gen-cmdlist.awk src/execute.c
 DISTCLEANFILES += src/cmdlist.h
 EXTRA_DIST += src/gen-cmdlist.awk
 
+src/typemap.h: src/gen-typemap.awk src/types.lst
+       $(AM_V_GEN) $(AWK) -f $(srcdir)/src/gen-typemap.awk \
+                             $(srcdir)/src/types.lst >$@.tmp
+       $(AM_V_at) mv -f $@.tmp $@
+DISTCLEANFILES += src/typemap.h
+EXTRA_DIST += src/gen-typemap.awk
+
 test/typegen.h: test/gen-typegen.awk src/types.lst
        $(AM_V_GEN) $(AWK) -f $(srcdir)/test/gen-typegen.awk \
                              $(srcdir)/src/types.lst >$@.tmp
index 8456972beac7c3def8036fb6ed72a440be435341..a82fb997abc570fbb30be2a4a178378fe49010c0 100644 (file)
@@ -1,10 +1,10 @@
 /*.stamp
-/parse.[ch]
-/scan.[ch]
+/cmdlist.h
+/commands.h
 /errtab.h
+/execute.c
 /namespecs.h
 /options.h
-/commands.h
-/validtypes.h
-/execute.c
-/cmdlist.h
+/parse.[ch]
+/scan.[ch]
+/typemap.h
diff --git a/src/gen-typemap.awk b/src/gen-typemap.awk
new file mode 100755 (executable)
index 0000000..68cc8a1
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/awk -f
+#
+# Copyright © 2021 Nick Bowler
+#
+# Generate a test for whether a particuar combination of type specifiers
+# represents a valid type, for internal use by the declaration parser.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+END {
+  print "/*"
+  if (FILENAME) {
+    print " * Automatically generated by gen-typemap.awk from " FILENAME
+  } else {
+    print " * Automatically generated by gen-typemap.awk"
+  }
+  print " * Do not edit."
+  print " */"
+}
+
+BEGIN {
+  OFS = "\n\t   | "
+  count = 0
+}
+
+$0 ~ /^[abcdefghijklmnopqrstuvwxyz_]/ {
+  long = 0
+  for (i = 1; i <= NF; i++) {
+    if ($i == "long") {
+      if (long++) {
+        $i = "llong"
+      }
+    }
+
+    sub(/_/, "", $i)
+    $i = "1ul<<(CDECL_TYPE_" toupper($i) "-CDECL_SPEC_TYPE)"
+  }
+  types[count++] = $0
+}
+
+END {
+  print "static inline int typemap_is_valid(unsigned long map)\n{"
+  print "\tswitch (map) {"
+
+  for (i = 0; i < count; i++) {
+    print "\tcase " types[i] ":"
+  }
+
+  print "\t\treturn 1;"
+  print "\t}\n"
+  print "\treturn 0;"
+  print "}"
+}
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) {
diff --git a/src/typemap.c b/src/typemap.c
deleted file mode 100644 (file)
index 918a037..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- *  Helpers for dealing with type specifiers.
- *  Copyright © 2011, 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
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <config.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <assert.h>
-
-#include "cdecl.h"
-#include "cdecl-internal.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 (CDECL_SPEC_TYPE + 31)
-
-static inline unsigned long spec_bit(unsigned type)
-{
-       return 1ul << (type & (CDECL_SPEC_TYPE - 1));
-}
-
-static unsigned long add_typespec(unsigned long map, struct cdecl_declspec *s)
-{
-       assert(s->type >= CDECL_SPEC_TYPE && s->type < CDECL_TYPE_LLONG);
-
-       if (s->type == CDECL_TYPE_LONG) {
-               if (map & spec_bit(CDECL_TYPE_LLONG)) {
-                       fprintf(stderr, "too many long specifiers\n");
-                       return -1;
-               } else if (map & spec_bit(CDECL_TYPE_LONG)) {
-                       return map | spec_bit(CDECL_TYPE_LLONG);
-               }
-       }
-
-       if (map & spec_bit(s->type)) {
-               fprintf(stderr, "duplicate type specifier\n");
-               return -1;
-       }
-
-       return map | spec_bit(s->type);
-}
-
-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)
-                       return -1;
-       }
-
-       switch (map) {
-       case 0:
-               fprintf(stderr, "no type specifiers\n");
-               return -1;
-#      include "validtypes.h"
-               return map;
-       default:
-               fprintf(stderr, "conflicting type specifiers\n");
-               return -1;
-       }
-}
diff --git a/src/validtypes.sed b/src/validtypes.sed
deleted file mode 100644 (file)
index 7052915..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-1i\
-/* This file is automatically generated by validtypes.sed */
-/[^_[:alpha:][:space:]]/b
-s/[[:space:]][[:space:]]*/ /g
-s/_//g
-y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
-s/LONG LONG/LLONG LONG/
-s/[[:upper:]][[:upper:]]*/(1ul<<(CDECL_TYPE_&-CDECL_SPEC_TYPE))/g
-s/ /|/g
-s/.*/case &:/