]> git.draconx.ca Git - cdecl99.git/blob - t/declgen.c
4526c0ee69f0f86cc047c5066705600f91e5b07b
[cdecl99.git] / t / declgen.c
1 /*
2  *  Generate random C declarations for testing.
3  *  Copyright © 2012, 2021-2023 Nick Bowler
4  *
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.
9  *
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.
14  *
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/>.
17  */
18
19 #include <config.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <limits.h>
24 #include <errno.h>
25 #include <assert.h>
26 #include <stdbool.h>
27
28 #include "declgen.h"
29 #include "cdecl.h"
30 #include "test.h"
31
32 /*
33  * Return a newly-allocated null declarator.  The child member is set by the
34  * argument; other members are initialized to zero.
35  */
36 struct cdecl_declarator *new_declarator(struct cdecl_declarator *child)
37 {
38         struct cdecl_declarator *d, init = { child, CDECL_DECL_NULL };
39
40         d = malloc_nofail(sizeof *d);
41         *d = init;
42
43         return d;
44 }
45
46 /*
47  * Return a newly-allocated void specifier.  The next member is set by the
48  * argument; other members are initialized to zero.
49  */
50 struct cdecl_declspec *new_specifier(struct cdecl_declspec *next)
51 {
52         struct cdecl_declspec *d, init = { next, CDECL_TYPE_VOID };
53
54         d = malloc_nofail(sizeof *d);
55         *d = init;
56
57         return d;
58 }
59
60 /*
61  * Return a newly-allocated declaration.  The next member is set by the
62  * argument; other members are initialized to zero.
63  */
64 struct cdecl *new_cdecl(struct cdecl *next)
65 {
66         struct cdecl *d, init = { next };
67
68         d = malloc_nofail(sizeof *d);
69         *d = init;
70
71         return d;
72 }
73
74 /*
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.
78  */
79 char *gen_identifier(struct test_rng *rng)
80 {
81         static const char valid[59] = "_bcdefghijklmpqrsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
82         size_t i, n;
83         char *str;
84
85         n = test_rng_uniform_int(rng, 10)+1;
86         str = malloc_nofail(n+1);
87
88         /* Exclude 10 digits from the first character. */
89         str[0] = valid[test_rng_uniform_int(rng, sizeof valid - 10)];
90         for (i = 1; i < n; i++)
91                 str[i] = valid[test_rng_uniform_int(rng, sizeof valid)];
92         str[n] = 0;
93
94         return str;
95 }
96
97 /*
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.
103  */
104 struct cdecl_declspec *gen_qualifiers(struct test_rng *rng, bool restrictqual)
105 {
106         struct cdecl_declspec *s = NULL;
107
108         while (test_rng_50_50(rng)) {
109                 s = new_specifier(s);
110
111                 switch (test_rng_uniform_int(rng, 2+restrictqual)) {
112                 case 0:
113                         s->type = CDECL_QUAL_CONST;
114                         break;
115                 case 1:
116                         s->type = CDECL_QUAL_VOLATILE;
117                         break;
118                 case 2: /* Only if restrictqual is true. */
119                         s->type = CDECL_QUAL_RESTRICT;
120                         break;
121                 default:
122                         assert(0);
123                 }
124         }
125
126         return s;
127 }
128
129 /*
130  * Generate random function specifiers.  Like qualifiers, function specifiers
131  * can appear multiple times.
132  */
133 struct cdecl_declspec *gen_funcspecs(struct test_rng *rng)
134 {
135         struct cdecl_declspec *s = NULL;
136
137         while (test_rng_50_50(rng)) {
138                 s = new_specifier(s);
139                 s->type = CDECL_FUNC_INLINE;
140         }
141
142         return s;
143 }
144
145 /*
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.
149  */
150 struct cdecl_declspec *gen_storspecs(struct test_rng *rng, bool registeronly)
151 {
152         struct cdecl_declspec *s;
153
154         if (test_rng_50_50(rng))
155                 return NULL;
156
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;
164         default: assert(0);
165         }
166
167         return s;
168 }
169
170 /*
171  * Generate random type specifiers.  There is a short list of valid
172  * combinations, from which we can select one uniformly at random.
173  */
174 #include "typegen.h"
175
176 struct cdecl_declspec *gen_typespecs(struct test_rng *rng, bool voidtype)
177 {
178         struct cdecl_declspec *specs;
179
180 retry:
181         specs = gen_raw_typespecs(test_rng_uniform_int(rng, GEN_TOTAL_TYPES));
182
183         switch (specs->type) {
184         /* void is not always valid, so we might need to pick again. */
185         case CDECL_TYPE_VOID:
186                 if (!voidtype) {
187                         assert(!specs->next);
188                         free(specs);
189                         goto retry;
190                 }
191                 break;
192         /* A few kinds of type specifiers need identifiers to go with them. */
193         case CDECL_TYPE_STRUCT:
194         case CDECL_TYPE_UNION:
195         case CDECL_TYPE_ENUM:
196         case CDECL_TYPE_IDENT:
197                 assert(!specs->next);
198                 specs->ident = gen_identifier(rng);
199                 break;
200         default:
201                 /* Nothing to be done. */
202                 ;
203         }
204
205         return specs;
206 }
207
208 struct cdecl_declspec *
209 gen_randomize_specs(struct test_rng *rng, struct cdecl_declspec *specs)
210 {
211         struct cdecl_declspec *s, **p;
212         size_t i, n = 0;
213
214         if (!specs)
215                 return specs;
216
217         for (s = specs; s; s = s->next)
218                 n++;
219
220         p = malloc_nofail((n+1) * sizeof *p);
221
222         /* Build a temporary array for easy element swapping. */
223         p[0] = specs;
224         p[n] = NULL;
225         for (i = 1; i < n; i++)
226                 p[i] = p[i-1]->next;
227
228         /* Knuth shuffle. */
229         for (i = 0; i < n; i++) {
230                 struct cdecl_declspec *tmp;
231                 size_t r;
232                 
233                 r = test_rng_uniform_int(rng, n-i);
234                 tmp = p[i];
235                 p[i] = p[r+i];
236                 p[r+i] = tmp;
237         }
238
239         /* Fix up the pointers. */
240         for (i = 1; i <= n; i++)
241                 p[i-1]->next = p[i];
242         specs = p[0];
243
244         free(p);
245         return specs;
246 }
247
248 /*
249  * Generate random declaration specifiers.  This consists of random qualifiers
250  * and type specifiers, as described in the functions above, plus up to one
251  * storage-class specifier and zero or more function specifiers.
252  *
253  * The flags parameter controls what sort of specifiers can be generated in
254  * order to handle various special cases in the C language.  It is the
255  * bitwise-or of zero or more values, which have the following meanings:
256  * 
257  *   GEN_NO_FUNCTION: Do not generate any function specifiers at all.
258  *   GEN_NO_STORAGE: Do not generate any storage-class specifiers at all.
259  *   GEN_NO_VOID: Do not generate the "void" type specifier.
260  *   GEN_ONLY_REGISTER: Never generate any storage-class specifiers other than
261  *                      "register".
262  *
263  * Notwithstanding any of the above, the "restrict" type qualifier will never
264  * be generated by this function: use gen_qualifiers directly.
265  */
266 struct cdecl_declspec *
267 gen_declspecs(struct test_rng *rng, unsigned flags)
268 {
269         struct cdecl_declspec *s, *p;
270
271         s = gen_typespecs(rng, ~flags & GEN_NO_VOID);
272         for (p = s; p->next;)
273                 p = p->next;
274
275         if (~flags & GEN_NO_FUNCTION)
276                 p->next = gen_funcspecs(rng);
277         for (p = s; p->next;)
278                 p = p->next;
279
280         if (~flags & GEN_NO_STORAGE)
281                 p->next = gen_storspecs(rng, flags & GEN_ONLY_REGISTER);
282         for (p = s; p->next;)
283                 p = p->next;
284
285         p->next = gen_qualifiers(rng, false);
286         return gen_randomize_specs(rng, s);
287 }
288
289 static uintmax_t gen_uintmax(struct test_rng *rng)
290 {
291         unsigned char tmp;
292         uintmax_t ret = 0;
293         size_t i;
294
295         for (i = 0; i < sizeof ret; i++) {
296                 tmp = test_rng_uniform_int(rng, UCHAR_MAX+1);
297                 ret <<= CHAR_BIT;
298                 ret |= tmp;
299         }
300
301         return ret;
302 }
303
304 /*
305  * Generate a random array declarator, selecting one of four possibilities
306  * uniformly at random.
307  */
308 static void gen_array(struct test_rng *rng, struct cdecl_declarator *d)
309 {
310         struct cdecl_array tmp = {0};
311
312         switch (test_rng_uniform_int(rng, 4)) {
313         case 0:
314                 tmp.vla = malloc_nofail(1);
315                 tmp.vla[0] = 0;
316                 break;
317         case 1:
318                 tmp.vla = gen_identifier(rng);
319                 break;
320         case 2:
321                 tmp.length = gen_uintmax(rng);
322         case 3:
323                 break;
324         default:
325                 assert(0);
326         }
327
328         d->type = CDECL_DECL_ARRAY;
329         d->u.array = tmp;
330 }
331
332 /* Generate a function declarator. */
333 static void gen_function(struct test_rng *rng, struct cdecl_declarator *d)
334 {
335         d->type = CDECL_DECL_FUNCTION;
336         d->u.function.parameters = NULL;
337
338         while (test_rng_50_50(rng)) {
339                 unsigned flags = GEN_ONLY_REGISTER | GEN_NO_FUNCTION;
340                 struct cdecl *param;
341
342                 param = new_cdecl(d->u.function.parameters);
343                 param->declarators = gen_declarators(rng);
344
345                 if (param->declarators->type != CDECL_DECL_POINTER
346                     && param->declarators->type != CDECL_DECL_FUNCTION)
347                         flags |= GEN_NO_VOID;
348
349                 param->specifiers = gen_declspecs(rng, flags);
350                 d->u.function.parameters = param;
351         }
352
353         if (d->u.function.parameters) {
354                 d->u.function.variadic = test_rng_50_50(rng);
355         } else if (test_rng_50_50(rng)) {
356                 struct cdecl *param;
357
358                 /* We will never generate (void) above; do it here. */
359                 param = new_cdecl(NULL);
360                 param->declarators = new_declarator(NULL);
361                 param->specifiers = new_specifier(NULL);
362
363                 d->u.function.parameters = param;
364         }
365 }
366
367 /*
368  * Generate a random chain of declarators.  Like qualifiers above, a chain of
369  * length N has probability 1/2^(N+1) of occurring.  All declarator chains
370  * are ultimately terminated by either a null declarator or an identifier,
371  * selected uniformly at random.
372  */
373 struct cdecl_declarator *gen_declarators(struct test_rng *rng)
374 {
375         struct cdecl_declarator *d, *p;
376         unsigned limit = 3;
377
378         d = new_declarator(NULL);
379         if (test_rng_50_50(rng)) {
380                 d->type = CDECL_DECL_IDENT;
381                 d->u.ident = gen_identifier(rng);
382         }
383
384         while (test_rng_50_50(rng)) {
385                 d = new_declarator((p = d));
386
387                 switch (test_rng_uniform_int(rng, limit)) {
388                 case 0:
389                         d->type = CDECL_DECL_POINTER;
390                         d->u.pointer.qualifiers = gen_qualifiers(rng, true);
391                         limit = 3;
392                         break;
393                 case 1:
394                         gen_array(rng, d);
395                         limit = 2;
396                         break;
397                 case 2:
398                         gen_function(rng, d);
399                         if (p && p->type == CDECL_DECL_POINTER) {
400                                 struct cdecl_pointer *ptr = &p->u.pointer;
401
402                                 gen_free_declspecs(ptr->qualifiers);
403                                 ptr->qualifiers = gen_qualifiers(rng, false);
404                         }
405                         limit = 1;
406                         break;
407                 default:
408                         assert(0);
409                 }
410         }
411
412         return d;
413 }
414
415 static void gen_free_parameters(struct cdecl *x)
416 {
417         struct cdecl *p;
418
419         while (x) {
420                 p = x->next;
421
422                 gen_free_declspecs(x->specifiers);
423                 gen_free_declarators(x->declarators);
424                 free(x);
425
426                 x = p;
427         }
428 }
429
430 void gen_free_declspecs(struct cdecl_declspec *x)
431 {
432         struct cdecl_declspec *p;
433
434         while (x) {
435                 p = x->next;
436                 free(x->ident);
437                 free(x);
438                 x = p;
439         }
440 }
441
442 void gen_free_declarators(struct cdecl_declarator *x)
443 {
444         struct cdecl_declarator *p;
445
446         while (x) {
447                 p = x->child;
448
449                 switch (x->type) {
450                 case CDECL_DECL_NULL:
451                         break;
452                 case CDECL_DECL_IDENT:
453                         free(x->u.ident);
454                         break;
455                 case CDECL_DECL_POINTER:
456                         gen_free_declspecs(x->u.pointer.qualifiers);
457                         break;
458                 case CDECL_DECL_ARRAY:
459                         free(x->u.array.vla);
460                         break;
461                 case CDECL_DECL_FUNCTION:
462                         gen_free_parameters(x->u.function.parameters);
463                         break;
464                 default:
465                         assert(0);
466                 }
467
468                 free(x);
469                 x = p;
470         }
471 }