X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/31ac11cc668bb8ecc1317fd2e8bd79b7925bceeb..9cb5aae31e1c126970843ef9b6e54036b185fd51:/src/explain.c diff --git a/src/explain.c b/src/explain.c index 1b46d20..10a7064 100644 --- a/src/explain.c +++ b/src/explain.c @@ -1,6 +1,6 @@ /* * Render C declarations as English. - * Copyright © 2011 Nick Bowler + * Copyright © 2011, 2021, 2023-2024 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,148 +15,133 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #include -#include -#include -#include -#include -#include +#include #include "cdecl.h" -#include "output.h" +#include "cdecl-internal.h" + +#define PRE_SPECS (CDECL_SPEC_FUNC|CDECL_SPEC_STOR) +#define POST_SPECS (CDECL_SPEC_QUAL|CDECL_SPEC_TYPE) + +static void explain_specs(struct output_state *dst, struct cdecl_declspec *s, unsigned mask) +{ + cdecl__emit(dst, cdecl__emit_specs(dst, s, mask)); +} /* - * Renders the start of the thing being declared. If top is true, print - * the "declare" or "type" keywords at the front, as appropriate. + * If declarator declares an identifier foo, then emit "foo as "; otherwise + * emit nothing. */ -static size_t -explain_prologue(char *buf, size_t n, struct cdecl_declarator *d, bool top) +static void +explain_name(struct output_state *dst, struct cdecl_declarator *d) { - size_t ret = 0, rc = 0; - - while (d) { - switch (d->type) { - case CDECL_DECL_NULL: - if (top) - return snprintf(buf, n, "type"); - return 0; - case CDECL_DECL_IDENT: - if (top) - rc = snprintf(buf, n, "declare"); - ret += cdecl__advance(&buf, &n, rc); - return ret + snprintf(buf, n, "%s as", d->u.ident); - } - + while (d->child) d = d->child; - } - assert(0); + if (d->type == CDECL_DECL_IDENT) { + cdecl__emit(dst, d->u.ident); + cdecl__emit(dst, " as "); + } } -static size_t -explain_pointer(char *buf, size_t n, struct cdecl_pointer *p) +/* + * For a pointer declarator, emit "[QUAL ]pointer to ", where + * QUAL is the (possibly empty) list of qualifiers. + */ +static void +explain_pointer(struct output_state *dst, 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); - - return ret + snprintf(buf, n, "pointer to"); + explain_specs(dst, p->qualifiers, -1); + cdecl__emit(dst, "pointer to "); } -static size_t -explain_array(char *buf, size_t n, struct cdecl_array *a) +/* + * 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 void +explain_array(struct output_state *dst, 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); + size_t rc = 0; + cdecl__emit(dst, "variable-length array " + (a->vla ? 0 : 16)); if (a->vla) { - rc = snprintf(buf, n, "%s", a->vla); - ret += cdecl__advance(&buf, &n, rc); - } else if (a->length) { - rc = snprintf(buf, n, "%ju", a->length); - ret += cdecl__advance(&buf, &n, rc); + rc = cdecl__emit(dst, a->vla); + } else { + rc = cdecl__emit_uint(dst, a->length); } - - return ret + snprintf(buf, n, "of"); + cdecl__emit(dst, " of " + !rc); } -static size_t -explain_declarators(char *buf, size_t n, struct cdecl_declarator *decl); +static void +explain_declarators(struct output_state *dst, struct cdecl_declarator *decl); -static size_t explain_decl(char *buf, size_t n, struct cdecl *decl, bool top) +static void explain_decl(struct output_state *dst, struct cdecl *decl) { - size_t ret = 0, rc; - - rc = explain_prologue(buf, n, decl->declarators, top); - ret += cdecl__advance(&buf, &n, rc); - - 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 + cdecl__explain_post_specs(buf, n, decl->specifiers); + explain_name(dst, decl->declarators); + explain_specs(dst, decl->specifiers, PRE_SPECS); + explain_declarators(dst, decl->declarators); + cdecl__emit_specs(dst, decl->specifiers, POST_SPECS); } -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 void +explain_function(struct output_state *dst, struct cdecl_function *f) { - size_t ret = 0, rc = 0; - - rc = snprintf(buf, n, "function"); - ret += cdecl__advance(&buf, &n, rc); + int tail_offset = 7; + cdecl__emit(dst, "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, false); - ret += cdecl__advance_(&buf, &n, rc); + cdecl__emit(dst, "("); + for (p = f->parameters; p; p = p->next) { + explain_decl(dst, 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); + cdecl__emit(dst, ", "); } - } - return ret + snprintf(buf, n, "returning"); + tail_offset = f->variadic ? 0 : 5; + } + cdecl__emit(dst, ", ...) returning " + tail_offset); } -static size_t -explain_declarators(char *buf, size_t n, struct cdecl_declarator *d) +static void +explain_declarators(struct output_state *dst, struct cdecl_declarator *d) { - size_t ret = 0, rc; - - 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); + if (d->child) + explain_declarators(dst, d->child); switch (d->type) { case CDECL_DECL_POINTER: - return ret + explain_pointer(buf, n, &d->u.pointer); + explain_pointer(dst, &d->u.pointer); + return; case CDECL_DECL_ARRAY: - return ret + explain_array(buf, n, &d->u.array); + explain_array(dst, &d->u.array); + return; case CDECL_DECL_FUNCTION: - return ret + explain_function(buf, n, &d->u.function); - default: - assert(0); + explain_function(dst, &d->u.function); + return; } } size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl) { - return explain_decl(buf, n, decl, true); + struct output_state dst = { buf, n }; + + if (cdecl_is_abstract(decl->declarators)) + cdecl__emit(&dst, "type "); + else + cdecl__emit(&dst, "declare "); + + explain_decl(&dst, decl); + return dst.accum; }