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 * Return a newly-allocated null declarator. The child member is set by the
34 * argument; other members are initialized to zero.
36 struct cdecl_declarator *new_declarator(struct cdecl_declarator *child)
38 struct cdecl_declarator *d, init = { child, CDECL_DECL_NULL };
40 d = malloc_nofail(sizeof *d);
47 * Return a newly-allocated void specifier. The next member is set by the
48 * argument; other members are initialized to zero.
50 struct cdecl_declspec *new_specifier(struct cdecl_declspec *next)
52 struct cdecl_declspec *d, init = { next, CDECL_TYPE_VOID };
54 d = malloc_nofail(sizeof *d);
61 * Return a newly-allocated declaration. The next member is set by the
62 * argument; other members are initialized to zero.
64 struct cdecl *new_cdecl(struct cdecl *next)
66 struct cdecl *d, init = { next };
68 d = malloc_nofail(sizeof *d);
75 * Generate a random identifier. We arbitrarily pick 10 as the largest
76 * possible. Avoid generating keywords, including the English ones, by
77 * excluding the letters t, o, a and n. Reserved words are OK.
79 char *gen_identifier(struct test_rng *rng)
81 static const char valid[59] = "_bcdefghijklmpqrsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
85 n = test_rng_uniform_int(rng, 10)+1;
86 str = malloc_nofail(n+1);
88 /* Exclude 10 digits from the first character. */
89 str[0] = valid[test_rng_uniform_int(rng, sizeof valid - 10)];
90 for (size_t i = 1; i < n; i++)
91 str[i] = valid[test_rng_uniform_int(rng, sizeof valid)];
98 * Generate random qualifiers. Qualifiers can appear multiple times, so the
99 * list is (potentially) unbounded. We handle the potential unboundedness by
100 * generating a list of n qualifiers with probability 1/2^(n+1). Each
101 * qualifier is chosen uniformly at random from the set of possibilities:
102 * const, volatile and, if restrictqual is true, restrict.
104 struct cdecl_declspec *gen_qualifiers(struct test_rng *rng, bool restrictqual)
106 struct cdecl_declspec *s = NULL;
108 while (test_rng_uniform(rng) < 0.5) {
109 s = new_specifier(s);
111 switch (test_rng_uniform_int(rng, 2+restrictqual)) {
113 s->type = CDECL_QUAL_CONST;
116 s->type = CDECL_QUAL_VOLATILE;
118 case 2: /* Only if restrictqual is true. */
119 s->type = CDECL_QUAL_RESTRICT;
130 * Generate random function specifiers. Like qualifiers, function specifiers
131 * can appear multiple times.
133 struct cdecl_declspec *gen_funcspecs(struct test_rng *rng)
135 struct cdecl_declspec *s = NULL;
137 while (test_rng_uniform(rng) < 0.5) {
138 s = new_specifier(s);
139 s->type = CDECL_FUNC_INLINE;
146 * Generate zero or one random storage-class specifier. If registeronly is
147 * true, then the only possible storage-class specifier is "register".
148 * Otherwise, a specifier type will be selected uniformly at random.
150 struct cdecl_declspec *gen_storspecs(struct test_rng *rng, bool registeronly)
152 struct cdecl_declspec *s;
154 if (test_rng_uniform(rng) < 0.5)
157 s = new_specifier(NULL);
158 switch (test_rng_uniform_int(rng, registeronly ? 1 : 5)) {
159 case 0: s->type = CDECL_STOR_REGISTER; break;
160 case 1: s->type = CDECL_STOR_TYPEDEF; break;
161 case 2: s->type = CDECL_STOR_STATIC; break;
162 case 3: s->type = CDECL_STOR_AUTO; break;
163 case 4: s->type = CDECL_STOR_EXTERN; break;
171 * Generate random type specifiers. There is a short list of valid
172 * combinations, from which we can select one uniformly at random.
176 struct cdecl_declspec *gen_typespecs(struct test_rng *rng, bool voidtype)
178 struct cdecl_declspec *specs;
181 specs = gen_raw_typespecs(test_rng_uniform_int(rng, GEN_TOTAL_TYPES));
183 switch (specs->type) {
184 /* void is not always valid, so we might need to pick again. */
185 case CDECL_TYPE_VOID:
189 /* A few kinds of type specifiers need identifiers to go with them. */
190 case CDECL_TYPE_STRUCT:
191 case CDECL_TYPE_UNION:
192 case CDECL_TYPE_ENUM:
193 case CDECL_TYPE_IDENT:
194 assert(!specs->next);
195 specs->ident = gen_identifier(rng);
198 /* Nothing to be done. */
205 struct cdecl_declspec *
206 gen_randomize_specs(struct test_rng *rng, struct cdecl_declspec *specs)
208 struct cdecl_declspec **p;
214 for (struct cdecl_declspec *s = specs; s; s = s->next)
217 p = malloc_nofail((n+1) * sizeof *p);
219 /* Build a temporary array for easy element swapping. */
222 for (size_t i = 1; i < n; i++)
226 for (size_t i = 0; i < n; i++) {
227 struct cdecl_declspec *tmp;
230 r = test_rng_uniform_int(rng, n-i);
236 /* Fix up the pointers. */
237 for (size_t i = 1; i <= n; i++)
246 * Generate random declaration specifiers. This consists of random qualifiers
247 * and type specifiers, as described in the functions above, plus up to one
248 * storage-class specifier and zero or more function specifiers.
250 * The flags parameter controls what sort of specifiers can be generated in
251 * order to handle various special cases in the C language. It is the
252 * bitwise-or of zero or more values, which have the following meanings:
254 * GEN_NO_FUNCTION: Do not generate any function specifiers at all.
255 * GEN_NO_STORAGE: Do not generate any storage-class specifiers at all.
256 * GEN_NO_VOID: Do not generate the "void" type specifier.
257 * GEN_ONLY_REGISTER: Never generate any storage-class specifiers other than
260 * Notwithstanding any of the above, the "restrict" type qualifier will never
261 * be generated by this function: use gen_qualifiers directly.
263 struct cdecl_declspec *
264 gen_declspecs(struct test_rng *rng, unsigned flags)
266 struct cdecl_declspec *s, *p;
268 s = gen_typespecs(rng, ~flags & GEN_NO_VOID);
269 for (p = s; p->next;)
272 if (~flags & GEN_NO_FUNCTION)
273 p->next = gen_funcspecs(rng);
274 for (p = s; p->next;)
277 if (~flags & GEN_NO_STORAGE)
278 p->next = gen_storspecs(rng, flags & GEN_ONLY_REGISTER);
279 for (p = s; p->next;)
282 p->next = gen_qualifiers(rng, false);
283 return gen_randomize_specs(rng, s);
286 static uintmax_t gen_uintmax(struct test_rng *rng)
291 for (size_t i = 0; i < sizeof ret; i++) {
292 tmp = test_rng_uniform_int(rng, UCHAR_MAX+1);
301 * Generate a random array declarator, selecting one of four possibilities
302 * uniformly at random.
304 static void gen_array(struct test_rng *rng, struct cdecl_declarator *d)
306 struct cdecl_array tmp = {0};
308 switch (test_rng_uniform_int(rng, 4)) {
310 tmp.vla = malloc_nofail(1);
314 tmp.vla = gen_identifier(rng);
317 tmp.length = gen_uintmax(rng);
324 d->type = CDECL_DECL_ARRAY;
328 /* Generate a function declarator. */
329 static void gen_function(struct test_rng *rng, struct cdecl_declarator *d)
331 d->type = CDECL_DECL_FUNCTION;
332 d->u.function.parameters = NULL;
334 while (test_rng_uniform(rng) < 0.5) {
335 unsigned flags = GEN_ONLY_REGISTER | GEN_NO_FUNCTION;
338 param = new_cdecl(d->u.function.parameters);
339 param->declarators = gen_declarators(rng);
341 if (param->declarators->type != CDECL_DECL_POINTER
342 && param->declarators->type != CDECL_DECL_FUNCTION)
343 flags |= GEN_NO_VOID;
345 param->specifiers = gen_declspecs(rng, flags);
346 d->u.function.parameters = param;
349 if (d->u.function.parameters) {
350 d->u.function.variadic = test_rng_uniform(rng) < 0.5;
351 } else if (test_rng_uniform(rng) < 0.5) {
354 /* We will never generate (void) above; do it here. */
355 param = new_cdecl(NULL);
356 param->declarators = new_declarator(NULL);
357 param->specifiers = new_specifier(NULL);
359 d->u.function.parameters = param;
364 * Generate a random chain of declarators. Like qualifiers above, a chain of
365 * length N has probability 1/2^(N+1) of occurring. All declarator chains
366 * are ultimately terminated by either a null declarator or an identifier,
367 * selected uniformly at random.
369 struct cdecl_declarator *gen_declarators(struct test_rng *rng)
371 struct cdecl_declarator *d, *p;
374 d = new_declarator(NULL);
375 if (test_rng_uniform(rng) < 0.5) {
376 d->type = CDECL_DECL_IDENT;
377 d->u.ident = gen_identifier(rng);
380 while (test_rng_uniform(rng) < 0.5) {
381 d = new_declarator((p = d));
383 switch (test_rng_uniform_int(rng, limit)) {
385 d->type = CDECL_DECL_POINTER;
386 d->u.pointer.qualifiers = gen_qualifiers(rng, true);
394 gen_function(rng, d);
395 if (p && p->type == CDECL_DECL_POINTER) {
396 struct cdecl_pointer *ptr = &p->u.pointer;
398 gen_free_declspecs(ptr->qualifiers);
399 ptr->qualifiers = gen_qualifiers(rng, false);
411 static void gen_free_parameters(struct cdecl *x)
418 gen_free_declspecs(x->specifiers);
419 gen_free_declarators(x->declarators);
426 void gen_free_declspecs(struct cdecl_declspec *x)
428 struct cdecl_declspec *p;
438 void gen_free_declarators(struct cdecl_declarator *x)
440 struct cdecl_declarator *p;
446 case CDECL_DECL_NULL:
448 case CDECL_DECL_IDENT:
451 case CDECL_DECL_POINTER:
452 gen_free_declspecs(x->u.pointer.qualifiers);
454 case CDECL_DECL_ARRAY:
455 free(x->u.array.vla);
457 case CDECL_DECL_FUNCTION:
458 gen_free_parameters(x->u.function.parameters);