xref: /PHP-7.0/ext/json/json_parser.y (revision 478f119a)
1 %code top {
2 /*
3   +----------------------------------------------------------------------+
4   | PHP Version 7                                                        |
5   +----------------------------------------------------------------------+
6   | Copyright (c) 1997-2017 The PHP Group                                |
7   +----------------------------------------------------------------------+
8   | This source file is subject to version 3.01 of the PHP license,      |
9   | that is bundled with this package in the file LICENSE, and is        |
10   | available through the world-wide-web at the following url:           |
11   | http://www.php.net/license/3_01.txt                                  |
12   | If you did not receive a copy of the PHP license and are unable to   |
13   | obtain it through the world-wide-web, please send a note to          |
14   | license@php.net so we can mail you a copy immediately.               |
15   +----------------------------------------------------------------------+
16   | Author: Jakub Zelenka <bukka@php.net>                                |
17   +----------------------------------------------------------------------+
18 */
19 
20 #include "php.h"
21 #include "php_json.h"
22 #include "php_json_parser.h"
23 
24 #define YYDEBUG 0
25 
26 #if YYDEBUG
27 int json_yydebug = 1;
28 #endif
29 
30 #ifdef _MSC_VER
31 #define YYMALLOC malloc
32 #define YYFREE free
33 #endif
34 
35 #define PHP_JSON_USE(uv) ((void) (uv))
36 #define PHP_JSON_USE_1(uvr, uv1) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1)
37 #define PHP_JSON_USE_2(uvr, uv1, uv2) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1); PHP_JSON_USE(uv2)
38 
39 }
40 
41 %pure-parser
42 %name-prefix "php_json_yy"
43 %lex-param  { php_json_parser *parser  }
44 %parse-param { php_json_parser *parser }
45 
46 %union {
47 	zval value;
48 	struct {
49 		zend_string *key;
50 		zval val;
51 	} pair;
52 }
53 
54 
55 %token <value> PHP_JSON_T_NUL
56 %token <value> PHP_JSON_T_TRUE
57 %token <value> PHP_JSON_T_FALSE
58 %token <value> PHP_JSON_T_INT
59 %token <value> PHP_JSON_T_DOUBLE
60 %token <value> PHP_JSON_T_STRING
61 %token <value> PHP_JSON_T_ESTRING
62 %token <value> PHP_JSON_T_EOI
63 %token <value> PHP_JSON_T_ERROR
64 
65 %type <value> start object key value array errlex
66 %type <value> members member elements element
67 %type <pair> pair
68 
69 %destructor { zval_dtor(&$$); } <value>
70 %destructor { zend_string_release($$.key); zval_dtor(&$$.val); } <pair>
71 
72 %code {
73 int php_json_yylex(union YYSTYPE *value, php_json_parser *parser);
74 void php_json_yyerror(php_json_parser *parser, char const *msg);
75 void php_json_parser_object_init(php_json_parser *parser, zval *object);
76 int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue);
77 void php_json_parser_array_init(zval *object);
78 void php_json_parser_array_append(zval *array, zval *zvalue);
79 
80 #define PHP_JSON_DEPTH_DEC --parser->depth
81 #define PHP_JSON_DEPTH_INC \
82 	if (parser->max_depth && parser->depth >= parser->max_depth) { \
83 		parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; \
84 		YYERROR; \
85 	} \
86 	++parser->depth
87 }
88 
89 %% /* Rules */
90 
91 start:
92 		value PHP_JSON_T_EOI
93 			{
94 				ZVAL_COPY_VALUE(&$$, &$1);
95 				ZVAL_COPY_VALUE(parser->return_value, &$1);
96 				PHP_JSON_USE($2); YYACCEPT;
97 			}
98 	|	value errlex
99 			{
100 				PHP_JSON_USE_2($$, $1, $2);
101 			}
102 ;
103 
104 object:
105 		'{' { PHP_JSON_DEPTH_INC; } members object_end
106 			{
107 				PHP_JSON_DEPTH_DEC;
108 				$$ = $3;
109 			}
110 ;
111 
112 object_end:
113 		'}'
114 	|	']'
115 			{
116 				parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH;
117 				YYERROR;
118 			}
119 ;
120 
121 members:
122 		/* empty */
123 			{
124 				php_json_parser_object_init(parser, &$$);
125 			}
126 	|	member
127 ;
128 
129 member:
130 		pair
131 			{
132 				php_json_parser_object_init(parser, &$$);
133 				if (php_json_parser_object_update(parser, &$$, $1.key, &$1.val) == FAILURE)
134 					YYERROR;
135 			}
136 	|	member ',' pair
137 			{
138 				if (php_json_parser_object_update(parser, &$1, $3.key, &$3.val) == FAILURE)
139 					YYERROR;
140 				ZVAL_COPY_VALUE(&$$, &$1);
141 			}
142 	|	member errlex
143 			{
144 				PHP_JSON_USE_2($$, $1, $2);
145 			}
146 ;
147 
148 pair:
149 		key ':' value
150 			{
151 				$$.key = Z_STR($1);
152 				ZVAL_COPY_VALUE(&$$.val, &$3);
153 			}
154 	|	key errlex
155 			{
156 				PHP_JSON_USE_2($$, $1, $2);
157 			}
158 ;
159 
160 array:
161 		'[' { PHP_JSON_DEPTH_INC; } elements array_end
162 			{
163 				PHP_JSON_DEPTH_DEC;
164 				ZVAL_COPY_VALUE(&$$, &$3);
165 			}
166 ;
167 
168 array_end:
169 		']'
170 	|	'}'
171 			{
172 				parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH;
173 				YYERROR;
174 			}
175 ;
176 
177 elements:
178 		/* empty */
179 			{
180 				php_json_parser_array_init(&$$);
181 			}
182 	|	element
183 ;
184 
185 element:
186 		value
187 			{
188 				php_json_parser_array_init(&$$);
189 				php_json_parser_array_append(&$$, &$1);
190 			}
191 	|	element ',' value
192 			{
193 				php_json_parser_array_append(&$1, &$3);
194 				ZVAL_COPY_VALUE(&$$, &$1);
195 			}
196 	|	element errlex
197 			{
198 				PHP_JSON_USE_2($$, $1, $2);
199 			}
200 ;
201 
202 key:
203 		PHP_JSON_T_STRING
204 	|	PHP_JSON_T_ESTRING
205 ;
206 
207 value:
208 		object
209 	|	array
210 	|	PHP_JSON_T_STRING
211 	|	PHP_JSON_T_ESTRING
212 	|	PHP_JSON_T_INT
213 	|	PHP_JSON_T_DOUBLE
214 	|	PHP_JSON_T_NUL
215 	|	PHP_JSON_T_TRUE
216 	|	PHP_JSON_T_FALSE
217 	|	errlex
218 ;
219 
220 errlex:
221 		PHP_JSON_T_ERROR
222 			{
223 				PHP_JSON_USE_1($$, $1);
224 				YYERROR;
225 			}
226 ;
227 
228 %% /* Functions */
229 
230 void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, int options, int max_depth)
231 {
232 	memset(parser, 0, sizeof(php_json_parser));
233 	php_json_scanner_init(&parser->scanner, str, str_len, options);
234 	parser->depth = 1;
235 	parser->max_depth = max_depth;
236 	parser->return_value = return_value;
237 }
238 
php_json_parser_error_code(php_json_parser * parser)239 php_json_error_code php_json_parser_error_code(php_json_parser *parser)
240 {
241 	return parser->scanner.errcode;
242 }
243 
php_json_parser_object_init(php_json_parser * parser,zval * object)244 void php_json_parser_object_init(php_json_parser *parser, zval *object)
245 {
246 	if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) {
247 		array_init(object);
248 	} else {
249 		object_init(object);
250 	}
251 }
252 
php_json_parser_object_update(php_json_parser * parser,zval * object,zend_string * key,zval * zvalue)253 int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
254 {
255 	/* if JSON_OBJECT_AS_ARRAY is set */
256 	if (Z_TYPE_P(object) == IS_ARRAY) {
257 		zend_symtable_update(Z_ARRVAL_P(object), key, zvalue);
258 	} else {
259 		zval zkey;
260 		if (ZSTR_LEN(key) == 0) {
261 			zend_string_release(key);
262 			key = zend_string_init("_empty_", sizeof("_empty_") - 1, 0);
263 		} else if (ZSTR_VAL(key)[0] == '\0') {
264 			parser->scanner.errcode = PHP_JSON_ERROR_INVALID_PROPERTY_NAME;
265 			zend_string_release(key);
266 			zval_dtor(zvalue);
267 			zval_dtor(object);
268 			return FAILURE;
269 		}
270 		ZVAL_NEW_STR(&zkey, key);
271 		zend_std_write_property(object, &zkey, zvalue, NULL);
272 
273 		if (Z_REFCOUNTED_P(zvalue)) {
274 			Z_DELREF_P(zvalue);
275 		}
276 	}
277 	zend_string_release(key);
278 
279 	return SUCCESS;
280 }
281 
php_json_parser_array_init(zval * array)282 void php_json_parser_array_init(zval *array)
283 {
284 	array_init(array);
285 }
286 
php_json_parser_array_append(zval * array,zval * zvalue)287 void php_json_parser_array_append(zval *array, zval *zvalue)
288 {
289 	zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue);
290 }
291 
php_json_yylex(union YYSTYPE * value,php_json_parser * parser)292 int php_json_yylex(union YYSTYPE *value, php_json_parser *parser)
293 {
294 	int token = php_json_scan(&parser->scanner);
295 	value->value = parser->scanner.value;
296 	return token;
297 }
298 
php_json_yyerror(php_json_parser * parser,char const * msg)299 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