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
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)
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
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
/*.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
--- /dev/null
+#!/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 "}"
+}
#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
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) {
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-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 &:/