]> git.draconx.ca Git - cdecl99.git/commitdiff
libcdecl: Rework cdecl_explain output logic.
authorNick Bowler <nbowler@draconx.ca>
Fri, 23 Jun 2023 01:21:46 +0000 (21:21 -0400)
committerNick Bowler <nbowler@draconx.ca>
Fri, 23 Jun 2023 02:02:33 +0000 (22:02 -0400)
Instead of adjusting the output pointer/length values after each
internal call, tweak all the functions in explain.c to take an
extra level of indirection so they can just directly adjust the
destination as they go.

A new helper, cdecl__emit, is provided to simplify the common pattern
of "print a single C string" followed by "advance pointer/length."

src/cdecl-internal.h
src/explain.c
src/output.c

index ab884898fa3ce2c3224b7a29240c612562521e96..0008c334fe4f5fc98d850ff5c82fcf45ec488be8 100644 (file)
@@ -45,4 +45,6 @@ size_t cdecl__advance(char **buf, size_t *n, size_t amount);
 size_t cdecl__explain_specs(char *buf, size_t n, struct cdecl_declspec *s,
                                                  unsigned mask);
 
+size_t cdecl__emit(char **dst, size_t *dstlen, const char *src);
+
 #endif
index fe3ed7d9904ea4bc9f4bb127858a23e1d3965a30..4deadac2d410baadc53355bc414aac9bf14fef4c 100644 (file)
 
 #include <config.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
 #include <inttypes.h>
-#include <stdbool.h>
 #include <assert.h>
 
 #include "cdecl.h"
 #include "cdecl-internal.h"
 
-static size_t explain_pre_specs(char *buf, size_t n, struct cdecl_declspec *s)
+#define PRE_SPECS (CDECL_SPEC_FUNC|CDECL_SPEC_STOR)
+#define POST_SPECS (CDECL_SPEC_QUAL|CDECL_SPEC_TYPE)
+
+static size_t explain_specs(char **dst, size_t *dstlen, struct cdecl_declspec *s, unsigned mask)
 {
-       return cdecl__explain_specs(buf, n, s, CDECL_SPEC_FUNC|CDECL_SPEC_STOR);
+       size_t rc;
+
+       rc = cdecl__explain_specs(*dst, *dstlen, s, mask);
+       return cdecl__advance(dst, dstlen, rc);
 }
 
-static size_t explain_post_specs(char *buf, size_t n, struct cdecl_declspec *s)
+static size_t
+explain_specs_post(char **dst, size_t *dstlen, struct cdecl_declspec *s)
 {
-       return cdecl__explain_specs(buf, n, s, CDECL_SPEC_QUAL|CDECL_SPEC_TYPE);
+       size_t rc;
+
+       rc = cdecl__explain_specs(*dst, *dstlen, s, POST_SPECS);
+       return cdecl__advance_(dst, dstlen, rc);
 }
 
+/*
+ * If declarator declares an identifier foo, then emit "foo as "; otherwise
+ * emit nothing.
+ */
 static size_t
-explain_name(char *buf, size_t n, struct cdecl_declarator *d)
+explain_name(char **dst, size_t *dstlen, struct cdecl_declarator *d)
 {
+       size_t ret;
+
        while (d->child)
                d = d->child;
 
        if (d->type != CDECL_DECL_IDENT)
                return 0;
 
-       return snprintf(buf, n, "%s as", d->u.ident);
+       ret = cdecl__emit(dst, dstlen, d->u.ident);
+       return ret + cdecl__emit(dst, dstlen, " as ");
 }
 
+/*
+ * For a pointer declarator, emit "[QUAL ]pointer to ", where
+ * QUAL is the (possibly empty) list of qualifiers.
+ */
 static size_t
-explain_pointer(char *buf, size_t n, struct cdecl_pointer *p)
+explain_pointer(char **dst, size_t *dstlen, struct cdecl_pointer *p)
 {
-       size_t ret = 0, rc;
-
-       rc = cdecl__explain_specs(buf, n, p->qualifiers, CDECL_SPEC_QUAL);
-       ret += cdecl__advance(&buf, &n, rc);
+       size_t ret;
 
-       return ret + snprintf(buf, n, "pointer to");
+       ret = explain_specs(dst, dstlen, p->qualifiers, -1);
+       return ret + cdecl__emit(dst, dstlen, "pointer to ");
 }
 
+/*
+ * For an array declarator, emit "[variable-length ]array [X ]of ", where
+ * for a variable-length array X is the (possibly omitted) identifier name,
+ * and for normal arrays X is the (possibly omitted) length.
+ */
 static size_t
-explain_array(char *buf, size_t n, struct cdecl_array *a)
+explain_array(char **dst, size_t *dstlen, struct cdecl_array *a)
 {
        size_t ret = 0, rc = 0;
 
        if (a->vla)
-               rc = snprintf(buf, n, "variable-length array");
-       else
-               rc = snprintf(buf, n, "array");
-       ret += cdecl__advance(&buf, &n, rc);
+               ret += cdecl__emit(dst, dstlen, "variable-length ");
+       ret += cdecl__emit(dst, dstlen, "array ");
 
        if (a->vla) {
-               rc = snprintf(buf, n, "%s", a->vla);
-               ret += cdecl__advance(&buf, &n, rc);
-       } else if (a->length) {
-               rc = snprintf(buf, n, "%" PRIuMAX, a->length);
-               ret += cdecl__advance(&buf, &n, rc);
+               rc = cdecl__emit(dst, dstlen, a->vla);
+               ret += rc;
+       } else {
+               rc = snprintf(*dst, *dstlen, "%.0" PRIuMAX, a->length);
+               ret += cdecl__advance_(dst, dstlen, rc);
        }
 
-       return ret + snprintf(buf, n, "of");
+       return ret + cdecl__emit(dst, dstlen, " of " + !rc);
 }
 
 static size_t
-explain_declarators(char *buf, size_t n, struct cdecl_declarator *decl);
+explain_declarators(char **dst, size_t *dstlen, struct cdecl_declarator *decl);
 
-static size_t explain_decl(char *buf, size_t n, struct cdecl *decl)
+static size_t explain_decl(char **dst, size_t *dstlen, struct cdecl *decl)
 {
-       size_t ret = 0, rc;
-
-       rc = explain_name(buf, n, decl->declarators);
-       ret += cdecl__advance(&buf, &n, rc);
-
-       rc = explain_pre_specs(buf, n, decl->specifiers);
-       ret += cdecl__advance(&buf, &n, rc);
+       size_t ret;
 
-       rc = explain_declarators(buf, n, decl->declarators);
-       ret += cdecl__advance(&buf, &n, rc);
+       ret  = explain_name(dst, dstlen, decl->declarators);
+       ret += explain_specs(dst, dstlen, decl->specifiers, PRE_SPECS);
+       ret += explain_declarators(dst, dstlen, decl->declarators);
+       ret += explain_specs_post(dst, dstlen, decl->specifiers);
 
-       return ret + explain_post_specs(buf, n, decl->specifiers);
+       return ret;
 }
 
-static size_t explain_function(char *buf, size_t n, struct cdecl_function *f)
+/*
+ * For a function declarator, emit "function [PARAM ]returning ", where
+ * PARAM is the (omitted in the case of an empty non-prototype identifier
+ * list) parameter or identifier lists enclosed in parentheses.
+ */
+static size_t
+explain_function(char **dst, size_t *dstlen, struct cdecl_function *f)
 {
-       size_t ret = 0, rc = 0;
+       size_t ret = 0;
 
-       rc = snprintf(buf, n, "function");
-       ret += cdecl__advance(&buf, &n, rc);
+       ret += cdecl__emit(dst, dstlen, "function ");
 
        if (f->parameters) {
-               rc = snprintf(buf, n, "(");
-               ret += cdecl__advance_(&buf, &n, rc);
+               struct cdecl *p;
 
-               for (struct cdecl *p = f->parameters; p; p = p->next) {
-                       rc = explain_decl(buf, n, p);
-                       ret += cdecl__advance_(&buf, &n, rc);
+               ret += cdecl__emit(dst, dstlen, "(");
 
+               for (p = f->parameters; p; p = p->next) {
+                       ret += explain_decl(dst, dstlen, p);
                        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);
+                               ret += cdecl__emit(dst, dstlen, ", ");
                }
+
+               if (f->variadic)
+                       ret += cdecl__emit(dst, dstlen, ", ...) ");
+               else
+                       ret += cdecl__emit(dst, dstlen, ") ");
        }
 
-       return ret + snprintf(buf, n, "returning");
+       return ret + cdecl__emit(dst, dstlen, "returning ");
 }
 
 static size_t
-explain_declarators(char *buf, size_t n, struct cdecl_declarator *d)
+explain_declarators(char **dst, size_t *dstlen, struct cdecl_declarator *d)
 {
-       size_t ret = 0, rc;
+       size_t ret;
 
        if (d->type == CDECL_DECL_IDENT || d->type == CDECL_DECL_NULL)
                return 0;
 
-       rc = explain_declarators(buf, n, d->child);
-       ret += cdecl__advance(&buf, &n, rc);
+       ret = explain_declarators(dst, dstlen, d->child);
 
        switch (d->type) {
        case CDECL_DECL_POINTER:
-               return ret + explain_pointer(buf, n, &d->u.pointer);
+               return ret + explain_pointer(dst, dstlen, &d->u.pointer);
        case CDECL_DECL_ARRAY:
-               return ret + explain_array(buf, n, &d->u.array);
+               return ret + explain_array(dst, dstlen, &d->u.array);
        case CDECL_DECL_FUNCTION:
-               return ret + explain_function(buf, n, &d->u.function);
+               return ret + explain_function(dst, dstlen, &d->u.function);
        default:
                assert(0);
        }
@@ -154,13 +172,12 @@ explain_declarators(char *buf, size_t n, struct cdecl_declarator *d)
 
 size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl)
 {
-       size_t ret, rc;
+       size_t ret;
 
        if (cdecl_is_abstract(decl->declarators))
-               rc = snprintf(buf, n, "type");
+               ret = cdecl__emit(&buf, &n, "type ");
        else
-               rc = snprintf(buf, n, "declare");
-       ret = cdecl__advance(&buf, &n, rc);
+               ret = cdecl__emit(&buf, &n, "declare ");
 
-       return ret + explain_decl(buf, n, decl);
+       return ret + explain_decl(&buf, &n, decl);
 }
index a8d7ea5ade969fef29be01855623105106e57dfe..d2359eb451187c0ea2068784b29fb66c445fb69a 100644 (file)
@@ -47,6 +47,12 @@ size_t cdecl__advance(char **buf, size_t *n, size_t amount)
        return ret + cdecl__advance_(buf, n, rc);
 }
 
+size_t cdecl__emit(char **dst, size_t *dstlen, const char *src)
+{
+       size_t rc = snprintf(*dst, *dstlen, "%s", src);
+       return cdecl__advance_(dst, dstlen, rc);
+}
+
 #include "specstr.h"
 
 static size_t explain_spec(char *buf, size_t n, struct cdecl_declspec *s)