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