return NULL;
case CDECL_DECL_POINTER:
return d->u.pointer.declarator;
+ case CDECL_DECL_ARRAY:
+ return d->u.array.declarator;
default:
abort();
}
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)
{
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();
}
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();
}
%token T_LEX_ERROR
%token <strval> T_IDENT "identifier"
+%token <uintval> T_UINT "integer constant"
+
%token T_SEMICOLON ";"
%token T_ASTERISK "*"
%token T_LPAREN "("
%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
%%
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;
};