3 * Parser for C declarations.
4 * Copyright © 2011 Nick Bowler
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.
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.
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/>.
21 %parse-param {struct cdecl **out}
32 #define FAIL(msg) do { \
33 yyerror(&yylloc, NULL, msg); \
37 #define ALLOC(ptr, size) do { \
38 (ptr) = malloc(size); \
40 FAIL("failed to allocate memory"); \
43 #define ALLOC_STRUCT(ptr, type, ...) do { \
44 ALLOC(ptr, sizeof (type)); \
45 *(ptr) = (type) { __VA_ARGS__ }; \
54 void yyerror(YYLTYPE *, struct cdecl **, const char *);
55 int yyparse(struct cdecl **out);
61 struct cdecl_declspec *declspec;
62 struct cdecl_declarator *declarator;
67 static void free_declspec(struct cdecl_declspec *x)
69 struct cdecl_declspec *p;
78 static void free_declarator(struct cdecl_declarator *x)
80 struct cdecl_declarator *p;
88 case CDECL_DECL_IDENT:
91 case CDECL_DECL_POINTER:
92 free_declspec(x->u.pointer.qualifiers);
94 case CDECL_DECL_ARRAY:
106 static void free_decl(struct cdecl *x)
113 /* The specifiers may be shared by an entire chain. */
114 if (!p || p->specifiers != x->specifiers)
115 free_declspec(x->specifiers);
117 free_declarator(x->declarators);
123 void cdecl_free(struct cdecl *decl)
129 %destructor { free($$); } <strval>
130 %destructor { free_declspec($$); } <declspec>
131 %destructor { free_declarator($$); } <declarator>
132 %destructor { free_decl($$); } <decl>
136 %token <strval> T_IDENT "identifier"
137 %token <uintval> T_UINT "integer constant"
139 %token T_SEMICOLON ";"
140 %token T_ASTERISK "*"
143 %token T_LBRACKET "["
144 %token T_RBRACKET "]"
147 %token T_TYPEDEF "typedef"
148 %token T_EXTERN "extern"
149 %token T_STATIC "static"
151 %token T_REGISTER "register"
153 %token T_INLINE "inline"
155 %token T_RESTRICT "restrict"
156 %token T_VOLATILE "volatile"
157 %token T_CONST "const"
161 %token T_SHORT "short"
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"
171 %token T_STRUCT "struct"
172 %token T_UNION "union"
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
189 declaration: declspecs declarators T_SEMICOLON {
192 for (struct cdecl *i = $$; i; i = i->next)
196 declspecs: declspec_notype declspecs {
199 } | typespec declspecs_noid {
204 declspecs_noid: { $$ = NULL; } | declspec_noid declspecs_noid {
209 qualifiers: { $$ = NULL; } | qualifiers qualifier {
214 declarators: declarator_wrap | declarator_wrap T_COMMA declarators {
219 declarator_wrap: declarator {
220 ALLOC_STRUCT($$, struct cdecl, .declarators = $1);
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; }
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; }
242 qualifier_simple: T_CONST { $$ = CDECL_QUAL_CONST; }
243 | T_RESTRICT { $$ = CDECL_QUAL_RESTRICT; }
244 | T_VOLATILE { $$ = CDECL_QUAL_VOLATILE; }
246 declspec_notype: qualifier | declspec_simple {
247 ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1);
250 typespec_noid: typespec_simple {
251 ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1);
254 qualifier: qualifier_simple {
255 ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1);
258 typespec: typespec_noid | T_STRUCT T_IDENT {
259 ALLOC_STRUCT($$, struct cdecl_declspec,
260 .type = CDECL_TYPE_STRUCT,
262 } | T_UNION T_IDENT {
263 ALLOC_STRUCT($$, struct cdecl_declspec,
264 .type = CDECL_TYPE_UNION,
267 ALLOC_STRUCT($$, struct cdecl_declspec,
268 .type = CDECL_TYPE_ENUM,
271 ALLOC_STRUCT($$, struct cdecl_declspec,
272 .type = CDECL_TYPE_IDENT,
276 declspec_noid: declspec_notype | typespec_noid
278 vla_ident: T_IDENT | T_ASTERISK {
279 ALLOC($$, sizeof "");
283 array: T_LBRACKET T_UINT T_RBRACKET {
285 FAIL("array length must be positive");
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,
294 } | T_LBRACKET T_RBRACKET {
295 ALLOC_STRUCT($$, struct cdecl_declarator,
296 .type = CDECL_DECL_ARRAY);
299 pointer: T_ASTERISK qualifiers direct_declarator {
300 ALLOC_STRUCT($$, struct cdecl_declarator,
301 .type = CDECL_DECL_POINTER,
302 .u.pointer.qualifiers = $2,
304 } | T_ASTERISK qualifiers pointer {
305 ALLOC_STRUCT($$, struct cdecl_declarator,
306 .type = CDECL_DECL_POINTER,
307 .u.pointer.qualifiers = $2,
311 declarator: direct_declarator | pointer
314 ALLOC_STRUCT($$, struct cdecl_declarator,
315 .type = CDECL_DECL_NULL);
317 ALLOC_STRUCT($$, struct cdecl_declarator,
318 .type = CDECL_DECL_IDENT,
320 } | direct_declarator array {
323 } | T_LPAREN declarator T_RPAREN {
328 void yyerror(YYLTYPE *loc, struct cdecl **out, const char *err)
330 if (strstr(err, "T_LEX_ERROR"))
333 fprintf(stderr, "%s\n", err);