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