2 * Render C declarations as English.
3 * Copyright © 2011 Nick Bowler
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 static size_t advance_(char **buf, size_t *n, size_t amount)
40 static size_t advance(char **buf, size_t *n, size_t amount)
47 ret = advance_(buf, n, amount);
48 rc = snprintf(*buf, *n, " ");
49 return ret + advance_(buf, n, rc);
53 explain_qualifiers(char *buf, size_t n, struct cdecl_declspec *s)
55 unsigned long qualmap = 0;
56 size_t ret = 0, rc = 0;
58 for (struct cdecl_declspec *c = s; c; c = c->next) {
59 if (cdecl_spec_kind(c) != CDECL_SPEC_QUAL)
61 qualmap |= 1ul << (c->type & 0xff);
64 if (qualmap & (1ul << (CDECL_QUAL_RESTRICT & 0xff))) {
65 ret += advance(&buf, &n, rc);
66 rc = snprintf(buf, n, "restrict");
68 if (qualmap & (1ul << (CDECL_QUAL_VOLATILE & 0xff))) {
69 ret += advance(&buf, &n, rc);
70 rc = snprintf(buf, n, "volatile");
72 if (qualmap & (1ul << (CDECL_QUAL_CONST & 0xff))) {
73 ret += advance(&buf, &n, rc);
74 rc = snprintf(buf, n, "const");
80 /* Renders the type qualifiers and type specifiers in canonical form. */
82 explain_post_specs(char *buf, size_t n, struct cdecl_declspec *s)
84 const char *tag = NULL;
85 unsigned long typemap;
88 typemap = cdecl__build_typemap(s);
92 for (struct cdecl_declspec *c = s; c; c = c->next) {
93 if (cdecl_spec_kind(c) != CDECL_SPEC_TYPE)
96 /* Valid C types have at most one identifier. */
101 rc = explain_qualifiers(buf, n, s);
102 ret += advance(&buf, &n, rc);
104 rc = snprintf(buf, n, "%s", cdecl__explain_typemap(typemap));
106 ret += advance(&buf, &n, rc);
107 rc = snprintf(buf, n, "%s", tag);
113 static size_t explain_storage(char *buf, size_t n, unsigned spec)
116 case CDECL_STOR_TYPEDEF:
117 return snprintf(buf, n, "typedef");
118 case CDECL_STOR_EXTERN:
119 return snprintf(buf, n, "extern");
120 case CDECL_STOR_STATIC:
121 return snprintf(buf, n, "static");
122 case CDECL_STOR_AUTO:
123 return snprintf(buf, n, "auto");
124 case CDECL_STOR_REGISTER:
125 return snprintf(buf, n, "register");
131 /* Renders the storage-class and function specifiers in canonical form. */
132 static size_t explain_pre_specs(char *buf, size_t n, struct cdecl_declspec *s)
134 unsigned long funcmap = 0;
135 size_t ret = 0, rc = 0;
137 for (struct cdecl_declspec *c = s; c; c = c->next) {
138 switch (cdecl_spec_kind(c)) {
139 case CDECL_SPEC_FUNC:
140 funcmap |= 1ul << (c->type & 0xff);
142 case CDECL_SPEC_STOR:
143 /* Valid C declarations have at most one
144 * storage-class specifier. */
145 rc = explain_storage(buf, n, c->type);
150 if (funcmap & (1ul << (CDECL_FUNC_INLINE & 0xff))) {
151 ret += advance(&buf, &n, rc);
152 rc = snprintf(buf, n, "inline");
159 * Renders the start of the thing being declared. If top is true, print
160 * the "declare" or "type" keywords at the front, as appropriate.
163 explain_prologue(char *buf, size_t n, struct cdecl_declarator *d, bool top)
165 size_t ret = 0, rc = 0;
169 case CDECL_DECL_NULL:
171 return snprintf(buf, n, "type");
173 case CDECL_DECL_IDENT:
175 rc = snprintf(buf, n, "declare");
176 ret += advance(&buf, &n, rc);
177 return ret + snprintf(buf, n, "%s as", d->u.ident);
185 explain_pointer(char *buf, size_t n, struct cdecl_pointer *p)
189 rc = explain_qualifiers(buf, n, p->qualifiers);
190 ret += advance(&buf, &n, rc);
192 return ret + snprintf(buf, n, "pointer to");
196 explain_array(char *buf, size_t n, struct cdecl_array *a)
198 size_t ret = 0, rc = 0;
201 rc = snprintf(buf, n, "variable-length array");
203 rc = snprintf(buf, n, "array");
204 ret += advance(&buf, &n, rc);
207 rc = snprintf(buf, n, "%s", a->vla);
208 ret += advance(&buf, &n, rc);
209 } else if (a->length) {
210 rc = snprintf(buf, n, "%ju", a->length);
211 ret += advance(&buf, &n, rc);
214 return ret + snprintf(buf, n, "of");
218 explain_declarators(char *buf, size_t n, struct cdecl_declarator *decl);
220 static size_t explain_decl(char *buf, size_t n, struct cdecl *decl, bool top)
224 rc = explain_prologue(buf, n, decl->declarators, top);
225 ret += advance(&buf, &n, rc);
227 rc = explain_pre_specs(buf, n, decl->specifiers);
228 ret += advance(&buf, &n, rc);
230 rc = explain_declarators(buf, n, decl->declarators);
231 ret += advance(&buf, &n, rc);
233 return ret + explain_post_specs(buf, n, decl->specifiers);
236 static size_t explain_function(char *buf, size_t n, struct cdecl_function *f)
238 size_t ret = 0, rc = 0;
240 rc = snprintf(buf, n, "function");
241 ret += advance(&buf, &n, rc);
244 rc = snprintf(buf, n, "(");
245 ret += advance_(&buf, &n, rc);
247 for (struct cdecl *p = f->parameters; p; p = p->next) {
248 rc = explain_decl(buf, n, p, false);
249 ret += advance_(&buf, &n, rc);
252 rc = snprintf(buf, n, ",");
253 else if (f->variadic)
254 rc = snprintf(buf, n, ", ...)");
256 rc = snprintf(buf, n, ")");
257 ret += advance(&buf, &n, rc);
261 return ret + snprintf(buf, n, "returning");
265 explain_declarators(char *buf, size_t n, struct cdecl_declarator *d)
269 if (d->type == CDECL_DECL_IDENT || d->type == CDECL_DECL_NULL)
272 rc = explain_declarators(buf, n, d->child);
273 ret += advance(&buf, &n, rc);
276 case CDECL_DECL_POINTER:
277 return ret + explain_pointer(buf, n, &d->u.pointer);
278 case CDECL_DECL_ARRAY:
279 return ret + explain_array(buf, n, &d->u.array);
280 case CDECL_DECL_FUNCTION:
281 return ret + explain_function(buf, n, &d->u.function);
287 size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl)
289 return explain_decl(buf, n, decl, true);