From: Nick Bowler Date: Tue, 25 Jul 2023 00:56:56 +0000 (-0400) Subject: libcdecl: Perform all parser allocations via cdecl__alloc_item. X-Git-Tag: v1.3~92 X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/commitdiff_plain/39aa5b577e6b01f53ed68e7851dcd982e0bb8015 libcdecl: Perform all parser allocations via cdecl__alloc_item. The cdecl__alloc_item function internally does some basic initialization and handles error reporting, so by using it consistently we can avoid some of this stuff being repeated throughout the parser actions, which gives a slight reduction in the size of the parser. As this function allocates a fixed-sized union of all the parse tree structures, this means a small amount of runtime memory may be wasted for the smaller ones, but it should be less than 12 bytes per allocation. --- diff --git a/src/cdecl-internal.h b/src/cdecl-internal.h index cae248b..0d8f2e8 100644 --- a/src/cdecl-internal.h +++ b/src/cdecl-internal.h @@ -106,6 +106,7 @@ struct parse_item { union { struct cdecl_declarator declarator; struct cdecl_declspec declspec; + struct cdecl decl; } u; char s[FLEXIBLE_ARRAY_MEMBER]; diff --git a/src/parse.y b/src/parse.y index 9e54761..bf22718 100644 --- a/src/parse.y +++ b/src/parse.y @@ -41,46 +41,67 @@ YYERROR; \ } while (0) -#define ALLOC(ptr, size) do { \ - (ptr) = malloc(size); \ - if (!(ptr)) { \ - cdecl__errmsg(CDECL__ENOMEM); \ +/* + * Allocate a parse tree node via cdecl__alloc_item. + * + * - m1 specifies the item's union member to assign to ptr, which selects the + * type of node to allocate. + * + * - m2 specifies the "next" or "child" member, which is initialized to a null + * pointer. The cdecl__alloc_item function sets the declarator.child member + * to null; we explicitly copy this null pointer to the returned union member + * to avoid type punning. It is hoped that compilers will notice that these + * pointers are at the same offset therefore the assignment can be elided. + * + * The resulting pointer can be passed directly to free, as the union is the + * first member of the parse_item structure. + * + * Use the wrapper macros below instead of this one. + */ +#define ALLOC_ITEM(ptr, m1, m2) do { \ + struct parse_item *item; \ + if (!(item = cdecl__alloc_item(0))) \ YYERROR; \ - } \ + item->u.m1.m2 = (void *)item->u.declarator.child; \ + (ptr) = &item->u.m1; \ } while (0) +/* Wrappers for ALLOC_ITEM to allocate various kinds of parser structures. */ +#define ALLOC_ITEM_DECLARATOR(ptr) ALLOC_ITEM(ptr, declarator, child) +#define ALLOC_ITEM_DECLSPEC(ptr) ALLOC_ITEM(ptr, declspec, next) +#define ALLOC_ITEM_DECL(ptr) ALLOC_ITEM(ptr, decl, next) + #define ALLOC_FUNCTION(ptr, parameters_, variadic_) do { \ - ALLOC(ptr, sizeof (struct cdecl_declarator)); \ + ALLOC_ITEM_DECLARATOR(ptr); \ (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)); \ + ALLOC_ITEM_DECLARATOR(ptr); \ (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)); \ + ALLOC_ITEM_DECLARATOR(ptr); \ (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)); \ + ALLOC_ITEM_DECLSPEC(ptr); \ (ptr)->type = type_; \ (ptr)->ident = NULL; \ } while (0) #define ALLOC_DECL(ptr, specifiers_, declarators_) do { \ - ALLOC(ptr, sizeof (struct cdecl)); \ + ALLOC_ITEM_DECL(ptr); \ (ptr)->specifiers = specifiers_; \ (ptr)->declarators = declarators_; \ - (ptr)->next = NULL; \ } while (0) /*