2 * Generate random C declarations for testing.
3 * Copyright © 2012, 2021-2022 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/>.
33 * Generate a random identifier. We arbitrarily pick 10 as the largest
34 * possible. Avoid generating keywords, including the English ones, by
35 * excluding the letters t, o, a and n. Reserved words are OK.
37 char *gen_identifier(struct test_rng *rng)
39 static const char valid[59] = "_bcdefghijklmpqrsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
43 n = test_rng_uniform_int(rng, 10)+1;
44 str = malloc_nofail(n+1);
46 /* Exclude 10 digits from the first character. */
47 str[0] = valid[test_rng_uniform_int(rng, sizeof valid - 10)];
48 for (size_t i = 1; i < n; i++)
49 str[i] = valid[test_rng_uniform_int(rng, sizeof valid)];
56 * Generate random qualifiers. Qualifiers can appear multiple times, so the
57 * list is (potentially) unbounded. We handle the potential unboundedness by
58 * generating a list of n qualifiers with probability 1/2^(n+1). Each
59 * qualifier is chosen uniformly at random from the set of possibilities:
60 * const, volatile and, if restrictqual is true, restrict.
62 struct cdecl_declspec *gen_qualifiers(struct test_rng *rng, bool restrictqual)
64 struct cdecl_declspec *s = NULL, *p;
66 while (test_rng_uniform(rng) < 0.5) {
68 s = malloc_nofail(sizeof *s);
69 *s = (struct cdecl_declspec) {
73 switch (test_rng_uniform_int(rng, 2+restrictqual)) {
75 s->type = CDECL_QUAL_CONST;
78 s->type = CDECL_QUAL_VOLATILE;
80 case 2: /* Only if restrictqual is true. */
81 s->type = CDECL_QUAL_RESTRICT;
92 * Generate random function specifiers. Like qualifiers, function specifiers
93 * can appear multiple times.
95 struct cdecl_declspec *gen_funcspecs(struct test_rng *rng)
97 struct cdecl_declspec *s = NULL, *p;
99 while (test_rng_uniform(rng) < 0.5) {
101 s = malloc_nofail(sizeof *s);
103 *s = (struct cdecl_declspec) {
104 .type = CDECL_FUNC_INLINE,
113 * Generate zero or one random storage-class specifier. If registeronly is
114 * true, then the only possible storage-class specifier is "register".
115 * Otherwise, a specifier type will be selected uniformly at random.
117 struct cdecl_declspec *gen_storspecs(struct test_rng *rng, bool registeronly)
119 struct cdecl_declspec *s;
121 if (test_rng_uniform(rng) < 0.5)
124 s = malloc_nofail(sizeof *s);
125 *s = (struct cdecl_declspec) {
126 .type = CDECL_STOR_REGISTER,
132 switch (test_rng_uniform_int(rng, 5)) {
133 case 0: s->type = CDECL_STOR_TYPEDEF; break;
134 case 1: s->type = CDECL_STOR_REGISTER; break;
135 case 2: s->type = CDECL_STOR_STATIC; break;
136 case 3: s->type = CDECL_STOR_AUTO; break;
137 case 4: s->type = CDECL_STOR_EXTERN; break;
145 * Generate random type specifiers. There is a short list of valid
146 * combinations, from which we can select one uniformly at random.
150 struct cdecl_declspec *gen_typespecs(struct test_rng *rng, bool voidtype)
152 struct cdecl_declspec *specs;
155 specs = gen_raw_typespecs(test_rng_uniform_int(rng, GEN_TOTAL_TYPES));
157 switch (specs->type) {
158 /* void is not always valid, so we might need to pick again. */
159 case CDECL_TYPE_VOID:
163 /* A few kinds of type specifiers need identifiers to go with them. */
164 case CDECL_TYPE_STRUCT:
165 case CDECL_TYPE_UNION:
166 case CDECL_TYPE_ENUM:
167 case CDECL_TYPE_IDENT:
168 assert(!specs->next);
169 specs->ident = gen_identifier(rng);
172 /* Nothing to be done. */
179 struct cdecl_declspec *
180 gen_randomize_specs(struct test_rng *rng, struct cdecl_declspec *specs)
182 struct cdecl_declspec **p;
188 for (struct cdecl_declspec *s = specs; s; s = s->next)
191 p = malloc_nofail((n+1) * sizeof *p);
193 /* Build a temporary array for easy element swapping. */
196 for (size_t i = 1; i < n; i++)
200 for (size_t i = 0; i < n; i++) {
201 struct cdecl_declspec *tmp;
204 r = test_rng_uniform_int(rng, n-i);
210 /* Fix up the pointers. */
211 for (size_t i = 1; i <= n; i++)
220 * Generate random declaration specifiers. This consists of random qualifiers
221 * and type specifiers, as described in the functions above, plus up to one
222 * storage-class specifier and zero or more function specifiers.
224 * The flags parameter controls what sort of specifiers can be generated in
225 * order to handle various special cases in the C language. It is the
226 * bitwise-or of zero or more values, which have the following meanings:
228 * GEN_NO_FUNCTION: Do not generate any function specifiers at all.
229 * GEN_NO_STORAGE: Do not generate any storage-class specifiers at all.
230 * GEN_NO_VOID: Do not generate the "void" type specifier.
231 * GEN_ONLY_REGISTER: Never generate any storage-class specifiers other than
234 * Notwithstanding any of the above, the "restrict" type qualifier will never
235 * be generated by this function: use gen_qualifiers directly.
237 struct cdecl_declspec *
238 gen_declspecs(struct test_rng *rng, unsigned flags)
240 struct cdecl_declspec *s, *p;
242 s = gen_typespecs(rng, ~flags & GEN_NO_VOID);
243 for (p = s; p->next;)
246 if (~flags & GEN_NO_FUNCTION)
247 p->next = gen_funcspecs(rng);
248 for (p = s; p->next;)
251 if (~flags & GEN_NO_STORAGE)
252 p->next = gen_storspecs(rng, flags & GEN_ONLY_REGISTER);
253 for (p = s; p->next;)
256 p->next = gen_qualifiers(rng, false);
257 return gen_randomize_specs(rng, s);
260 static uintmax_t gen_uintmax(struct test_rng *rng)
265 for (size_t i = 0; i < sizeof ret; i++) {
266 tmp = test_rng_uniform_int(rng, UCHAR_MAX+1);
275 * Generate a random array declarator, selecting one of four possibilities
276 * uniformly at random.
278 static void gen_array(struct test_rng *rng, struct cdecl_declarator *d)
280 d->type = CDECL_DECL_ARRAY;
281 d->u.array = (struct cdecl_array){0};
283 switch (test_rng_uniform_int(rng, 4)) {
285 d->u.array.vla = malloc_nofail(1);
286 d->u.array.vla[0] = 0;
289 d->u.array.vla = gen_identifier(rng);
292 d->u.array.length = 0;
295 d->u.array.length = gen_uintmax(rng);
302 /* Generate a function declarator. */
303 static void gen_function(struct test_rng *rng, struct cdecl_declarator *d)
305 d->type = CDECL_DECL_FUNCTION;
306 d->u.function.parameters = NULL;
308 while (test_rng_uniform(rng) < 0.5) {
309 unsigned flags = GEN_ONLY_REGISTER | GEN_NO_FUNCTION;
312 param = malloc_nofail(sizeof *param);
313 *param = (struct cdecl) {
314 .next = d->u.function.parameters,
315 .declarators = gen_declarators(rng),
318 if (param->declarators->type != CDECL_DECL_POINTER
319 && param->declarators->type != CDECL_DECL_FUNCTION)
320 flags |= GEN_NO_VOID;
322 param->specifiers = gen_declspecs(rng, flags);
323 d->u.function.parameters = param;
326 if (d->u.function.parameters) {
327 d->u.function.variadic = test_rng_uniform(rng) < 0.5;
328 } else if (test_rng_uniform(rng) < 0.5) {
331 /* We will never generate (void) above; do it here. */
332 param = malloc_nofail(sizeof *param);
333 *param = (struct cdecl) { 0 };
335 param->declarators = malloc_nofail(sizeof *param->declarators);
336 *param->declarators = (struct cdecl_declarator) {
337 .type = CDECL_DECL_NULL,
340 param->specifiers = malloc_nofail(sizeof *param->specifiers);
341 *param->specifiers = (struct cdecl_declspec) {
342 .type = CDECL_TYPE_VOID,
345 d->u.function.parameters = param;
350 * Generate a random chain of declarators. Like qualifiers above, a chain of
351 * length N has probability 1/2^(N+1) of occurring. All declarator chains
352 * are ultimately terminated by either a null declarator or an identifier,
353 * selected uniformly at random.
355 struct cdecl_declarator *gen_declarators(struct test_rng *rng)
357 struct cdecl_declarator *d, *p;
360 d = malloc_nofail(sizeof *d);
361 if (test_rng_uniform(rng) < 0.5) {
362 *d = (struct cdecl_declarator) {
363 .type = CDECL_DECL_NULL,
366 *d = (struct cdecl_declarator) {
367 .type = CDECL_DECL_IDENT,
368 .u.ident = gen_identifier(rng),
372 while (test_rng_uniform(rng) < 0.5) {
374 d = malloc_nofail(sizeof *d);
375 *d = (struct cdecl_declarator) {
379 switch (test_rng_uniform_int(rng, limit)) {
381 d->type = CDECL_DECL_POINTER;
382 d->u.pointer = (struct cdecl_pointer) {
383 .qualifiers = gen_qualifiers(rng, true),
392 gen_function(rng, d);
393 if (p && p->type == CDECL_DECL_POINTER) {
394 struct cdecl_pointer *ptr = &p->u.pointer;
396 gen_free_declspecs(ptr->qualifiers);
397 ptr->qualifiers = gen_qualifiers(rng, false);
409 static void gen_free_parameters(struct cdecl *x)
416 gen_free_declspecs(x->specifiers);
417 gen_free_declarators(x->declarators);
424 void gen_free_declspecs(struct cdecl_declspec *x)
426 struct cdecl_declspec *p;
436 void gen_free_declarators(struct cdecl_declarator *x)
438 struct cdecl_declarator *p;
444 case CDECL_DECL_NULL:
446 case CDECL_DECL_IDENT:
449 case CDECL_DECL_POINTER:
450 gen_free_declspecs(x->u.pointer.qualifiers);
452 case CDECL_DECL_ARRAY:
453 free(x->u.array.vla);
455 case CDECL_DECL_FUNCTION:
456 gen_free_parameters(x->u.function.parameters);