/* * Render C declarations as English. * Copyright © 2011 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 * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * 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 "cdecl.h" #include "output.h" /* * Renders the start of the thing being declared. If top is true, print * the "declare" or "type" keywords at the front, as appropriate. */ static size_t explain_prologue(char *buf, size_t n, struct cdecl_declarator *d, bool top) { 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); } d = d->child; } assert(0); } static size_t explain_pointer(char *buf, size_t n, 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"); } static size_t explain_array(char *buf, size_t n, 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); 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); } return ret + snprintf(buf, n, "of"); } static size_t explain_declarators(char *buf, size_t n, struct cdecl_declarator *decl); static size_t explain_decl(char *buf, size_t n, struct cdecl *decl, bool top) { 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); } static size_t explain_function(char *buf, size_t n, struct cdecl_function *f) { size_t ret = 0, rc = 0; rc = snprintf(buf, n, "function"); ret += cdecl__advance(&buf, &n, rc); if (f->parameters) { rc = snprintf(buf, n, "("); ret += cdecl__advance_(&buf, &n, rc); for (struct cdecl *p = f->parameters; p; p = p->next) { rc = explain_decl(buf, n, p, false); 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 + snprintf(buf, n, "returning"); } static size_t explain_declarators(char *buf, size_t n, 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); switch (d->type) { case CDECL_DECL_POINTER: return ret + explain_pointer(buf, n, &d->u.pointer); case CDECL_DECL_ARRAY: return ret + explain_array(buf, n, &d->u.array); case CDECL_DECL_FUNCTION: return ret + explain_function(buf, n, &d->u.function); default: assert(0); } } size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl) { return explain_decl(buf, n, decl, true); }