]> git.draconx.ca Git - cdecl99.git/commitdiff
libcdecl: Perform all parser allocations via cdecl__alloc_item.
authorNick Bowler <nbowler@draconx.ca>
Tue, 25 Jul 2023 00:56:56 +0000 (20:56 -0400)
committerNick Bowler <nbowler@draconx.ca>
Fri, 28 Jul 2023 04:20:58 +0000 (00:20 -0400)
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.

src/cdecl-internal.h
src/parse.y

index cae248bc899c38330510d9433a8bd2ceb79eb15b..0d8f2e86946d6c5214a3f0669ba8f52373d4cbfd 100644 (file)
@@ -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];
index 9e547617d228e78d006014c0ccc0822822775638..bf2271837758b81634336b614e90963cc789d694 100644 (file)
        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)
 
 /*