/* Declarator types. */
enum {
CDECL_DECL_IDENT,
+ CDECL_DECL_POINTER,
};
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;
};
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);
}
#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;
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");
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;
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)
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;
}
%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
$$->next = $2;
}
+qualifiers: { $$ = NULL; } | qualifiers qualifier {
+ $$ = $2;
+ $$->next = $1;
+}
+
declarators: declarator | declarator T_COMMA declarators {
$$ = $1;
$$->next = $3;
| 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; }
| 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);
}
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,
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;
};