]> git.draconx.ca Git - cdecl99.git/commitdiff
Add support for array declarators.
authorNick Bowler <nbowler@draconx.ca>
Sat, 25 Jun 2011 13:45:16 +0000 (09:45 -0400)
committerNick Bowler <nbowler@draconx.ca>
Sat, 25 Jun 2011 13:45:16 +0000 (09:45 -0400)
Currently there is a (I think quite reasonable) restriction that the
array length either be unspecified, a positive integer constant, an
identifier, or *.

src/cdecl.h
src/explain.c
src/parse.y
src/scan.l

index 6055ea84a37858856214795fc59ee74cc6c7e7d8..9c06b799c261a674df2301f9f26ab2055006cf32 100644 (file)
@@ -2,6 +2,7 @@
 #define CEDCL_H_
 
 #include <stddef.h>
+#include <stdint.h>
 
 /* Declaration specifier kinds. */
 enum {
@@ -42,6 +43,7 @@ enum {
 enum {
        CDECL_DECL_IDENT,
        CDECL_DECL_POINTER,
+       CDECL_DECL_ARRAY,
 };
 
 struct cdecl {
@@ -60,6 +62,11 @@ struct cdecl {
                                struct cdecl_declspec   *qualifiers;
                                struct cdecl_declarator *declarator;
                        } pointer;
+                       struct cdecl_array {
+                               char *vla;
+                               uintmax_t length;
+                               struct cdecl_declarator *declarator;
+                       } array;
                } u;
        } *declarators;
 };
index c6c7e9c49b4ffcd87cc259ca3209068329b45951..d8a5f057915191bbf392ef47186a5231e6cf9102 100644 (file)
@@ -161,6 +161,8 @@ static struct cdecl_declarator *next_declarator(struct cdecl_declarator *d)
                return NULL;
        case CDECL_DECL_POINTER:
                return d->u.pointer.declarator;
+       case CDECL_DECL_ARRAY:
+               return d->u.array.declarator;
        default:
                abort();
        }
@@ -188,6 +190,28 @@ explain_pointer(char *buf, size_t n, struct cdecl_pointer *p)
        return ret + snprintf(buf, n, "pointer to");
 }
 
+static size_t
+explain_array(char *buf, size_t n, struct cdecl_array *a)
+{
+       size_t ret = 0, rc = 0;
+
+       if (a->vla)
+               rc = snprintf(buf, n, "variable-length array");
+       else
+               rc = snprintf(buf, n, "array");
+       ret += advance(&buf, &n, rc);
+
+       if (a->vla) {
+               rc = snprintf(buf, n, "%s", a->vla);
+               ret += advance(&buf, &n, rc);
+       } else if (a->length) {
+               rc = snprintf(buf, n, "%ju", a->length);
+               ret += advance(&buf, &n, rc);
+       }
+
+       return ret + snprintf(buf, n, "of");
+}
+
 static size_t
 explain_declarators(char *buf, size_t n, struct cdecl_declarator *d)
 {
@@ -202,6 +226,8 @@ explain_declarators(char *buf, size_t n, struct cdecl_declarator *d)
        switch (d->type) {
        case CDECL_DECL_POINTER:
                return ret + explain_pointer(buf, n, &d->u.pointer);
+       case CDECL_DECL_ARRAY:
+               return ret + explain_array(buf, n, &d->u.array);
        default:
                abort();
        }
index 7b73eae26d9a053066b2850fbc03513b18d77a4f..8840279b020b9ab8e945eb6ae812254a8297d759 100644 (file)
@@ -84,6 +84,10 @@ static void free_declarator(struct cdecl_declarator *x)
                        free_declspec(x->u.pointer.qualifiers);
                        free_declarator(x->u.pointer.declarator);
                        break;
+               case CDECL_DECL_ARRAY:
+                       free(x->u.array.vla);
+                       free_declarator(x->u.array.declarator);
+                       break;
                default:
                        abort();
                }
@@ -114,6 +118,8 @@ void cdecl_free(struct cdecl *decl)
 %token T_LEX_ERROR
 
 %token <strval> T_IDENT "identifier"
+%token <uintval> T_UINT "integer constant"
+
 %token T_SEMICOLON ";"
 %token T_ASTERISK  "*"
 %token T_LPAREN    "("
@@ -150,11 +156,12 @@ void cdecl_free(struct cdecl *decl)
 %token T_UNION    "union"
 %token T_ENUM     "enum"
 
+%type <strval>     vla_ident
 %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 <declarator> direct_declarator declarator declarators array
 %type <decl>       declaration
 
 %%
@@ -249,15 +256,41 @@ declspec_noid: declspec_notype | typespec_noid
 
 pointer: T_ASTERISK qualifiers { $$ = $2; }
 
-declarator: T_IDENT {
+vla_ident: T_IDENT | T_ASTERISK {
+       ALLOC($$, sizeof "");
+       strcpy($$, "");
+}
+
+array: T_LBRACKET T_UINT T_RBRACKET {
+       if ($2 == 0)
+               FAIL("array length must be positive");
+
        ALLOC_STRUCT($$, struct cdecl_declarator,
-               .type = CDECL_DECL_IDENT,
-               .u.ident = $1);
-} | pointer declarator {
+               .type = CDECL_DECL_ARRAY,
+               .u.array.length = $2);
+} | T_LBRACKET vla_ident T_RBRACKET {
+       ALLOC_STRUCT($$, struct cdecl_declarator,
+               .type = CDECL_DECL_ARRAY,
+               .u.array.vla = $2);
+} | T_LBRACKET T_RBRACKET {
+       ALLOC_STRUCT($$, struct cdecl_declarator,
+               .type = CDECL_DECL_ARRAY);
+}
+
+declarator: direct_declarator | pointer direct_declarator {
        ALLOC_STRUCT($$, struct cdecl_declarator,
                .type = CDECL_DECL_POINTER,
                .u.pointer.qualifiers = $1,
                .u.pointer.declarator = $2);
+}
+
+direct_declarator: T_IDENT {
+       ALLOC_STRUCT($$, struct cdecl_declarator,
+               .type = CDECL_DECL_IDENT,
+               .u.ident = $1);
+} | direct_declarator array {
+       $$ = $2;
+       $$->u.array.declarator = $1;
 } | T_LPAREN declarator T_RPAREN {
        $$ = $2;
 };
index f2e92a8703509d32c734abfa7a42391ab7d9559c..b17d4ee6802d44acfafdb974a9b0313fc8bb86fa 100644 (file)
@@ -30,6 +30,7 @@
 %}
 
 IDENT [_[:alpha:]][_[:alnum:]]*
+INTEGER 0x[[:xdigit:]]+|0[0-7]+|[[:digit:]]+
 
 %%
 
@@ -69,6 +70,19 @@ IDENT [_[:alpha:]][_[:alnum:]]*
 "union"    return T_UNION;
 "enum"     return T_ENUM;
 
+{INTEGER} {
+       char *end;
+
+       errno = 0;
+       yylval->uintval = strtoumax(yytext, &end, 0);
+       if (errno == ERANGE)
+               lex_error("integer constant out of range");
+       if (*end)
+               lex_error("invalid integer constant");
+
+       return T_UINT;
+}
+
 {IDENT} {
        yylval->strval = malloc(yyleng+1);
        if (!yylval->strval)