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