From 8b46a260a9af1e1cd07ae51924022724f73aa830 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Sat, 25 Jun 2011 09:41:41 -0400 Subject: [PATCH] Add support for pointer declarators. --- src/cdecl.h | 9 ++++++- src/explain.c | 61 ++++++++++++++++++++++++++++++++++++++++++++---- src/parse-decl.c | 11 ++++----- src/parse.y | 42 +++++++++++++++++++++++++++------ 4 files changed, 104 insertions(+), 19 deletions(-) diff --git a/src/cdecl.h b/src/cdecl.h index 489be83..6055ea8 100644 --- a/src/cdecl.h +++ b/src/cdecl.h @@ -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; }; diff --git a/src/explain.c b/src/explain.c index 823cb3a..c6c7e9c 100644 --- a/src/explain.c +++ b/src/explain.c @@ -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); } diff --git a/src/parse-decl.c b/src/parse-decl.c index 39a3e3c..eb543ec 100644 --- a/src/parse-decl.c +++ b/src/parse-decl.c @@ -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) diff --git a/src/parse.y b/src/parse.y index 394c12a..7b73eae 100644 --- a/src/parse.y +++ b/src/parse.y @@ -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 declspec_simple typespec_simple +%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 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; }; -- 2.43.2