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