Christian Schoenebeck wrote: > When it comes to error handling in Bison/Flex user actions, I would > recommend to always define and use your own macros and/or functions in > user actions instead of calling Bison/Flex ones directly. That safes > you refactoring work over time.
Makes sense, I'll do that. > #define PARSER_ALLOC(x) parser_alloc(x, #x) Cool trick! > static void* parser_alloc(size_t n, const char* expr) { > if (!n) return NULL; Oh good idea to check for zero size. POSIX says malloc() *might* return NULL for zero size, which would then make us trigger a false out-of-memory error. https://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html#tag_16_311_04 "If size is 0, either a null pointer or a unique pointer that can be successfully passed to free() shall be returned." > void* p = malloc(n); > if (!p) { > fprintf(stderr, "Parser: malloc(%s) with size %zu failed. > Aborting.\n", > expr, n); Might be more flexible to call yyerror() than printing directly to stderr? Although the name of that function depends on api.prefix, and its arguments depend on %param and %parse-param, so I'm not sure how our general-purpose parser_alloc() would know what to do. Plus we'd have to build the error string ourselves, which probably requires a malloc()... > abort(); Rather than aborting, maybe we could do something like this #ifdef YYNOMEM /* newer bison version */ YYNOMEM; #else /* older bison (undocumented feature) */ goto yyexhaustedlab; #endif > } > memset(p, 0, n); What about using calloc() rather than the combination of malloc() and memset()?