/* * Render C declarations. * Copyright © 2011, 2021, 2023 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 "cdecl.h" #include "cdecl-internal.h" static void declare_declarator(struct output_state *dst, struct cdecl_declarator *d); static void declare_decl(struct output_state *dst, struct cdecl *decl) { cdecl__emit_specs(dst, decl->specifiers, -1); if (decl->declarators->type != CDECL_DECL_NULL) cdecl__emit(dst, " "); declare_declarator(dst, decl->declarators); } static void declare_postfix_child(struct output_state *dst, struct cdecl_declarator *d) { if (d->type == CDECL_DECL_POINTER) cdecl__emit(dst, "("); declare_declarator(dst, d); if (d->type == CDECL_DECL_POINTER) cdecl__emit(dst, ")"); } static void declare_pointer(struct output_state *dst, struct cdecl_pointer *p) { struct cdecl_declspec *q = p->qualifiers; if (q) { cdecl__emit(dst, "* "); cdecl__emit_specs(dst, q, -1); cdecl__emit(dst, " "); } else { cdecl__emit(dst, "*"); } } static void declare_array(struct output_state *dst, struct cdecl_array *a) { cdecl__emit(dst, "["); if (a->vla) { const char *s = a->vla[0] ? a->vla : "*"; cdecl__emit(dst, s); } else { size_t rc = snprintf(dst->dst, dst->dstlen, "%.0" PRIuMAX, a->length); cdecl__advance(dst, rc); } cdecl__emit(dst, "]"); } static void declare_function(struct output_state *dst, struct cdecl_function *f) { struct cdecl *p; cdecl__emit(dst, "("); for (p = f->parameters; p; p = p->next) { declare_decl(dst, p); if (p->next) cdecl__emit(dst, ", "); else if (f->variadic) cdecl__emit(dst, ", ..."); } cdecl__emit(dst, ")"); } static void declare_declarator(struct output_state *dst, struct cdecl_declarator *d) { for (; d; d = d->child) { switch (d->type) { case CDECL_DECL_NULL: break; case CDECL_DECL_IDENT: cdecl__emit(dst, d->u.ident); break; case CDECL_DECL_POINTER: declare_pointer(dst, &d->u.pointer); break; /* * Arrays and functions are special: since they are postfix, * we need to render the children before rendering their * "bodies". */ case CDECL_DECL_ARRAY: declare_postfix_child(dst, d->child); declare_array(dst, &d->u.array); return; case CDECL_DECL_FUNCTION: declare_postfix_child(dst, d->child); declare_function(dst, &d->u.function); return; default: assert(0); } } } size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl) { struct output_state dst = { buf, n }; declare_decl(&dst, decl); return dst.accum; }