]> git.draconx.ca Git - cdecl99.git/blob - src/parse.y
libcdecl: Simplify Bison error message reporting.
[cdecl99.git] / src / parse.y
1 %code top {
2 /*
3  *  Parser for C declarations.
4  *  Copyright © 2011-2012, 2021, 2023 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 #define FAIL(msg) do { \
40         yyerror(&yylloc, NULL, NULL, msg); \
41         YYERROR; \
42 } while (0)
43
44 #define ALLOC(ptr, size) do { \
45         (ptr) = malloc(size); \
46         if (!(ptr)) { \
47                 cdecl__errmsg(CDECL__ENOMEM); \
48                 YYERROR; \
49         } \
50 } while (0)
51
52 #define ALLOC_STRUCT(ptr, type, ...) do { \
53         ALLOC(ptr, sizeof (type)); \
54         *(ptr) = (type) { __VA_ARGS__ }; \
55 } while (0)
56
57 /*
58  * With the postprocessing performed by fix-yytname.awk, all the symbol
59  * name strings can be used directly in error messages and there is no
60  * need for any string processing.
61  */
62 #define yytnamerr(a, b) cdecl__strlcpy(a, b, (a) ? INT_MAX : 0)
63 %}
64
65 %code requires {
66 #include <inttypes.h>
67 }
68
69 %code provides {
70 void cdecl__free(struct cdecl *);
71 int cdecl__yyparse(void *scanner, struct cdecl **out);
72 const char *cdecl__token_name(unsigned token);
73 }
74
75 %union {
76         uintmax_t uintval;
77         unsigned spectype;
78         _Bool boolval;
79         char *strval;
80         struct cdecl_declspec *declspec;
81         struct cdecl_declarator *declarator;
82         struct cdecl *decl;
83 }
84
85 %{
86 static void yyerror(YYLTYPE *, yyscan_t, struct cdecl **, const char *);
87 static void free_decl(struct cdecl *);
88
89 static void free_declspec(struct cdecl_declspec *x)
90 {
91         struct cdecl_declspec *p;
92         while (x) {
93                 p = x->next;
94                 free(x->ident);
95                 free(x);
96                 x = p;
97         }
98 }
99
100 static void free_declarator(struct cdecl_declarator *x)
101 {
102         struct cdecl_declarator *p;
103
104         while (x) {
105                 p = x->child;
106
107                 switch (x->type) {
108                 case CDECL_DECL_NULL:
109                         break;
110                 case CDECL_DECL_IDENT:
111                         free(x->u.ident);
112                         break;
113                 case CDECL_DECL_POINTER:
114                         free_declspec(x->u.pointer.qualifiers);
115                         break;
116                 case CDECL_DECL_ARRAY:
117                         free(x->u.array.vla);
118                         break;
119                 case CDECL_DECL_FUNCTION:
120                         free_decl(x->u.function.parameters);
121                         break;
122                 default:
123                         assert(0);
124                 }
125
126                 free(x);
127                 x = p;
128         }
129 }
130
131 static void free_decl(struct cdecl *x)
132 {
133         struct cdecl *p;
134
135         while (x) {
136                 p = x->next;
137
138                 /* The specifiers may be shared by an entire chain. */
139                 if (!p || p->specifiers != x->specifiers)
140                         free_declspec(x->specifiers);
141
142                 free_declarator(x->declarators);
143                 free(x);
144                 x = p;
145         }
146 }
147
148 void cdecl__free(struct cdecl *decl)
149 {
150         free_decl(decl);
151 }
152
153 /*
154  * Join two declaration specifier lists into a single list, with "a" being the
155  * head of the new list.
156  *
157  * The list "a" is assumed to be nonempty.
158  */
159 static void join_specs(struct cdecl_declspec *a, struct cdecl_declspec *b)
160 {
161         while (a->next)
162                 a = a->next;
163         a->next = b;
164 }
165
166 /*
167  * Alter an abstract declarator (type name) to declare an identifier instead,
168  * used by the English parser rules to reduce "identifier as type" sequences.
169  */
170 static struct cdecl *insert_identifier(struct cdecl *decl, char *ident)
171 {
172         struct cdecl_declarator *d = decl->declarators;
173
174         while (d->child)
175                 d = d->child;
176
177         d->type = CDECL_DECL_IDENT;
178         d->u.ident = ident;
179
180         return decl;
181 }
182 %}
183
184 %destructor { free($$); }            <strval>
185 %destructor { free_declspec($$); }   <declspec>
186 %destructor { free_declarator($$); } <declarator>
187 %destructor { free_decl($$); }       <decl>
188
189 /* Magic tokens */
190 %token T_LEX_ERROR
191 %token T_ENGLISH
192
193 %token <strval> T_IDENT "identifier"
194 %token <uintval> T_UINT "integer constant"
195
196 %token T_SEMICOLON ";"
197 %token T_ASTERISK  "*"
198 %token T_LPAREN    "("
199 %token T_RPAREN    ")"
200 %token T_LBRACKET  "["
201 %token T_RBRACKET  "]"
202 %token T_COMMA     ","
203 %token T_ELLIPSIS  "..."
204
205 %token <spectype> T_TYPEDEF   "typedef"
206 %token <spectype> T_EXTERN    "extern"
207 %token <spectype> T_STATIC    "static"
208 %token <spectype> T_AUTO      "auto"
209 %token <spectype> T_REGISTER  "register"
210
211 %token <spectype> T_INLINE    "inline"
212
213 %token <spectype> T_RESTRICT  "restrict"
214 %token <spectype> T_VOLATILE  "volatile"
215 %token <spectype> T_CONST     "const"
216
217 %token <spectype> T_VOID      "void"
218 %token <spectype> T_CHAR      "char"
219 %token <spectype> T_SHORT     "short"
220 %token <spectype> T_INT       "int"
221 %token <spectype> T_LONG      "long"
222 %token <spectype> T_FLOAT     "float"
223 %token <spectype> T_DOUBLE    "double"
224 %token <spectype> T_SIGNED    "signed"
225 %token <spectype> T_UNSIGNED  "unsigned"
226 %token <spectype> T_BOOL      "_Bool"
227 %token <spectype> T_COMPLEX   "_Complex"
228 %token <spectype> T_IMAGINARY "_Imaginary"
229
230 %token <spectype> T_STRUCT    "struct"
231 %token <spectype> T_UNION     "union"
232 %token <spectype> T_ENUM      "enum"
233
234 /*
235  * English keywords.
236  */
237 %token T_TYPE      "type"
238 %token T_DECLARE   "declare"
239 %token T_POINTER   "pointer"
240 %token T_FUNCTION  "function"
241 %token T_RETURNING "returning"
242 %token T_ARRAY     "array"
243 %token T_TO        "to"
244 %token T_OF        "of"
245 %token T_AS        "as"
246 %token T_VLA       "variable-length"
247
248 %type <strval>     vla_ident
249 %type <uintval>    array_length
250 %type <boolval>    varargs
251 %type <spectype>   declspec_simple qualifier_simple
252 %type <spectype>   typespec_simple typespec_tagged
253 %type <declspec>   declspec_notype declspec_noid typespec_noid typespec
254 %type <declspec>   qualifier qualifiers
255 %type <declspec>   declspecs declspecs_noid
256 %type <declarator> direct_declarator declarator pointer array parens postfix
257 %type <declarator> direct_declarator_ish declarator_ish parameter_type_list
258 %type <decl>       declaration declarators declarator_wrap
259 %type <decl>       parameter
260
261 %type <strval>     english_vla
262 %type <declspec>   storage_func_specs post_specs
263 %type <declspec>   type_qual_spec type_qual_specs typedef_name_qual
264 %type <declarator> english_declarator english_array english_function
265 %type <declarator> english_parameter_list null_decl
266 %type <decl>       english english_declaration
267 %type <decl>       english_parameter
268
269 /*
270  * Harmless shift/reduce conflicts in english_parameter.  See comments below
271  * for more details.
272  */
273 %expect 2
274
275 %%
276
277 input: T_ENGLISH english {
278         *out = $2;
279 } | declaration {
280         *out = $1;
281 };
282
283 semi: | T_SEMICOLON
284
285 declaration: declspecs declarators semi {
286         $$ = $2;
287         $$->specifiers = $1;
288 };
289
290 /*
291  * We support parsing declarations using arbitrary identifiers as type
292  * specifiers (a la C typedef).  To avoid confusion with identifiers that
293  * may also be used as declarators, note the following:
294  *
295  *  (a) Every valid C declaration must have at least one type specifier, and
296  *  (b) Valid declarations with typedef names have exactly one type specifier.
297  *
298  * So the rule applied when parsing specifiers is: an identifier is a type
299  * specifier only if we have not yet seen any type specifiers whatsoever
300  * (within one declaration specifier list).
301  *
302  * Treating identifiers as type specifiers by default can lead to strange and
303  * unexpected parses; libcdecl applies a simplification step to the resulting
304  * parse tree afterwards.
305  */
306 declspecs: declspec_notype declspecs {
307         $$ = $1;
308         $$->next = $2;
309 } | typespec declspecs_noid {
310         $$ = $1;
311         $$->next = $2;
312 }
313
314 declspecs_noid: { $$ = NULL; } | declspec_noid declspecs_noid {
315         $$ = $1;
316         $$->next = $2;
317 }
318
319 qualifiers: { $$ = NULL; } | qualifiers qualifier {
320         $$ = $2;
321         $$->next = $1;
322 }
323
324 declarators: declarator_wrap | declarator_wrap T_COMMA declarators {
325         $$ = $1;
326         $$->next = $3;
327 }
328
329 declarator_wrap: declarator {
330         ALLOC_STRUCT($$, struct cdecl, .declarators = $1);
331 }
332
333 declspec_simple: T_AUTO
334         | T_TYPEDEF
335         | T_EXTERN
336         | T_STATIC
337         | T_REGISTER
338         | T_INLINE
339
340 typespec_simple: T_VOID
341         | T_CHAR
342         | T_SHORT
343         | T_INT
344         | T_LONG
345         | T_FLOAT
346         | T_DOUBLE
347         | T_SIGNED
348         | T_UNSIGNED
349         | T_BOOL
350         | T_COMPLEX
351         | T_IMAGINARY
352
353 typespec_tagged: T_STRUCT | T_UNION | T_ENUM | { $$ = CDECL_TYPE_IDENT; }
354
355 qualifier_simple: T_CONST
356         | T_RESTRICT
357         | T_VOLATILE
358
359 declspec_notype: qualifier | declspec_simple {
360         ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1);
361 }
362
363 typespec_noid: typespec_simple {
364         ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1);
365 }
366
367 qualifier: qualifier_simple {
368         ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1);
369 }
370
371 typespec: typespec_noid | typespec_tagged T_IDENT {
372         ALLOC_STRUCT($$, struct cdecl_declspec,
373                 .type  = $1,
374                 .ident = $2);
375 }
376
377 declspec_noid: declspec_notype | typespec_noid
378
379 vla_ident: T_IDENT | T_ASTERISK {
380         ALLOC($$, sizeof "");
381         *$$ = 0;
382 }
383
384 array: T_LBRACKET array_length T_RBRACKET {
385         ALLOC_STRUCT($$, struct cdecl_declarator,
386                 .type = CDECL_DECL_ARRAY,
387                 .u.array.length = $2);
388 } | T_LBRACKET vla_ident T_RBRACKET {
389         ALLOC_STRUCT($$, struct cdecl_declarator,
390                 .type = CDECL_DECL_ARRAY,
391                 .u.array.vla = $2);
392 }
393
394 parameter: declspecs declarator {
395         ALLOC_STRUCT($$, struct cdecl,
396                 .specifiers = $1,
397                 .declarators = $2);
398 }
399
400 varargs: { $$ = false; } | T_COMMA T_ELLIPSIS { $$ = true; }
401
402 parameter_type_list: parameter varargs {
403         ALLOC_STRUCT($$, struct cdecl_declarator,
404                 .type = CDECL_DECL_FUNCTION,
405                 .u.function.parameters = $1,
406                 .u.function.variadic = $2);
407 } | parameter T_COMMA parameter_type_list {
408         $$ = $3;
409         $1->next = $$->u.function.parameters;
410         $$->u.function.parameters = $1;
411 }
412
413 parens: T_LPAREN parameter_type_list T_RPAREN {
414         $$ = $2;
415 } | T_LPAREN declarator_ish T_RPAREN {
416         ALLOC_STRUCT($$, struct cdecl_declarator,
417                 .type = CDECL_DECL_FUNCTION);
418         ALLOC_STRUCT($$->u.function.parameters, struct cdecl,
419                 .declarators = $2);
420 }
421
422 pointer: T_ASTERISK qualifiers direct_declarator {
423         ALLOC_STRUCT($$, struct cdecl_declarator,
424                 .type = CDECL_DECL_POINTER,
425                 .u.pointer.qualifiers = $2,
426                 .child = $3);
427 } | T_ASTERISK qualifiers pointer {
428         ALLOC_STRUCT($$, struct cdecl_declarator,
429                 .type = CDECL_DECL_POINTER,
430                 .u.pointer.qualifiers = $2,
431                 .child = $3);
432 }
433
434 declarator: direct_declarator | pointer
435 declarator_ish: direct_declarator_ish | pointer
436 postfix: array | parens
437
438 direct_declarator_ish: {
439         ALLOC_STRUCT($$, struct cdecl_declarator,
440                 .type = CDECL_DECL_NULL);
441 } | direct_declarator_ish postfix {
442         $$ = $2;
443         $$->child = $1;
444 }
445
446 direct_declarator: {
447         ALLOC_STRUCT($$, struct cdecl_declarator,
448                 .type = CDECL_DECL_NULL);
449 } | T_IDENT {
450         ALLOC_STRUCT($$, struct cdecl_declarator,
451                 .type = CDECL_DECL_IDENT,
452                 .u.ident = $1);
453 } | direct_declarator postfix {
454         $$ = $2;
455         $$->child = $1;
456 }
457
458 english: T_DECLARE T_IDENT T_AS english_declaration {
459         $$ = insert_identifier($4, $2);
460 } | T_TYPE english_declaration {
461         $$ = $2;
462 }
463
464 storage_func_specs: { $$ = NULL; } | declspec_simple storage_func_specs {
465         ALLOC_STRUCT($$, struct cdecl_declspec,
466                 .type = $1,
467                 .next = $2);
468 }
469
470 type_qual_spec: typespec_noid | qualifier
471
472 type_qual_specs: { $$ = NULL; } | type_qual_spec type_qual_specs {
473         $$ = $1;
474         $$->next = $2;
475 }
476
477 /*
478  * The "qualifiers" nonterminal needs to be used here to avoid shift/reduce
479  * conflicts with pointer declarators.  So we end up needing to stitch
480  * together three different specifiers lists.
481  */
482 post_specs: qualifiers typespec type_qual_specs {
483         $2->next = $3;
484         join_specs($2, $1);
485         $$ = $2;
486 }
487
488 english_declaration: storage_func_specs english_declarator post_specs {
489         join_specs($3, $1);
490         ALLOC_STRUCT($$, struct cdecl,
491                 .specifiers = $3,
492                 .declarators = $2);
493 }
494
495 english_declarator: {
496         ALLOC_STRUCT($$, struct cdecl_declarator,
497                 .type = CDECL_DECL_NULL);
498 } | english_declarator qualifiers T_POINTER T_TO {
499         ALLOC_STRUCT($$, struct cdecl_declarator,
500                 .type = CDECL_DECL_POINTER,
501                 .child = $1,
502                 .u.pointer.qualifiers = $2);
503 } | english_declarator english_array {
504         $$ = $2;
505         $$->child = $1;
506 } | english_declarator english_function {
507         $$ = $2;
508         $$->child = $1;
509 }
510
511 english_function: T_FUNCTION T_RETURNING {
512         ALLOC_STRUCT($$, struct cdecl_declarator,
513                 .type = CDECL_DECL_FUNCTION,
514                 .u.function.parameters = NULL);
515 } | T_FUNCTION T_LPAREN english_parameter_list T_RPAREN T_RETURNING {
516         $$ = $3;
517 }
518
519 english_parameter_list: english_parameter varargs {
520         ALLOC_STRUCT($$, struct cdecl_declarator,
521                 .type = CDECL_DECL_FUNCTION,
522                 .u.function.parameters = $1,
523                 .u.function.variadic = $2);
524 } | english_parameter T_COMMA english_parameter_list {
525         $$ = $3;
526         $1->next = $$->u.function.parameters;
527         $$->u.function.parameters = $1;
528 }
529
530 typedef_name_qual: T_IDENT qualifiers {
531         ALLOC_STRUCT($$, struct cdecl_declspec,
532                 .type = CDECL_TYPE_IDENT,
533                 .ident = $1,
534                 .next = $2);
535 }
536
537 null_decl: {
538         ALLOC_STRUCT($$, struct cdecl_declarator,
539                 .type = CDECL_DECL_NULL);
540 }
541
542 /*
543  * There is a small shift/reduce conflict here.  An unadorned identifier
544  * as the first thing in the parameter might be a typedef name deep in the
545  * first english_declaration (thus empty storage_func_specs and empty
546  * english_declarator need to be reduced) or it might be the identifier
547  * before the "as" (thus the identifier should be shifted).
548  *
549  * The typedef name conflict is the only issue, so treating it as a special
550  * case makes the shift harmless.
551  */
552 english_parameter: english_declaration | typedef_name_qual null_decl {
553         ALLOC_STRUCT($$, struct cdecl,
554                 .specifiers = $1,
555                 .declarators = $2);
556 } | T_IDENT T_AS english_declaration {
557         $$ = insert_identifier($3, $1);
558 }
559
560 english_array: T_VLA T_ARRAY english_vla T_OF {
561         ALLOC_STRUCT($$, struct cdecl_declarator,
562                 .type = CDECL_DECL_ARRAY,
563                 .u.array.vla = $3);
564 } | T_ARRAY array_length T_OF {
565         ALLOC_STRUCT($$, struct cdecl_declarator,
566                 .type = CDECL_DECL_ARRAY,
567                 .u.array.length = $2);
568 }
569
570 array_length: { $$ = 0; }
571 array_length: T_UINT {
572         if (!($$ = $1))
573                 FAIL(_("array length must be positive"));
574 }
575
576 english_vla: T_IDENT | {
577         ALLOC($$, sizeof "");
578         *$$ = 0;
579 }
580
581 %%
582
583 /*
584  * Expose the token string table to the rest of the library, in order to
585  * produce strings that match parser keywords.
586  *
587  * In order for this to work properly, the Bison output must be postprocessed
588  * by fix-yytname.awk to remove pointless quotation marks from the keyword
589  * strings.
590  */
591 const char *cdecl__token_name(unsigned token)
592 {
593         return yytname[YYTRANSLATE(token)];
594 }
595
596 static void
597 yyerror(YYLTYPE *loc, yyscan_t scanner, struct cdecl **out, const char *err)
598 {
599         if (strstr(err, yytname[YYTRANSLATE(T_LEX_ERROR)]))
600                 return;
601
602         cdecl__err(CDECL_ENOPARSE, "%s", err);
603 }