xref: /PHP-8.2/ext/json/json_parser.y (revision 107ad283)
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_yylex(union YYSTYPE * value,php_json_parser * parser)258 static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser)
259 {
260 	int token = php_json_scan(&parser->scanner);
261 	value->value = parser->scanner.value;
262 	return token;
263 }
264 
php_json_yyerror(php_json_parser * parser,char const * msg)265 static void php_json_yyerror(php_json_parser *parser, char const *msg)
266 {
267 	if (!parser->scanner.errcode) {
268 		parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX;
269 	}
270 }
271 
php_json_parser_error_code(const php_json_parser * parser)272 PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser)
273 {
274 	return parser->scanner.errcode;
275 }
276 
277 static const php_json_parser_methods default_parser_methods =
278 {
279 	php_json_parser_array_create,
280 	php_json_parser_array_append,
281 	NULL,
282 	NULL,
283 	php_json_parser_object_create,
284 	php_json_parser_object_update,
285 	NULL,
286 	NULL,
287 };
288 
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)289 PHP_JSON_API void php_json_parser_init_ex(php_json_parser *parser,
290 		zval *return_value,
291 		const char *str,
292 		size_t str_len,
293 		int options,
294 		int max_depth,
295 		const php_json_parser_methods *parser_methods)
296 {
297 	memset(parser, 0, sizeof(php_json_parser));
298 	php_json_scanner_init(&parser->scanner, str, str_len, options);
299 	parser->depth = 1;
300 	parser->max_depth = max_depth;
301 	parser->return_value = return_value;
302 	memcpy(&parser->methods, parser_methods, sizeof(php_json_parser_methods));
303 }
304 
php_json_parser_init(php_json_parser * parser,zval * return_value,const char * str,size_t str_len,int options,int max_depth)305 PHP_JSON_API void php_json_parser_init(php_json_parser *parser,
306 		zval *return_value,
307 		const char *str,
308 		size_t str_len,
309 		int options,
310 		int max_depth)
311 {
312 	php_json_parser_init_ex(
313 			parser,
314 			return_value,
315 			str,
316 			str_len,
317 			options,
318 			max_depth,
319 			&default_parser_methods);
320 }
321 
php_json_parse(php_json_parser * parser)322 PHP_JSON_API int php_json_parse(php_json_parser *parser)
323 {
324 	return php_json_yyparse(parser);
325 }
326