X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/8d1fb21fe111eba2b54579d5115017f40d0d949c..HEAD:/src/parse.y diff --git a/src/parse.y b/src/parse.y index 14d593e..6f3b304 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1,7 +1,7 @@ %code top { /* * Parser for C declarations. - * Copyright © 2011-2012, 2021, 2023 Nick Bowler + * Copyright © 2011-2012, 2021, 2023-2024 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,15 +32,9 @@ #include #include "scan.h" -#include "cdecl.h" #include "cdecl-internal.h" #include "errmsg.h" -#define FAIL(msg) do { \ - yyerror(&yylloc, NULL, NULL, msg); \ - YYERROR; \ -} while (0) - /* * Allocate a parse tree node via cdecl__alloc_item. * @@ -71,10 +65,14 @@ #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 { \ +#define ALLOC_FUNCTION_(ptr, parameters_) do { \ ALLOC_ITEM_DECLARATOR(ptr); \ (ptr)->type = CDECL_DECL_FUNCTION; \ (ptr)->u.function.parameters = parameters_; \ +} while (0) + +#define ALLOC_FUNCTION(ptr, parameters_, variadic_) do { \ + ALLOC_FUNCTION_(ptr, parameters_); \ (ptr)->u.function.variadic = variadic_; \ } while (0) @@ -109,17 +107,13 @@ * name strings can be used directly in error messages and there is no * need for any string processing. */ -#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); -} +#define yytnamerr(a, b) ( (a) ? cdecl__strlcpy(a, b, -1) : strlen(b) ) %} %code requires { #include +#include +#include "cdecl.h" } %code provides { @@ -129,9 +123,9 @@ const char *cdecl__token_name(unsigned token); } %union { - uintmax_t uintval; + cdecl_uintmax uintval; unsigned spectype; - _Bool boolval; + bool boolval; struct cdecl_declspec *declspec; struct cdecl_declarator *declarator; struct cdecl *decl; @@ -215,11 +209,44 @@ static void join_specs(struct cdecl_declspec *a, struct cdecl_declspec *b) a->next = b; } +/* + * Join three specifier lists into a single list, and returns the head of + * the new list. + * + * The list "b" is assumed to be a singleton list. + */ +static struct cdecl_declspec *join_specs3(struct cdecl_declspec *a, + struct cdecl_declspec *b, + struct cdecl_declspec *c) +{ + b->next = c; + join_specs(b, a); + return b; +} + +/* + * Reverse the order of a "struct cdecl" list, and return the new first + * element of the list (i.e., the last element of the original list). + */ +static struct cdecl *reverse_decls(struct cdecl *decl) +{ + struct cdecl *prev, *next; + + for (prev = NULL; decl; decl = next) { + next = decl->next; + decl->next = prev; + prev = decl; + } + + return prev; +} + /* * Alter an abstract declarator (type name) to declare an identifier instead, * used by the English parser rules to reduce "identifier as type" sequences. */ -static struct cdecl *insert_identifier(struct cdecl *decl, struct parse_item *ident) +static struct cdecl * +insert_identifier(struct cdecl *decl, struct parse_item *ident) { struct cdecl_declarator *d, **p = &decl->declarators; @@ -245,7 +272,7 @@ static struct cdecl_declarator *nulldecl(void) %destructor { free_decl($$); } /* Magic tokens */ -%token T_LEX_ERROR +%token T_LEX_ERROR "@@@" %token T_IDENT "identifier" %token T_UINT "integer constant" @@ -309,7 +336,7 @@ static struct cdecl_declarator *nulldecl(void) %type typespec_simple typespec_tagged %type declspec_notype declspec_noid typespec_noid typespec %type qualifier qualifiers -%type declspecs declspecs_noid +%type declspecs declspecs_notype declspecs_noid %type direct_declarator declarator pointer array parens postfix %type direct_declarator_ish declarator_ish parameter_type_list %type cdecl declaration declarators declarator_wrap parameter @@ -332,7 +359,7 @@ cdecl: english | declaration semi: | T_SEMICOLON declaration: declspecs declarators semi { - $$ = $2; + $$ = reverse_decls($2); $$->specifiers = $1; }; @@ -352,17 +379,18 @@ declaration: declspecs declarators semi { * unexpected parses; libcdecl applies a simplification step to the resulting * parse tree afterwards. */ -declspecs: declspec_notype declspecs { - $$ = $1; - $$->next = $2; -} | typespec declspecs_noid { - $$ = $1; - $$->next = $2; +declspecs: declspecs_notype typespec declspecs_noid { + $$ = join_specs3($1, $2, $3); } -declspecs_noid: { $$ = NULL; } | declspec_noid declspecs_noid { - $$ = $1; - $$->next = $2; +declspecs_notype: { $$ = NULL; } | declspecs_notype declspec_notype { + $$ = $2; + $$->next = $1; +} + +declspecs_noid: { $$ = NULL; } | declspecs_noid declspec_noid { + $$ = $2; + $$->next = $1; } qualifiers: { $$ = NULL; } | qualifiers qualifier { @@ -370,9 +398,9 @@ qualifiers: { $$ = NULL; } | qualifiers qualifier { $$->next = $1; } -declarators: declarator_wrap | declarator_wrap T_COMMA declarators { - $$ = $1; - $$->next = $3; +declarators: declarator_wrap | declarators T_COMMA declarator_wrap { + $$ = $3; + $$->next = $1; } declarator_wrap: declarator { @@ -440,21 +468,23 @@ parameter: declspecs declarator { varargs: { $$ = false; } | T_COMMA T_ELLIPSIS { $$ = true; } -parameter_type_list: parameter varargs { - ALLOC_FUNCTION($$, $1, $2); -} | parameter T_COMMA parameter_type_list { - $$ = $3; - $1->next = $$->u.function.parameters; - $$->u.function.parameters = $1; +parameter_type_list: parameter { + ALLOC_FUNCTION_($$, $1); +} | parameter_type_list T_COMMA parameter { + $$ = $1; + $3->next = $$->u.function.parameters; + $$->u.function.parameters = $3; } -parens: T_LPAREN parameter_type_list T_RPAREN { +parens: T_LPAREN parameter_type_list varargs T_RPAREN { + $2->u.function.parameters = reverse_decls($2->u.function.parameters); + $2->u.function.variadic = $3; $$ = $2; } | T_LPAREN declarator_ish T_RPAREN { struct cdecl *fake_params; ALLOC_DECL(fake_params, NULL, $2); - ALLOC_FUNCTION($$, fake_params, false); + ALLOC_FUNCTION_($$, fake_params); } pointer: T_ASTERISK qualifiers direct_declarator { @@ -494,16 +524,16 @@ english: T_DECLARE T_IDENT T_AS english_declaration { * over reducing this empty rule; see below. */ storage_func_specs: %prec T_TYPE { $$ = NULL; } -storage_func_specs: declspec_simple storage_func_specs { - ALLOC_DECLSPEC($$, $1); - $$->next = $2; +storage_func_specs: storage_func_specs declspec_simple { + ALLOC_DECLSPEC($$, $2); + $$->next = $1; } type_qual_spec: typespec_noid | qualifier -type_qual_specs: { $$ = NULL; } | type_qual_spec type_qual_specs { - $$ = $1; - $$->next = $2; +type_qual_specs: { $$ = NULL; } | type_qual_specs type_qual_spec { + $$ = $2; + $$->next = $1; } /* @@ -512,9 +542,7 @@ type_qual_specs: { $$ = NULL; } | type_qual_spec type_qual_specs { * together three different specifiers lists. */ post_specs: qualifiers typespec type_qual_specs { - $2->next = $3; - join_specs($2, $1); - $$ = $2; + $$ = join_specs3($1, $2, $3); } english_declaration: storage_func_specs english_declarator post_specs { @@ -536,16 +564,18 @@ english_declarator: { english_function: T_FUNCTION T_RETURNING { ALLOC_FUNCTION($$, NULL, false); -} | T_FUNCTION T_LPAREN english_parameter_list T_RPAREN T_RETURNING { +} | T_FUNCTION T_LPAREN english_parameter_list varargs T_RPAREN T_RETURNING { + $3->u.function.parameters = reverse_decls($3->u.function.parameters); + $3->u.function.variadic = $4; $$ = $3; } -english_parameter_list: english_parameter varargs { - ALLOC_FUNCTION($$, $1, $2); -} | english_parameter T_COMMA english_parameter_list { - $$ = $3; - $1->next = $$->u.function.parameters; - $$->u.function.parameters = $1; +english_parameter_list: english_parameter { + ALLOC_FUNCTION_($$, $1); +} | english_parameter_list T_COMMA english_parameter { + $$ = $1; + $3->next = $$->u.function.parameters; + $$->u.function.parameters = $3; } typedef_name_qual: T_IDENT qualifiers { @@ -592,8 +622,10 @@ english_array: T_VLA T_ARRAY english_vla T_OF { array_length: { $$ = 0; } array_length: T_UINT { - if (!($$ = $1)) - FAIL(_("array length must be positive")); + if (!($$ = $1)) { + cdecl__errmsg(CDECL__EZEROARRAY); + YYERROR; + } } english_vla: T_IDENT | { @@ -617,11 +649,16 @@ const char *cdecl__token_name(unsigned token) return yytname[YYTRANSLATE(token)]; } -static void +/* + * Current versions of GCC (up to 13) want to inline this function into the + * parser even when optimizing for size and the results are not great, so + * try to prevent such inlining. + */ +CDECL__NOINLINE static void yyerror(YYLTYPE *loc, yyscan_t scanner, struct cdecl **out, const char *err) { if (strstr(err, yytname[YYTRANSLATE(T_LEX_ERROR)])) return; - cdecl__err(CDECL_ENOPARSE, "%s", err); + cdecl__err("%s", err); }