This permits us to define a nifty "simplify" function.
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
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)
{
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);
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];
--- /dev/null
+#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);
+}
#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.
{
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");
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)
#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)
{
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;
+}
#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
#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);