xref: /PHP-8.3/ext/ffi/ffi.g (revision c0de7214)
1/*
2   +----------------------------------------------------------------------+
3   | Copyright (c) The PHP Group                                          |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 3.01 of the PHP license,      |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | https://www.php.net/license/3_01.txt                                 |
9   | If you did not receive a copy of the PHP license and are unable to   |
10   | obtain it through the world-wide-web, please send a note to          |
11   | license@php.net so we can mail you a copy immediately.               |
12   +----------------------------------------------------------------------+
13   | Author: Dmitry Stogov <dmitry@zend.com>                              |
14   +----------------------------------------------------------------------+
15*/
16
17/*
18To generate ffi_parser.c use llk <https://github.com/dstogov/llk>:
19php llk.php ffi.g
20*/
21
22%start          declarations
23%sub-start      type_name
24%case-sensetive true
25%global-vars    false
26%output         "ffi_parser.c"
27%language       "c"
28%indent         "\t"
29
30%{
31/*
32   +----------------------------------------------------------------------+
33   | Copyright (c) The PHP Group                                          |
34   +----------------------------------------------------------------------+
35   | This source file is subject to version 3.01 of the PHP license,      |
36   | that is bundled with this package in the file LICENSE, and is        |
37   | available through the world-wide-web at the following url:           |
38   | https://www.php.net/license/3_01.txt                                 |
39   | If you did not receive a copy of the PHP license and are unable to   |
40   | obtain it through the world-wide-web, please send a note to          |
41   | license@php.net so we can mail you a copy immediately.               |
42   +----------------------------------------------------------------------+
43   | Author: Dmitry Stogov <dmitry@zend.com>                              |
44   +----------------------------------------------------------------------+
45*/
46
47#ifdef HAVE_CONFIG_H
48# include "config.h"
49#endif
50
51#include "php.h"
52#include "php_ffi.h"
53
54#include <stdio.h>
55#include <stdlib.h>
56#include <string.h>
57
58#define yy_buf  FFI_G(buf)
59#define yy_end  FFI_G(end)
60#define yy_pos  FFI_G(pos)
61#define yy_text FFI_G(text)
62#define yy_line FFI_G(line)
63
64/* forward declarations */
65static void yy_error(const char *msg);
66static void yy_error_sym(const char *msg, int sym);
67static void yy_error_str(const char *msg, const char *str);
68
69%}
70
71declarations:
72	(
73		{zend_ffi_dcl common_dcl = ZEND_FFI_ATTR_INIT;}
74		"__extension__"?
75		declaration_specifiers(&common_dcl)
76		(
77			{const char *name;}
78			{size_t name_len;}
79			{zend_ffi_dcl dcl;}
80			{dcl = common_dcl;}
81			declarator(&dcl, &name, &name_len)
82			(
83				{zend_ffi_val asm_str;}
84				"__asm__"
85				"("
86				STRING(&asm_str)+
87				/*TODO*/
88				")"
89			)?
90			attributes(&dcl)?
91			initializer?
92			{zend_ffi_declare(name, name_len, &dcl);}
93			(	","
94				{dcl = common_dcl;}
95				declarator(&dcl, &name, &name_len)
96				attributes(&dcl)?
97				initializer?
98				{zend_ffi_declare(name, name_len, &dcl);}
99			)*
100		|
101			/* empty */
102			{if (common_dcl.flags & (ZEND_FFI_DCL_ENUM | ZEND_FFI_DCL_STRUCT | ZEND_FFI_DCL_UNION)) zend_ffi_cleanup_dcl(&common_dcl);}
103		)
104		";"
105	)*
106;
107
108declaration_specifiers(zend_ffi_dcl *dcl):
109	(	?{sym != YY_ID || !(dcl->flags & ZEND_FFI_DCL_TYPE_SPECIFIERS)}
110		(	{if (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) yy_error_sym("unexpected", sym);}
111			"typedef"
112			{dcl->flags |= ZEND_FFI_DCL_TYPEDEF;}
113		|	{if (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) yy_error_sym("unexpected", sym);}
114			"extern"
115			{dcl->flags |= ZEND_FFI_DCL_EXTERN;}
116		|	{if (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) yy_error_sym("unexpected", sym);}
117			"static"
118			{dcl->flags |= ZEND_FFI_DCL_STATIC;}
119		|	{if (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) yy_error_sym("unexpected", sym);}
120			"auto"
121			{dcl->flags |= ZEND_FFI_DCL_AUTO;}
122		|	{if (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) yy_error_sym("unexpected", sym);}
123			"register"
124			{dcl->flags |= ZEND_FFI_DCL_REGISTER;}
125//		|	"_Thread_local" // TODO: not-implemented ???
126		|	("inline"|"__inline"|"__inline__")
127			{dcl->flags |= ZEND_FFI_DCL_INLINE;}
128		|	"_Noreturn"
129			{dcl->flags |= ZEND_FFI_DCL_NO_RETURN;}
130		|	"_Alignas"
131			"("
132			(	&type_name_start
133				{zend_ffi_dcl align_dcl = ZEND_FFI_ATTR_INIT;}
134				type_name(&align_dcl)
135				{zend_ffi_align_as_type(dcl, &align_dcl);}
136			|	{zend_ffi_val align_val;}
137				constant_expression(&align_val)
138				{zend_ffi_align_as_val(dcl, &align_val);}
139			)
140			")"
141		|	attributes(dcl)
142		|	type_qualifier(dcl)
143		|	type_specifier(dcl)
144		)
145	)+
146;
147
148specifier_qualifier_list(zend_ffi_dcl *dcl):
149	"__extension__"?
150	(	?{sym != YY_ID || zend_ffi_is_typedef_name((const char*)yy_text, yy_pos - yy_text) || (dcl->flags & ZEND_FFI_DCL_TYPE_SPECIFIERS) == 0}
151		(	type_specifier(dcl)
152		|	type_qualifier(dcl)
153		|	attributes(dcl)
154		)
155	)+
156;
157
158type_qualifier_list(zend_ffi_dcl *dcl):
159	(	type_qualifier(dcl)
160	|	attributes(dcl)
161	)+
162;
163
164type_qualifier(zend_ffi_dcl *dcl):
165		("const"|"__const"|"__const__")
166		{dcl->flags |= ZEND_FFI_DCL_CONST;}
167		{dcl->attr |= ZEND_FFI_ATTR_CONST;}
168	|	("restrict"|"__restrict"|"__restrict__")
169		{dcl->flags |= ZEND_FFI_DCL_RESTRICT;}
170	|	("volatile"|"__volatile"|"__volatile__")
171		{dcl->flags |= ZEND_FFI_DCL_VOLATILE;}
172	|	"_Atomic"
173		{dcl->flags |= ZEND_FFI_DCL_ATOMIC;}
174;
175
176type_specifier(zend_ffi_dcl *dcl):
177    {const char *name;}
178    {size_t name_len;}
179	(	{if (dcl->flags & ZEND_FFI_DCL_TYPE_SPECIFIERS) yy_error_sym("unexpected", sym);}
180		"void"
181		{dcl->flags |= ZEND_FFI_DCL_VOID;}
182	|	{if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_UNSIGNED))) yy_error_sym("unexpected", sym);}
183		"char"
184		{dcl->flags |= ZEND_FFI_DCL_CHAR;}
185	|	{if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT))) yy_error_sym("unexpected", sym);}
186		"short"
187		{dcl->flags |= ZEND_FFI_DCL_SHORT;}
188	|   {if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG))) yy_error_sym("unexpected", sym);}
189		"int"
190		{dcl->flags |= ZEND_FFI_DCL_INT;}
191	|	{
192			if (dcl->flags & ZEND_FFI_DCL_LONG) {
193				if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT))) yy_error_sym("unexpected", sym);
194				dcl->flags |= ZEND_FFI_DCL_LONG_LONG;
195			} else {
196				if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_DOUBLE|ZEND_FFI_DCL_COMPLEX))) yy_error_sym("unexpected", sym);
197				dcl->flags |= ZEND_FFI_DCL_LONG;
198			}
199		}
200		"long"
201	|	{if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_COMPLEX))) yy_error_sym("unexpected", sym);}
202		"float"
203		{dcl->flags |= ZEND_FFI_DCL_FLOAT;}
204	|	{if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_COMPLEX))) yy_error_sym("unexpected", sym);}
205		"double"
206		{dcl->flags |= ZEND_FFI_DCL_DOUBLE;}
207	|	{if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_INT))) yy_error_sym("unexpected", sym);}
208		"signed"
209		{dcl->flags |= ZEND_FFI_DCL_SIGNED;}
210	|	{if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_INT))) yy_error_sym("unexpected", sym);}
211		"unsigned"
212		{dcl->flags |= ZEND_FFI_DCL_UNSIGNED;}
213	|	{if (dcl->flags & ZEND_FFI_DCL_TYPE_SPECIFIERS) yy_error_sym("unexpected", sym);}
214		"_Bool"
215		{dcl->flags |= ZEND_FFI_DCL_BOOL;}
216	|	{if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE|ZEND_FFI_DCL_LONG))) yy_error_sym("unexpected", sym);}
217		("_Complex"|"complex"|"__complex"|"__complex__")
218		{dcl->flags |= ZEND_FFI_DCL_COMPLEX;}
219//	|	"_Atomic" "(" type_name ")" // TODO: not-implemented ???
220	|	{if (dcl->flags & ZEND_FFI_DCL_TYPE_SPECIFIERS) yy_error_sym("unexpected", sym);}
221		struct_or_union_specifier(dcl)
222	|	{if (dcl->flags & ZEND_FFI_DCL_TYPE_SPECIFIERS) yy_error_sym("unexpected", sym);}
223		enum_specifier(dcl)
224	|   {if (dcl->flags & ZEND_FFI_DCL_TYPE_SPECIFIERS) yy_error_sym("unexpected", sym);}
225		{/*redeclaration of '%.*s' ??? */}
226		ID(&name, &name_len)
227		{dcl->flags |= ZEND_FFI_DCL_TYPEDEF_NAME;}
228		{zend_ffi_resolve_typedef(name, name_len, dcl);}
229	)
230;
231
232struct_or_union_specifier(zend_ffi_dcl *dcl):
233	(	"struct"
234		{dcl->flags |= ZEND_FFI_DCL_STRUCT;}
235	| 	"union"
236		{dcl->flags |= ZEND_FFI_DCL_UNION;}
237	)
238	attributes(dcl)?
239	(   {const char *name;}
240		{size_t name_len;}
241		ID(&name, &name_len)
242		{zend_ffi_declare_tag(name, name_len, dcl, 1);}
243		(	struct_contents(dcl)
244			{zend_ffi_declare_tag(name, name_len, dcl, 0);}
245		)?
246	|	{zend_ffi_make_struct_type(dcl);}
247		struct_contents(dcl)
248	)
249;
250
251struct_contents(zend_ffi_dcl *dcl):
252	"{"
253	(	struct_declaration(dcl)
254		(	";"
255			struct_declaration(dcl)
256		)*
257		(";")?
258	)?
259    "}"
260	attributes(dcl)?+
261	{zend_ffi_adjust_struct_size(dcl);}
262;
263
264
265struct_declaration(zend_ffi_dcl *struct_dcl):
266	{zend_ffi_dcl common_field_dcl = ZEND_FFI_ATTR_INIT;}
267	specifier_qualifier_list(&common_field_dcl)
268	(	/* empty */
269		{zend_ffi_add_anonymous_field(struct_dcl, &common_field_dcl);}
270	|	struct_declarator(struct_dcl, &common_field_dcl)
271		(	","
272			{zend_ffi_dcl field_dcl = common_field_dcl;}
273			attributes(&field_dcl)?
274			struct_declarator(struct_dcl, &field_dcl)
275		)*
276	)
277;
278
279struct_declarator(zend_ffi_dcl *struct_dcl, zend_ffi_dcl *field_dcl):
280	{const char *name = NULL;}
281	{size_t name_len = 0;}
282	{zend_ffi_val bits;}
283	(	declarator(field_dcl, &name, &name_len)
284		(	":"
285			constant_expression(&bits)
286			attributes(field_dcl)?
287			{zend_ffi_add_bit_field(struct_dcl, name, name_len, field_dcl, &bits);}
288		|	/*empty */
289			attributes(field_dcl)?
290			{zend_ffi_add_field(struct_dcl, name, name_len, field_dcl);}
291		)
292	|	":"
293		constant_expression(&bits)
294		{zend_ffi_add_bit_field(struct_dcl, NULL, 0, field_dcl, &bits);}
295	)
296;
297
298enum_specifier(zend_ffi_dcl *dcl):
299	"enum"
300	{dcl->flags |= ZEND_FFI_DCL_ENUM;}
301	attributes(dcl)?
302	(   {const char *name;}
303		{size_t name_len;}
304		ID(&name, &name_len)
305		(	{zend_ffi_declare_tag(name, name_len, dcl, 0);}
306			"{"
307			enumerator_list(dcl)
308			"}"
309			attributes(dcl)?+
310		|	{zend_ffi_declare_tag(name, name_len, dcl, 1);}
311		)
312	|	"{"
313		{zend_ffi_make_enum_type(dcl);}
314		enumerator_list(dcl)
315		"}"
316		attributes(dcl)?+
317	)
318;
319
320enumerator_list(zend_ffi_dcl *enum_dcl):
321	{int64_t min = 0, max = 0, last = -1;}
322	enumerator(enum_dcl, &min, &max, &last)
323	(	","
324		enumerator(enum_dcl, &min, &max, &last)
325	)*
326	","?
327;
328
329enumerator(zend_ffi_dcl *enum_dcl, int64_t *min, int64_t *max, int64_t *last):
330	{const char *name;}
331	{size_t name_len;}
332	{zend_ffi_val val = {.kind = ZEND_FFI_VAL_EMPTY};}
333	ID(&name, &name_len)
334	(	"="
335		constant_expression(&val)
336	)?
337	{zend_ffi_add_enum_val(enum_dcl, name, name_len, &val, min, max, last);}
338;
339
340declarator(zend_ffi_dcl *dcl, const char **name, size_t *name_len):
341	{zend_ffi_dcl nested_dcl = {ZEND_FFI_DCL_CHAR, 0, 0, 0, NULL};}
342	{bool nested = 0;}
343	pointer(dcl)?
344	(	ID(name, name_len)
345	|	"("
346		attributes(&nested_dcl)?
347		declarator(&nested_dcl, name, name_len)
348		")"
349		{nested = 1;}
350	)
351	array_or_function_declarators(dcl, &nested_dcl)?
352	{if (nested) zend_ffi_nested_declaration(dcl, &nested_dcl);}
353;
354
355abstract_declarator(zend_ffi_dcl *dcl):
356	{zend_ffi_dcl nested_dcl = {ZEND_FFI_DCL_CHAR, 0, 0, 0, NULL};}
357	{bool nested = 0;}
358	pointer(dcl)?
359	(	&nested_declarator_start
360		"("
361		attributes(&nested_dcl)?
362		abstract_declarator(&nested_dcl)
363		")"
364		{nested = 1;}
365	)?
366	array_or_function_declarators(dcl, &nested_dcl)?
367	{if (nested) zend_ffi_nested_declaration(dcl, &nested_dcl);}
368;
369
370parameter_declarator(zend_ffi_dcl *dcl, const char **name, size_t *name_len):
371	{zend_ffi_dcl nested_dcl = {ZEND_FFI_DCL_CHAR, 0, 0, 0, NULL};}
372	{bool nested = 0;}
373	pointer(dcl)?
374	(	&nested_declarator_start
375		"("
376		attributes(&nested_dcl)?
377		parameter_declarator(&nested_dcl, name, name_len)
378		")"
379		{nested = 1;}
380	|	ID(name, name_len)
381	|	/* empty */
382	)
383	array_or_function_declarators(dcl, &nested_dcl)?
384	{if (nested) zend_ffi_nested_declaration(dcl, &nested_dcl);}
385;
386
387pointer(zend_ffi_dcl *dcl):
388	(	"*"
389		{zend_ffi_make_pointer_type(dcl);}
390		type_qualifier_list(dcl)?
391	)+
392;
393
394array_or_function_declarators(zend_ffi_dcl *dcl, zend_ffi_dcl *nested_dcl):
395	{zend_ffi_dcl dummy = ZEND_FFI_ATTR_INIT;}
396	{zend_ffi_val len = {.kind = ZEND_FFI_VAL_EMPTY};}
397	{HashTable *args = NULL;}
398	{uint32_t attr = 0;}
399	(	"["
400	    (	"static"
401			type_qualifier_list(&dummy)?
402			assignment_expression(&len)
403		|	type_qualifier_list(&dummy)
404			(	"static" assignment_expression(&len)
405			|	/* empty */
406				{attr |= ZEND_FFI_ATTR_INCOMPLETE_ARRAY;}
407			|	"*"
408				{attr |= ZEND_FFI_ATTR_VLA;}
409			|	assignment_expression(&len)
410			)
411		|	(	/* empty */
412				{attr |= ZEND_FFI_ATTR_INCOMPLETE_ARRAY;}
413			|	"*"
414				{attr |= ZEND_FFI_ATTR_VLA;}
415			|	assignment_expression(&len)
416			)
417		)
418		"]"
419		array_or_function_declarators(dcl, nested_dcl)?
420		{dcl->attr |= attr;}
421		{zend_ffi_make_array_type(dcl, &len);}
422	|	"("
423		(
424			parameter_declaration(&args)
425			(	","
426				parameter_declaration(&args)
427			)*
428			(
429				","
430				"..."
431				{attr |= ZEND_FFI_ATTR_VARIADIC;}
432			)?
433		|	"..."
434			{attr |= ZEND_FFI_ATTR_VARIADIC;}
435		)?
436		")"
437		array_or_function_declarators(dcl, nested_dcl)?
438		{dcl->attr |= attr;}
439		{zend_ffi_make_func_type(dcl, args, nested_dcl);}
440//	|	"(" (ID ("," ID)*)? ")" // TODO: ANSI function not-implemented ???
441	)
442;
443
444parameter_declaration(HashTable **args):
445	{const char *name = NULL;}
446	{size_t name_len = 0;}
447	{bool old_allow_vla = FFI_G(allow_vla);}
448	{FFI_G(allow_vla) = 1;}
449	{zend_ffi_dcl param_dcl = ZEND_FFI_ATTR_INIT;}
450	specifier_qualifier_list(&param_dcl)
451	parameter_declarator(&param_dcl, &name, &name_len)
452	/*attributes(&param_dcl)? conflict ???*/
453	{zend_ffi_add_arg(args, name, name_len, &param_dcl);}
454	{FFI_G(allow_vla) = old_allow_vla;}
455;
456
457type_name(zend_ffi_dcl *dcl):
458	specifier_qualifier_list(dcl)
459	abstract_declarator(dcl)
460;
461
462attributes(zend_ffi_dcl *dcl):
463	{const char *name;}
464	{size_t name_len;}
465	{zend_ffi_val val;}
466	(
467		("__attribute"|"__attribute__")
468		"("
469		"("
470		attrib(dcl)
471		(	","
472			attrib(dcl)
473		)*
474		")"
475		")"
476	|	"__declspec"
477		"("
478			(	ID(&name, &name_len)
479				(
480					"("
481						assignment_expression(&val)
482						{zend_ffi_add_msvc_attribute_value(dcl, name, name_len, &val);}
483					")"
484				)?
485			)+
486		")"
487	|	"__cdecl"
488		{zend_ffi_set_abi(dcl, ZEND_FFI_ABI_CDECL);}
489	|	"__stdcall"
490		{zend_ffi_set_abi(dcl, ZEND_FFI_ABI_STDCALL);}
491	|	"__fastcall"
492		{zend_ffi_set_abi(dcl, ZEND_FFI_ABI_FASTCALL);}
493	|	"__thiscall"
494		{zend_ffi_set_abi(dcl, ZEND_FFI_ABI_THISCALL);}
495	|	"__vectorcall"
496		{zend_ffi_set_abi(dcl, ZEND_FFI_ABI_VECTORCALL);}
497	)++
498;
499
500attrib(zend_ffi_dcl *dcl):
501	{const char *name;}
502	{size_t name_len;}
503	{int n;}
504	{zend_ffi_val val;}
505	{bool orig_attribute_parsing;}
506	(   ID(&name, &name_len)
507		(	/* empty */
508			{zend_ffi_add_attribute(dcl, name, name_len);}
509		|	"("
510			{orig_attribute_parsing = FFI_G(attribute_parsing);}
511			{FFI_G(attribute_parsing) = 1;}
512			assignment_expression(&val)
513			{zend_ffi_add_attribute_value(dcl, name, name_len, 0, &val);}
514			{n = 0;}
515			(	","
516				assignment_expression(&val)
517				{zend_ffi_add_attribute_value(dcl, name, name_len, ++n, &val);}
518			)*
519			{FFI_G(attribute_parsing) = orig_attribute_parsing;}
520			")"
521		)
522	|	"const"
523	|	"__const"
524	|	"__const__"
525	)?
526;
527
528initializer:
529	{zend_ffi_val dummy;}
530	"="
531	(	assignment_expression(&dummy)
532	|	"{" designation? initializer ( "," designation? initializer)* ","? "}"
533	)
534;
535
536designation:
537	{const char *name;}
538	{size_t name_len;}
539	{zend_ffi_val dummy;}
540	(	"[" constant_expression(&dummy) "]"
541	|	"." ID(&name, &name_len)
542	)+
543	"="
544;
545
546expr_list:
547	{zend_ffi_val dummy;}
548	assignment_expression(&dummy)
549	(	","
550		assignment_expression(&dummy)
551	)*
552;
553
554expression(zend_ffi_val *val):
555	assignment_expression(val)
556	(	","
557		assignment_expression(val)
558	)*
559;
560
561assignment_expression(zend_ffi_val *val):
562//	(	unary_expression
563//		("="|"*="|"/="|"%="|"+="|"-="|"<<="|">>="|"&="|"^="|"|=")
564//	)* // TODO: not-implemented ???
565	conditional_expression(val)
566;
567
568constant_expression(zend_ffi_val *val):
569	conditional_expression(val)
570;
571
572conditional_expression(zend_ffi_val *val):
573	{zend_ffi_val op2, op3;}
574	logical_or_expression(val)
575	(	"?"
576		expression(&op2)
577		":"
578		conditional_expression(&op3)
579		{zend_ffi_expr_conditional(val, &op2, &op3);}
580	)?
581;
582
583logical_or_expression(zend_ffi_val *val):
584	{zend_ffi_val op2;}
585	logical_and_expression(val)
586	(   "||"
587		logical_and_expression(&op2)
588		{zend_ffi_expr_bool_or(val, &op2);}
589	)*
590;
591
592logical_and_expression(zend_ffi_val *val):
593	{zend_ffi_val op2;}
594	inclusive_or_expression(val)
595	(   "&&"
596		inclusive_or_expression(&op2)
597		{zend_ffi_expr_bool_and(val, &op2);}
598	)*
599;
600
601inclusive_or_expression(zend_ffi_val *val):
602	{zend_ffi_val op2;}
603	exclusive_or_expression(val)
604	(	"|"
605		exclusive_or_expression(&op2)
606		{zend_ffi_expr_bw_or(val, &op2);}
607	)*
608;
609
610exclusive_or_expression(zend_ffi_val *val):
611	{zend_ffi_val op2;}
612	and_expression(val)
613	(	"^"
614		and_expression(&op2)
615		{zend_ffi_expr_bw_xor(val, &op2);}
616	)*
617;
618
619and_expression(zend_ffi_val *val):
620	{zend_ffi_val op2;}
621	equality_expression(val)
622	(	"&"
623		equality_expression(&op2)
624		{zend_ffi_expr_bw_and(val, &op2);}
625	)*
626;
627
628equality_expression(zend_ffi_val *val):
629	{zend_ffi_val op2;}
630	relational_expression(val)
631	(	"=="
632		relational_expression(&op2)
633		{zend_ffi_expr_is_equal(val, &op2);}
634	|	"!="
635		relational_expression(&op2)
636		{zend_ffi_expr_is_not_equal(val, &op2);}
637	)*
638;
639
640relational_expression(zend_ffi_val *val):
641	{zend_ffi_val op2;}
642	shift_expression(val)
643	(	"<"
644		shift_expression(&op2)
645		{zend_ffi_expr_is_less(val, &op2);}
646	|	">"
647		shift_expression(&op2)
648		{zend_ffi_expr_is_greater(val, &op2);}
649	|	"<="
650		shift_expression(&op2)
651		{zend_ffi_expr_is_less_or_equal(val, &op2);}
652	|	">="
653		shift_expression(&op2)
654		{zend_ffi_expr_is_greater_or_equal(val, &op2);}
655	)*
656;
657
658shift_expression(zend_ffi_val *val):
659	{zend_ffi_val op2;}
660	additive_expression(val)
661	(	"<<"
662		additive_expression(&op2)
663		{zend_ffi_expr_shift_left(val, &op2);}
664	|	">>"
665		additive_expression(&op2)
666		{zend_ffi_expr_shift_right(val, &op2);}
667	)*
668;
669
670additive_expression(zend_ffi_val *val):
671	{zend_ffi_val op2;}
672	multiplicative_expression(val)
673	(	"+"
674		multiplicative_expression(&op2)
675		{zend_ffi_expr_add(val, &op2);}
676	|	"-"
677		multiplicative_expression(&op2)
678		{zend_ffi_expr_sub(val, &op2);}
679	)*
680;
681
682multiplicative_expression(zend_ffi_val *val):
683	{zend_ffi_val op2;}
684	cast_expression(val)
685	(	"*"
686		cast_expression(&op2)
687		{zend_ffi_expr_mul(val, &op2);}
688	|	"/"
689		cast_expression(&op2)
690		{zend_ffi_expr_div(val, &op2);}
691	|	"%"
692		cast_expression(&op2)
693		{zend_ffi_expr_mod(val, &op2);}
694	)*
695;
696
697cast_expression(zend_ffi_val *val):
698	{int do_cast = 0;}
699	{zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;}
700	(	&( "(" type_name_start )
701		"("
702		type_name(&dcl)
703		")"
704		{do_cast = 1;}
705	)?
706	unary_expression(val)
707	{if (do_cast) zend_ffi_expr_cast(val, &dcl);}
708;
709
710unary_expression(zend_ffi_val *val):
711	{const char *name;}
712	{size_t name_len;}
713	{zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;}
714	(	ID(&name, &name_len)
715		{zend_ffi_resolve_const(name, name_len, val);}
716		(
717			(	"["
718				expr_list
719				"]"
720			|	"("
721				expr_list?
722				")"
723			|	"."
724				ID(&name, &name_len)
725			|	"->"
726				ID(&name, &name_len)
727		    |	"++"
728			|	"--"
729			)
730			{zend_ffi_val_error(val);}
731		)*
732	|	OCTNUMBER(val)
733	|	DECNUMBER(val)
734	|	HEXNUMBER(val)
735	|	FLOATNUMBER(val)
736	|	STRING(val)
737	|	CHARACTER(val)
738	|	"("
739		expression(val)
740		")"
741	|	"++"
742		unary_expression(val)
743		{zend_ffi_val_error(val);}
744	|	"--"
745		unary_expression(val)
746		{zend_ffi_val_error(val);}
747	|	"&"
748		cast_expression(val)
749		{zend_ffi_val_error(val);}
750	|	"*"
751		cast_expression(val)
752		{zend_ffi_val_error(val);}
753	|	"+"
754		cast_expression(val)
755		{zend_ffi_expr_plus(val);}
756	|	"-"
757		cast_expression(val)
758		{zend_ffi_expr_neg(val);}
759	|	"~"
760		cast_expression(val)
761		{zend_ffi_expr_bw_not(val);}
762	|	"!"
763		cast_expression(val)
764		{zend_ffi_expr_bool_not(val);}
765	|	"sizeof"
766		(	&( "(" type_name_start )
767			"("
768			type_name(&dcl)
769			")"
770			{zend_ffi_expr_sizeof_type(val, &dcl);}
771		|	unary_expression(val)
772			{zend_ffi_expr_sizeof_val(val);}
773		)
774	|	"_Alignof"
775		"("
776		type_name(&dcl)
777		")"
778		{zend_ffi_expr_alignof_type(val, &dcl);}
779	|	("__alignof"|"__alignof__")
780		(	&( "(" type_name_start )
781			"("
782			type_name(&dcl)
783			")"
784			{zend_ffi_expr_alignof_type(val, &dcl);}
785		|	unary_expression(val)
786			{zend_ffi_expr_alignof_val(val);}
787		)
788	)
789;
790
791/* lookahead rules */
792nested_declarator_start:
793    "("
794	(   ?{!zend_ffi_is_typedef_name((const char*)yy_text, yy_pos - yy_text)}
795		ID
796	|	"__attribute"
797	|	"__attribute__"
798	|	"__declspec"
799	|	"*"
800	|	"("
801	|	"["
802	)
803;
804
805type_name_start:
806	(	?{zend_ffi_is_typedef_name((const char*)yy_text, yy_pos - yy_text)}
807		ID
808	|	"void"
809	|	"char"
810	|	"short"
811	|   "int"
812	|	"long"
813	|	"float"
814	|	"double"
815	|	"signed"
816	|	"unsigned"
817	|	"_Bool"
818	|	"_Complex"
819	|	"complex"
820	|	"__complex"
821	|	"__complex__"
822	|	"struct"
823	|	"union"
824	|	"enum"
825	|	"const"
826	|	"__const"
827	|	"__const__"
828	|	"restrict"
829	|	"__restict"
830	|	"__restrict__"
831	|	"volatile"
832	|	"__volatile"
833	|	"__volatile__"
834	|	"_Atomic"
835	|	"__attribute"
836	|	"__attribute__"
837	|	"__declspec"
838	)
839;
840
841/* scanner rules */
842ID(const char **name, size_t *name_len):
843	/[A-Za-z_][A-Za-z_0-9]*/
844	{*name = (const char*)yy_text; *name_len = yy_pos - yy_text;}
845;
846
847OCTNUMBER(zend_ffi_val *val):
848	/0[0-7]*([Uu](L|l|LL|l)?|[Ll][Uu]?|(LL|ll)[Uu])?/
849	{zend_ffi_val_number(val, 8, (const char*)yy_text, yy_pos - yy_text);}
850;
851
852DECNUMBER(zend_ffi_val *val):
853	/[1-9][0-9]*([Uu](L|l|LL|l)?|[Ll][Uu]?|(LL|ll)[Uu])?/
854	{zend_ffi_val_number(val, 10, (const char*)yy_text, yy_pos - yy_text);}
855;
856
857HEXNUMBER(zend_ffi_val *val):
858	/0[xX][0-9A-Fa-f][0-9A-Fa-f]*([Uu](L|l|LL|l)?|[Ll][Uu]?|(LL|ll)[Uu])?/
859	{zend_ffi_val_number(val, 16, (const char*)yy_text + 2, yy_pos - yy_text - 2);}
860;
861
862FLOATNUMBER(zend_ffi_val *val):
863	/([0-9]*\.[0-9]+([Ee][\+\-]?[0-9]+)?|[0-9]+\.([Ee][\+\-]?[0-9]+)?|[0-9]+[Ee][\+\-]?[0-9]+)[flFL]?/
864	{zend_ffi_val_float_number(val, (const char*)yy_text, yy_pos - yy_text);}
865;
866
867STRING(zend_ffi_val *val):
868	/(u8|u|U|L)?"([^"\\]|\\.)*"/
869	{zend_ffi_val_string(val, (const char*)yy_text, yy_pos - yy_text);}
870;
871
872CHARACTER(zend_ffi_val *val):
873	/[LuU]?'([^'\\]|\\.)*'/
874	{zend_ffi_val_character(val, (const char*)yy_text, yy_pos - yy_text);}
875;
876
877EOL: /\r\n|\r|\n/;
878WS: /[ \t\f\v]+/;
879ONE_LINE_COMMENT: /(\/\/|#)[^\r\n]*(\r\n|\r|\n)/;
880COMMENT: /\/\*([^\*]|\*+[^\*\/])*\*+\//;
881
882SKIP: ( EOL | WS | ONE_LINE_COMMENT | COMMENT )*;
883
884%%
885zend_result zend_ffi_parse_decl(const char *str, size_t len) {
886	if (SETJMP(FFI_G(bailout))==0) {
887		FFI_G(allow_vla) = 0;
888		FFI_G(attribute_parsing) = 0;
889		yy_buf = (unsigned char*)str;
890		yy_end = yy_buf + len;
891		parse();
892		return SUCCESS;
893	} else {
894		return FAILURE;
895	}
896}
897
898zend_result zend_ffi_parse_type(const char *str, size_t len, zend_ffi_dcl *dcl) {
899	int sym;
900
901	if (SETJMP(FFI_G(bailout))==0) {
902		FFI_G(allow_vla) = 0;
903		FFI_G(attribute_parsing) = 0;
904		yy_pos = yy_text = yy_buf = (unsigned char*)str;
905		yy_end = yy_buf + len;
906		yy_line = 1;
907		sym = parse_type_name(get_sym(), dcl);
908		if (sym != YY_EOF) {
909			yy_error_sym("<EOF> expected, got", sym);
910		}
911		zend_ffi_validate_type_name(dcl);
912		return SUCCESS;
913	} else {
914		return FAILURE;
915	};
916}
917
918static void yy_error(const char *msg) {
919	zend_ffi_parser_error("%s at line %d", msg, yy_line);
920}
921
922static void yy_error_sym(const char *msg, int sym) {
923	zend_ffi_parser_error("%s '%s' at line %d", msg, sym_name[sym], yy_line);
924}
925
926static void yy_error_str(const char *msg, const char *str) {
927	zend_ffi_parser_error("%s '%s' at line %d\n", msg, str, yy_line);
928}
929