From: Nick Bowler Date: Sat, 25 Jun 2011 13:45:16 +0000 (-0400) Subject: Add support for array declarators. X-Git-Tag: v1~161 X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/commitdiff_plain/b3c6b8ad6aef24301d8ec511966140757e49f815 Add support for array declarators. Currently there is a (I think quite reasonable) restriction that the array length either be unspecified, a positive integer constant, an identifier, or *. --- diff --git a/src/cdecl.h b/src/cdecl.h index 6055ea8..9c06b79 100644 --- a/src/cdecl.h +++ b/src/cdecl.h @@ -2,6 +2,7 @@ #define CEDCL_H_ #include +#include /* 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; }; diff --git a/src/explain.c b/src/explain.c index c6c7e9c..d8a5f05 100644 --- a/src/explain.c +++ b/src/explain.c @@ -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(); } diff --git a/src/parse.y b/src/parse.y index 7b73eae..8840279 100644 --- a/src/parse.y +++ b/src/parse.y @@ -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 T_IDENT "identifier" +%token 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 vla_ident %type declspec_simple typespec_simple qualifier_simple %type declspec_notype declspec_noid typespec_noid typespec %type qualifier qualifiers pointer %type declspecs declspecs_noid -%type declarator declarators +%type direct_declarator declarator declarators array %type 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; }; diff --git a/src/scan.l b/src/scan.l index f2e92a8..b17d4ee 100644 --- a/src/scan.l +++ b/src/scan.l @@ -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)