/* * Render C declarations. * 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 * 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 "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) { struct cdecl_declarator *d = decl->declarators; const char *sep; sep = cdecl__emit_specs(dst, decl->specifiers, -1); if (d->type != CDECL_DECL_NULL) cdecl__emit(dst, sep); declare_declarator(dst, d); } static void declare_postfix_child(struct output_state *dst, struct cdecl_declarator *d) { bool need_parens = (d->type == CDECL_DECL_POINTER); if (need_parens) cdecl__emit(dst, "("); declare_declarator(dst, d); if (need_parens) cdecl__emit(dst, ")"); } static void declare_pointer(struct output_state *dst, struct cdecl_declarator *d) { struct cdecl_declspec *q = d->u.pointer.qualifiers; if (q) { const char *sep; cdecl__emit(dst, "* "); sep = cdecl__emit_specs(dst, q, -1); if (d->child->type != CDECL_DECL_NULL) cdecl__emit(dst, sep); } 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 { cdecl__emit_uint(dst, a->length); } 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); 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; } } } 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; }