]> git.draconx.ca Git - cdecl99.git/blob - src/parse.y
Initial support for function declarators.
[cdecl99.git] / src / parse.y
1 %code top {
2 /*
3  *  Parser for C declarations.
4  *  Copyright © 2011 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 %parse-param {struct cdecl **out}
22 %define api.pure
23 %error-verbose
24 %locations
25
26 %{
27 #include <assert.h>
28 #include <stdbool.h>
29
30 #include "scan.h"
31 #include "cdecl.h"
32
33 #define FAIL(msg) do { \
34         yyerror(&yylloc, NULL, msg); \
35         YYERROR; \
36 } while (0)
37
38 #define ALLOC(ptr, size) do { \
39         (ptr) = malloc(size); \
40         if (!(ptr)) \
41                 FAIL("failed to allocate memory"); \
42 } while (0)
43
44 #define ALLOC_STRUCT(ptr, type, ...) do { \
45         ALLOC(ptr, sizeof (type)); \
46         *(ptr) = (type) { __VA_ARGS__ }; \
47 } while (0)
48 %}
49
50 %code requires {
51 #include <inttypes.h>
52 }
53
54 %code provides {
55 void yyerror(YYLTYPE *, struct cdecl **, const char *);
56 int yyparse(struct cdecl **out);
57 }
58
59 %union {
60         uintmax_t uintval;
61         _Bool boolval;
62         char *strval;
63         struct cdecl_declspec *declspec;
64         struct cdecl_declarator *declarator;
65         struct cdecl *decl;
66 }
67
68 %{
69 static void free_decl(struct cdecl *);
70
71 static void free_declspec(struct cdecl_declspec *x)
72 {
73         struct cdecl_declspec *p;
74         while (x) {
75                 p = x->next;
76                 free(x->ident);
77                 free(x);
78                 x = p;
79         }
80 }
81
82 static void free_declarator(struct cdecl_declarator *x)
83 {
84         struct cdecl_declarator *p;
85
86         while (x) {
87                 p = x->child;
88
89                 switch (x->type) {
90                 case CDECL_DECL_NULL:
91                         break;
92                 case CDECL_DECL_IDENT:
93                         free(x->u.ident);
94                         break;
95                 case CDECL_DECL_POINTER:
96                         free_declspec(x->u.pointer.qualifiers);
97                         break;
98                 case CDECL_DECL_ARRAY:
99                         free(x->u.array.vla);
100                         break;
101                 case CDECL_DECL_FUNCTION:
102                         free_decl(x->u.function.parameters);
103                         break;
104                 default:
105                         assert(0);
106                 }
107
108                 free(x);
109                 x = p;
110         }
111 }
112
113 static void free_decl(struct cdecl *x)
114 {
115         struct cdecl *p;
116
117         while (x) {
118                 p = x->next;
119
120                 /* The specifiers may be shared by an entire chain. */
121                 if (!p || p->specifiers != x->specifiers)
122                         free_declspec(x->specifiers);
123
124                 free_declarator(x->declarators);
125                 free(x);
126                 x = p;
127         }
128 }
129
130 void cdecl_free(struct cdecl *decl)
131 {
132         free_decl(decl);
133 }
134 %}
135
136 %destructor { free($$); }            <strval>
137 %destructor { free_declspec($$); }   <declspec>
138 %destructor { free_declarator($$); } <declarator>
139 %destructor { free_decl($$); }       <decl>
140
141 %token T_LEX_ERROR
142
143 %token <strval> T_IDENT "identifier"
144 %token <uintval> T_UINT "integer constant"
145
146 %token T_SEMICOLON ";"
147 %token T_ASTERISK  "*"
148 %token T_LPAREN    "("
149 %token T_RPAREN    ")"
150 %token T_LBRACKET  "["
151 %token T_RBRACKET  "]"
152 %token T_COMMA     ","
153 %token T_ELLIPSIS  "."
154
155 %token T_TYPEDEF  "typedef"
156 %token T_EXTERN   "extern"
157 %token T_STATIC   "static"
158 %token T_AUTO     "auto"
159 %token T_REGISTER "register"
160
161 %token T_INLINE   "inline"
162
163 %token T_RESTRICT "restrict"
164 %token T_VOLATILE "volatile"
165 %token T_CONST    "const"
166
167 %token T_VOID     "void"
168 %token T_CHAR     "char"
169 %token T_SHORT    "short"
170 %token T_INT      "int"
171 %token T_LONG     "long"
172 %token T_FLOAT    "float"
173 %token T_DOUBLE   "double"
174 %token T_SIGNED   "signed"
175 %token T_UNSIGNED "unsigned"
176 %token T_BOOL     "_Bool"
177 %token T_COMPLEX  "_Complex"
178
179 %token T_STRUCT   "struct"
180 %token T_UNION    "union"
181 %token T_ENUM     "enum"
182
183 %type <strval>     vla_ident
184 %type <boolval>    varargs
185 %type <uintval>    declspec_simple typespec_simple qualifier_simple
186 %type <declspec>   declspec_notype declspec_noid typespec_noid typespec
187 %type <declspec>   qualifier qualifiers
188 %type <declspec>   declspecs declspecs_noid
189 %type <declarator> direct_declarator declarator pointer array parens postfix
190 %type <declarator> direct_declarator_ish declarator_ish parameter_type_list
191 %type <decl>       declaration declarators declarator_wrap
192 %type <decl>       parameter parameters
193
194 %%
195
196 input: declaration {
197         *out = $1;
198 };
199
200 declaration: declspecs declarators T_SEMICOLON {
201         $$ = $2;
202
203         for (struct cdecl *i = $$; i; i = i->next)
204                 i->specifiers = $1;
205 };
206
207 declspecs: declspec_notype declspecs {
208         $$ = $1;
209         $$->next = $2;
210 } | typespec declspecs_noid {
211         $$ = $1;
212         $$->next = $2;
213 }
214
215 declspecs_noid: { $$ = NULL; } | declspec_noid declspecs_noid {
216         $$ = $1;
217         $$->next = $2;
218 }
219
220 qualifiers: { $$ = NULL; } | qualifiers qualifier {
221         $$ = $2;
222         $$->next = $1;
223 }
224
225 declarators: declarator_wrap | declarator_wrap T_COMMA declarators {
226         $$ = $1;
227         $$->next = $3;
228 }
229
230 declarator_wrap: declarator {
231         ALLOC_STRUCT($$, struct cdecl, .declarators = $1);
232 }
233
234 declspec_simple: T_AUTO { $$ = CDECL_STOR_AUTO;     }
235         | T_TYPEDEF     { $$ = CDECL_STOR_TYPEDEF;  }
236         | T_EXTERN      { $$ = CDECL_STOR_EXTERN;   }
237         | T_STATIC      { $$ = CDECL_STOR_STATIC;   }
238         | T_REGISTER    { $$ = CDECL_STOR_REGISTER; }
239         | T_INLINE      { $$ = CDECL_FUNC_INLINE;   }
240
241 typespec_simple: T_VOID { $$ = CDECL_TYPE_VOID;     }
242         | T_CHAR        { $$ = CDECL_TYPE_CHAR;     }
243         | T_SHORT       { $$ = CDECL_TYPE_SHORT;    }
244         | T_INT         { $$ = CDECL_TYPE_INT;      }
245         | T_LONG        { $$ = CDECL_TYPE_LONG;     }
246         | T_FLOAT       { $$ = CDECL_TYPE_FLOAT;    }
247         | T_DOUBLE      { $$ = CDECL_TYPE_DOUBLE;   }
248         | T_SIGNED      { $$ = CDECL_TYPE_SIGNED;   }
249         | T_UNSIGNED    { $$ = CDECL_TYPE_UNSIGNED; }
250         | T_BOOL        { $$ = CDECL_TYPE_BOOL;     }
251         | T_COMPLEX     { $$ = CDECL_TYPE_COMPLEX;  }
252
253 qualifier_simple: T_CONST { $$ = CDECL_QUAL_CONST;    }
254         | T_RESTRICT      { $$ = CDECL_QUAL_RESTRICT; }
255         | T_VOLATILE      { $$ = CDECL_QUAL_VOLATILE; }
256
257 declspec_notype: qualifier | declspec_simple {
258         ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1);
259 }
260
261 typespec_noid: typespec_simple {
262         ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1);
263 }
264
265 qualifier: qualifier_simple {
266         ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1);
267 }
268
269 typespec: typespec_noid | T_STRUCT T_IDENT {
270         ALLOC_STRUCT($$, struct cdecl_declspec,
271                 .type = CDECL_TYPE_STRUCT,
272                 .ident = $2);
273 } | T_UNION T_IDENT {
274         ALLOC_STRUCT($$, struct cdecl_declspec,
275                 .type = CDECL_TYPE_UNION,
276                 .ident = $2);
277 } | T_ENUM T_IDENT {
278         ALLOC_STRUCT($$, struct cdecl_declspec,
279                 .type = CDECL_TYPE_ENUM,
280                 .ident = $2);
281 } | T_IDENT {
282         ALLOC_STRUCT($$, struct cdecl_declspec,
283                 .type = CDECL_TYPE_IDENT,
284                 .ident = $1);
285 }
286
287 declspec_noid: declspec_notype | typespec_noid
288
289 vla_ident: T_IDENT | T_ASTERISK {
290         ALLOC($$, sizeof "");
291         strcpy($$, "");
292 }
293
294 array: T_LBRACKET T_UINT T_RBRACKET {
295         if ($2 == 0)
296                 FAIL("array length must be positive");
297
298         ALLOC_STRUCT($$, struct cdecl_declarator,
299                 .type = CDECL_DECL_ARRAY,
300                 .u.array.length = $2);
301 } | T_LBRACKET vla_ident T_RBRACKET {
302         ALLOC_STRUCT($$, struct cdecl_declarator,
303                 .type = CDECL_DECL_ARRAY,
304                 .u.array.vla = $2);
305 } | T_LBRACKET T_RBRACKET {
306         ALLOC_STRUCT($$, struct cdecl_declarator,
307                 .type = CDECL_DECL_ARRAY);
308 }
309
310 parameter: declspecs declarator {
311         ALLOC_STRUCT($$, struct cdecl,
312                 .specifiers = $1,
313                 .declarators = $2);
314 }
315
316 parameters: parameter | parameters T_COMMA parameter {
317         $$ = $3;
318         $$->next = $1;
319 }
320
321 varargs: { $$ = false; } | T_COMMA T_ELLIPSIS { $$ = true; }
322
323 parameter_type_list: parameters varargs {
324         struct cdecl *p, *c, *n;
325
326         /* Parameters were accumulated in reverse order. */
327         for (p = NULL, c = $1; c; p = c, c = n) {
328                 n = c->next;
329                 c->next = p;
330         }
331
332         ALLOC_STRUCT($$, struct cdecl_declarator,
333                 .type = CDECL_DECL_FUNCTION,
334                 .u.function.parameters = p,
335                 .u.function.variadic = $2);
336 }
337
338 parens: T_LPAREN parameter_type_list T_RPAREN {
339         $$ = $2;
340 } | T_LPAREN declarator_ish T_RPAREN {
341         ALLOC_STRUCT($$, struct cdecl_declarator,
342                 .type = CDECL_DECL_FUNCTION);
343         ALLOC_STRUCT($$->u.function.parameters, struct cdecl,
344                 .declarators = $2);
345 }
346
347 pointer: T_ASTERISK qualifiers direct_declarator {
348         ALLOC_STRUCT($$, struct cdecl_declarator,
349                 .type = CDECL_DECL_POINTER,
350                 .u.pointer.qualifiers = $2,
351                 .child = $3);
352 } | T_ASTERISK qualifiers pointer {
353         ALLOC_STRUCT($$, struct cdecl_declarator,
354                 .type = CDECL_DECL_POINTER,
355                 .u.pointer.qualifiers = $2,
356                 .child = $3);
357 }
358
359 declarator: direct_declarator | pointer
360 declarator_ish: direct_declarator_ish | pointer
361 postfix: array | parens
362
363 direct_declarator_ish: {
364         ALLOC_STRUCT($$, struct cdecl_declarator,
365                 .type = CDECL_DECL_NULL);
366 } | direct_declarator_ish postfix {
367         $$ = $2;
368         $$->child = $1;
369 }
370
371 direct_declarator: {
372         ALLOC_STRUCT($$, struct cdecl_declarator,
373                 .type = CDECL_DECL_NULL);
374 } | T_IDENT {
375         ALLOC_STRUCT($$, struct cdecl_declarator,
376                 .type = CDECL_DECL_IDENT,
377                 .u.ident = $1);
378 } | direct_declarator postfix {
379         $$ = $2;
380         $$->child = $1;
381 }
382
383 %%
384 void yyerror(YYLTYPE *loc, struct cdecl **out, const char *err)
385 {
386         if (strstr(err, "T_LEX_ERROR"))
387                 return;
388
389         fprintf(stderr, "%s\n", err);
390 }