]> git.draconx.ca Git - cdecl99.git/commitdiff
Add support for outputting declarations as C code.
authorNick Bowler <nbowler@draconx.ca>
Sat, 9 Jul 2011 00:00:44 +0000 (20:00 -0400)
committerNick Bowler <nbowler@draconx.ca>
Sat, 9 Jul 2011 00:00:44 +0000 (20:00 -0400)
This permits us to define a nifty "simplify" function.

Makefile.am
src/cdecl.h
src/cdecl99.c
src/declare.c [new file with mode: 0644]
src/explain.c
src/output.c
src/output.h
src/typemap.h

index 07d3f8fe765278640838df525f44d5daa4ef1a6f..ad56e4ad3471e61d5bb1dd37846e61fbd18b7fb2 100644 (file)
@@ -24,7 +24,7 @@ noinst_HEADERS = src/typemap.h src/output.h src/scan.h src/parse.h
 lib_LTLIBRARIES = libcdecl.la
 libcdecl_la_LDFLAGS = -export-symbols-regex '^cdecl_[[:lower:]]'
 libcdecl_la_SOURCES = src/scan.c src/parse.c src/parse-decl.c src/typemap.c \
-       src/output.c src/explain.c
+       src/output.c src/explain.c src/declare.c
 
 bin_PROGRAMS = cdecl99
 cdecl99_SOURCES = src/cdecl99.c
index 9b3e5da9a28b2ab7042b0e89d532723a5b040f59..29dab352297848524708f925e907ff095db7086e 100644 (file)
@@ -99,6 +99,7 @@ struct cdecl *cdecl_parse_decl(const char *declstr);
 void cdecl_free(struct cdecl *decl);
 
 size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl);
+size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl);
 
 static inline int cdecl_spec_kind(struct cdecl_declspec *spec)
 {
index b47565d62adffc85549a4eb2fc60ef97afb28b00..44bcd3e527828e2492af1a2603cd53beba348d48 100644 (file)
@@ -55,39 +55,93 @@ static void print_help(void)
        puts("Detailed help coming soon.");
 }
 
-static int cmd_explain(char *cmd, char *arg)
+/*
+ * Format a declaration according to the given function and return a pointer
+ * to the formatted string.  The returned pointer remains valid until the
+ * next call, after which it must not be re-used.
+ *
+ * Returns NULL on failure.
+ */
+static const char *
+do_format(size_t func(char *, size_t, struct cdecl *), struct cdecl *decl)
 {
        static size_t bufsz;
        static char *buf;
-       int ret = -1;
 
-       struct cdecl *decl;
        size_t rc;
 
+retry:
+       rc = func(buf, bufsz, decl);
+       if (rc >= bufsz) {
+               char *tmp;
+
+               tmp = realloc(buf, rc + 1);
+               if (!tmp) {
+                       fprintf(stderr, "failed to allocate memory\n");
+                       return NULL;
+               }
+
+               buf = tmp;
+               bufsz = rc + 1;
+               goto retry;
+       }
+
+       return buf;
+}
+
+static int cmd_explain(char *cmd, char *arg)
+{
+       struct cdecl *decl;
+       const char *str;
+       int ret = -1;
+
        decl = cdecl_parse_decl(arg);
        if (!decl)
                goto out;
 
        for (struct cdecl *i = decl; i; i = i->next) {
-retry:
-               rc = cdecl_explain(buf, bufsz, i);
-               if (rc >= bufsz) {
-                       char *tmp;
+               str = do_format(cdecl_explain, i);
+               if (!str)
+                       goto out;
 
-                       tmp = realloc(buf, rc + 1);
-                       if (!tmp) {
-                               fprintf(stderr, "failed to allocate memory\n");
-                               goto out;
-                       }
+               printf("%s\n", str);
+       }
+
+       ret = 1;
+out:
+       cdecl_free(decl);
+       return ret;
+}
+
+static int cmd_simplify(char *cmd, char *arg)
+{
+       struct cdecl *decl;
+       const char *str;
+       int ret = -1;
+
+       decl = cdecl_parse_decl(arg);
+       if (!decl)
+               goto out;
 
-                       buf = tmp;
-                       bufsz = rc + 1;
-                       goto retry;
+       for (struct cdecl *i = decl; i; i = i->next) {
+               struct cdecl_declspec *s = i->specifiers;
+
+               if (i != decl) {
+                       i->specifiers = NULL;
+                       printf(", ");
                }
 
-               printf("%s\n", buf);
+               str = do_format(cdecl_declare, i);
+               i->specifiers = s;
+
+               if (!str)
+                       goto out;
+
+               printf("%s", str);
        }
 
+       putchar('\n');
+
        ret = 1;
 out:
        cdecl_free(decl);
@@ -106,10 +160,11 @@ static const struct command {
        int (*func)(char *cmd, char *arg);
        const char *blurb;
 } commands[] = {
-       { "explain", cmd_explain, "Explain a C declaration." },
-       { "help",    cmd_help,    "Print this list of commands." },
-       { "quit",    cmd_quit,    "Quit the program." },
-       { "exit",    cmd_quit,    NULL }
+       { "explain",  cmd_explain,  "Explain a C declaration." },
+       { "simplify", cmd_simplify, "Simplify a C declaration." },
+       { "help",     cmd_help,     "Print this list of commands." },
+       { "quit",     cmd_quit,     "Quit the program." },
+       { "exit",     cmd_quit,     NULL }
 };
 static const size_t ncommands = sizeof commands / sizeof commands[0];
 
diff --git a/src/declare.c b/src/declare.c
new file mode 100644 (file)
index 0000000..bc8af4a
--- /dev/null
@@ -0,0 +1,152 @@
+#include <stdio.h>
+#include <assert.h>
+
+#include "cdecl.h"
+#include "output.h"
+
+static size_t declare_specs(char *buf, size_t n, struct cdecl_declspec *s)
+{
+       size_t ret = 0, rc;
+
+       if (!s)
+               return 0;
+
+       rc = cdecl__explain_pre_specs(buf, n, s);
+       ret += cdecl__advance(&buf, &n, rc);
+
+       rc = cdecl__explain_post_specs(buf, n, s);
+       return ret + rc;
+}
+
+static size_t
+declare_declarator(char *buf, size_t n, struct cdecl_declarator *d);
+
+static size_t declare_decl(char *buf, size_t n, struct cdecl *decl)
+{
+       size_t ret = 0, rc;
+
+       rc = declare_specs(buf, n, decl->specifiers);
+       if (decl->declarators->type != CDECL_DECL_NULL)
+               ret += cdecl__advance(&buf, &n, rc);
+       else
+               ret += cdecl__advance_(&buf, &n, rc);
+
+       return ret + declare_declarator(buf, n, decl->declarators);
+}
+
+static size_t
+declare_postfix_child(char *buf, size_t n, struct cdecl_declarator *d)
+{
+       size_t ret = 0, rc;
+
+       if (d->type == CDECL_DECL_POINTER) {
+               rc = snprintf(buf, n, "(");
+               ret += cdecl__advance_(&buf, &n, rc);
+       }
+
+       rc = declare_declarator(buf, n, d);
+       ret += cdecl__advance_(&buf, &n, rc);
+
+       if (d->type == CDECL_DECL_POINTER) {
+               rc = snprintf(buf, n, ")");
+               ret += cdecl__advance_(&buf, &n, rc);
+       }
+
+       return ret;
+}
+
+static size_t declare_pointer(char *buf, size_t n, struct cdecl_pointer *p)
+{
+       size_t ret = 0, rc;
+
+       rc = snprintf(buf, n, "*");
+       if (p->qualifiers)
+               ret += cdecl__advance(&buf, &n, rc);
+       else
+               ret += cdecl__advance_(&buf, &n, rc);
+
+       rc = cdecl__explain_qualifiers(buf, n, p->qualifiers);
+       return ret + cdecl__advance(&buf, &n, rc);
+}
+
+static size_t declare_array(char *buf, size_t n, struct cdecl_array *a)
+{
+       size_t ret = 0, rc;
+
+       rc = snprintf(buf, n, "[");
+       ret += cdecl__advance_(&buf, &n, rc);
+
+       if (a->vla)
+               rc = snprintf(buf, n, "%s", a->vla[0] ? a->vla : "*");
+       else
+               rc = snprintf(buf, n, "%.0ju", a->length);
+       ret += cdecl__advance_(&buf, &n, rc);
+
+       return ret + snprintf(buf, n, "]");
+}
+
+static size_t declare_function(char *buf, size_t n, struct cdecl_function *f)
+{
+       size_t ret = 0, rc;
+
+       rc = snprintf(buf, n, "(");
+       ret += cdecl__advance_(&buf, &n, rc);
+
+       for (struct cdecl *p = f->parameters; p; p = p->next) {
+               rc = declare_decl(buf, n, p);
+               ret += cdecl__advance_(&buf, &n, rc);
+
+               if (p->next)
+                       rc = snprintf(buf, n, ", ");
+               else if (f->variadic)
+                       rc = snprintf(buf, n, ", ...)");
+               else
+                       rc = snprintf(buf, n, ")");
+               ret += cdecl__advance_(&buf, &n, rc);
+       }
+
+       return ret;
+}
+
+static size_t
+declare_declarator(char *buf, size_t n, struct cdecl_declarator *d)
+{
+       size_t ret = 0, rc;
+
+       for (; d; d = d->child) {
+               switch (d->type) {
+               case CDECL_DECL_NULL:
+                       break;
+               case CDECL_DECL_IDENT:
+                       rc = snprintf(buf, n, "%s", d->u.ident);
+                       ret += cdecl__advance_(&buf, &n, rc);
+                       break;
+               case CDECL_DECL_POINTER:
+                       rc = declare_pointer(buf, n, &d->u.pointer);
+                       ret += cdecl__advance_(&buf, &n, rc);
+                       break;
+               /*
+                * Arrays and functions are special: since they are postfix,
+                * we need to render the children before rendering their
+                * "bodies".
+                */
+               case CDECL_DECL_ARRAY:
+                       rc = declare_postfix_child(buf, n, d->child);
+                       ret += cdecl__advance_(&buf, &n, rc);
+                       return ret + declare_array(buf, n, &d->u.array);
+               case CDECL_DECL_FUNCTION:
+                       rc = declare_postfix_child(buf, n, d->child);
+                       ret += cdecl__advance_(&buf, &n, rc);
+                       return ret + declare_function(buf, n, &d->u.function);
+               default:
+                       assert(0);
+               }
+       }
+
+       return ret;
+}
+
+size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl)
+{
+       return declare_decl(buf, n, decl);
+}
index dadc65f3058122732fcc3107924a4dc3bfaee4e2..41d4f7be744c4ce23de7adbbe6ed9a6d9dc33b62 100644 (file)
 #include <assert.h>
 
 #include "cdecl.h"
-#include "typemap.h"
 #include "output.h"
 
-static size_t
-explain_qualifiers(char *buf, size_t n, struct cdecl_declspec *s)
-{
-       unsigned long qualmap = 0;
-       size_t ret = 0, rc = 0;
-
-       for (struct cdecl_declspec *c = s; c; c = c->next) {
-               if (cdecl_spec_kind(c) != CDECL_SPEC_QUAL)
-                       continue;
-               qualmap |= 1ul << (c->type & 0xff);
-       }
-
-       if (qualmap & (1ul << (CDECL_QUAL_RESTRICT & 0xff))) {
-               ret += cdecl__advance(&buf, &n, rc);
-               rc = snprintf(buf, n, "restrict");
-       }
-       if (qualmap & (1ul << (CDECL_QUAL_VOLATILE & 0xff))) {
-               ret += cdecl__advance(&buf, &n, rc);
-               rc = snprintf(buf, n, "volatile");
-       }
-       if (qualmap & (1ul << (CDECL_QUAL_CONST & 0xff))) {
-               ret += cdecl__advance(&buf, &n, rc);
-               rc = snprintf(buf, n, "const");
-       }
-
-       return ret + rc;
-}
-
-/* Renders the type qualifiers and type specifiers in canonical form. */
-static size_t
-explain_post_specs(char *buf, size_t n, struct cdecl_declspec *s)
-{
-       const char *tag = NULL;
-       unsigned long typemap;
-       size_t ret = 0, rc;
-
-       typemap = cdecl__build_typemap(s);
-       if (typemap == -1)
-               return 0;
-
-       for (struct cdecl_declspec *c = s; c; c = c->next) {
-               if (cdecl_spec_kind(c) != CDECL_SPEC_TYPE)
-                       continue;
-
-               /* Valid C types have at most one identifier. */
-               if (c->ident)
-                       tag = c->ident;
-       }
-
-       rc = explain_qualifiers(buf, n, s);
-       ret += cdecl__advance(&buf, &n, rc);
-
-       rc = snprintf(buf, n, "%s", cdecl__explain_typemap(typemap));
-       if (tag) {
-               ret += cdecl__advance(&buf, &n, rc);
-               rc = snprintf(buf, n, "%s", tag);
-       }
-
-       return ret + rc;
-}
-
-static size_t explain_storage(char *buf, size_t n, unsigned spec)
-{
-       switch (spec) {
-       case CDECL_STOR_TYPEDEF:
-               return snprintf(buf, n, "typedef");
-       case CDECL_STOR_EXTERN:
-               return snprintf(buf, n, "extern");
-       case CDECL_STOR_STATIC:
-               return snprintf(buf, n, "static");
-       case CDECL_STOR_AUTO:
-               return snprintf(buf, n, "auto");
-       case CDECL_STOR_REGISTER:
-               return snprintf(buf, n, "register");
-       default:
-               assert(0);
-       }
-}
-
-/* Renders the storage-class and function specifiers in canonical form. */
-static size_t explain_pre_specs(char *buf, size_t n, struct cdecl_declspec *s)
-{
-       unsigned long funcmap = 0;
-       size_t ret = 0, rc = 0;
-
-       for (struct cdecl_declspec *c = s; c; c = c->next) {
-               switch (cdecl_spec_kind(c)) {
-               case CDECL_SPEC_FUNC:
-                       funcmap |= 1ul << (c->type & 0xff);
-                       break;
-               case CDECL_SPEC_STOR:
-                       /* Valid C declarations have at most one
-                        * storage-class specifier. */
-                       rc = explain_storage(buf, n, c->type);
-                       break;
-               }
-       }
-
-       if (funcmap & (1ul << (CDECL_FUNC_INLINE & 0xff))) {
-               ret += cdecl__advance(&buf, &n, rc);
-               rc = snprintf(buf, n, "inline");
-       }
-
-       return ret + rc;
-}
-
 /*
  * Renders the start of the thing being declared.  If top is true, print
  * the "declare" or "type" keywords at the front, as appropriate.
@@ -162,7 +55,7 @@ explain_pointer(char *buf, size_t n, struct cdecl_pointer *p)
 {
        size_t ret = 0, rc;
 
-       rc = explain_qualifiers(buf, n, p->qualifiers);
+       rc = cdecl__explain_qualifiers(buf, n, p->qualifiers);
        ret += cdecl__advance(&buf, &n, rc);
 
        return ret + snprintf(buf, n, "pointer to");
@@ -200,13 +93,13 @@ static size_t explain_decl(char *buf, size_t n, struct cdecl *decl, bool top)
        rc = explain_prologue(buf, n, decl->declarators, top);
        ret += cdecl__advance(&buf, &n, rc);
 
-       rc = explain_pre_specs(buf, n, decl->specifiers);
+       rc = cdecl__explain_pre_specs(buf, n, decl->specifiers);
        ret += cdecl__advance(&buf, &n, rc);
 
        rc = explain_declarators(buf, n, decl->declarators);
        ret += cdecl__advance(&buf, &n, rc);
 
-       return ret + explain_post_specs(buf, n, decl->specifiers);
+       return ret + cdecl__explain_post_specs(buf, n, decl->specifiers);
 }
 
 static size_t explain_function(char *buf, size_t n, struct cdecl_function *f)
index 8c2cd0b6b1b4e9b9fe2d2934f6538d95abdb4be4..3d0a9236532a8953e05553cd22f3340f1fb43ef4 100644 (file)
@@ -1,5 +1,9 @@
 #include <stdio.h>
+#include <assert.h>
+
+#include "typemap.h"
 #include "output.h"
+#include "cdecl.h"
 
 size_t cdecl__advance_(char **buf, size_t *n, size_t amount)
 {
@@ -25,3 +29,107 @@ size_t cdecl__advance(char **buf, size_t *n, size_t amount)
        rc = snprintf(*buf, *n, " ");
        return ret + cdecl__advance_(buf, n, rc);
 }
+
+static size_t explain_storage(char *buf, size_t n, unsigned spec)
+{
+       switch (spec) {
+       case CDECL_STOR_TYPEDEF:
+               return snprintf(buf, n, "typedef");
+       case CDECL_STOR_EXTERN:
+               return snprintf(buf, n, "extern");
+       case CDECL_STOR_STATIC:
+               return snprintf(buf, n, "static");
+       case CDECL_STOR_AUTO:
+               return snprintf(buf, n, "auto");
+       case CDECL_STOR_REGISTER:
+               return snprintf(buf, n, "register");
+       default:
+               assert(0);
+       }
+}
+
+/* Renders the storage-class and function specifiers in canonical form. */
+size_t cdecl__explain_pre_specs(char *buf, size_t n, struct cdecl_declspec *s)
+{
+       unsigned long funcmap = 0;
+       size_t ret = 0, rc = 0;
+
+       for (struct cdecl_declspec *c = s; c; c = c->next) {
+               switch (cdecl_spec_kind(c)) {
+               case CDECL_SPEC_FUNC:
+                       funcmap |= 1ul << (c->type & 0xff);
+                       break;
+               case CDECL_SPEC_STOR:
+                       /* Valid C declarations have at most one
+                        * storage-class specifier. */
+                       rc = explain_storage(buf, n, c->type);
+                       break;
+               }
+       }
+
+       if (funcmap & (1ul << (CDECL_FUNC_INLINE & 0xff))) {
+               ret += cdecl__advance(&buf, &n, rc);
+               rc = snprintf(buf, n, "inline");
+       }
+
+       return ret + rc;
+}
+
+size_t cdecl__explain_qualifiers(char *buf, size_t n, struct cdecl_declspec *s)
+{
+       unsigned long qualmap = 0;
+       size_t ret = 0, rc = 0;
+
+       for (struct cdecl_declspec *c = s; c; c = c->next) {
+               if (cdecl_spec_kind(c) != CDECL_SPEC_QUAL)
+                       continue;
+               qualmap |= 1ul << (c->type & 0xff);
+       }
+
+       if (qualmap & (1ul << (CDECL_QUAL_RESTRICT & 0xff))) {
+               ret += cdecl__advance(&buf, &n, rc);
+               rc = snprintf(buf, n, "restrict");
+       }
+       if (qualmap & (1ul << (CDECL_QUAL_VOLATILE & 0xff))) {
+               ret += cdecl__advance(&buf, &n, rc);
+               rc = snprintf(buf, n, "volatile");
+       }
+       if (qualmap & (1ul << (CDECL_QUAL_CONST & 0xff))) {
+               ret += cdecl__advance(&buf, &n, rc);
+               rc = snprintf(buf, n, "const");
+       }
+
+       return ret + rc;
+}
+
+/* Renders the type qualifiers and type specifiers in canonical form. */
+size_t cdecl__explain_post_specs(char *buf, size_t n, struct cdecl_declspec *s)
+{
+       const char *tag = NULL;
+       unsigned long typemap;
+       size_t ret = 0, rc;
+
+       typemap = cdecl__build_typemap(s);
+       if (typemap == -1)
+               return 0;
+
+       for (struct cdecl_declspec *c = s; c; c = c->next) {
+               if (cdecl_spec_kind(c) != CDECL_SPEC_TYPE)
+                       continue;
+
+               /* Valid C types have at most one identifier. */
+               if (c->ident)
+                       tag = c->ident;
+       }
+
+       rc = cdecl__explain_qualifiers(buf, n, s);
+       ret += cdecl__advance(&buf, &n, rc);
+
+       rc = snprintf(buf, n, "%s", cdecl__explain_typemap(typemap));
+       if (tag) {
+               ret += cdecl__advance(&buf, &n, rc);
+               rc = snprintf(buf, n, "%s", tag);
+       }
+
+       return ret + rc;
+}
index 03f7acb1a6f2247762c9fa3c012064090e6d0aff..ecb9a753a29ac787eda950e6d61c2da2d3dee59e 100644 (file)
@@ -2,8 +2,12 @@
 #define CDECL_OUTPUT_H_
 
 #include <stddef.h>
+#include "cdecl.h"
 
 size_t cdecl__advance_(char **buf, size_t *n, size_t amount);
 size_t cdecl__advance(char **buf, size_t *n, size_t amount);
+size_t cdecl__explain_pre_specs(char *buf, size_t n, struct cdecl_declspec *s);
+size_t cdecl__explain_qualifiers(char *buf, size_t n, struct cdecl_declspec *s);
+size_t cdecl__explain_post_specs(char *buf, size_t n, struct cdecl_declspec *s);
 
 #endif
index ddb5dc60cc334351aaee1ff9c3902effbee2affc..10eeec341f63a2671d5bb64634cb344fbb90e1c7 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef CDECL_TYPEMAP_H_
 #define CDECL_TYPEMAP_H_
 
+#include "cdecl.h"
+
 unsigned long cdecl__build_typemap(struct cdecl_declspec *s);
 const char *cdecl__explain_typemap(unsigned long map);