]> git.draconx.ca Git - cdecl99.git/commitdiff
Add support for pointer declarators.
authorNick Bowler <nbowler@draconx.ca>
Sat, 25 Jun 2011 13:41:41 +0000 (09:41 -0400)
committerNick Bowler <nbowler@draconx.ca>
Sat, 25 Jun 2011 13:41:41 +0000 (09:41 -0400)
src/cdecl.h
src/explain.c
src/parse-decl.c
src/parse.y

index 489be835284d65caf634d91f956d908a216edb69..6055ea84a37858856214795fc59ee74cc6c7e7d8 100644 (file)
@@ -41,6 +41,7 @@ enum {
 /* Declarator types. */
 enum {
        CDECL_DECL_IDENT,
+       CDECL_DECL_POINTER,
 };
 
 struct cdecl {
@@ -53,7 +54,13 @@ struct cdecl {
        struct cdecl_declarator {
                struct cdecl_declarator *next;
                unsigned type;
-               char *ident;
+               union {
+                       char *ident;
+                       struct cdecl_pointer {
+                               struct cdecl_declspec   *qualifiers;
+                               struct cdecl_declarator *declarator;
+                       } pointer;
+               } u;
        } *declarators;
 };
 
index 823cb3a17fe23127ca64677981b9fb1a28120cdd..c6c7e9c49b4ffcd87cc259ca3209068329b45951 100644 (file)
@@ -154,20 +154,71 @@ static size_t explain_pre_specs(char *buf, size_t n, struct cdecl_declspec *s)
        return ret;
 }
 
+static struct cdecl_declarator *next_declarator(struct cdecl_declarator *d)
+{
+       switch (d->type) {
+       case CDECL_DECL_IDENT:
+               return NULL;
+       case CDECL_DECL_POINTER:
+               return d->u.pointer.declarator;
+       default:
+               abort();
+       }
+}
+
+/* Renders the name of the thing being declared. */
+static size_t
+explain_prologue(char *buf, size_t n, struct cdecl_declarator *d)
+{
+       while (d) {
+               if (d->type == CDECL_DECL_IDENT)
+                       return snprintf(buf, n, "declare %s as", d->u.ident);
+               d = next_declarator(d);
+       }
+}
+
+static size_t
+explain_pointer(char *buf, size_t n, struct cdecl_pointer *p)
+{
+       size_t ret = 0, rc;
+
+       rc = explain_qualifiers(buf, n, p->qualifiers);
+       ret += advance(&buf, &n, rc);
+
+       return ret + snprintf(buf, n, "pointer to");
+}
+
+static size_t
+explain_declarators(char *buf, size_t n, struct cdecl_declarator *d)
+{
+       size_t ret = 0, rc;
+
+       if (d->type == CDECL_DECL_IDENT)
+               return 0;
+
+       rc = explain_declarators(buf, n, next_declarator(d));
+       ret += advance(&buf, &n, rc);
+
+       switch (d->type) {
+       case CDECL_DECL_POINTER:
+               return ret + explain_pointer(buf, n, &d->u.pointer);
+       default:
+               abort();
+       }
+}
 
 size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl)
 {
        size_t ret = 0, rc;
 
-       /*
-        * XXX: This won't work when we add support for more complicated
-        * declarators.
-        */
-       rc = output(buf, n, 0, "declare %s as", decl->declarators->ident);
+       rc = explain_prologue(buf, n, decl->declarators);
        ret += advance(&buf, &n, rc);
 
        rc = explain_pre_specs(buf, n, decl->specifiers);
        ret += advance(&buf, &n, rc);
 
+       rc = explain_declarators(buf, n, decl->declarators);
+       ret += advance(&buf, &n, rc);
+
        return ret + explain_post_specs(buf, n, decl->specifiers);
 }
index 39a3e3cd0161aecc15e8dcdb81d2cf699d7c51f8..eb543ec8cc99fc5aafccbc2d1d3c1411430d7cc6 100644 (file)
@@ -6,7 +6,7 @@
 #include "parse.h"
 #include "scan.h"
 
-static int verify_specs(struct cdecl_declspec *s)
+static int verify_declspecs(struct cdecl_declspec *s)
 {
        unsigned num_storage = 0;
        unsigned long typemap;
@@ -27,9 +27,8 @@ static int verify_specs(struct cdecl_declspec *s)
                        break;
                case CDECL_SPEC_QUAL:
                        /*
-                        * Since we don't support pointer types yet, all
-                        * restrict qualifiers are invalid.  Other qualifiers
-                        * are always valid.
+                        * Restrict qualifiers are only valid in the
+                        * pointer qualifier list, which isn't checked here.
                         */
                        if (c->type == CDECL_QUAL_RESTRICT) {
                                fprintf(stderr, "only pointer types can be restrict-qualified.\n");
@@ -38,7 +37,7 @@ static int verify_specs(struct cdecl_declspec *s)
                        break;
                case CDECL_SPEC_FUNC:
                        /*
-                        * Likewise for function specifiers.
+                        * We don't support functions yet.
                         */
                        fprintf(stderr, "only function declarations may have function specifiers.\n");
                        return -1;
@@ -52,7 +51,7 @@ static int verify_specs(struct cdecl_declspec *s)
 
 static int verify_decl(struct cdecl *decl)
 {
-       return verify_specs(decl->specifiers);
+       return verify_declspecs(decl->specifiers);
 }
 
 struct cdecl *cdecl_parse_decl(const char *declstr)
index 394c12a083e1fb30ebbb9bb3e63381ee165654e2..7b73eae26d9a053066b2850fbc03513b18d77a4f 100644 (file)
@@ -76,7 +76,17 @@ static void free_declarator(struct cdecl_declarator *x)
        struct cdecl_declarator *p;
        while (x) {
                p = x->next;
-               free(x->ident);
+               switch (x->type) {
+               case CDECL_DECL_IDENT:
+                       free(x->u.ident);
+                       break;
+               case CDECL_DECL_POINTER:
+                       free_declspec(x->u.pointer.qualifiers);
+                       free_declarator(x->u.pointer.declarator);
+                       break;
+               default:
+                       abort();
+               }
                free(x);
                x = p;
        }
@@ -140,8 +150,9 @@ void cdecl_free(struct cdecl *decl)
 %token T_UNION    "union"
 %token T_ENUM     "enum"
 
-%type <uintval>    declspec_simple typespec_simple
+%type <uintval>    declspec_simple typespec_simple qualifier_simple
 %type <declspec>   declspec_notype declspec_noid typespec_noid typespec
+%type <declspec>   qualifier qualifiers pointer
 %type <declspec>   declspecs declspecs_noid
 %type <declarator> declarator declarators
 %type <decl>       declaration
@@ -171,6 +182,11 @@ declspecs_noid: { $$ = NULL; } | declspec_noid declspecs_noid {
        $$->next = $2;
 }
 
+qualifiers: { $$ = NULL; } | qualifiers qualifier {
+       $$ = $2;
+       $$->next = $1;
+}
+
 declarators: declarator | declarator T_COMMA declarators {
        $$ = $1;
        $$->next = $3;
@@ -181,9 +197,6 @@ declspec_simple: T_AUTO { $$ = CDECL_STOR_AUTO;     }
        | T_EXTERN      { $$ = CDECL_STOR_EXTERN;   }
        | T_STATIC      { $$ = CDECL_STOR_STATIC;   }
        | T_REGISTER    { $$ = CDECL_STOR_REGISTER; }
-       | T_RESTRICT    { $$ = CDECL_QUAL_RESTRICT; }
-       | T_VOLATILE    { $$ = CDECL_QUAL_VOLATILE; }
-       | T_CONST       { $$ = CDECL_QUAL_CONST;    }
        | T_INLINE      { $$ = CDECL_FUNC_INLINE;   }
 
 typespec_simple: T_VOID { $$ = CDECL_TYPE_VOID;     }
@@ -198,7 +211,11 @@ typespec_simple: T_VOID { $$ = CDECL_TYPE_VOID;     }
        | T_BOOL        { $$ = CDECL_TYPE_BOOL;     }
        | T_COMPLEX     { $$ = CDECL_TYPE_COMPLEX;  }
 
-declspec_notype: declspec_simple  {
+qualifier_simple: T_CONST { $$ = CDECL_QUAL_CONST;    }
+       | T_RESTRICT      { $$ = CDECL_QUAL_RESTRICT; }
+       | T_VOLATILE      { $$ = CDECL_QUAL_VOLATILE; }
+
+declspec_notype: qualifier | declspec_simple {
        ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1);
 }
 
@@ -206,6 +223,10 @@ typespec_noid: typespec_simple {
        ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1);
 }
 
+qualifier: qualifier_simple {
+       ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1);
+}
+
 typespec: typespec_noid | T_STRUCT T_IDENT {
        ALLOC_STRUCT($$, struct cdecl_declspec,
                .type = CDECL_TYPE_STRUCT,
@@ -226,10 +247,17 @@ typespec: typespec_noid | T_STRUCT T_IDENT {
 
 declspec_noid: declspec_notype | typespec_noid
 
+pointer: T_ASTERISK qualifiers { $$ = $2; }
+
 declarator: T_IDENT {
        ALLOC_STRUCT($$, struct cdecl_declarator,
                .type = CDECL_DECL_IDENT,
-               .ident = $1);
+               .u.ident = $1);
+} | pointer declarator {
+       ALLOC_STRUCT($$, struct cdecl_declarator,
+               .type = CDECL_DECL_POINTER,
+               .u.pointer.qualifiers = $1,
+               .u.pointer.declarator = $2);
 } | T_LPAREN declarator T_RPAREN {
        $$ = $2;
 };