]> git.draconx.ca Git - cdecl99.git/blobdiff - test/declgen.c
Clean up declgen a bit.
[cdecl99.git] / test / declgen.c
index 9c774ff6a97ace92499c5020d5f92718c622c640..221c71ac247e885cf834fa86a4a6e4264a4a3bcb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Generate random C declarations for testing.
- *  Copyright © 2011 Nick Bowler
+ *  Copyright © 2012, 2021-2022 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
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 #include <errno.h>
 #include <assert.h>
 #include <stdbool.h>
-#include <gsl/gsl_rng.h>
 
 #include "declgen.h"
 #include "cdecl.h"
 #include "test.h"
 
-struct gen_rng {
-       gsl_rng *rng;
-};
+/*
+ * Return a newly-allocated null declarator.  The child member is set by the
+ * argument; other members are initialized to zero.
+ */
+struct cdecl_declarator *new_declarator(struct cdecl_declarator *child)
+{
+       struct cdecl_declarator *d, init = { child, CDECL_DECL_NULL };
+
+       d = malloc_nofail(sizeof *d);
+       *d = init;
+
+       return d;
+}
+
+/*
+ * Return a newly-allocated void specifier.  The next member is set by the
+ * argument; other members are initialized to zero.
+ */
+struct cdecl_declspec *new_specifier(struct cdecl_declspec *next)
+{
+       struct cdecl_declspec *d, init = { next, CDECL_TYPE_VOID };
+
+       d = malloc_nofail(sizeof *d);
+       *d = init;
+
+       return d;
+}
+
+/*
+ * Return a newly-allocated declaration.  The next member is set by the
+ * argument; other members are initialized to zero.
+ */
+struct cdecl *new_cdecl(struct cdecl *next)
+{
+       struct cdecl *d, init = { next };
+
+       d = malloc_nofail(sizeof *d);
+       *d = init;
+
+       return d;
+}
 
 /*
  * Generate a random identifier.  We arbitrarily pick 10 as the largest
  * possible.  Avoid generating keywords, including the English ones, by
  * excluding the letters t, o, a and n.  Reserved words are OK.
  */
-char *gen_identifier(struct gen_rng *rng)
+char *gen_identifier(struct test_rng *rng)
 {
        static const char valid[59] = "_bcdefghijklmpqrsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        char *str;
        size_t n;
 
-       n = gsl_rng_uniform_int(rng->rng, 10)+1;
+       n = test_rng_uniform_int(rng, 10)+1;
        str = malloc_nofail(n+1);
 
        /* Exclude 10 digits from the first character. */
-       str[0] = valid[gsl_rng_uniform_int(rng->rng, sizeof valid - 10)];
+       str[0] = valid[test_rng_uniform_int(rng, sizeof valid - 10)];
        for (size_t i = 1; i < n; i++)
-               str[i] = valid[gsl_rng_uniform_int(rng->rng, sizeof valid)];
+               str[i] = valid[test_rng_uniform_int(rng, sizeof valid)];
        str[n] = 0;
 
        return str;
@@ -63,18 +101,14 @@ char *gen_identifier(struct gen_rng *rng)
  * qualifier is chosen uniformly at random from the set of possibilities:
  * const, volatile and, if restrictqual is true, restrict.
  */
-struct cdecl_declspec *gen_qualifiers(struct gen_rng *rng, bool restrictqual)
+struct cdecl_declspec *gen_qualifiers(struct test_rng *rng, bool restrictqual)
 {
-       struct cdecl_declspec *s = NULL, *p;
+       struct cdecl_declspec *s = NULL;
 
-       while (gsl_rng_uniform(rng->rng) < 0.5) {
-               p = s;
-               s = malloc_nofail(sizeof *s);
-               *s = (struct cdecl_declspec) {
-                       .next = p,
-               };
+       while (test_rng_uniform(rng) < 0.5) {
+               s = new_specifier(s);
 
-               switch (gsl_rng_uniform_int(rng->rng, 2+restrictqual)) {
+               switch (test_rng_uniform_int(rng, 2+restrictqual)) {
                case 0:
                        s->type = CDECL_QUAL_CONST;
                        break;
@@ -96,18 +130,13 @@ struct cdecl_declspec *gen_qualifiers(struct gen_rng *rng, bool restrictqual)
  * Generate random function specifiers.  Like qualifiers, function specifiers
  * can appear multiple times.
  */
-struct cdecl_declspec *gen_funcspecs(struct gen_rng *rng)
+struct cdecl_declspec *gen_funcspecs(struct test_rng *rng)
 {
-       struct cdecl_declspec *s = NULL, *p;
-
-       while (gsl_rng_uniform(rng->rng) < 0.5) {
-               p = s;
-               s = malloc_nofail(sizeof *s);
+       struct cdecl_declspec *s = NULL;
 
-               *s = (struct cdecl_declspec) {
-                       .type = CDECL_FUNC_INLINE,
-                       .next = p,
-               };
+       while (test_rng_uniform(rng) < 0.5) {
+               s = new_specifier(s);
+               s->type = CDECL_FUNC_INLINE;
        }
 
        return s;
@@ -118,24 +147,17 @@ struct cdecl_declspec *gen_funcspecs(struct gen_rng *rng)
  * true, then the only possible storage-class specifier is "register".
  * Otherwise, a specifier type will be selected uniformly at random.
  */
-struct cdecl_declspec *gen_storspecs(struct gen_rng *rng, bool registeronly)
+struct cdecl_declspec *gen_storspecs(struct test_rng *rng, bool registeronly)
 {
        struct cdecl_declspec *s;
 
-       if (gsl_rng_uniform(rng->rng) < 0.5)
+       if (test_rng_uniform(rng) < 0.5)
                return NULL;
 
-       s = malloc_nofail(sizeof *s);
-       *s = (struct cdecl_declspec) {
-               .type = CDECL_STOR_REGISTER,
-       };
-
-       if (registeronly)
-               return s;
-
-       switch (gsl_rng_uniform_int(rng->rng, 5)) {
-       case 0: s->type = CDECL_STOR_TYPEDEF;  break;
-       case 1: s->type = CDECL_STOR_REGISTER; break;
+       s = new_specifier(NULL);
+       switch (test_rng_uniform_int(rng, registeronly ? 1 : 5)) {
+       case 0: s->type = CDECL_STOR_REGISTER; break;
+       case 1: s->type = CDECL_STOR_TYPEDEF;  break;
        case 2: s->type = CDECL_STOR_STATIC;   break;
        case 3: s->type = CDECL_STOR_AUTO;     break;
        case 4: s->type = CDECL_STOR_EXTERN;   break;
@@ -149,21 +171,14 @@ struct cdecl_declspec *gen_storspecs(struct gen_rng *rng, bool registeronly)
  * Generate random type specifiers.  There is a short list of valid
  * combinations, from which we can select one uniformly at random.
  */
-static const unsigned long total_types;
-static struct cdecl_declspec *gen_raw_typespecs(struct gen_rng *rng)
-{
-       switch (gsl_rng_uniform_int(rng->rng, total_types)) {
-#      include "typegen.h"
-       }
-}
-static const unsigned long total_types = TOTAL_TYPES;
+#include "typegen.h"
 
-struct cdecl_declspec *gen_typespecs(struct gen_rng *rng, bool voidtype)
+struct cdecl_declspec *gen_typespecs(struct test_rng *rng, bool voidtype)
 {
        struct cdecl_declspec *specs;
 
 retry:
-       specs = gen_raw_typespecs(rng);
+       specs = gen_raw_typespecs(test_rng_uniform_int(rng, GEN_TOTAL_TYPES));
 
        switch (specs->type) {
        /* void is not always valid, so we might need to pick again. */
@@ -178,13 +193,17 @@ retry:
        case CDECL_TYPE_IDENT:
                assert(!specs->next);
                specs->ident = gen_identifier(rng);
+               break;
+       default:
+               /* Nothing to be done. */
+               ;
        }
 
        return specs;
 }
 
 struct cdecl_declspec *
-gen_randomize_specs(struct gen_rng *rng, struct cdecl_declspec *specs)
+gen_randomize_specs(struct test_rng *rng, struct cdecl_declspec *specs)
 {
        struct cdecl_declspec **p;
        size_t n = 0;
@@ -208,7 +227,7 @@ gen_randomize_specs(struct gen_rng *rng, struct cdecl_declspec *specs)
                struct cdecl_declspec *tmp;
                size_t r;
                
-               r = gsl_rng_uniform_int(rng->rng, n-i);
+               r = test_rng_uniform_int(rng, n-i);
                tmp = p[i];
                p[i] = p[r+i];
                p[r+i] = tmp;
@@ -242,7 +261,7 @@ gen_randomize_specs(struct gen_rng *rng, struct cdecl_declspec *specs)
  * be generated by this function: use gen_qualifiers directly.
  */
 struct cdecl_declspec *
-gen_declspecs(struct gen_rng *rng, unsigned flags)
+gen_declspecs(struct test_rng *rng, unsigned flags)
 {
        struct cdecl_declspec *s, *p;
 
@@ -264,47 +283,60 @@ gen_declspecs(struct gen_rng *rng, unsigned flags)
        return gen_randomize_specs(rng, s);
 }
 
+static uintmax_t gen_uintmax(struct test_rng *rng)
+{
+       unsigned char tmp;
+       uintmax_t ret = 0;
+
+       for (size_t i = 0; i < sizeof ret; i++) {
+               tmp = test_rng_uniform_int(rng, UCHAR_MAX+1);
+               ret <<= CHAR_BIT;
+               ret |= tmp;
+       }
+
+       return ret;
+}
+
 /*
  * Generate a random array declarator, selecting one of four possibilities
  * uniformly at random.
  */
-static void gen_array(struct gen_rng *rng, struct cdecl_declarator *d)
+static void gen_array(struct test_rng *rng, struct cdecl_declarator *d)
 {
-       d->type = CDECL_DECL_ARRAY;
-       d->u.array = (struct cdecl_array){0};
+       struct cdecl_array tmp = {0};
 
-       switch (gsl_rng_uniform_int(rng->rng, 4)) {
-       case '0':
-               d->u.array.vla = malloc_nofail(1);
-               d->u.array.vla[0] = 0;
+       switch (test_rng_uniform_int(rng, 4)) {
+       case 0:
+               tmp.vla = malloc_nofail(1);
+               tmp.vla[0] = 0;
                break;
-       case '1':
-               d->u.array.vla = gen_identifier(rng);
+       case 1:
+               tmp.vla = gen_identifier(rng);
                break;
-       case '2':
-               d->u.array.length = 0;
-               break;
-       case '3':
-               d->u.array.length = gsl_rng_uniform_int(rng->rng, -1);
+       case 2:
+               tmp.length = gen_uintmax(rng);
+       case 3:
                break;
+       default:
+               assert(0);
        }
+
+       d->type = CDECL_DECL_ARRAY;
+       d->u.array = tmp;
 }
 
 /* Generate a function declarator. */
-static void gen_function(struct gen_rng *rng, struct cdecl_declarator *d)
+static void gen_function(struct test_rng *rng, struct cdecl_declarator *d)
 {
        d->type = CDECL_DECL_FUNCTION;
        d->u.function.parameters = NULL;
 
-       while (gsl_rng_uniform(rng->rng) < 0.5) {
+       while (test_rng_uniform(rng) < 0.5) {
                unsigned flags = GEN_ONLY_REGISTER | GEN_NO_FUNCTION;
                struct cdecl *param;
 
-               param = malloc_nofail(sizeof *param);
-               *param = (struct cdecl) {
-                       .next = d->u.function.parameters,
-                       .declarators = gen_declarators(rng),
-               };
+               param = new_cdecl(d->u.function.parameters);
+               param->declarators = gen_declarators(rng);
 
                if (param->declarators->type != CDECL_DECL_POINTER
                    && param->declarators->type != CDECL_DECL_FUNCTION)
@@ -315,7 +347,16 @@ static void gen_function(struct gen_rng *rng, struct cdecl_declarator *d)
        }
 
        if (d->u.function.parameters) {
-               d->u.function.variadic = gsl_rng_uniform(rng->rng) < 0.5;
+               d->u.function.variadic = test_rng_uniform(rng) < 0.5;
+       } else if (test_rng_uniform(rng) < 0.5) {
+               struct cdecl *param;
+
+               /* We will never generate (void) above; do it here. */
+               param = new_cdecl(NULL);
+               param->declarators = new_declarator(NULL);
+               param->specifiers = new_specifier(NULL);
+
+               d->u.function.parameters = param;
        }
 }
 
@@ -325,36 +366,24 @@ static void gen_function(struct gen_rng *rng, struct cdecl_declarator *d)
  * are ultimately terminated by either a null declarator or an identifier,
  * selected uniformly at random.
  */
-struct cdecl_declarator *gen_declarators(struct gen_rng *rng)
+struct cdecl_declarator *gen_declarators(struct test_rng *rng)
 {
        struct cdecl_declarator *d, *p;
        unsigned limit = 3;
 
-       d = malloc_nofail(sizeof *d);
-       if (gsl_rng_uniform(rng->rng) < 0.5) {
-               *d = (struct cdecl_declarator) {
-                       .type = CDECL_DECL_NULL,
-               };
-       } else {
-               *d = (struct cdecl_declarator) {
-                       .type = CDECL_DECL_IDENT,
-                       .u.ident = gen_identifier(rng),
-               };
+       d = new_declarator(NULL);
+       if (test_rng_uniform(rng) < 0.5) {
+               d->type = CDECL_DECL_IDENT;
+               d->u.ident = gen_identifier(rng);
        }
 
-       while (gsl_rng_uniform(rng->rng) < 0.5) {
-               p = d;
-               d = malloc_nofail(sizeof *d);
-               *d = (struct cdecl_declarator) {
-                       .child = p,
-               };
+       while (test_rng_uniform(rng) < 0.5) {
+               d = new_declarator((p = d));
 
-               switch (gsl_rng_uniform_int(rng->rng, limit)) {
+               switch (test_rng_uniform_int(rng, limit)) {
                case 0:
                        d->type = CDECL_DECL_POINTER;
-                       d->u.pointer = (struct cdecl_pointer) {
-                               .qualifiers = gen_qualifiers(rng, true),
-                       };
+                       d->u.pointer.qualifiers = gen_qualifiers(rng, true);
                        limit = 3;
                        break;
                case 1:
@@ -363,6 +392,12 @@ struct cdecl_declarator *gen_declarators(struct gen_rng *rng)
                        break;
                case 2:
                        gen_function(rng, d);
+                       if (p && p->type == CDECL_DECL_POINTER) {
+                               struct cdecl_pointer *ptr = &p->u.pointer;
+
+                               gen_free_declspecs(ptr->qualifiers);
+                               ptr->qualifiers = gen_qualifiers(rng, false);
+                       }
                        limit = 1;
                        break;
                default:
@@ -373,37 +408,6 @@ struct cdecl_declarator *gen_declarators(struct gen_rng *rng)
        return d;
 }
 
-struct gen_rng *gen_alloc_rng(const char *seed_str)
-{
-       unsigned long seed;
-       struct gen_rng *rng;
-       char *end;
-
-       errno = 0;
-       seed = strtoul(seed_str, &end, 0);
-       if (*end != 0) {
-               fprintf(stderr, "%s: invalid seed\n", seed_str);
-               return NULL;
-       } else if (errno != 0) {
-               fprintf(stderr, "%s: invalid seed: %s\n",
-                               seed_str, strerror(errno));
-               return NULL;
-       }
-
-       rng = malloc_nofail(sizeof *rng);
-       rng->rng = gsl_rng_alloc(gsl_rng_mt19937);
-       gsl_rng_set(rng->rng, seed);
-
-       return rng;
-}
-
-void gen_free_rng(struct gen_rng *rng)
-{
-       if (rng)
-               gsl_rng_free(rng->rng);
-       free(rng);
-}
-
 static void gen_free_parameters(struct cdecl *x)
 {
        struct cdecl *p;