From ccab8e9fa4419c944f831612d5b5474c847485fa Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Mon, 24 Jul 2023 19:57:56 -0400 Subject: [PATCH] libcdecl: Replace ALLOC_STRUCT with specialized macros. While there is some appeal to this generic "do everything" macro, it depends on a bunch of modern C syntax (variadic macros, compound literals, designated initializers) which is not always correctly implemented. We've already had to work around at least one compiler bug in the code directly related to this macro. Using specialized macros for each kind of allocation works better on older implementations, and moreover we seem to get more compact code out of modern ones too, probably because compound literals initialize all members and we don't always need that. --- src/parse.y | 113 ++++++++++++++++++++++++---------------------------- 1 file changed, 53 insertions(+), 60 deletions(-) diff --git a/src/parse.y b/src/parse.y index f8c9608..9e54761 100644 --- a/src/parse.y +++ b/src/parse.y @@ -49,9 +49,38 @@ } \ } while (0) -#define ALLOC_STRUCT(ptr, type, ...) do { \ - ALLOC(ptr, sizeof (type)); \ - *(ptr) = (type) { __VA_ARGS__ }; \ +#define ALLOC_FUNCTION(ptr, parameters_, variadic_) do { \ + ALLOC(ptr, sizeof (struct cdecl_declarator)); \ + (ptr)->type = CDECL_DECL_FUNCTION; \ + (ptr)->u.function.parameters = parameters_; \ + (ptr)->u.function.variadic = variadic_; \ +} while (0) + +#define ALLOC_ARRAY(ptr, length_) do { \ + ALLOC(ptr, sizeof (struct cdecl_declarator)); \ + (ptr)->type = CDECL_DECL_ARRAY; \ + (ptr)->u.array.vla = NULL; \ + (ptr)->u.array.length = length_; \ +} while (0) + +#define ALLOC_POINTER(ptr, qualifiers_, child_) do { \ + ALLOC(ptr, sizeof (struct cdecl_declarator)); \ + (ptr)->child = child_; \ + (ptr)->type = CDECL_DECL_POINTER; \ + (ptr)->u.pointer.qualifiers = qualifiers_; \ +} while (0) + +#define ALLOC_DECLSPEC(ptr, type_) do { \ + ALLOC(ptr, sizeof (struct cdecl_declspec)); \ + (ptr)->type = type_; \ + (ptr)->ident = NULL; \ +} while (0) + +#define ALLOC_DECL(ptr, specifiers_, declarators_) do { \ + ALLOC(ptr, sizeof (struct cdecl)); \ + (ptr)->specifiers = specifiers_; \ + (ptr)->declarators = declarators_; \ + (ptr)->next = NULL; \ } while (0) /* @@ -320,7 +349,7 @@ declarators: declarator_wrap | declarator_wrap T_COMMA declarators { } declarator_wrap: declarator { - ALLOC_STRUCT($$, struct cdecl, .declarators = $1); + ALLOC_DECL($$, NULL, $1); } declspec_simple: T_AUTO @@ -349,17 +378,9 @@ qualifier_simple: T_CONST | T_RESTRICT | T_VOLATILE -declspec_notype: qualifier | declspec_simple { - ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1); -} - -typespec_noid: typespec_simple { - ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1); -} - -qualifier: qualifier_simple { - ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1); -} +declspec_notype: qualifier | declspec_simple { ALLOC_DECLSPEC($$, $1); } +typespec_noid: typespec_simple { ALLOC_DECLSPEC($$, $1); } +qualifier: qualifier_simple { ALLOC_DECLSPEC($$, $1); } typespec: typespec_noid | typespec_tagged T_IDENT { /* Compiler should be able to elide this assignment. */ @@ -378,9 +399,7 @@ vla_ident: T_IDENT | T_ASTERISK { } array: T_LBRACKET array_length T_RBRACKET { - ALLOC_STRUCT($$, struct cdecl_declarator, - .type = CDECL_DECL_ARRAY, - .u.array.length = $2); + ALLOC_ARRAY($$, $2); } | T_LBRACKET vla_ident T_RBRACKET { $$ = &$2->u.declarator; $$->type = CDECL_DECL_ARRAY; @@ -389,18 +408,13 @@ array: T_LBRACKET array_length T_RBRACKET { } parameter: declspecs declarator { - ALLOC_STRUCT($$, struct cdecl, - .specifiers = $1, - .declarators = $2); + ALLOC_DECL($$, $1, $2); } varargs: { $$ = false; } | T_COMMA T_ELLIPSIS { $$ = true; } parameter_type_list: parameter varargs { - ALLOC_STRUCT($$, struct cdecl_declarator, - .type = CDECL_DECL_FUNCTION, - .u.function.parameters = $1, - .u.function.variadic = $2); + ALLOC_FUNCTION($$, $1, $2); } | parameter T_COMMA parameter_type_list { $$ = $3; $1->next = $$->u.function.parameters; @@ -410,22 +424,16 @@ parameter_type_list: parameter varargs { parens: T_LPAREN parameter_type_list T_RPAREN { $$ = $2; } | T_LPAREN declarator_ish T_RPAREN { - ALLOC_STRUCT($$, struct cdecl_declarator, - .type = CDECL_DECL_FUNCTION); - ALLOC_STRUCT($$->u.function.parameters, struct cdecl, - .declarators = $2); + struct cdecl *fake_params; + + ALLOC_DECL(fake_params, NULL, $2); + ALLOC_FUNCTION($$, fake_params, false); } pointer: T_ASTERISK qualifiers direct_declarator { - ALLOC_STRUCT($$, struct cdecl_declarator, - .type = CDECL_DECL_POINTER, - .u.pointer.qualifiers = $2, - .child = $3); + ALLOC_POINTER($$, $2, $3); } | T_ASTERISK qualifiers pointer { - ALLOC_STRUCT($$, struct cdecl_declarator, - .type = CDECL_DECL_POINTER, - .u.pointer.qualifiers = $2, - .child = $3); + ALLOC_POINTER($$, $2, $3); } declarator: direct_declarator | pointer @@ -460,9 +468,8 @@ english: T_DECLARE T_IDENT T_AS english_declaration { */ storage_func_specs: %prec T_TYPE { $$ = NULL; } storage_func_specs: declspec_simple storage_func_specs { - ALLOC_STRUCT($$, struct cdecl_declspec, - .type = $1, - .next = $2); + ALLOC_DECLSPEC($$, $1); + $$->next = $2; } type_qual_spec: typespec_noid | qualifier @@ -485,18 +492,13 @@ post_specs: qualifiers typespec type_qual_specs { english_declaration: storage_func_specs english_declarator post_specs { join_specs($3, $1); - ALLOC_STRUCT($$, struct cdecl, - .specifiers = $3, - .declarators = $2); + ALLOC_DECL($$, $3, $2); } english_declarator: { $$ = NULLDECL; } | english_declarator qualifiers T_POINTER T_TO { - ALLOC_STRUCT($$, struct cdecl_declarator, - .type = CDECL_DECL_POINTER, - .child = $1, - .u.pointer.qualifiers = $2); + ALLOC_POINTER($$, $2, $1); } | english_declarator english_array { $$ = $2; $$->child = $1; @@ -506,18 +508,13 @@ english_declarator: { } english_function: T_FUNCTION T_RETURNING { - ALLOC_STRUCT($$, struct cdecl_declarator, - .type = CDECL_DECL_FUNCTION, - .u.function.parameters = NULL); + ALLOC_FUNCTION($$, NULL, false); } | T_FUNCTION T_LPAREN english_parameter_list T_RPAREN T_RETURNING { $$ = $3; } english_parameter_list: english_parameter varargs { - ALLOC_STRUCT($$, struct cdecl_declarator, - .type = CDECL_DECL_FUNCTION, - .u.function.parameters = $1, - .u.function.variadic = $2); + ALLOC_FUNCTION($$, $1, $2); } | english_parameter T_COMMA english_parameter_list { $$ = $3; $1->next = $$->u.function.parameters; @@ -552,9 +549,7 @@ null_decl: { * by shifting, so long as we have a special-case reduction to handle this. */ english_parameter: english_declaration | typedef_name_qual null_decl { - ALLOC_STRUCT($$, struct cdecl, - .specifiers = $1, - .declarators = $2); + ALLOC_DECL($$, $1, $2); } | T_IDENT T_AS english_declaration { $$ = insert_identifier($3, $1); } @@ -565,9 +560,7 @@ english_array: T_VLA T_ARRAY english_vla T_OF { $$->u.array.vla = $$->u.ident; $$->u.array.length = 0; } | T_ARRAY array_length T_OF { - ALLOC_STRUCT($$, struct cdecl_declarator, - .type = CDECL_DECL_ARRAY, - .u.array.length = $2); + ALLOC_ARRAY($$, $2); } array_length: { $$ = 0; } -- 2.43.2