]> git.draconx.ca Git - cdecl99.git/blob - src/parse.y
0a12f3f9e7aa6cdeacaba331afd5785bc7d9da35
[cdecl99.git] / src / parse.y
1 %code top {
2 /*
3  *  Parser for C declarations.
4  *  Copyright © 2011-2012, 2021, 2023-2024 Nick Bowler
5  *
6  *  This program is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 }
20
21 %name-prefix "cdecl__yy"
22 %parse-param {void *scanner}
23 %parse-param {struct cdecl **out}
24 %lex-param {yyscan_t scanner}
25 %define api.pure
26 %error-verbose
27 %locations
28
29 %{
30 #include <config.h>
31 #include <assert.h>
32 #include <stdbool.h>
33
34 #include "scan.h"
35 #include "cdecl.h"
36 #include "cdecl-internal.h"
37 #include "errmsg.h"
38
39 /*
40  * Allocate a parse tree node via cdecl__alloc_item.
41  *
42  * - m1 specifies the item's union member to assign to ptr, which selects the
43  *   type of node to allocate.
44  *
45  * - m2 specifies the "next" or "child" member, which is initialized to a null
46  *   pointer.  The cdecl__alloc_item function sets the declarator.child member
47  *   to null; we explicitly copy this null pointer to the returned union member
48  *   to avoid type punning.  It is hoped that compilers will notice that these
49  *   pointers are at the same offset therefore the assignment can be elided.
50  *
51  * The resulting pointer can be passed directly to free, as the union is the
52  * first member of the parse_item structure.
53  *
54  * Use the wrapper macros below instead of this one.
55  */
56 #define ALLOC_ITEM(ptr, m1, m2) do { \
57         struct parse_item *item; \
58         if (!(item = cdecl__alloc_item(0))) \
59                 YYERROR; \
60         item->u.m1.m2 = (void *)item->u.declarator.child; \
61         (ptr) = &item->u.m1; \
62 } while (0)
63
64 /* Wrappers for ALLOC_ITEM to allocate various kinds of parser structures. */
65 #define ALLOC_ITEM_DECLARATOR(ptr) ALLOC_ITEM(ptr, declarator, child)
66 #define ALLOC_ITEM_DECLSPEC(ptr)   ALLOC_ITEM(ptr, declspec, next)
67 #define ALLOC_ITEM_DECL(ptr)       ALLOC_ITEM(ptr, decl, next)
68
69 #define ALLOC_FUNCTION(ptr, parameters_, variadic_) do { \
70         ALLOC_ITEM_DECLARATOR(ptr); \
71         (ptr)->type = CDECL_DECL_FUNCTION; \
72         (ptr)->u.function.parameters = parameters_; \
73         (ptr)->u.function.variadic = variadic_; \
74 } while (0)
75
76 #define ALLOC_ARRAY(ptr, length_) do { \
77         ALLOC_ITEM_DECLARATOR(ptr); \
78         (ptr)->type = CDECL_DECL_ARRAY; \
79         (ptr)->u.array.vla = NULL; \
80         (ptr)->u.array.length = length_; \
81 } while (0)
82
83 #define ALLOC_POINTER(ptr, qualifiers_, child_) do { \
84         ALLOC_ITEM_DECLARATOR(ptr); \
85         (ptr)->child = child_; \
86         (ptr)->type = CDECL_DECL_POINTER; \
87         (ptr)->u.pointer.qualifiers = qualifiers_; \
88 } while (0)
89
90 #define ALLOC_DECLSPEC(ptr, type_) do { \
91         ALLOC_ITEM_DECLSPEC(ptr); \
92         (ptr)->type = type_; \
93         (ptr)->ident = NULL; \
94 } while (0)
95
96 #define ALLOC_DECL(ptr, specifiers_, declarators_) do { \
97         ALLOC_ITEM_DECL(ptr); \
98         (ptr)->specifiers = specifiers_; \
99         (ptr)->declarators = declarators_; \
100 } while (0)
101
102 /*
103  * With the postprocessing performed by fix-yytname.awk, all the symbol
104  * name strings can be used directly in error messages and there is no
105  * need for any string processing.
106  */
107 #define yytnamerr(a, b) ( (a) ? yytnamerr_copy(a, b) \
108                               : strlen(b) )
109
110 static size_t yytnamerr_copy(char *dst, const char *src)
111 {
112         return cdecl__strlcpy(dst, src, strlen(src)+1);
113 }
114 %}
115
116 %code requires {
117 #include <inttypes.h>
118 #include <stdbool.h>
119 }
120
121 %code provides {
122 void cdecl__free(struct cdecl *);
123 int cdecl__yyparse(void *scanner, struct cdecl **out);
124 const char *cdecl__token_name(unsigned token);
125 }
126
127 %union {
128         uintmax_t uintval;
129         unsigned spectype;
130         bool boolval;
131         struct cdecl_declspec *declspec;
132         struct cdecl_declarator *declarator;
133         struct cdecl *decl;
134         struct parse_item *item;
135 }
136
137 %{
138 static void yyerror(YYLTYPE *, yyscan_t, struct cdecl **, const char *);
139 static void free_decl(struct cdecl *);
140
141 static void free_declspec(struct cdecl_declspec *x)
142 {
143         struct cdecl_declspec *p;
144         while (x) {
145                 p = x->next;
146                 free(x);
147                 x = p;
148         }
149 }
150
151 static void free_declarator(struct cdecl_declarator *x)
152 {
153         struct cdecl_declarator *p;
154
155         while (x) {
156                 p = x->child;
157
158                 switch (x->type) {
159                 case CDECL_DECL_NULL:
160                         x = NULL;
161                 case CDECL_DECL_IDENT:
162                 case CDECL_DECL_ARRAY:
163                         break;
164                 case CDECL_DECL_POINTER:
165                         free_declspec(x->u.pointer.qualifiers);
166                         break;
167                 case CDECL_DECL_FUNCTION:
168                         free_decl(x->u.function.parameters);
169                         break;
170                 default:
171                         assert(0);
172                 }
173
174                 free(x);
175                 x = p;
176         }
177 }
178
179 static void free_decl(struct cdecl *x)
180 {
181         struct cdecl *p;
182
183         while (x) {
184                 p = x->next;
185
186                 /* The specifiers may be shared by an entire chain. */
187                 if (!p || p->specifiers != x->specifiers)
188                         free_declspec(x->specifiers);
189
190                 free_declarator(x->declarators);
191                 free(x);
192                 x = p;
193         }
194 }
195
196 void cdecl__free(struct cdecl *decl)
197 {
198         free_decl(decl);
199 }
200
201 /*
202  * Join two declaration specifier lists into a single list, with "a" being the
203  * head of the new list.
204  *
205  * The list "a" is assumed to be nonempty.
206  */
207 static void join_specs(struct cdecl_declspec *a, struct cdecl_declspec *b)
208 {
209         while (a->next)
210                 a = a->next;
211         a->next = b;
212 }
213
214 /*
215  * Join three specifier lists into a single list, and returns the head of
216  * the new list.
217  *
218  * The list "b" is assumed to be a singleton list.
219  */
220 static struct cdecl_declspec *join_specs3(struct cdecl_declspec *a,
221                                           struct cdecl_declspec *b,
222                                           struct cdecl_declspec *c)
223 {
224         b->next = c;
225         join_specs(b, a);
226         return b;
227 }
228
229 /*
230  * Reverse the order of a "struct cdecl" list, and return the new first
231  * element of the list (i.e., the last element of the original list).
232  */
233 static struct cdecl *reverse_decls(struct cdecl *decl)
234 {
235         struct cdecl *prev, *next;
236
237         for (prev = NULL; decl; decl = next) {
238                 next = decl->next;
239                 decl->next = prev;
240                 prev = decl;
241         }
242
243         return prev;
244 }
245
246 /*
247  * Alter an abstract declarator (type name) to declare an identifier instead,
248  * used by the English parser rules to reduce "identifier as type" sequences.
249  */
250 static struct cdecl *
251 insert_identifier(struct cdecl *decl, struct parse_item *ident)
252 {
253         struct cdecl_declarator *d, **p = &decl->declarators;
254
255         while ((d = *p)->child)
256                 p = &d->child;
257
258         *p = &ident->u.declarator;
259         return decl;
260 }
261
262 static struct cdecl_declarator *nulldecl(void)
263 {
264         static const struct cdecl_declarator nulldecl = {0};
265         return (void *)&nulldecl;
266 }
267 #define NULLDECL (nulldecl())
268
269 %}
270
271 %destructor { free($$); }            <item>
272 %destructor { free_declspec($$); }   <declspec>
273 %destructor { free_declarator($$); } <declarator>
274 %destructor { free_decl($$); }       <decl>
275
276 /* Magic tokens */
277 %token T_LEX_ERROR
278
279 %token <item>    T_IDENT "identifier"
280 %token <uintval> T_UINT  "integer constant"
281
282 %token T_SEMICOLON ";"
283 %token T_ASTERISK  "*"
284 %token T_LPAREN    "("
285 %token T_RPAREN    ")"
286 %token T_LBRACKET  "["
287 %token T_RBRACKET  "]"
288 %token T_COMMA     ","
289 %token T_ELLIPSIS  "..."
290
291 %token <spectype> T_TYPEDEF   "typedef"
292 %token <spectype> T_EXTERN    "extern"
293 %token <spectype> T_STATIC    "static"
294 %token <spectype> T_AUTO      "auto"
295 %token <spectype> T_REGISTER  "register"
296
297 %token <spectype> T_INLINE    "inline"
298
299 %token <spectype> T_RESTRICT  "restrict"
300 %token <spectype> T_VOLATILE  "volatile"
301 %token <spectype> T_CONST     "const"
302
303 %token <spectype> T_VOID      "void"
304 %token <spectype> T_CHAR      "char"
305 %token <spectype> T_SHORT     "short"
306 %token <spectype> T_INT       "int"
307 %token <spectype> T_LONG      "long"
308 %token <spectype> T_FLOAT     "float"
309 %token <spectype> T_DOUBLE    "double"
310 %token <spectype> T_SIGNED    "signed"
311 %token <spectype> T_UNSIGNED  "unsigned"
312 %token <spectype> T_BOOL      "_Bool"
313 %token <spectype> T_COMPLEX   "_Complex"
314 %token <spectype> T_IMAGINARY "_Imaginary"
315
316 %token <spectype> T_STRUCT    "struct"
317 %token <spectype> T_UNION     "union"
318 %token <spectype> T_ENUM      "enum"
319
320 /*
321  * English keywords.
322  */
323 %token T_TYPE      "type"
324 %token T_DECLARE   "declare"
325 %token T_POINTER   "pointer"
326 %token T_FUNCTION  "function"
327 %token T_RETURNING "returning"
328 %token T_ARRAY     "array"
329 %token T_TO        "to"
330 %token T_OF        "of"
331 %token T_AS        "as"
332 %token T_VLA       "variable-length"
333
334 %type <item>       vla_ident
335 %type <uintval>    array_length
336 %type <boolval>    varargs
337 %type <spectype>   declspec_simple qualifier_simple
338 %type <spectype>   typespec_simple typespec_tagged
339 %type <declspec>   declspec_notype declspec_noid typespec_noid typespec
340 %type <declspec>   qualifier qualifiers
341 %type <declspec>   declspecs declspecs_notype declspecs_noid
342 %type <declarator> direct_declarator declarator pointer array parens postfix
343 %type <declarator> direct_declarator_ish declarator_ish parameter_type_list
344 %type <decl>       cdecl declaration declarators declarator_wrap parameter
345
346 %type <item>       english_vla
347 %type <declspec>   storage_func_specs post_specs
348 %type <declspec>   type_qual_spec type_qual_specs typedef_name_qual
349 %type <declarator> english_declarator english_array english_function
350 %type <declarator> english_parameter_list null_decl
351 %type <decl>       english english_declaration english_parameter
352
353 /* Precedence declaration to avoid conflict in english_parameter; see below. */
354 %right T_TYPE
355 %right T_IDENT
356
357 %%
358
359 input: cdecl { *out = $1; }
360 cdecl: english | declaration
361
362 semi: | T_SEMICOLON
363 declaration: declspecs declarators semi {
364         $$ = reverse_decls($2);
365         $$->specifiers = $1;
366 };
367
368 /*
369  * We support parsing declarations using arbitrary identifiers as type
370  * specifiers (a la C typedef).  To avoid confusion with identifiers that
371  * may also be used as declarators, note the following:
372  *
373  *  (a) Every valid C declaration must have at least one type specifier, and
374  *  (b) Valid declarations with typedef names have exactly one type specifier.
375  *
376  * So the rule applied when parsing specifiers is: an identifier is a type
377  * specifier only if we have not yet seen any type specifiers whatsoever
378  * (within one declaration specifier list).
379  *
380  * Treating identifiers as type specifiers by default can lead to strange and
381  * unexpected parses; libcdecl applies a simplification step to the resulting
382  * parse tree afterwards.
383  */
384 declspecs: declspecs_notype typespec declspecs_noid {
385         $$ = join_specs3($1, $2, $3);
386 }
387
388 declspecs_notype: { $$ = NULL; } | declspecs_notype declspec_notype {
389         $$ = $2;
390         $$->next = $1;
391 }
392
393 declspecs_noid: { $$ = NULL; } | declspecs_noid declspec_noid {
394         $$ = $2;
395         $$->next = $1;
396 }
397
398 qualifiers: { $$ = NULL; } | qualifiers qualifier {
399         $$ = $2;
400         $$->next = $1;
401 }
402
403 declarators: declarator_wrap | declarators T_COMMA declarator_wrap {
404         $$ = $3;
405         $$->next = $1;
406 }
407
408 declarator_wrap: declarator {
409         ALLOC_DECL($$, NULL, $1);
410 }
411
412 declspec_simple: T_AUTO
413         | T_TYPEDEF
414         | T_EXTERN
415         | T_STATIC
416         | T_REGISTER
417         | T_INLINE
418
419 typespec_simple: T_VOID
420         | T_CHAR
421         | T_SHORT
422         | T_INT
423         | T_LONG
424         | T_FLOAT
425         | T_DOUBLE
426         | T_SIGNED
427         | T_UNSIGNED
428         | T_BOOL
429         | T_COMPLEX
430         | T_IMAGINARY
431
432 typespec_tagged: T_STRUCT | T_UNION | T_ENUM | { $$ = CDECL_TYPE_IDENT; }
433
434 qualifier_simple: T_CONST
435         | T_RESTRICT
436         | T_VOLATILE
437
438 declspec_notype: qualifier | declspec_simple { ALLOC_DECLSPEC($$, $1); }
439 typespec_noid: typespec_simple { ALLOC_DECLSPEC($$, $1); }
440 qualifier: qualifier_simple { ALLOC_DECLSPEC($$, $1); }
441
442 typespec: typespec_noid | typespec_tagged T_IDENT {
443         /* Compiler should be able to elide this assignment. */
444         $2->u.declspec.ident = $2->u.declarator.u.ident;
445
446         $$ = &$2->u.declspec;
447         $$->type = $1;
448 }
449
450 declspec_noid: declspec_notype | typespec_noid
451
452 vla_ident: T_IDENT | T_ASTERISK {
453         if (!($$ = cdecl__alloc_item(1)))
454                 YYERROR;
455         *$$->s = 0;
456 }
457
458 array: T_LBRACKET array_length T_RBRACKET {
459         ALLOC_ARRAY($$, $2);
460 } | T_LBRACKET vla_ident T_RBRACKET {
461         $$ = &$2->u.declarator;
462         $$->type = CDECL_DECL_ARRAY;
463         $$->u.array.vla = $$->u.ident;
464         $$->u.array.length = 0;
465 }
466
467 parameter: declspecs declarator {
468         ALLOC_DECL($$, $1, $2);
469 }
470
471 varargs: { $$ = false; } | T_COMMA T_ELLIPSIS { $$ = true; }
472
473 parameter_type_list: parameter varargs {
474         ALLOC_FUNCTION($$, $1, $2);
475 } | parameter T_COMMA parameter_type_list {
476         $$ = $3;
477         $1->next = $$->u.function.parameters;
478         $$->u.function.parameters = $1;
479 }
480
481 parens: T_LPAREN parameter_type_list T_RPAREN {
482         $$ = $2;
483 } | T_LPAREN declarator_ish T_RPAREN {
484         struct cdecl *fake_params;
485
486         ALLOC_DECL(fake_params, NULL, $2);
487         ALLOC_FUNCTION($$, fake_params, false);
488 }
489
490 pointer: T_ASTERISK qualifiers direct_declarator {
491         ALLOC_POINTER($$, $2, $3);
492 } | T_ASTERISK qualifiers pointer {
493         ALLOC_POINTER($$, $2, $3);
494 }
495
496 declarator: direct_declarator | pointer
497 declarator_ish: direct_declarator_ish | pointer
498 postfix: array | parens
499
500 direct_declarator_ish: {
501         $$ = NULLDECL;
502 } | direct_declarator_ish postfix {
503         $$ = $2;
504         $$->child = $1;
505 }
506
507 direct_declarator: {
508         $$ = NULLDECL;
509 } | T_IDENT {
510         $$ = &$1->u.declarator;
511 } | direct_declarator postfix {
512         $$ = $2;
513         $$->child = $1;
514 }
515
516 english: T_DECLARE T_IDENT T_AS english_declaration {
517         $$ = insert_identifier($4, $2);
518 } | T_TYPE english_declaration {
519         $$ = $2;
520 }
521
522 /*
523  * We use a precedence declaration to prefer shifting an identifier
524  * over reducing this empty rule; see below.
525  */
526 storage_func_specs: %prec T_TYPE { $$ = NULL; }
527 storage_func_specs: storage_func_specs declspec_simple {
528         ALLOC_DECLSPEC($$, $2);
529         $$->next = $1;
530 }
531
532 type_qual_spec: typespec_noid | qualifier
533
534 type_qual_specs: { $$ = NULL; } | type_qual_specs type_qual_spec {
535         $$ = $2;
536         $$->next = $1;
537 }
538
539 /*
540  * The "qualifiers" nonterminal needs to be used here to avoid shift/reduce
541  * conflicts with pointer declarators.  So we end up needing to stitch
542  * together three different specifiers lists.
543  */
544 post_specs: qualifiers typespec type_qual_specs {
545         $$ = join_specs3($1, $2, $3);
546 }
547
548 english_declaration: storage_func_specs english_declarator post_specs {
549         join_specs($3, $1);
550         ALLOC_DECL($$, $3, $2);
551 }
552
553 english_declarator: {
554         $$ = NULLDECL;
555 } | english_declarator qualifiers T_POINTER T_TO {
556         ALLOC_POINTER($$, $2, $1);
557 } | english_declarator english_array {
558         $$ = $2;
559         $$->child = $1;
560 } | english_declarator english_function {
561         $$ = $2;
562         $$->child = $1;
563 }
564
565 english_function: T_FUNCTION T_RETURNING {
566         ALLOC_FUNCTION($$, NULL, false);
567 } | T_FUNCTION T_LPAREN english_parameter_list T_RPAREN T_RETURNING {
568         $$ = $3;
569 }
570
571 english_parameter_list: english_parameter varargs {
572         ALLOC_FUNCTION($$, $1, $2);
573 } | english_parameter T_COMMA english_parameter_list {
574         $$ = $3;
575         $1->next = $$->u.function.parameters;
576         $$->u.function.parameters = $1;
577 }
578
579 typedef_name_qual: T_IDENT qualifiers {
580         /* Compiler should be able to elide this assignment. */
581         $1->u.declspec.ident = $1->u.declarator.u.ident;
582
583         $$ = &$1->u.declspec;
584         $$->type = CDECL_TYPE_IDENT;
585         $$->next = $2;
586 }
587
588 null_decl: {
589         $$ = NULLDECL;
590 }
591
592 /*
593  * There is a shift/reduce conflict here when an identifier appears as the
594  * first token.  The conflict is between shifting T_IDENT, or reducing the
595  * empty production for storage_func_specs (cf. english_declaration).
596  *
597  *   - In either case, if we reduce, we won't match T_IDENT T_AS since the
598  *     stack now has the extra storage_func_specs nonterminal symbol.
599  *   - And if we shift, we won't match english_declaration since it is
600  *     too late to add storage_func_specs to the stack.
601  *
602  * The only valid input affected by the conflict is a simple type names,
603  * possibly followed by qualifiers.  So the conflict is adequately resolved
604  * by shifting, so long as we have a special-case reduction to handle this.
605  */
606 english_parameter: english_declaration | typedef_name_qual null_decl {
607         ALLOC_DECL($$, $1, $2);
608 } | T_IDENT T_AS english_declaration {
609         $$ = insert_identifier($3, $1);
610 }
611
612 english_array: T_VLA T_ARRAY english_vla T_OF {
613         $$ = &$3->u.declarator;
614         $$->type = CDECL_DECL_ARRAY;
615         $$->u.array.vla = $$->u.ident;
616         $$->u.array.length = 0;
617 } | T_ARRAY array_length T_OF {
618         ALLOC_ARRAY($$, $2);
619 }
620
621 array_length: { $$ = 0; }
622 array_length: T_UINT {
623         if (!($$ = $1)) {
624                 cdecl__errmsg(CDECL__EZEROARRAY);
625                 YYERROR;
626         }
627 }
628
629 english_vla: T_IDENT | {
630         if (!($$ = cdecl__alloc_item(1)))
631                 YYERROR;
632         *$$->s = 0;
633 }
634
635 %%
636
637 /*
638  * Expose the token string table to the rest of the library, in order to
639  * produce strings that match parser keywords.
640  *
641  * In order for this to work properly, the Bison output must be postprocessed
642  * by fix-yytname.awk to remove pointless quotation marks from the keyword
643  * strings.
644  */
645 const char *cdecl__token_name(unsigned token)
646 {
647         return yytname[YYTRANSLATE(token)];
648 }
649
650 /*
651  * Current versions of GCC (up to 13) want to inline this function into the
652  * parser even when optimizing for size and the results are not great, so
653  * try to prevent such inlining.
654  */
655 CDECL__NOINLINE static void
656 yyerror(YYLTYPE *loc, yyscan_t scanner, struct cdecl **out, const char *err)
657 {
658         if (strstr(err, yytname[YYTRANSLATE(T_LEX_ERROR)]))
659                 return;
660
661         cdecl__err("%s", err);
662 }