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