xref: /PHP-8.1/ext/json/json_parser.y (revision 01b3fc03)
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 				YYACCEPT;
84 			}
85 ;
86 
87 object:
88 		'{'
89 			{
90 				PHP_JSON_DEPTH_INC;
91 				if (parser->methods.object_start && FAILURE == parser->methods.object_start(parser)) {
92 					YYERROR;
93 				}
94 			}
95 		members object_end
96 			{
97 				ZVAL_COPY_VALUE(&$$, &$3);
98 				PHP_JSON_DEPTH_DEC;
99 				if (parser->methods.object_end && FAILURE == parser->methods.object_end(parser, &$$)) {
100 					YYERROR;
101 				}
102 			}
103 ;
104 
105 object_end:
106 		'}'
107 	|	']'
108 			{
109 				parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH;
110 				YYERROR;
111 			}
112 ;
113 
114 members:
115 		%empty
116 			{
117 				if ((parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) && parser->methods.object_create == php_json_parser_object_create) {
118 					ZVAL_EMPTY_ARRAY(&$$);
119 				} else {
120 					parser->methods.object_create(parser, &$$);
121 				}
122 			}
123 	|	member
124 ;
125 
126 member:
127 		key ':' value
128 			{
129 				parser->methods.object_create(parser, &$$);
130 				if (parser->methods.object_update(parser, &$$, Z_STR($1), &$3) == FAILURE) {
131 					YYERROR;
132 				}
133 			}
134 	|	member ',' key ':' value
135 			{
136 				if (parser->methods.object_update(parser, &$1, Z_STR($3), &$5) == FAILURE) {
137 					YYERROR;
138 				}
139 				ZVAL_COPY_VALUE(&$$, &$1);
140 			}
141 ;
142 
143 array:
144 		'['
145 			{
146 				PHP_JSON_DEPTH_INC;
147 				if (parser->methods.array_start && FAILURE == parser->methods.array_start(parser)) {
148 					YYERROR;
149 				}
150 			}
151 		elements array_end
152 			{
153 				ZVAL_COPY_VALUE(&$$, &$3);
154 				PHP_JSON_DEPTH_DEC;
155 				if (parser->methods.array_end && FAILURE == parser->methods.array_end(parser, &$$)) {
156 					YYERROR;
157 				}
158 			}
159 ;
160 
161 array_end:
162 		']'
163 	|	'}'
164 			{
165 				parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH;
166 				YYERROR;
167 			}
168 ;
169 
170 elements:
171 		%empty
172 			{
173 				if (parser->methods.array_create == php_json_parser_array_create) {
174 					ZVAL_EMPTY_ARRAY(&$$);
175 				} else {
176 					parser->methods.array_create(parser, &$$);
177 				}
178 			}
179 	|	element
180 ;
181 
182 element:
183 		value
184 			{
185 				parser->methods.array_create(parser, &$$);
186 				parser->methods.array_append(parser, &$$, &$1);
187 			}
188 	|	element ',' value
189 			{
190 				parser->methods.array_append(parser, &$1, &$3);
191 				ZVAL_COPY_VALUE(&$$, &$1);
192 			}
193 ;
194 
195 key:
196 		PHP_JSON_T_STRING
197 	|	PHP_JSON_T_ESTRING
198 ;
199 
200 value:
201 		object
202 	|	array
203 	|	PHP_JSON_T_STRING
204 	|	PHP_JSON_T_ESTRING
205 	|	PHP_JSON_T_INT
206 	|	PHP_JSON_T_DOUBLE
207 	|	PHP_JSON_T_NUL
208 	|	PHP_JSON_T_TRUE
209 	|	PHP_JSON_T_FALSE
210 ;
211 
212 %% /* Functions */
213 
214 static int php_json_parser_array_create(php_json_parser *parser, zval *array)
215 {
216 	array_init(array);
217 	return SUCCESS;
218 }
219 
php_json_parser_array_append(php_json_parser * parser,zval * array,zval * zvalue)220 static int php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue)
221 {
222 	zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue);
223 	return SUCCESS;
224 }
225 
php_json_parser_object_create(php_json_parser * parser,zval * object)226 static int php_json_parser_object_create(php_json_parser *parser, zval *object)
227 {
228 	if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) {
229 		array_init(object);
230 	} else {
231 		object_init(object);
232 	}
233 	return SUCCESS;
234 }
235 
php_json_parser_object_update(php_json_parser * parser,zval * object,zend_string * key,zval * zvalue)236 static int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
237 {
238 	/* if JSON_OBJECT_AS_ARRAY is set */
239 	if (Z_TYPE_P(object) == IS_ARRAY) {
240 		zend_symtable_update(Z_ARRVAL_P(object), key, zvalue);
241 	} else {
242 		if (ZSTR_LEN(key) > 0 && ZSTR_VAL(key)[0] == '\0') {
243 			parser->scanner.errcode = PHP_JSON_ERROR_INVALID_PROPERTY_NAME;
244 			zend_string_release_ex(key, 0);
245 			zval_ptr_dtor_nogc(zvalue);
246 			zval_ptr_dtor_nogc(object);
247 			return FAILURE;
248 		}
249 		zend_std_write_property(Z_OBJ_P(object), key, zvalue, NULL);
250 		Z_TRY_DELREF_P(zvalue);
251 	}
252 	zend_string_release_ex(key, 0);
253 
254 	return SUCCESS;
255 }
256 
php_json_yylex(union YYSTYPE * value,php_json_parser * parser)257 static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser)
258 {
259 	int token = php_json_scan(&parser->scanner);
260 	value->value = parser->scanner.value;
261 	return token;
262 }
263 
php_json_yyerror(php_json_parser * parser,char const * msg)264 static void php_json_yyerror(php_json_parser *parser, char const *msg)
265 {
266 	if (!parser->scanner.errcode) {
267 		parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX;
268 	}
269 }
270 
php_json_parser_error_code(const php_json_parser * parser)271 PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser)
272 {
273 	return parser->scanner.errcode;
274 }
275 
276 static const php_json_parser_methods default_parser_methods =
277 {
278 	php_json_parser_array_create,
279 	php_json_parser_array_append,
280 	NULL,
281 	NULL,
282 	php_json_parser_object_create,
283 	php_json_parser_object_update,
284 	NULL,
285 	NULL,
286 };
287 
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)288 PHP_JSON_API void php_json_parser_init_ex(php_json_parser *parser,
289 		zval *return_value,
290 		const char *str,
291 		size_t str_len,
292 		int options,
293 		int max_depth,
294 		const php_json_parser_methods *parser_methods)
295 {
296 	memset(parser, 0, sizeof(php_json_parser));
297 	php_json_scanner_init(&parser->scanner, str, str_len, options);
298 	parser->depth = 1;
299 	parser->max_depth = max_depth;
300 	parser->return_value = return_value;
301 	memcpy(&parser->methods, parser_methods, sizeof(php_json_parser_methods));
302 }
303 
php_json_parser_init(php_json_parser * parser,zval * return_value,const char * str,size_t str_len,int options,int max_depth)304 PHP_JSON_API void php_json_parser_init(php_json_parser *parser,
305 		zval *return_value,
306 		const char *str,
307 		size_t str_len,
308 		int options,
309 		int max_depth)
310 {
311 	php_json_parser_init_ex(
312 			parser,
313 			return_value,
314 			str,
315 			str_len,
316 			options,
317 			max_depth,
318 			&default_parser_methods);
319 }
320 
php_json_parse(php_json_parser * parser)321 PHP_JSON_API int php_json_parse(php_json_parser *parser)
322 {
323 	return php_json_yyparse(parser);
324 }
325