]> git.draconx.ca Git - cdecl99.git/blobdiff - src/declare.c
Add support for outputting declarations as C code.
[cdecl99.git] / src / declare.c
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);
+}