xref: /PHP-8.4/ext/json/json_parser.y (revision 7c3b92fc)
1 %require "3.0"
2 %code top {
3 /*
4   +----------------------------------------------------------------------+
5   | Copyright (c) The PHP Group                                          |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | https://www.php.net/license/3_01.txt                                 |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Author: Jakub Zelenka <bukka@php.net>                                |
16   +----------------------------------------------------------------------+
17 */
18 
19 #include "php.h"
20 #include "php_json.h"
21 #include "php_json_parser.h"
22 
23 #define YYDEBUG 0
24 
25 #if YYDEBUG
26 int json_yydebug = 1;
27 #endif
28 
29 #ifdef _MSC_VER
30 #define YYMALLOC malloc
31 #define YYFREE free
32 #endif
33 
34 #define PHP_JSON_DEPTH_DEC --parser->depth
35 #define PHP_JSON_DEPTH_INC \
36 	if (parser->max_depth && parser->depth >= parser->max_depth) { \
37 		parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; \
38 		YYERROR; \
39 	} \
40 	++parser->depth
41 
42 }
43 
44 %define api.prefix {php_json_yy}
45 %define api.pure full
46 %param  { php_json_parser *parser  }
47 
48 %union {
49 	zval value;
50 }
51 
52 
53 %token <value> PHP_JSON_T_NUL
54 %token <value> PHP_JSON_T_TRUE
55 %token <value> PHP_JSON_T_FALSE
56 %token <value> PHP_JSON_T_INT
57 %token <value> PHP_JSON_T_DOUBLE
58 %token <value> PHP_JSON_T_STRING
59 %token <value> PHP_JSON_T_ESTRING
60 %token PHP_JSON_T_EOI
61 %token PHP_JSON_T_ERROR
62 
63 %type <value> start object key value array
64 %type <value> members member elements element
65 
66 %destructor { zval_ptr_dtor_nogc(&$$); } <value>
67 
68 %code {
69 static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser);
70 static void php_json_yyerror(php_json_parser *parser, char const *msg);
71 static int php_json_parser_array_create(php_json_parser *parser, zval *array);
72 static int php_json_parser_object_create(php_json_parser *parser, zval *array);
73 
74 }
75 
76 %% /* Rules */
77 
78 start:
79 		value PHP_JSON_T_EOI
80 			{
81 				ZVAL_COPY_VALUE(&$$, &$1);
82 				ZVAL_COPY_VALUE(parser->return_value, &$1);
83 				(void) php_json_yynerrs;
84 				YYACCEPT;
85 			}
86 ;
87 
88 object:
89 		'{'
90 			{
91 				PHP_JSON_DEPTH_INC;
92 				if (parser->methods.object_start && FAILURE == parser->methods.object_start(parser)) {
93 					YYERROR;
94 				}
95 			}
96 		members object_end
97 			{
98 				ZVAL_COPY_VALUE(&$$, &$3);
99 				PHP_JSON_DEPTH_DEC;
100 				if (parser->methods.object_end && FAILURE == parser->methods.object_end(parser, &$$)) {
101 					YYERROR;
102 				}
103 			}
104 ;
105 
106 object_end:
107 		'}'
108 	|	']'
109 			{
110 				parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH;
111 				YYERROR;
112 			}
113 ;
114 
115 members:
116 		%empty
117 			{
118 				if ((parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) && parser->methods.object_create == php_json_parser_object_create) {
119 					ZVAL_EMPTY_ARRAY(&$$);
120 				} else {
121 					parser->methods.object_create(parser, &$$);
122 				}
123 			}
124 	|	member
125 ;
126 
127 member:
128 		key ':' value
129 			{
130 				parser->methods.object_create(parser, &$$);
131 				if (parser->methods.object_update(parser, &$$, Z_STR($1), &$3) == FAILURE) {
132 					YYERROR;
133 				}
134 			}
135 	|	member ',' key ':' value
136 			{
137 				if (parser->methods.object_update(parser, &$1, Z_STR($3), &$5) == FAILURE) {
138 					YYERROR;
139 				}
140 				ZVAL_COPY_VALUE(&$$, &$1);
141 			}
142 ;
143 
144 array:
145 		'['
146 			{
147 				PHP_JSON_DEPTH_INC;
148 				if (parser->methods.array_start && FAILURE == parser->methods.array_start(parser)) {
149 					YYERROR;
150 				}
151 			}
152 		elements array_end
153 			{
154 				ZVAL_COPY_VALUE(&$$, &$3);
155 				PHP_JSON_DEPTH_DEC;
156 				if (parser->methods.array_end && FAILURE == parser->methods.array_end(parser, &$$)) {
157 					YYERROR;
158 				}
159 			}
160 ;
161 
162 array_end:
163 		']'
164 	|	'}'
165 			{
166 				parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH;
167 				YYERROR;
168 			}
169 ;
170 
171 elements:
172 		%empty
173 			{
174 				if (parser->methods.array_create == php_json_parser_array_create) {
175 					ZVAL_EMPTY_ARRAY(&$$);
176 				} else {
177 					parser->methods.array_create(parser, &$$);
178 				}
179 			}
180 	|	element
181 ;
182 
183 element:
184 		value
185 			{
186 				parser->methods.array_create(parser, &$$);
187 				parser->methods.array_append(parser, &$$, &$1);
188 			}
189 	|	element ',' value
190 			{
191 				parser->methods.array_append(parser, &$1, &$3);
192 				ZVAL_COPY_VALUE(&$$, &$1);
193 			}
194 ;
195 
196 key:
197 		PHP_JSON_T_STRING
198 	|	PHP_JSON_T_ESTRING
199 ;
200 
201 value:
202 		object
203 	|	array
204 	|	PHP_JSON_T_STRING
205 	|	PHP_JSON_T_ESTRING
206 	|	PHP_JSON_T_INT
207 	|	PHP_JSON_T_DOUBLE
208 	|	PHP_JSON_T_NUL
209 	|	PHP_JSON_T_TRUE
210 	|	PHP_JSON_T_FALSE
211 ;
212 
213 %% /* Functions */
214 
215 static int php_json_parser_array_create(php_json_parser *parser, zval *array)
216 {
217 	array_init(array);
218 	return SUCCESS;
219 }
220 
php_json_parser_array_append(php_json_parser * parser,zval * array,zval * zvalue)221 static int php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue)
222 {
223 	zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue);
224 	return SUCCESS;
225 }
226 
php_json_parser_object_create(php_json_parser * parser,zval * object)227 static int php_json_parser_object_create(php_json_parser *parser, zval *object)
228 {
229 	if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) {
230 		array_init(object);
231 	} else {
232 		object_init(object);
233 	}
234 	return SUCCESS;
235 }
236 
php_json_parser_object_update(php_json_parser * parser,zval * object,zend_string * key,zval * zvalue)237 static int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
238 {
239 	/* if JSON_OBJECT_AS_ARRAY is set */
240 	if (Z_TYPE_P(object) == IS_ARRAY) {
241 		zend_symtable_update(Z_ARRVAL_P(object), key, zvalue);
242 	} else {
243 		if (ZSTR_LEN(key) > 0 && ZSTR_VAL(key)[0] == '\0') {
244 			parser->scanner.errcode = PHP_JSON_ERROR_INVALID_PROPERTY_NAME;
245 			zend_string_release_ex(key, 0);
246 			zval_ptr_dtor_nogc(zvalue);
247 			zval_ptr_dtor_nogc(object);
248 			return FAILURE;
249 		}
250 		zend_std_write_property(Z_OBJ_P(object), key, zvalue, NULL);
251 		Z_TRY_DELREF_P(zvalue);
252 	}
253 	zend_string_release_ex(key, 0);
254 
255 	return SUCCESS;
256 }
257 
php_json_parser_array_create_validate(php_json_parser * parser,zval * array)258 static int php_json_parser_array_create_validate(php_json_parser *parser, zval *array)
259 {
260 	ZVAL_NULL(array);
261 	return SUCCESS;
262 }
263 
php_json_parser_array_append_validate(php_json_parser * parser,zval * array,zval * zvalue)264 static int php_json_parser_array_append_validate(php_json_parser *parser, zval *array, zval *zvalue)
265 {
266 	return SUCCESS;
267 }
268 
php_json_parser_object_create_validate(php_json_parser * parser,zval * object)269 static int php_json_parser_object_create_validate(php_json_parser *parser, zval *object)
270 {
271 	ZVAL_NULL(object);
272 	return SUCCESS;
273 }
274 
php_json_parser_object_update_validate(php_json_parser * parser,zval * object,zend_string * key,zval * zvalue)275 static int php_json_parser_object_update_validate(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
276 {
277 	return SUCCESS;
278 }
279 
php_json_yylex(union YYSTYPE * value,php_json_parser * parser)280 static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser)
281 {
282 	int token = php_json_scan(&parser->scanner);
283 
284 	bool validate = parser->methods.array_create == php_json_parser_array_create_validate
285 		&& parser->methods.array_append == php_json_parser_array_append_validate
286 		&& parser->methods.object_create == php_json_parser_object_create_validate
287 		&& parser->methods.object_update == php_json_parser_object_update_validate;
288 
289 	if (validate) {
290 		zval_ptr_dtor_str(&(parser->scanner.value));
291 		ZVAL_UNDEF(&value->value);
292 	} else {
293 		value->value = parser->scanner.value;
294 	}
295 
296 	return token;
297 }
298 
php_json_yyerror(php_json_parser * parser,char const * msg)299 static void php_json_yyerror(php_json_parser *parser, char const *msg)
300 {
301 	if (!parser->scanner.errcode) {
302 		parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX;
303 	}
304 }
305 
php_json_parser_error_code(const php_json_parser * parser)306 PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser)
307 {
308 	return parser->scanner.errcode;
309 }
310 
311 static const php_json_parser_methods default_parser_methods =
312 {
313 	php_json_parser_array_create,
314 	php_json_parser_array_append,
315 	NULL,
316 	NULL,
317 	php_json_parser_object_create,
318 	php_json_parser_object_update,
319 	NULL,
320 	NULL,
321 };
322 
323 static const php_json_parser_methods validate_parser_methods =
324 {
325 	php_json_parser_array_create_validate,
326 	php_json_parser_array_append_validate,
327 	NULL,
328 	NULL,
329 	php_json_parser_object_create_validate,
330 	php_json_parser_object_update_validate,
331 	NULL,
332 	NULL,
333 };
334 
php_json_parser_init_ex(php_json_parser * parser,zval * return_value,const char * str,size_t str_len,int options,int max_depth,const php_json_parser_methods * parser_methods)335 PHP_JSON_API void php_json_parser_init_ex(php_json_parser *parser,
336 		zval *return_value,
337 		const char *str,
338 		size_t str_len,
339 		int options,
340 		int max_depth,
341 		const php_json_parser_methods *parser_methods)
342 {
343 	memset(parser, 0, sizeof(php_json_parser));
344 	php_json_scanner_init(&parser->scanner, str, str_len, options);
345 	parser->depth = 1;
346 	parser->max_depth = max_depth;
347 	parser->return_value = return_value;
348 	memcpy(&parser->methods, parser_methods, sizeof(php_json_parser_methods));
349 }
350 
php_json_parser_init(php_json_parser * parser,zval * return_value,const char * str,size_t str_len,int options,int max_depth)351 PHP_JSON_API void php_json_parser_init(php_json_parser *parser,
352 		zval *return_value,
353 		const char *str,
354 		size_t str_len,
355 		int options,
356 		int max_depth)
357 {
358 	php_json_parser_init_ex(
359 			parser,
360 			return_value,
361 			str,
362 			str_len,
363 			options,
364 			max_depth,
365 			&default_parser_methods);
366 }
367 
php_json_parse(php_json_parser * parser)368 PHP_JSON_API int php_json_parse(php_json_parser *parser)
369 {
370 	return php_json_yyparse(parser);
371 }
372 
php_json_get_validate_methods(void)373 const php_json_parser_methods* php_json_get_validate_methods(void)
374 {
375 	return &validate_parser_methods;
376 }
377