]> git.draconx.ca Git - cdecl99.git/blobdiff - src/parse-decl.c
libcdecl: Remove unused YY_INPUT from scanner.
[cdecl99.git] / src / parse-decl.c
index a6204a18a00c32b524d9bc5dc89cff67cc5b7905..8f0bd388a1bcad91f83b23a4676e16652e2ccee8 100644 (file)
 #include "scan.h"
 #include "errmsg.h"
 
+/*
+ * Allocate a "parse item", which is a union of several parse tree
+ * structure types, together with a string buffer.  The s_sz argument
+ * specifies the size of the string (including its terminator), which
+ * may be zero.
+ *
+ * The union's declarator member is pre-initialized to a valid "identifier"
+ * declarator, which shares several interesting offsets with the "declspec"
+ * structure for an "identifier" type specifier.
+ */
+struct parse_item *cdecl__alloc_item(size_t s_sz)
+{
+       struct parse_item *ret;
+
+       ret = malloc(offsetof(struct parse_item, s) + s_sz);
+       if (!ret) {
+               cdecl__errmsg(CDECL__ENOMEM);
+               return NULL;
+       }
+
+       ret->u.declarator.child   = NULL;
+       ret->u.declarator.type    = CDECL_DECL_IDENT;
+       ret->u.declarator.u.ident = ret->s;
+
+       return ret;
+}
+
 /*
  * We can represent type specifiers as a bitmap, which gives us a finite
  * list of acceptable bitmap values according to the C standard.  However,
  */
 static int valid_typespec(struct cdecl_declspec *s)
 {
+       struct cdecl_declspec *c;
        unsigned long map = 0;
 
-       for (struct cdecl_declspec *c = s; c; c = c->next) {
+       for (c = s; c; c = c->next) {
                unsigned long bit;
 
                if (cdecl_spec_kind(c) != CDECL_SPEC_TYPE)
@@ -90,7 +118,7 @@ static int valid_typespec(struct cdecl_declspec *s)
  */
 static bool valid_declspecs(struct cdecl *decl, bool top)
 {
-       struct cdecl_declspec *specs = decl->specifiers;
+       struct cdecl_declspec *c, *specs = decl->specifiers;
        struct cdecl_declarator *d   = decl->declarators;
        bool abstract = cdecl_is_abstract(d);
        unsigned num_storage = 0;
@@ -98,7 +126,7 @@ static bool valid_declspecs(struct cdecl *decl, bool top)
        if (!valid_typespec(specs))
                return false;
 
-       for (struct cdecl_declspec *c = specs; c; c = c->next) {
+       for (c = specs; c; c = c->next) {
                switch (cdecl_spec_kind(c)) {
                case CDECL_SPEC_TYPE:
                        if (c->type == CDECL_TYPE_VOID &&
@@ -173,22 +201,29 @@ static bool valid_declspecs(struct cdecl *decl, bool top)
 
 static struct cdecl_declarator *reduce_function(struct cdecl *param)
 {
-       struct cdecl_declspec   *spec = param->specifiers;
-       struct cdecl_declarator *decl = param->declarators;
-       struct cdecl_declarator *last;
+       struct cdecl_declarator *d, **p = &param->declarators;
+       struct parse_item *spec = (void *)param->specifiers;
 
-       for (last = decl; last && last->type != CDECL_DECL_NULL;)
-               last = last->child;
+       while ((d = *p)->child)
+               p = &d->child;
 
-       if (!last)
+       if (d->type != CDECL_DECL_NULL)
                return NULL;
 
-       last->type = CDECL_DECL_IDENT;
-       last->u.ident = spec->ident;
-       free(param);
-       free(spec);
+       /*
+        * The child and u.ident members of cdecl_declarator are expected
+        * to be located at identical offsets as, respectively, the next
+        * and ident members within cdecl_declspec, so the expectation is
+        * that the compiler can elide both assignments.
+        */
+       spec->u.declarator.child = (void *)spec->u.declspec.next;
+       spec->u.declarator.u.ident = spec->u.declspec.ident;
+       spec->u.declarator.type = CDECL_DECL_IDENT;
+       *p = &spec->u.declarator;
 
-       return decl;
+       d = param->declarators;
+       free(param);
+       return d;
 }
 
 static bool function_is_reducible(struct cdecl_declarator *d)
@@ -227,7 +262,6 @@ simplify_functions(struct cdecl_declarator **p, struct cdecl_declarator *d)
        if (!new)
                return 0; /* e.g. int (foo bar) */
        *p = new;
-       free(d->child);
        free(d);
 
        return 1;
@@ -467,9 +501,9 @@ static int forall_declarators(struct cdecl *decl,
 
 static struct cdecl *do_parse(const char *str, int english_mode)
 {
+       struct cdecl *decl = NULL;
        YY_BUFFER_STATE state;
        yyscan_t scanner;
-       struct cdecl *decl;
 
 #if YYDEBUG
        extern int cdecl__yydebug;
@@ -481,8 +515,15 @@ static struct cdecl *do_parse(const char *str, int english_mode)
                return NULL;
 
        state = cdecl__yy_scan_string(str, scanner);
-       if (cdecl__yyparse(scanner, &decl) != 0)
+       if (cdecl__yyparse(scanner, &decl) != 0) {
+               /*
+                * If the input consists of a complete, valid declaration
+                * followed by some garbage, that parsed declaration will
+                * be output by the parser and we need to free it here.
+                */
+               cdecl__free(decl);
                decl = NULL;
+       }
        cdecl__yy_delete_buffer(state, scanner);
        cdecl__yylex_destroy(scanner);