X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/ccab8e9fa4419c944f831612d5b5474c847485fa..eda9528293fbc32857a5856a30ebd6585b281215:/src/parse.y diff --git a/src/parse.y b/src/parse.y index 9e54761..14d593e 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) /* @@ -88,7 +109,13 @@ * name strings can be used directly in error messages and there is no * need for any string processing. */ -#define yytnamerr(a, b) cdecl__strlcpy(a, b, (a) ? INT_MAX : 0) +#define yytnamerr(a, b) ( (a) ? yytnamerr_copy(a, b) \ + : strlen(b) ) + +static size_t yytnamerr_copy(char *dst, const char *src) +{ + return cdecl__strlcpy(dst, src, strlen(src)+1); +} %} %code requires {