mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00

Don't use <value> type for JSON tokens that don't have a value and remove the errlex productions -- we're going to get an unexpected token error anyway, there's no need to handle these explicitly. This also removes the awkward workarounds for the unused value warnings.
332 lines
7.2 KiB
Text
332 lines
7.2 KiB
Text
%code top {
|
|
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP Version 7 |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Author: Jakub Zelenka <bukka@php.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "php.h"
|
|
#include "php_json.h"
|
|
#include "php_json_parser.h"
|
|
|
|
#define YYDEBUG 0
|
|
|
|
#if YYDEBUG
|
|
int json_yydebug = 1;
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
#define YYMALLOC malloc
|
|
#define YYFREE free
|
|
#endif
|
|
|
|
#define PHP_JSON_DEPTH_DEC --parser->depth
|
|
#define PHP_JSON_DEPTH_INC \
|
|
if (parser->max_depth && parser->depth >= parser->max_depth) { \
|
|
parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; \
|
|
YYERROR; \
|
|
} \
|
|
++parser->depth
|
|
|
|
}
|
|
|
|
%define api.pure full
|
|
%define api.prefix {php_json_yy}
|
|
%lex-param { php_json_parser *parser }
|
|
%parse-param { php_json_parser *parser }
|
|
|
|
%union {
|
|
zval value;
|
|
struct {
|
|
zend_string *key;
|
|
zval val;
|
|
} pair;
|
|
}
|
|
|
|
|
|
%token <value> PHP_JSON_T_NUL
|
|
%token <value> PHP_JSON_T_TRUE
|
|
%token <value> PHP_JSON_T_FALSE
|
|
%token <value> PHP_JSON_T_INT
|
|
%token <value> PHP_JSON_T_DOUBLE
|
|
%token <value> PHP_JSON_T_STRING
|
|
%token <value> PHP_JSON_T_ESTRING
|
|
%token PHP_JSON_T_EOI
|
|
%token PHP_JSON_T_ERROR
|
|
|
|
%type <value> start object key value array
|
|
%type <value> members member elements element
|
|
%type <pair> pair
|
|
|
|
%destructor { zval_ptr_dtor_nogc(&$$); } <value>
|
|
%destructor { zend_string_release_ex($$.key, 0); zval_ptr_dtor_nogc(&$$.val); } <pair>
|
|
|
|
%code {
|
|
static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser);
|
|
static void php_json_yyerror(php_json_parser *parser, char const *msg);
|
|
|
|
}
|
|
|
|
%% /* Rules */
|
|
|
|
start:
|
|
value PHP_JSON_T_EOI
|
|
{
|
|
ZVAL_COPY_VALUE(&$$, &$1);
|
|
ZVAL_COPY_VALUE(parser->return_value, &$1);
|
|
YYACCEPT;
|
|
}
|
|
;
|
|
|
|
object:
|
|
'{'
|
|
{
|
|
PHP_JSON_DEPTH_INC;
|
|
if (parser->methods.object_start && FAILURE == parser->methods.object_start(parser)) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
members object_end
|
|
{
|
|
ZVAL_COPY_VALUE(&$$, &$3);
|
|
PHP_JSON_DEPTH_DEC;
|
|
if (parser->methods.object_end && FAILURE == parser->methods.object_end(parser, &$$)) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
object_end:
|
|
'}'
|
|
| ']'
|
|
{
|
|
parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH;
|
|
YYERROR;
|
|
}
|
|
;
|
|
|
|
members:
|
|
/* empty */
|
|
{
|
|
parser->methods.object_create(parser, &$$);
|
|
}
|
|
| member
|
|
;
|
|
|
|
member:
|
|
pair
|
|
{
|
|
parser->methods.object_create(parser, &$$);
|
|
if (parser->methods.object_update(parser, &$$, $1.key, &$1.val) == FAILURE) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
| member ',' pair
|
|
{
|
|
if (parser->methods.object_update(parser, &$1, $3.key, &$3.val) == FAILURE) {
|
|
YYERROR;
|
|
}
|
|
ZVAL_COPY_VALUE(&$$, &$1);
|
|
}
|
|
;
|
|
|
|
pair:
|
|
key ':' value
|
|
{
|
|
$$.key = Z_STR($1);
|
|
ZVAL_COPY_VALUE(&$$.val, &$3);
|
|
}
|
|
;
|
|
|
|
array:
|
|
'['
|
|
{
|
|
PHP_JSON_DEPTH_INC;
|
|
if (parser->methods.array_start && FAILURE == parser->methods.array_start(parser)) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
elements array_end
|
|
{
|
|
ZVAL_COPY_VALUE(&$$, &$3);
|
|
PHP_JSON_DEPTH_DEC;
|
|
if (parser->methods.array_end && FAILURE == parser->methods.array_end(parser, &$$)) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
array_end:
|
|
']'
|
|
| '}'
|
|
{
|
|
parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH;
|
|
YYERROR;
|
|
}
|
|
;
|
|
|
|
elements:
|
|
/* empty */
|
|
{
|
|
parser->methods.array_create(parser, &$$);
|
|
}
|
|
| element
|
|
;
|
|
|
|
element:
|
|
value
|
|
{
|
|
parser->methods.array_create(parser, &$$);
|
|
parser->methods.array_append(parser, &$$, &$1);
|
|
}
|
|
| element ',' value
|
|
{
|
|
parser->methods.array_append(parser, &$1, &$3);
|
|
ZVAL_COPY_VALUE(&$$, &$1);
|
|
}
|
|
;
|
|
|
|
key:
|
|
PHP_JSON_T_STRING
|
|
| PHP_JSON_T_ESTRING
|
|
;
|
|
|
|
value:
|
|
object
|
|
| array
|
|
| PHP_JSON_T_STRING
|
|
| PHP_JSON_T_ESTRING
|
|
| PHP_JSON_T_INT
|
|
| PHP_JSON_T_DOUBLE
|
|
| PHP_JSON_T_NUL
|
|
| PHP_JSON_T_TRUE
|
|
| PHP_JSON_T_FALSE
|
|
;
|
|
|
|
%% /* Functions */
|
|
|
|
static int php_json_parser_array_create(php_json_parser *parser, zval *array)
|
|
{
|
|
array_init(array);
|
|
return SUCCESS;
|
|
}
|
|
|
|
static int php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue)
|
|
{
|
|
zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue);
|
|
return SUCCESS;
|
|
}
|
|
|
|
static int php_json_parser_object_create(php_json_parser *parser, zval *object)
|
|
{
|
|
if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) {
|
|
array_init(object);
|
|
return SUCCESS;
|
|
} else {
|
|
return object_init(object);
|
|
}
|
|
}
|
|
|
|
static int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
|
|
{
|
|
/* if JSON_OBJECT_AS_ARRAY is set */
|
|
if (Z_TYPE_P(object) == IS_ARRAY) {
|
|
zend_symtable_update(Z_ARRVAL_P(object), key, zvalue);
|
|
} else {
|
|
zval zkey;
|
|
if (ZSTR_LEN(key) > 0 && ZSTR_VAL(key)[0] == '\0') {
|
|
parser->scanner.errcode = PHP_JSON_ERROR_INVALID_PROPERTY_NAME;
|
|
zend_string_release_ex(key, 0);
|
|
zval_ptr_dtor_nogc(zvalue);
|
|
zval_ptr_dtor_nogc(object);
|
|
return FAILURE;
|
|
}
|
|
ZVAL_NEW_STR(&zkey, key);
|
|
zend_std_write_property(object, &zkey, zvalue, NULL);
|
|
Z_TRY_DELREF_P(zvalue);
|
|
}
|
|
zend_string_release_ex(key, 0);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser)
|
|
{
|
|
int token = php_json_scan(&parser->scanner);
|
|
value->value = parser->scanner.value;
|
|
return token;
|
|
}
|
|
|
|
static void php_json_yyerror(php_json_parser *parser, char const *msg)
|
|
{
|
|
if (!parser->scanner.errcode) {
|
|
parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX;
|
|
}
|
|
}
|
|
|
|
PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser)
|
|
{
|
|
return parser->scanner.errcode;
|
|
}
|
|
|
|
static const php_json_parser_methods default_parser_methods =
|
|
{
|
|
php_json_parser_array_create,
|
|
php_json_parser_array_append,
|
|
NULL,
|
|
NULL,
|
|
php_json_parser_object_create,
|
|
php_json_parser_object_update,
|
|
NULL,
|
|
NULL,
|
|
};
|
|
|
|
PHP_JSON_API void php_json_parser_init_ex(php_json_parser *parser,
|
|
zval *return_value,
|
|
char *str,
|
|
size_t str_len,
|
|
int options,
|
|
int max_depth,
|
|
const php_json_parser_methods *parser_methods)
|
|
{
|
|
memset(parser, 0, sizeof(php_json_parser));
|
|
php_json_scanner_init(&parser->scanner, str, str_len, options);
|
|
parser->depth = 1;
|
|
parser->max_depth = max_depth;
|
|
parser->return_value = return_value;
|
|
memcpy(&parser->methods, parser_methods, sizeof(php_json_parser_methods));
|
|
}
|
|
|
|
PHP_JSON_API void php_json_parser_init(php_json_parser *parser,
|
|
zval *return_value,
|
|
char *str,
|
|
size_t str_len,
|
|
int options,
|
|
int max_depth)
|
|
{
|
|
php_json_parser_init_ex(
|
|
parser,
|
|
return_value,
|
|
str,
|
|
str_len,
|
|
options,
|
|
max_depth,
|
|
&default_parser_methods);
|
|
}
|
|
|
|
PHP_JSON_API int php_json_parse(php_json_parser *parser)
|
|
{
|
|
return php_json_yyparse(parser);
|
|
}
|