mirror of
https://github.com/php/php-src.git
synced 2026-03-26 01:02:25 +01:00
With Bison 3.0 some directives are deprecated:
- %name-prefix "x" should be %define api.prefix {x}
- %error-verbose should be %define parse.error verbose
Bison 3.3 also started emiting more warnings and since PHP souce parsers
are not POSIX compliant this patch fixes this as pointed out via
495a46aa1d.
362 lines
7.8 KiB
Plaintext
362 lines
7.8 KiB
Plaintext
%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_USE(uv) ((void) (uv))
|
|
#define PHP_JSON_USE_1(uvr, uv1) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1)
|
|
#define PHP_JSON_USE_2(uvr, uv1, uv2) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1); PHP_JSON_USE(uv2)
|
|
|
|
#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
|
|
|
|
}
|
|
|
|
%pure-parser
|
|
%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 <value> PHP_JSON_T_EOI
|
|
%token <value> PHP_JSON_T_ERROR
|
|
|
|
%type <value> start object key value array errlex
|
|
%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);
|
|
PHP_JSON_USE($2); YYACCEPT;
|
|
}
|
|
| value errlex
|
|
{
|
|
PHP_JSON_USE_2($$, $1, $2);
|
|
}
|
|
;
|
|
|
|
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);
|
|
}
|
|
| member errlex
|
|
{
|
|
PHP_JSON_USE_2($$, $1, $2);
|
|
}
|
|
;
|
|
|
|
pair:
|
|
key ':' value
|
|
{
|
|
$$.key = Z_STR($1);
|
|
ZVAL_COPY_VALUE(&$$.val, &$3);
|
|
}
|
|
| key errlex
|
|
{
|
|
PHP_JSON_USE_2($$, $1, $2);
|
|
}
|
|
;
|
|
|
|
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);
|
|
}
|
|
| element errlex
|
|
{
|
|
PHP_JSON_USE_2($$, $1, $2);
|
|
}
|
|
;
|
|
|
|
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
|
|
| errlex
|
|
;
|
|
|
|
errlex:
|
|
PHP_JSON_T_ERROR
|
|
{
|
|
PHP_JSON_USE_1($$, $1);
|
|
YYERROR;
|
|
}
|
|
;
|
|
|
|
%% /* 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);
|
|
}
|