From 0b6c0a1a3749b47249c4347530862ca034bac674 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 21 Jun 2011 18:29:30 -0400 Subject: [PATCH] Move typemap stuff into a separate file. These functions will be generally useful. They are not part of the public API, so we use the cdecl__ prefix for internal functions. While we're at it, make the code easier to understand by automatically generating the huge switch statement and eliminating the silly macros. --- Makefile.am | 10 +++- src/.gitignore | 1 + src/parse-decl.c | 112 ++++----------------------------------------- src/typemap.c | 63 +++++++++++++++++++++++++ src/typemap.h | 7 +++ src/validtypes.in | 39 ++++++++++++++++ src/validtypes.sed | 8 ++++ 7 files changed, 136 insertions(+), 104 deletions(-) create mode 100644 src/typemap.c create mode 100644 src/typemap.h create mode 100644 src/validtypes.in create mode 100644 src/validtypes.sed diff --git a/Makefile.am b/Makefile.am index 0caecb2..8f82af4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,8 +9,8 @@ include_HEADERS = src/cdecl.h noinst_HEADERS = src/scan.h src/parse.h lib_LTLIBRARIES = libcdecl.la -libcdecl_la_LDFLAGS = -export-symbols-regex '^cdecl_' -libcdecl_la_SOURCES = src/scan.c src/parse.c src/parse-decl.c +libcdecl_la_LDFLAGS = -export-symbols-regex '^cdecl_[[:lower:]]' +libcdecl_la_SOURCES = src/scan.c src/parse.c src/parse-decl.c src/typemap.c bin_PROGRAMS = cdecl99 cdecl99_SOURCES = src/cdecl99.c @@ -19,6 +19,12 @@ cdecl99_LDADD = libcdecl.la 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/validtypes.h: src/validtypes.in $(srcdir)/src/validtypes.sed + $(AM_V_GEN)sed -f $(srcdir)/src/validtypes.sed \ + < src/validtypes.in > $@.tmp + $(AM_V_at)mv -f $@.tmp $@ # These are required to prevent the builtin lex/yacc rules from # superseding ours... diff --git a/src/.gitignore b/src/.gitignore index 47a2c45..6cb92c6 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -2,3 +2,4 @@ parse.stamp parse.[ch] scan.stamp scan.[ch] +validtypes.h diff --git a/src/parse-decl.c b/src/parse-decl.c index c06080b..e9756e3 100644 --- a/src/parse-decl.c +++ b/src/parse-decl.c @@ -2,115 +2,28 @@ #include #include "cdecl.h" +#include "typemap.h" #include "parse.h" #include "scan.h" -#define PASTE(a, b) a ## b -#define PASTE2(a, b) PASTE(a, b) - -#define BIT1(a) ((1ul<<(CDECL_TYPE_ ## a))) -#define BIT2(a, b) ((1ul<<(CDECL_TYPE_ ## a))|(1ul<<(CDECL_TYPE_ ## b))) -#define BIT3(a, b, c) ((1ul<<(CDECL_TYPE_ ## a))|(1ul<<(CDECL_TYPE_ ## b))|(1ul<<(CDECL_TYPE_ ## c))) -#define BIT4(a, b, c, d) ((1ul<<(CDECL_TYPE_ ## a))|(1ul<<(CDECL_TYPE_ ## b))|(1ul<<(CDECL_TYPE_ ## c))|(1ul<<(CDECL_TYPE_ ## d))) - -#define NARG_(_4, _3, _2, _1, n, ...) n -#define NARG(...) NARG_(__VA_ARGS__, 4, 3, 2, 1) - -#define BITS(...) PASTE2(BIT, NARG(__VA_ARGS__))(__VA_ARGS__) - -/* - * 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 32 - -static int typemap_verify(unsigned long map) -{ - /* - * This is the complete list of valid type specifiers from C99§6.7.2#2 - */ - - switch (map) { - case BITS(VOID): - case BITS(CHAR): - case BITS(SIGNED, CHAR): - case BITS(UNSIGNED, CHAR): - case BITS(SHORT): - case BITS(SIGNED, SHORT): - case BITS(SHORT, INT): - case BITS(SIGNED, SHORT, INT): - case BITS(UNSIGNED, SHORT): - case BITS(UNSIGNED, SHORT, INT): - case BITS(INT): - case BITS(SIGNED): - case BITS(SIGNED, INT): - case BITS(UNSIGNED): - case BITS(UNSIGNED, INT): - case BITS(LONG): - case BITS(SIGNED, LONG): - case BITS(SIGNED, LONG, INT): - case BITS(UNSIGNED, LONG): - case BITS(UNSIGNED, LONG, INT): - case BITS(LLONG, LONG): - case BITS(SIGNED, LLONG, LONG): - case BITS(SIGNED, LLONG, LONG, INT): - case BITS(UNSIGNED, LLONG, LONG): - case BITS(UNSIGNED, LLONG, LONG, INT): - case BITS(BOOL): - case BITS(FLOAT): - case BITS(DOUBLE): - case BITS(LONG, DOUBLE): - case BITS(FLOAT, COMPLEX): - case BITS(DOUBLE, COMPLEX): - case BITS(LONG, DOUBLE, COMPLEX): - case BITS(STRUCT): - case BITS(UNION): - case BITS(ENUM): - case BITS(IDENT): - return 0; - } - - return -1; -} - -static unsigned long -typemap_add_typespec(unsigned long map, struct cdecl_declspec *s) +static int verify_specs(struct cdecl_declspec *s) { - assert(s->type < CDECL_TYPE_LLONG); + unsigned num_storage = 0; + unsigned long typemap; - if (s->type == CDECL_TYPE_LONG) { - if (map & BITS(LLONG)) { - fprintf(stderr, "too many long specifiers\n"); - return -1; - } else if (map & BITS(LONG)) { - return map | BITS(LLONG); - } - } + typemap = cdecl__build_typemap(s); + if (typemap == -1) + return -1; - if (map & (1ul<type)) { - fprintf(stderr, "duplicate type specifier\n"); + if (!cdecl__typemap_is_valid(typemap)) { + fprintf(stderr, "conflicting type specifiers\n"); return -1; } - return map | (1<type); -} - -static int verify_specs(struct cdecl_declspec *s) -{ - unsigned long typemap = 0; - unsigned num_storage = 0; - for (struct cdecl_declspec *c = s; c; c = c->next) { switch (cdecl_spec_kind(c)) { case CDECL_SPEC_TYPE: - typemap = typemap_add_typespec(typemap, c); - if (typemap == -1) { - return -1; - } - break; + continue; case CDECL_SPEC_STOR: if (++num_storage > 1) { fprintf(stderr, "too many storage-class specifiers\n"); @@ -139,11 +52,6 @@ static int verify_specs(struct cdecl_declspec *s) } } - if (typemap_verify(typemap) == -1) { - fprintf(stderr, "conflicting type specifiers\n"); - return -1; - } - return 0; } diff --git a/src/typemap.c b/src/typemap.c new file mode 100644 index 0000000..0e5b41c --- /dev/null +++ b/src/typemap.c @@ -0,0 +1,63 @@ +#include +#include +#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<type)) { + fprintf(stderr, "duplicate type specifier\n"); + return -1; + } + + return map | (1ul<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; +} diff --git a/src/typemap.h b/src/typemap.h new file mode 100644 index 0000000..285ff29 --- /dev/null +++ b/src/typemap.h @@ -0,0 +1,7 @@ +#ifndef CDECL_TYPEMAP_H_ +#define CDECL_TYPEMAP_H_ + +_Bool cdecl__typemap_is_valid(unsigned long map); +unsigned long cdecl__build_typemap(struct cdecl_declspec *s); + +#endif diff --git a/src/validtypes.in b/src/validtypes.in new file mode 100644 index 0000000..f81b424 --- /dev/null +++ b/src/validtypes.in @@ -0,0 +1,39 @@ +/* The complete list of valid type specifiers according to C99§6.7.2#2 */ +void +char +signed char +unsigned char +short +signed short +short int +signed short int +unsigned short +unsigned short int +int +signed +signed int +unsigned +unsigned int +long +long int +signed long +signed long int +unsigned long +unsigned long int +long long +long long int +signed long long +signed long long int +unsigned long long +unsigned long long int +bool +float +double +long double +float complex +double complex +long double complex +struct +union +enum +ident diff --git a/src/validtypes.sed b/src/validtypes.sed new file mode 100644 index 0000000..fd45fde --- /dev/null +++ b/src/validtypes.sed @@ -0,0 +1,8 @@ +1i\ +/* This file is automatically generated by validtypes.sed */ +/[^[:alpha:][:space:]]/b +y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ +s/LONG[[:space:]][[:space:]]*LONG/LLONG LONG/ +s/[[:upper:]][[:upper:]]*/(1ul<