├── .gitignore ├── CMakeLists.txt ├── README.md ├── examples └── file.json5 ├── hashmap.h ├── main.c ├── zua_parser.c ├── zua_parser.h ├── zua_parser.y ├── zua_parser_defs.h ├── zua_scanner.c ├── zua_scanner.h ├── zua_scanner.re ├── zua_scanner_defs.h ├── zua_type.c └── zua_type.h /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | cmake-build-debug -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(zua C) 3 | 4 | set(CMAKE_C_STANDARD 99) 5 | 6 | include_directories(.) 7 | 8 | #find_package(BISON) 9 | #BISON_TARGET(zuaParser parser.y ${CMAKE_CURRENT_BINARY_DIR}/zua_parser.c 10 | # DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/zua_parser.h) 11 | # 12 | #find_package(FLEX) 13 | #FLEX_TARGET(zuaLexer lexer.l ${CMAKE_CURRENT_BINARY_DIR}/zua_lexer.c) 14 | 15 | add_executable(zua 16 | main.c 17 | zua_scanner.c 18 | zua_type.c 19 | zua_parser.c 20 | ) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Zua 一个易用的 `JSON` & `JSON5` 解析引擎 2 | 3 | Zua 采用纯C语言开发, 可以在任意支持标准C的机器上运行,占用内存少,解码格式多的特点,既可以解析 标准`JSON` 也可以解析`JSON5`格式 4 | 采用 `HashMap` 结构保存数据,查询性能能够达到 O(1), 无内存泄漏风险. 5 | 6 | 7 | ## C++版本 8 | 9 | C++ Language press this to obtain: [jsoncpp](https://github.com/liqiongfan/jsoncpp) 10 | 11 | 12 | 建议C++语言使用上面的C++版本 13 | 14 | 15 | ## 项目地址 16 | 17 | `https://github.com/liqiongfan/Zua` 18 | 19 | ### 设计理念 20 | 21 | 整个解析引擎使用 `zval` 结构体(struct _zua_struct) 来表达各个节点值,为了达到 O(1) 的查询性能,解析的数据存储到 `HashMap` 。 22 | 23 | 24 | ### JSON5 特性 25 | 26 | ##### Objects(对象) 27 | 28 | - [x] 对象的键名可以不使用引号 29 | - [x] 对象的键名可以使用单引号 30 | - [x] 对象元素的末尾可以以一个逗号结束 31 | 32 | 33 | ##### Arrays(数组) 34 | 35 | - [x] 数组元素的末尾可以以一个逗号结束 36 | 37 | 38 | ##### Strings(字符串) 39 | 40 | - [x] 字符串可以使用单引号 41 | - [x] 字符串可以跨越多行, 每行以转义符 '\\' 结尾 42 | - [x] 字符串可以包含转义字符 43 | 44 | 45 | ##### Numbers(数字) 46 | 47 | - [x] 数字可以是十六进制 48 | - [x] 浮点数字可以只是单纯的 `.` 或者 以 `.` 开头或者结尾 49 | - [x] 数字可以是 IEEE754标准的无穷大(`Infinity`)或者负无穷大(`-Infinity`)以及 `NaN` 50 | - [x] 正数可以使用`+`明确指定 51 | 52 | 53 | ##### Comments(注释) 54 | 55 | - [x] 可以使用单行注释(`//`)或者多行注释(`/* */`) 56 | 57 | 58 | ##### White Space(空白符) 59 | 60 | - [x] 允许额外的空白字符 61 | 62 | 63 | ### APIs 64 | 65 | + ZUA_API zua_string *zua_file_gets(const char *file_name): 66 | 67 | 读取文件全部内容为`zua_string`,返回数据需要 `zua_string_free` 68 | 69 | + zval *json_decode(const char *str, unsigned int str_len): 70 | 71 | 解码`JSON`字符串 72 | 73 | + zua_string *json_encode(zval *v): 74 | 75 | 编码为`JSON`字符串 76 | 77 | + zua_string *json_encode_pretty(zval *val): 78 | 79 | 编码为格式化的`JSON`字符串 80 | 81 | + zval *zua_get_value(zval *v, const char *key, unsigned int key_len): 82 | 83 | 从对象中查询指定`key`的值 84 | 85 | + zval *zua_get_value_by_index(zval *v, uint32_t index): 86 | 87 | 从数组中查询指定索引坐标的值,偏移值从 `0` 开始计数 88 | 89 | + zval *zua_get_value_by_path(zval *r, const char *str, uint32_t str_len): 90 | 91 | 使用点号的字符串查询 `JSON` 格式获取数据 92 | 93 | + bool zua_in_array(zval *r, zval *value): 94 | 95 | 查询 value 是否在 r 中,注意如果 value 是 `array` 或者 `object` 则直接返回 FALSE 96 | 97 | + zval *zval_init(): 98 | 99 | 得到一个分配好内存的`zval` 100 | 101 | + object_init(zval *v): 102 | 103 | 初始化为对象 104 | 105 | + array_init(zval *v): 106 | 107 | 初始化为数组 108 | 109 | + zua_hash_str_add_or_update(zval *h, const char *key, uint32_t key_len, zval *value): 110 | 111 | 往对象里面新增`key` & `value`对 112 | 113 | + void zua_hash_index_add(zval *h, zval *value): 114 | 115 | 往数组里面新增值 116 | 117 | + zval_free(zval *v): 118 | 119 | 释放内存 120 | 121 | 122 | ### 示例 123 | 124 | + 解码 125 | 126 | ```C 127 | zval *response = json_decode(ZUA_STR("{ code: 200, message: 'SUCCESS', language: ['Golang', 'C/C++'] }")); 128 | if (response->u2.errcode != 0) { 129 | printf("解析错误~"); 130 | zval_free(response); 131 | return 0; 132 | } 133 | zval *code = zua_get_value(response, ZUA_STR("code")); 134 | code != NULL && printf("code:%ld\n", Z_LVAL_P(code)); 135 | 136 | zval *message = zua_get_value(response, ZUA_STR("message")); 137 | message != NULL && printf("message: %s\n", ZSTR_VAL(Z_STR_P(message))); 138 | 139 | zval *lang = zua_get_value(response, ZUA_STR("language")); 140 | if (lang != NULL) { 141 | zval *favor_language = zua_get_value_by_index(lang, 0); 142 | printf("Favor Language: %s\n", ZSTR_VAL(Z_STR_P(favor_language))); 143 | } 144 | zval_free(response); 145 | ``` 146 | 147 | 148 | + 编码 149 | 150 | ```C 151 | zval *obj = zval_init(); 152 | object_init(obj); 153 | 154 | zval name; 155 | ZVAL_STRING(&name, "v1.0.1"); 156 | zua_hash_str_add_or_update(obj, ZUA_STR("version"), &name); 157 | 158 | zval code; 159 | ZVAL_LONG(&code, 200); 160 | zua_hash_str_add_or_update(obj, ZUA_STR("code"), &code); 161 | 162 | zua_string *str = json_encode(obj); 163 | 164 | printf("%s\n", ZSTR_VAL(str)); 165 | 166 | zua_string_free(str); 167 | zval_free(obj); 168 | ``` -------------------------------------------------------------------------------- /examples/file.json5: -------------------------------------------------------------------------------- 1 | { 2 | // comments 3 | unquoted: 'and you can quote me on that', 4 | singleQuotes: 'I can use "double quotes" here', 5 | lineBreaks: "Look, Mom! \ 6 | No \\n's!", 7 | test: { 8 | "bb": "test.bb", 9 | "cc": [11, 22, 33, 44, "55"] 10 | }, 11 | positiveSign: +1, 12 | trailingComma: 'in objects', andIn: ['arrays',], 13 | "backwardsCompatible": "with JSON", 14 | } -------------------------------------------------------------------------------- /hashmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | The latest version of this library is available on GitHub; 3 | https://github.com/sheredom/hashmap.h 4 | modified by Terry|Josin (xeapplee@gmail.com) 5 | remove const char * to char *, with other code remain it's original face. 6 | */ 7 | 8 | /* 9 | This is free and unencumbered software released into the public domain. 10 | 11 | Anyone is free to copy, modify, publish, use, compile, sell, or 12 | distribute this software, either in source code form or as a compiled 13 | binary, for any purpose, commercial or non-commercial, and by any 14 | means. 15 | 16 | In jurisdictions that recognize copyright laws, the author or authors 17 | of this software dedicate any and all copyright interest in the 18 | software to the public domain. We make this dedication for the benefit 19 | of the public at large and to the detriment of our heirs and 20 | successors. We intend this dedication to be an overt act of 21 | relinquishment in perpetuity of all present and future rights to this 22 | software under copyright law. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 27 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 28 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 29 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 30 | OTHER DEALINGS IN THE SOFTWARE. 31 | 32 | For more information, please refer to 33 | */ 34 | #ifndef SHEREDOM_HASHMAP_H_INCLUDED 35 | #define SHEREDOM_HASHMAP_H_INCLUDED 36 | 37 | #if defined(_MSC_VER) 38 | // Workaround a bug in the MSVC runtime where it uses __cplusplus when not 39 | // defined. 40 | #pragma warning(push, 0) 41 | #pragma warning(disable : 4668) 42 | #endif 43 | #include 44 | #include 45 | 46 | #if (defined(_MSC_VER) && defined(__AVX__)) || \ 47 | (!defined(_MSC_VER) && defined(__SSE4_2__)) 48 | #define HASHMAP_SSE42 49 | #endif 50 | 51 | #if defined(HASHMAP_SSE42) 52 | #include 53 | #endif 54 | 55 | #if defined(_MSC_VER) 56 | #pragma warning(pop) 57 | #endif 58 | 59 | #if defined(_MSC_VER) 60 | #pragma warning(push) 61 | /* Stop MSVC complaining about unreferenced functions */ 62 | #pragma warning(disable : 4505) 63 | /* Stop MSVC complaining about not inlining functions */ 64 | #pragma warning(disable : 4710) 65 | /* Stop MSVC complaining about inlining functions! */ 66 | #pragma warning(disable : 4711) 67 | #elif defined(__clang__) 68 | #pragma clang diagnostic push 69 | #pragma clang diagnostic ignored "-Wunused-function" 70 | #endif 71 | 72 | #if defined(_MSC_VER) 73 | #define HASHMAP_USED 74 | #elif defined(__GNUC__) 75 | #define HASHMAP_USED __attribute__((used)) 76 | #else 77 | #define HASHMAP_USED 78 | #endif 79 | 80 | /* We need to keep keys and values. */ 81 | struct hashmap_element_s { 82 | char *key; 83 | unsigned key_len; 84 | int in_use; 85 | void *data; 86 | }; 87 | 88 | /* A hashmap has some maximum size and current size, as well as the data to 89 | * hold. */ 90 | struct hashmap_s { 91 | unsigned table_size; 92 | unsigned size; 93 | struct hashmap_element_s *data; 94 | }; 95 | 96 | #define HASHMAP_MAX_CHAIN_LENGTH (8) 97 | 98 | #if defined(__cplusplus) 99 | extern "C" { 100 | #endif 101 | 102 | /// @brief Create a hashmap. 103 | /// @param initial_size The initial size of the hashmap. Must be a power of two. 104 | /// @param out_hashmap The storage for the created hashmap. 105 | /// @return On success 0 is returned. 106 | /// 107 | /// Note that the initial size of the hashmap must be a power of two, and 108 | /// creation of the hashmap will fail if this is not the case. 109 | static int hashmap_create(const unsigned initial_size, 110 | struct hashmap_s *const out_hashmap) HASHMAP_USED; 111 | 112 | /// @brief Put an element into the hashmap. 113 | /// @param hashmap The hashmap to insert into. 114 | /// @param key The string key to use. 115 | /// @param len The length of the string key. 116 | /// @param value The value to insert. 117 | /// @return On success 0 is returned. 118 | /// 119 | /// The key string slice is not copied when creating the hashmap entry, and thus 120 | /// must remain a valid pointer until the hashmap entry is removed or the 121 | /// hashmap is destroyed. 122 | static int hashmap_put(struct hashmap_s *const hashmap, char *const key, 123 | const unsigned len, void *const value) HASHMAP_USED; 124 | 125 | /// @brief Get an element from the hashmap. 126 | /// @param hashmap The hashmap to get from. 127 | /// @param key The string key to use. 128 | /// @param len The length of the string key. 129 | /// @return The previously set element, or NULL if none exists. 130 | static void *hashmap_get(const struct hashmap_s *const hashmap, 131 | const char *const key, 132 | const unsigned len) HASHMAP_USED; 133 | 134 | /// @brief Remove an element from the hashmap. 135 | /// @param hashmap The hashmap to remove from. 136 | /// @param key The string key to use. 137 | /// @param len The length of the string key. 138 | /// @return On success 0 is returned. 139 | static int hashmap_remove(struct hashmap_s *const hashmap, 140 | const char *const key, 141 | const unsigned len) HASHMAP_USED; 142 | 143 | /// @brief Remove an element from the hashmap. 144 | /// @param hashmap The hashmap to remove from. 145 | /// @param key The string key to use. 146 | /// @param len The length of the string key. 147 | /// @return On success the original stored key pointer is returned, on failure 148 | /// NULL is returned. 149 | static const char * 150 | hashmap_remove_and_return_key(struct hashmap_s *const hashmap, 151 | const char *const key, 152 | const unsigned len) HASHMAP_USED; 153 | 154 | /// @brief Iterate over all the elements in a hashmap. 155 | /// @param hashmap The hashmap to iterate over. 156 | /// @param f The function pointer to call on each element. 157 | /// @param context The context to pass as the first argument to f. 158 | /// @return If the entire hashmap was iterated then 0 is returned. Otherwise if 159 | /// the callback function f returned non-zero then non-zero is returned. 160 | static int hashmap_iterate(const struct hashmap_s *const hashmap, 161 | int (*f)(void *const context, void *const value), 162 | void *const context) HASHMAP_USED; 163 | 164 | /// @brief Iterate over all the elements in a hashmap. 165 | /// @param hashmap The hashmap to iterate over. 166 | /// @param f The function pointer to call on each element. 167 | /// @param context The context to pass as the first argument to f. 168 | /// @return If the entire hashmap was iterated then 0 is returned. 169 | /// Otherwise if the callback function f returned positive then the positive 170 | /// value is returned. If the callback function returns -1, the current item 171 | /// is removed and iteration continues. 172 | static int hashmap_iterate_pairs(struct hashmap_s *const hashmap, 173 | int (*f)(void *const, 174 | struct hashmap_element_s *const), 175 | void *const context) HASHMAP_USED; 176 | 177 | /// @brief Get the size of the hashmap. 178 | /// @param hashmap The hashmap to get the size of. 179 | /// @return The size of the hashmap. 180 | static unsigned 181 | hashmap_num_entries(const struct hashmap_s *const hashmap) HASHMAP_USED; 182 | 183 | /// @brief Destroy the hashmap. 184 | /// @param hashmap The hashmap to destroy. 185 | static void hashmap_destroy(struct hashmap_s *const hashmap) HASHMAP_USED; 186 | 187 | static unsigned hashmap_crc32_helper(const char *const s, 188 | const unsigned len) HASHMAP_USED; 189 | static unsigned hashmap_hash_helper_int_helper(const struct hashmap_s *const m, 190 | const char *const keystring, 191 | const unsigned len) HASHMAP_USED; 192 | static int hashmap_match_helper(const struct hashmap_element_s *const element, 193 | const char *const key, 194 | const unsigned len) HASHMAP_USED; 195 | static int hashmap_hash_helper(const struct hashmap_s *const m, 196 | const char *const key, const unsigned len, 197 | unsigned *const out_index) HASHMAP_USED; 198 | static int 199 | hashmap_rehash_iterator(void *const new_hash, 200 | struct hashmap_element_s *const e) HASHMAP_USED; 201 | static int hashmap_rehash_helper(struct hashmap_s *const m) HASHMAP_USED; 202 | 203 | #if defined(__cplusplus) 204 | } 205 | #endif 206 | 207 | #if defined(__cplusplus) 208 | #define HASHMAP_CAST(type, x) static_cast(x) 209 | #define HASHMAP_PTR_CAST(type, x) reinterpret_cast(x) 210 | #define HASHMAP_NULL NULL 211 | #else 212 | #define HASHMAP_CAST(type, x) ((type)x) 213 | #define HASHMAP_PTR_CAST(type, x) ((type)x) 214 | #define HASHMAP_NULL 0 215 | #endif 216 | 217 | int hashmap_create(const unsigned initial_size, 218 | struct hashmap_s *const out_hashmap) { 219 | out_hashmap->table_size = initial_size; 220 | out_hashmap->size = 0; 221 | 222 | if (0 == initial_size || 0 != (initial_size & (initial_size - 1))) { 223 | return 1; 224 | } 225 | 226 | out_hashmap->data = 227 | HASHMAP_CAST(struct hashmap_element_s *, 228 | calloc(initial_size, sizeof(struct hashmap_element_s))); 229 | if (!out_hashmap->data) { 230 | return 1; 231 | } 232 | 233 | return 0; 234 | } 235 | 236 | int hashmap_put(struct hashmap_s *const m, char *const key, 237 | const unsigned len, void *const value) { 238 | unsigned int index; 239 | 240 | /* Find a place to put our value. */ 241 | while (!hashmap_hash_helper(m, key, len, &index)) { 242 | if (hashmap_rehash_helper(m)) { 243 | return 1; 244 | } 245 | } 246 | 247 | /* Set the data. */ 248 | m->data[index].data = value; 249 | m->data[index].key = key; 250 | m->data[index].key_len = len; 251 | 252 | /* If the hashmap element was not already in use, set that it is being used 253 | * and bump our size. */ 254 | if (0 == m->data[index].in_use) { 255 | m->data[index].in_use = 1; 256 | m->size++; 257 | } 258 | 259 | return 0; 260 | } 261 | 262 | void *hashmap_get(const struct hashmap_s *const m, const char *const key, 263 | const unsigned len) { 264 | unsigned int curr; 265 | unsigned int i; 266 | 267 | /* Find data location */ 268 | curr = hashmap_hash_helper_int_helper(m, key, len); 269 | 270 | /* Linear probing, if necessary */ 271 | for (i = 0; i < HASHMAP_MAX_CHAIN_LENGTH; i++) { 272 | if (m->data[curr].in_use) { 273 | if (hashmap_match_helper(&m->data[curr], key, len)) { 274 | return m->data[curr].data; 275 | } 276 | } 277 | 278 | curr = (curr + 1) % m->table_size; 279 | } 280 | 281 | /* Not found */ 282 | return HASHMAP_NULL; 283 | } 284 | 285 | int hashmap_remove(struct hashmap_s *const m, const char *const key, 286 | const unsigned len) { 287 | unsigned int i; 288 | unsigned int curr; 289 | 290 | /* Find key */ 291 | curr = hashmap_hash_helper_int_helper(m, key, len); 292 | 293 | /* Linear probing, if necessary */ 294 | for (i = 0; i < HASHMAP_MAX_CHAIN_LENGTH; i++) { 295 | if (m->data[curr].in_use) { 296 | if (hashmap_match_helper(&m->data[curr], key, len)) { 297 | /* Blank out the fields including in_use */ 298 | memset(&m->data[curr], 0, sizeof(struct hashmap_element_s)); 299 | 300 | /* Reduce the size */ 301 | m->size--; 302 | 303 | return 0; 304 | } 305 | } 306 | 307 | curr = (curr + 1) % m->table_size; 308 | } 309 | 310 | return 1; 311 | } 312 | 313 | const char *hashmap_remove_and_return_key(struct hashmap_s *const m, 314 | const char *const key, 315 | const unsigned len) { 316 | unsigned int i; 317 | unsigned int curr; 318 | 319 | /* Find key */ 320 | curr = hashmap_hash_helper_int_helper(m, key, len); 321 | 322 | /* Linear probing, if necessary */ 323 | for (i = 0; i < HASHMAP_MAX_CHAIN_LENGTH; i++) { 324 | if (m->data[curr].in_use) { 325 | if (hashmap_match_helper(&m->data[curr], key, len)) { 326 | const char *const stored_key = m->data[curr].key; 327 | 328 | /* Blank out the fields */ 329 | m->data[curr].in_use = 0; 330 | m->data[curr].data = HASHMAP_NULL; 331 | m->data[curr].key = HASHMAP_NULL; 332 | 333 | /* Reduce the size */ 334 | m->size--; 335 | 336 | return stored_key; 337 | } 338 | } 339 | curr = (curr + 1) % m->table_size; 340 | } 341 | 342 | return HASHMAP_NULL; 343 | } 344 | 345 | int hashmap_iterate(const struct hashmap_s *const m, 346 | int (*f)(void *const, void *const), void *const context) { 347 | unsigned int i; 348 | 349 | /* Linear probing */ 350 | for (i = 0; i < m->table_size; i++) { 351 | if (m->data[i].in_use) { 352 | if (!f(context, m->data[i].data)) { 353 | return 1; 354 | } 355 | } 356 | } 357 | return 0; 358 | } 359 | 360 | int hashmap_iterate_pairs(struct hashmap_s *const hashmap, 361 | int (*f)(void *const, 362 | struct hashmap_element_s *const), 363 | void *const context) { 364 | unsigned int i; 365 | struct hashmap_element_s *p; 366 | int r; 367 | 368 | /* Linear probing */ 369 | for (i = 0; i < hashmap->table_size; i++) { 370 | p = &hashmap->data[i]; 371 | if (p->in_use) { 372 | r = f(context, p); 373 | switch (r) { 374 | case -1: /* remove item */ 375 | memset(p, 0, sizeof(struct hashmap_element_s)); 376 | hashmap->size--; 377 | break; 378 | case 0: /* continue iterating */ 379 | break; 380 | default: /* early exit */ 381 | return 1; 382 | } 383 | } 384 | } 385 | return 0; 386 | } 387 | 388 | void hashmap_destroy(struct hashmap_s *const m) { 389 | free(m->data); 390 | memset(m, 0, sizeof(struct hashmap_s)); 391 | } 392 | 393 | unsigned hashmap_num_entries(const struct hashmap_s *const m) { 394 | return m->size; 395 | } 396 | 397 | unsigned hashmap_crc32_helper(const char *const s, const unsigned len) { 398 | unsigned i; 399 | unsigned crc32val = 0; 400 | 401 | #if defined(HASHMAP_SSE42) 402 | for (i = 0; i < len; i++) { 403 | crc32val = _mm_crc32_u8(crc32val, HASHMAP_CAST(unsigned char, s[i])); 404 | } 405 | 406 | return crc32val; 407 | #else 408 | // Using polynomial 0x11EDC6F41 to match SSE 4.2's crc function. 409 | static const unsigned crc32_tab[] = { 410 | 0x00000000U, 0xF26B8303U, 0xE13B70F7U, 0x1350F3F4U, 0xC79A971FU, 411 | 0x35F1141CU, 0x26A1E7E8U, 0xD4CA64EBU, 0x8AD958CFU, 0x78B2DBCCU, 412 | 0x6BE22838U, 0x9989AB3BU, 0x4D43CFD0U, 0xBF284CD3U, 0xAC78BF27U, 413 | 0x5E133C24U, 0x105EC76FU, 0xE235446CU, 0xF165B798U, 0x030E349BU, 414 | 0xD7C45070U, 0x25AFD373U, 0x36FF2087U, 0xC494A384U, 0x9A879FA0U, 415 | 0x68EC1CA3U, 0x7BBCEF57U, 0x89D76C54U, 0x5D1D08BFU, 0xAF768BBCU, 416 | 0xBC267848U, 0x4E4DFB4BU, 0x20BD8EDEU, 0xD2D60DDDU, 0xC186FE29U, 417 | 0x33ED7D2AU, 0xE72719C1U, 0x154C9AC2U, 0x061C6936U, 0xF477EA35U, 418 | 0xAA64D611U, 0x580F5512U, 0x4B5FA6E6U, 0xB93425E5U, 0x6DFE410EU, 419 | 0x9F95C20DU, 0x8CC531F9U, 0x7EAEB2FAU, 0x30E349B1U, 0xC288CAB2U, 420 | 0xD1D83946U, 0x23B3BA45U, 0xF779DEAEU, 0x05125DADU, 0x1642AE59U, 421 | 0xE4292D5AU, 0xBA3A117EU, 0x4851927DU, 0x5B016189U, 0xA96AE28AU, 422 | 0x7DA08661U, 0x8FCB0562U, 0x9C9BF696U, 0x6EF07595U, 0x417B1DBCU, 423 | 0xB3109EBFU, 0xA0406D4BU, 0x522BEE48U, 0x86E18AA3U, 0x748A09A0U, 424 | 0x67DAFA54U, 0x95B17957U, 0xCBA24573U, 0x39C9C670U, 0x2A993584U, 425 | 0xD8F2B687U, 0x0C38D26CU, 0xFE53516FU, 0xED03A29BU, 0x1F682198U, 426 | 0x5125DAD3U, 0xA34E59D0U, 0xB01EAA24U, 0x42752927U, 0x96BF4DCCU, 427 | 0x64D4CECFU, 0x77843D3BU, 0x85EFBE38U, 0xDBFC821CU, 0x2997011FU, 428 | 0x3AC7F2EBU, 0xC8AC71E8U, 0x1C661503U, 0xEE0D9600U, 0xFD5D65F4U, 429 | 0x0F36E6F7U, 0x61C69362U, 0x93AD1061U, 0x80FDE395U, 0x72966096U, 430 | 0xA65C047DU, 0x5437877EU, 0x4767748AU, 0xB50CF789U, 0xEB1FCBADU, 431 | 0x197448AEU, 0x0A24BB5AU, 0xF84F3859U, 0x2C855CB2U, 0xDEEEDFB1U, 432 | 0xCDBE2C45U, 0x3FD5AF46U, 0x7198540DU, 0x83F3D70EU, 0x90A324FAU, 433 | 0x62C8A7F9U, 0xB602C312U, 0x44694011U, 0x5739B3E5U, 0xA55230E6U, 434 | 0xFB410CC2U, 0x092A8FC1U, 0x1A7A7C35U, 0xE811FF36U, 0x3CDB9BDDU, 435 | 0xCEB018DEU, 0xDDE0EB2AU, 0x2F8B6829U, 0x82F63B78U, 0x709DB87BU, 436 | 0x63CD4B8FU, 0x91A6C88CU, 0x456CAC67U, 0xB7072F64U, 0xA457DC90U, 437 | 0x563C5F93U, 0x082F63B7U, 0xFA44E0B4U, 0xE9141340U, 0x1B7F9043U, 438 | 0xCFB5F4A8U, 0x3DDE77ABU, 0x2E8E845FU, 0xDCE5075CU, 0x92A8FC17U, 439 | 0x60C37F14U, 0x73938CE0U, 0x81F80FE3U, 0x55326B08U, 0xA759E80BU, 440 | 0xB4091BFFU, 0x466298FCU, 0x1871A4D8U, 0xEA1A27DBU, 0xF94AD42FU, 441 | 0x0B21572CU, 0xDFEB33C7U, 0x2D80B0C4U, 0x3ED04330U, 0xCCBBC033U, 442 | 0xA24BB5A6U, 0x502036A5U, 0x4370C551U, 0xB11B4652U, 0x65D122B9U, 443 | 0x97BAA1BAU, 0x84EA524EU, 0x7681D14DU, 0x2892ED69U, 0xDAF96E6AU, 444 | 0xC9A99D9EU, 0x3BC21E9DU, 0xEF087A76U, 0x1D63F975U, 0x0E330A81U, 445 | 0xFC588982U, 0xB21572C9U, 0x407EF1CAU, 0x532E023EU, 0xA145813DU, 446 | 0x758FE5D6U, 0x87E466D5U, 0x94B49521U, 0x66DF1622U, 0x38CC2A06U, 447 | 0xCAA7A905U, 0xD9F75AF1U, 0x2B9CD9F2U, 0xFF56BD19U, 0x0D3D3E1AU, 448 | 0x1E6DCDEEU, 0xEC064EEDU, 0xC38D26C4U, 0x31E6A5C7U, 0x22B65633U, 449 | 0xD0DDD530U, 0x0417B1DBU, 0xF67C32D8U, 0xE52CC12CU, 0x1747422FU, 450 | 0x49547E0BU, 0xBB3FFD08U, 0xA86F0EFCU, 0x5A048DFFU, 0x8ECEE914U, 451 | 0x7CA56A17U, 0x6FF599E3U, 0x9D9E1AE0U, 0xD3D3E1ABU, 0x21B862A8U, 452 | 0x32E8915CU, 0xC083125FU, 0x144976B4U, 0xE622F5B7U, 0xF5720643U, 453 | 0x07198540U, 0x590AB964U, 0xAB613A67U, 0xB831C993U, 0x4A5A4A90U, 454 | 0x9E902E7BU, 0x6CFBAD78U, 0x7FAB5E8CU, 0x8DC0DD8FU, 0xE330A81AU, 455 | 0x115B2B19U, 0x020BD8EDU, 0xF0605BEEU, 0x24AA3F05U, 0xD6C1BC06U, 456 | 0xC5914FF2U, 0x37FACCF1U, 0x69E9F0D5U, 0x9B8273D6U, 0x88D28022U, 457 | 0x7AB90321U, 0xAE7367CAU, 0x5C18E4C9U, 0x4F48173DU, 0xBD23943EU, 458 | 0xF36E6F75U, 0x0105EC76U, 0x12551F82U, 0xE03E9C81U, 0x34F4F86AU, 459 | 0xC69F7B69U, 0xD5CF889DU, 0x27A40B9EU, 0x79B737BAU, 0x8BDCB4B9U, 460 | 0x988C474DU, 0x6AE7C44EU, 0xBE2DA0A5U, 0x4C4623A6U, 0x5F16D052U, 461 | 0xAD7D5351U}; 462 | 463 | for (i = 0; i < len; i++) { 464 | crc32val = crc32_tab[(HASHMAP_CAST(unsigned char, crc32val) ^ 465 | HASHMAP_CAST(unsigned char, s[i]))] ^ 466 | (crc32val >> 8); 467 | } 468 | return crc32val; 469 | #endif 470 | } 471 | 472 | unsigned hashmap_hash_helper_int_helper(const struct hashmap_s *const m, 473 | const char *const keystring, 474 | const unsigned len) { 475 | unsigned key = hashmap_crc32_helper(keystring, len); 476 | 477 | /* Robert Jenkins' 32 bit Mix Function */ 478 | key += (key << 12); 479 | key ^= (key >> 22); 480 | key += (key << 4); 481 | key ^= (key >> 9); 482 | key += (key << 10); 483 | key ^= (key >> 2); 484 | key += (key << 7); 485 | key ^= (key >> 12); 486 | 487 | /* Knuth's Multiplicative Method */ 488 | key = (key >> 3) * 2654435761; 489 | 490 | return key % m->table_size; 491 | } 492 | 493 | int hashmap_match_helper(const struct hashmap_element_s *const element, 494 | const char *const key, const unsigned len) { 495 | return (element->key_len == len) && (0 == memcmp(element->key, key, len)); 496 | } 497 | 498 | int hashmap_hash_helper(const struct hashmap_s *const m, const char *const key, 499 | const unsigned len, unsigned *const out_index) { 500 | unsigned int start, curr; 501 | unsigned int i; 502 | int total_in_use; 503 | 504 | /* If full, return immediately */ 505 | if (m->size >= m->table_size) { 506 | return 0; 507 | } 508 | 509 | /* Find the best index */ 510 | curr = start = hashmap_hash_helper_int_helper(m, key, len); 511 | 512 | /* First linear probe to check if we've already insert the element */ 513 | total_in_use = 0; 514 | 515 | for (i = 0; i < HASHMAP_MAX_CHAIN_LENGTH; i++) { 516 | const int in_use = m->data[curr].in_use; 517 | 518 | total_in_use += in_use; 519 | 520 | if (in_use && hashmap_match_helper(&m->data[curr], key, len)) { 521 | *out_index = curr; 522 | return 1; 523 | } 524 | 525 | curr = (curr + 1) % m->table_size; 526 | } 527 | 528 | curr = start; 529 | 530 | /* Second linear probe to actually insert our element (only if there was at 531 | * least one empty entry) */ 532 | if (HASHMAP_MAX_CHAIN_LENGTH > total_in_use) { 533 | for (i = 0; i < HASHMAP_MAX_CHAIN_LENGTH; i++) { 534 | if (!m->data[curr].in_use) { 535 | *out_index = curr; 536 | return 1; 537 | } 538 | 539 | curr = (curr + 1) % m->table_size; 540 | } 541 | } 542 | 543 | return 0; 544 | } 545 | 546 | int hashmap_rehash_iterator(void *const new_hash, 547 | struct hashmap_element_s *const e) { 548 | int temp = hashmap_put(HASHMAP_PTR_CAST(struct hashmap_s *, new_hash), e->key, 549 | e->key_len, e->data); 550 | if (0 < temp) { 551 | return 1; 552 | } 553 | /* clear old value to avoid stale pointers */ 554 | return -1; 555 | } 556 | /* 557 | * Doubles the size of the hashmap, and rehashes all the elements 558 | */ 559 | int hashmap_rehash_helper(struct hashmap_s *const m) { 560 | /* If this multiplication overflows hashmap_create will fail. */ 561 | unsigned new_size = 2 * m->table_size; 562 | 563 | struct hashmap_s new_hash; 564 | 565 | int flag = hashmap_create(new_size, &new_hash); 566 | 567 | if (0 != flag) { 568 | return flag; 569 | } 570 | 571 | /* copy the old elements to the new table */ 572 | flag = hashmap_iterate_pairs(m, hashmap_rehash_iterator, 573 | HASHMAP_PTR_CAST(void *, &new_hash)); 574 | 575 | if (0 != flag) { 576 | return flag; 577 | } 578 | 579 | hashmap_destroy(m); 580 | /* put new hash into old hash structure by copying */ 581 | memcpy(m, &new_hash, sizeof(struct hashmap_s)); 582 | 583 | return 0; 584 | } 585 | 586 | #if defined(_MSC_VER) 587 | #pragma warning(pop) 588 | #elif defined(__clang__) 589 | #pragma clang diagnostic pop 590 | #endif 591 | 592 | #endif 593 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "zua_parser_defs.h" 3 | 4 | int main(int argc, char *argv[]) { 5 | 6 | zua_string *file_json = zua_file_gets("../examples/file.json5"); 7 | 8 | zval *response = json_decode(ZSTRL(file_json)); 9 | printf("%s\n", ZSTR_VAL(file_json)); 10 | 11 | if (response->u2.errcode != 0) { 12 | printf("解析错误~"); 13 | zval_free(response); 14 | return 0; 15 | } 16 | zval *unquoted = zua_get_value(response, ZUA_STR("unquoted")); 17 | printf("unquoted:%s\n", ZSTR_VAL(Z_STR_P(unquoted))); 18 | 19 | zval *lineBreaks = zua_get_value(response, ZUA_STR("lineBreaks")); 20 | printf("lineBreaks: %s\n", ZSTR_VAL(Z_STR_P(lineBreaks))); 21 | 22 | zval *positiveSign = zua_get_value_by_path(response, ZUA_STR("test.cc.4")); 23 | printf("positiveSign: %s\n", ZSTR_VAL(Z_STR_P(positiveSign))); 24 | 25 | zval_free(response); 26 | zua_string_free(file_json); 27 | 28 | return 0; 29 | } -------------------------------------------------------------------------------- /zua_parser.c: -------------------------------------------------------------------------------- 1 | /* A Bison parser, made by GNU Bison 3.3.2. */ 2 | 3 | /* Bison implementation for Yacc-like parsers in C 4 | 5 | Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation, 6 | Inc. 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . */ 20 | 21 | /* As a special exception, you may create a larger work that contains 22 | part or all of the Bison parser skeleton and distribute that work 23 | under terms of your choice, so long as that work isn't itself a 24 | parser generator using the skeleton or a modified version thereof 25 | as a parser skeleton. Alternatively, if you modify or redistribute 26 | the parser skeleton itself, you may (at your option) remove this 27 | special exception, which will cause the skeleton and the resulting 28 | Bison output files to be licensed under the GNU General Public 29 | License without this special exception. 30 | 31 | This special exception was added by the Free Software Foundation in 32 | version 2.2 of Bison. */ 33 | 34 | /* C LALR(1) parser skeleton written by Richard Stallman, by 35 | simplifying the original so-called "semantic" parser. */ 36 | 37 | /* All symbols defined below should begin with yy or YY, to avoid 38 | infringing on user name space. This should be done even for local 39 | variables, as they might otherwise be expanded by user macros. 40 | There are some unavoidable exceptions within include files to 41 | define necessary library symbols; they are noted "INFRINGES ON 42 | USER NAME SPACE" below. */ 43 | 44 | /* Undocumented macros, especially those whose name start with YY_, 45 | are private implementation details. Do not rely on them. */ 46 | 47 | /* Identify Bison output. */ 48 | #define YYBISON 1 49 | 50 | /* Bison version. */ 51 | #define YYBISON_VERSION "3.3.2" 52 | 53 | /* Skeleton name. */ 54 | #define YYSKELETON_NAME "yacc.c" 55 | 56 | /* Pure parsers. */ 57 | #define YYPURE 2 58 | 59 | /* Push parsers. */ 60 | #define YYPUSH 0 61 | 62 | /* Pull parsers. */ 63 | #define YYPULL 1 64 | 65 | /* "%code top" blocks. */ 66 | 67 | 68 | /* bison --defines -l zua_parser.y -o zua_parser.c */ 69 | #include 70 | #include "zua_scanner.h" 71 | 72 | #define YYDEBUG 1 73 | #define YYERROR_VERBOSE 1 74 | 75 | 76 | /* Substitute the type names. */ 77 | #define YYSTYPE ZUA_YYSTYPE 78 | /* Substitute the variable and function names. */ 79 | #define yyparse zua_yyparse 80 | #define yylex zua_yylex 81 | #define yyerror zua_yyerror 82 | #define yydebug zua_yydebug 83 | #define yynerrs zua_yynerrs 84 | 85 | 86 | 87 | # ifndef YY_NULLPTR 88 | # if defined __cplusplus 89 | # if 201103L <= __cplusplus 90 | # define YY_NULLPTR nullptr 91 | # else 92 | # define YY_NULLPTR 0 93 | # endif 94 | # else 95 | # define YY_NULLPTR ((void*)0) 96 | # endif 97 | # endif 98 | 99 | /* Enabling verbose error messages. */ 100 | #ifdef YYERROR_VERBOSE 101 | # undef YYERROR_VERBOSE 102 | # define YYERROR_VERBOSE 1 103 | #else 104 | # define YYERROR_VERBOSE 0 105 | #endif 106 | 107 | /* In a future release of Bison, this section will be replaced 108 | by #include "zua_parser.h". */ 109 | #ifndef YY_ZUA_YY_ZUA_PARSER_H_INCLUDED 110 | # define YY_ZUA_YY_ZUA_PARSER_H_INCLUDED 111 | /* Debug traces. */ 112 | #ifndef ZUA_YYDEBUG 113 | # if defined YYDEBUG 114 | #if YYDEBUG 115 | # define ZUA_YYDEBUG 1 116 | # else 117 | # define ZUA_YYDEBUG 0 118 | # endif 119 | # else /* ! defined YYDEBUG */ 120 | # define ZUA_YYDEBUG 0 121 | # endif /* ! defined YYDEBUG */ 122 | #endif /* ! defined ZUA_YYDEBUG */ 123 | #if ZUA_YYDEBUG 124 | extern int zua_yydebug; 125 | #endif 126 | /* "%code requires" blocks. */ 127 | 128 | 129 | #include "zua_type.h" 130 | #include "zua_parser_defs.h" 131 | 132 | 133 | 134 | /* Token type. */ 135 | #ifndef ZUA_YYTOKENTYPE 136 | # define ZUA_YYTOKENTYPE 137 | enum zua_yytokentype 138 | { 139 | ZUA_JSON_T_NUL = 258, 140 | ZUA_JSON_T_NAN = 259, 141 | ZUA_JSON_T_INFINITY = 260, 142 | ZUA_JSON_T_NEGATIVE_INFINITY = 261, 143 | ZUA_JSON_T_TRUE = 262, 144 | ZUA_JSON_T_FALSE = 263, 145 | ZUA_JSON_T_INT = 264, 146 | ZUA_JSON_T_DOUBLE = 265, 147 | ZUA_JSON_T_STRING = 266, 148 | ZUA_JSON_T_ETRING = 267, 149 | ZUA_JSON_T_EOI = 268, 150 | ZUA_JSON_T_ERROR = 269, 151 | ZUA_JSON_T_COMMENT_NOT_CLOSED = 270 152 | }; 153 | #endif 154 | 155 | /* Value type. */ 156 | #if ! defined ZUA_YYSTYPE && ! defined ZUA_YYSTYPE_IS_DECLARED 157 | 158 | union ZUA_YYSTYPE 159 | { 160 | 161 | 162 | zval value; 163 | 164 | 165 | }; 166 | 167 | typedef union ZUA_YYSTYPE ZUA_YYSTYPE; 168 | # define ZUA_YYSTYPE_IS_TRIVIAL 1 169 | # define ZUA_YYSTYPE_IS_DECLARED 1 170 | #endif 171 | 172 | 173 | 174 | int zua_yyparse (zua_json_parser *parser); 175 | 176 | #endif /* !YY_ZUA_YY_ZUA_PARSER_H_INCLUDED */ 177 | 178 | 179 | /* Unqualified %code blocks. */ 180 | 181 | 182 | static int zua_yylex(ZUA_YYSTYPE *, zua_json_parser *parser); 183 | static void zua_yyerror(zua_json_parser *parser, const char *str); 184 | 185 | 186 | 187 | #ifdef short 188 | # undef short 189 | #endif 190 | 191 | #ifdef YYTYPE_UINT8 192 | typedef YYTYPE_UINT8 yytype_uint8; 193 | #else 194 | typedef unsigned char yytype_uint8; 195 | #endif 196 | 197 | #ifdef YYTYPE_INT8 198 | typedef YYTYPE_INT8 yytype_int8; 199 | #else 200 | typedef signed char yytype_int8; 201 | #endif 202 | 203 | #ifdef YYTYPE_UINT16 204 | typedef YYTYPE_UINT16 yytype_uint16; 205 | #else 206 | typedef unsigned short yytype_uint16; 207 | #endif 208 | 209 | #ifdef YYTYPE_INT16 210 | typedef YYTYPE_INT16 yytype_int16; 211 | #else 212 | typedef short yytype_int16; 213 | #endif 214 | 215 | #ifndef YYSIZE_T 216 | # ifdef __SIZE_TYPE__ 217 | # define YYSIZE_T __SIZE_TYPE__ 218 | # elif defined size_t 219 | # define YYSIZE_T size_t 220 | # elif ! defined YYSIZE_T 221 | # include /* INFRINGES ON USER NAME SPACE */ 222 | # define YYSIZE_T size_t 223 | # else 224 | # define YYSIZE_T unsigned 225 | # endif 226 | #endif 227 | 228 | #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) 229 | 230 | #ifndef YY_ 231 | # if defined YYENABLE_NLS && YYENABLE_NLS 232 | # if ENABLE_NLS 233 | # include /* INFRINGES ON USER NAME SPACE */ 234 | # define YY_(Msgid) dgettext ("bison-runtime", Msgid) 235 | # endif 236 | # endif 237 | # ifndef YY_ 238 | # define YY_(Msgid) Msgid 239 | # endif 240 | #endif 241 | 242 | #ifndef YY_ATTRIBUTE 243 | # if (defined __GNUC__ \ 244 | && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ 245 | || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C 246 | # define YY_ATTRIBUTE(Spec) __attribute__(Spec) 247 | # else 248 | # define YY_ATTRIBUTE(Spec) /* empty */ 249 | # endif 250 | #endif 251 | 252 | #ifndef YY_ATTRIBUTE_PURE 253 | # define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) 254 | #endif 255 | 256 | #ifndef YY_ATTRIBUTE_UNUSED 257 | # define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) 258 | #endif 259 | 260 | /* Suppress unused-variable warnings by "using" E. */ 261 | #if ! defined lint || defined __GNUC__ 262 | # define YYUSE(E) ((void) (E)) 263 | #else 264 | # define YYUSE(E) /* empty */ 265 | #endif 266 | 267 | #if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ 268 | /* Suppress an incorrect diagnostic about yylval being uninitialized. */ 269 | # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ 270 | _Pragma ("GCC diagnostic push") \ 271 | _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ 272 | _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") 273 | # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ 274 | _Pragma ("GCC diagnostic pop") 275 | #else 276 | # define YY_INITIAL_VALUE(Value) Value 277 | #endif 278 | #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN 279 | # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN 280 | # define YY_IGNORE_MAYBE_UNINITIALIZED_END 281 | #endif 282 | #ifndef YY_INITIAL_VALUE 283 | # define YY_INITIAL_VALUE(Value) /* Nothing. */ 284 | #endif 285 | 286 | 287 | #if ! defined yyoverflow || YYERROR_VERBOSE 288 | 289 | /* The parser invokes alloca or malloc; define the necessary symbols. */ 290 | 291 | # ifdef YYSTACK_USE_ALLOCA 292 | # if YYSTACK_USE_ALLOCA 293 | # ifdef __GNUC__ 294 | # define YYSTACK_ALLOC __builtin_alloca 295 | # elif defined __BUILTIN_VA_ARG_INCR 296 | # include /* INFRINGES ON USER NAME SPACE */ 297 | # elif defined _AIX 298 | # define YYSTACK_ALLOC __alloca 299 | # elif defined _MSC_VER 300 | # include /* INFRINGES ON USER NAME SPACE */ 301 | # define alloca _alloca 302 | # else 303 | # define YYSTACK_ALLOC alloca 304 | # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS 305 | # include /* INFRINGES ON USER NAME SPACE */ 306 | /* Use EXIT_SUCCESS as a witness for stdlib.h. */ 307 | # ifndef EXIT_SUCCESS 308 | # define EXIT_SUCCESS 0 309 | # endif 310 | # endif 311 | # endif 312 | # endif 313 | # endif 314 | 315 | # ifdef YYSTACK_ALLOC 316 | /* Pacify GCC's 'empty if-body' warning. */ 317 | # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) 318 | # ifndef YYSTACK_ALLOC_MAXIMUM 319 | /* The OS might guarantee only one guard page at the bottom of the stack, 320 | and a page size can be as small as 4096 bytes. So we cannot safely 321 | invoke alloca (N) if N exceeds 4096. Use a slightly smaller number 322 | to allow for a few compiler-allocated temporary stack slots. */ 323 | # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ 324 | # endif 325 | # else 326 | # define YYSTACK_ALLOC YYMALLOC 327 | # define YYSTACK_FREE YYFREE 328 | # ifndef YYSTACK_ALLOC_MAXIMUM 329 | # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM 330 | # endif 331 | # if (defined __cplusplus && ! defined EXIT_SUCCESS \ 332 | && ! ((defined YYMALLOC || defined malloc) \ 333 | && (defined YYFREE || defined free))) 334 | # include /* INFRINGES ON USER NAME SPACE */ 335 | # ifndef EXIT_SUCCESS 336 | # define EXIT_SUCCESS 0 337 | # endif 338 | # endif 339 | # ifndef YYMALLOC 340 | # define YYMALLOC malloc 341 | # if ! defined malloc && ! defined EXIT_SUCCESS 342 | void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ 343 | # endif 344 | # endif 345 | # ifndef YYFREE 346 | # define YYFREE free 347 | # if ! defined free && ! defined EXIT_SUCCESS 348 | void free (void *); /* INFRINGES ON USER NAME SPACE */ 349 | # endif 350 | # endif 351 | # endif 352 | #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ 353 | 354 | 355 | #if (! defined yyoverflow \ 356 | && (! defined __cplusplus \ 357 | || (defined ZUA_YYSTYPE_IS_TRIVIAL && ZUA_YYSTYPE_IS_TRIVIAL))) 358 | 359 | /* A type that is properly aligned for any stack member. */ 360 | union yyalloc 361 | { 362 | yytype_int16 yyss_alloc; 363 | YYSTYPE yyvs_alloc; 364 | }; 365 | 366 | /* The size of the maximum gap between one aligned stack and the next. */ 367 | # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) 368 | 369 | /* The size of an array large to enough to hold all stacks, each with 370 | N elements. */ 371 | # define YYSTACK_BYTES(N) \ 372 | ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ 373 | + YYSTACK_GAP_MAXIMUM) 374 | 375 | # define YYCOPY_NEEDED 1 376 | 377 | /* Relocate STACK from its old location to the new one. The 378 | local variables YYSIZE and YYSTACKSIZE give the old and new number of 379 | elements in the stack, and YYPTR gives the new location of the 380 | stack. Advance YYPTR to a properly aligned location for the next 381 | stack. */ 382 | # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ 383 | do \ 384 | { \ 385 | YYSIZE_T yynewbytes; \ 386 | YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ 387 | Stack = &yyptr->Stack_alloc; \ 388 | yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ 389 | yyptr += yynewbytes / sizeof (*yyptr); \ 390 | } \ 391 | while (0) 392 | 393 | #endif 394 | 395 | #if defined YYCOPY_NEEDED && YYCOPY_NEEDED 396 | /* Copy COUNT objects from SRC to DST. The source and destination do 397 | not overlap. */ 398 | # ifndef YYCOPY 399 | # if defined __GNUC__ && 1 < __GNUC__ 400 | # define YYCOPY(Dst, Src, Count) \ 401 | __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) 402 | # else 403 | # define YYCOPY(Dst, Src, Count) \ 404 | do \ 405 | { \ 406 | YYSIZE_T yyi; \ 407 | for (yyi = 0; yyi < (Count); yyi++) \ 408 | (Dst)[yyi] = (Src)[yyi]; \ 409 | } \ 410 | while (0) 411 | # endif 412 | # endif 413 | #endif /* !YYCOPY_NEEDED */ 414 | 415 | /* YYFINAL -- State number of the termination state. */ 416 | #define YYFINAL 18 417 | /* YYLAST -- Last index in YYTABLE. */ 418 | #define YYLAST 27 419 | 420 | /* YYNTOKENS -- Number of terminals. */ 421 | #define YYNTOKENS 22 422 | /* YYNNTS -- Number of nonterminals. */ 423 | #define YYNNTS 16 424 | /* YYNRULES -- Number of rules. */ 425 | #define YYNRULES 35 426 | /* YYNSTATES -- Number of states. */ 427 | #define YYNSTATES 44 428 | 429 | #define YYUNDEFTOK 2 430 | #define YYMAXUTOK 270 431 | 432 | /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM 433 | as returned by yylex, with out-of-bounds checking. */ 434 | #define YYTRANSLATE(YYX) \ 435 | ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) 436 | 437 | /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM 438 | as returned by yylex. */ 439 | static const yytype_uint8 yytranslate[] = 440 | { 441 | 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 442 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 443 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 444 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 445 | 2, 2, 2, 2, 20, 2, 2, 2, 2, 2, 446 | 2, 2, 2, 2, 2, 2, 2, 2, 19, 2, 447 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 448 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 449 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 450 | 2, 21, 2, 18, 2, 2, 2, 2, 2, 2, 451 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 452 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 453 | 2, 2, 2, 16, 2, 17, 2, 2, 2, 2, 454 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 455 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 456 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 457 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 458 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 459 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 460 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 461 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 462 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 463 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 464 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 465 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 466 | 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 467 | 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 468 | 15 469 | }; 470 | 471 | #if ZUA_YYDEBUG 472 | /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ 473 | static const yytype_uint8 yyrline[] = 474 | { 475 | 0, 52, 52, 63, 62, 73, 74, 82, 86, 91, 476 | 97, 106, 107, 113, 112, 122, 123, 131, 135, 140, 477 | 145, 153, 154, 158, 159, 164, 165, 166, 167, 168, 478 | 169, 170, 171, 172, 173, 174 479 | }; 480 | #endif 481 | 482 | #if ZUA_YYDEBUG || YYERROR_VERBOSE || 0 483 | /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. 484 | First, the terminals, then, starting at YYNTOKENS, nonterminals. */ 485 | static const char *const yytname[] = 486 | { 487 | "$end", "error", "$undefined", "ZUA_JSON_T_NUL", "ZUA_JSON_T_NAN", 488 | "ZUA_JSON_T_INFINITY", "ZUA_JSON_T_NEGATIVE_INFINITY", "ZUA_JSON_T_TRUE", 489 | "ZUA_JSON_T_FALSE", "ZUA_JSON_T_INT", "ZUA_JSON_T_DOUBLE", 490 | "ZUA_JSON_T_STRING", "ZUA_JSON_T_ETRING", "ZUA_JSON_T_EOI", 491 | "ZUA_JSON_T_ERROR", "ZUA_JSON_T_COMMENT_NOT_CLOSED", "'{'", "'}'", "']'", 492 | "':'", "','", "'['", "$accept", "start", "object", "$@1", "object_end", 493 | "members", "member", "member_end", "array", "$@2", "array_end", 494 | "elements", "element", "element_end", "key", "value", YY_NULLPTR 495 | }; 496 | #endif 497 | 498 | # ifdef YYPRINT 499 | /* YYTOKNUM[NUM] -- (External) token number corresponding to the 500 | (internal) symbol number NUM (which must be that of a token). */ 501 | static const yytype_uint16 yytoknum[] = 502 | { 503 | 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 504 | 265, 266, 267, 268, 269, 270, 123, 125, 93, 58, 505 | 44, 91 506 | }; 507 | # endif 508 | 509 | #define YYPACT_NINF -18 510 | 511 | #define yypact_value_is_default(Yystate) \ 512 | (!!((Yystate) == (-18))) 513 | 514 | #define YYTABLE_NINF -1 515 | 516 | #define yytable_value_is_error(Yytable_value) \ 517 | 0 518 | 519 | /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing 520 | STATE-NUM. */ 521 | static const yytype_int8 yypact[] = 522 | { 523 | -2, -18, -18, -18, -18, -18, -18, -18, -18, -18, 524 | -18, -18, 15, -18, -18, 8, -1, -2, -18, -18, 525 | -18, -18, -5, 2, 4, 0, 6, -18, -18, -18, 526 | -18, -1, -18, -2, -18, -18, -18, -2, -18, 5, 527 | -18, -18, -2, -18 528 | }; 529 | 530 | /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. 531 | Performed when YYTABLE does not specify something else to do. Zero 532 | means the default is an error. */ 533 | static const yytype_uint8 yydefact[] = 534 | { 535 | 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, 536 | 3, 13, 0, 25, 26, 0, 7, 17, 1, 2, 537 | 23, 24, 0, 11, 0, 0, 21, 19, 5, 6, 538 | 4, 12, 8, 0, 16, 15, 14, 22, 18, 0, 539 | 9, 20, 0, 10 540 | }; 541 | 542 | /* YYPGOTO[NTERM-NUM]. */ 543 | static const yytype_int8 yypgoto[] = 544 | { 545 | -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, 546 | -18, -18, -18, -18, -4, -17 547 | }; 548 | 549 | /* YYDEFGOTO[NTERM-NUM]. */ 550 | static const yytype_int8 yydefgoto[] = 551 | { 552 | -1, 12, 13, 16, 30, 22, 23, 32, 14, 17, 553 | 36, 25, 26, 38, 24, 15 554 | }; 555 | 556 | /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If 557 | positive, shift that token. If negative, reduce the rule whose 558 | number is the opposite. If YYTABLE_NINF, syntax error. */ 559 | static const yytype_uint8 yytable[] = 560 | { 561 | 27, 1, 2, 3, 4, 5, 6, 7, 8, 9, 562 | 20, 21, 28, 29, 10, 18, 40, 34, 35, 11, 563 | 41, 19, 31, 33, 42, 43, 37, 39 564 | }; 565 | 566 | static const yytype_uint8 yycheck[] = 567 | { 568 | 17, 3, 4, 5, 6, 7, 8, 9, 10, 11, 569 | 11, 12, 17, 18, 16, 0, 33, 17, 18, 21, 570 | 37, 13, 20, 19, 19, 42, 20, 31 571 | }; 572 | 573 | /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing 574 | symbol of state STATE-NUM. */ 575 | static const yytype_uint8 yystos[] = 576 | { 577 | 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 578 | 16, 21, 23, 24, 30, 37, 25, 31, 0, 13, 579 | 11, 12, 27, 28, 36, 33, 34, 37, 17, 18, 580 | 26, 20, 29, 19, 17, 18, 32, 20, 35, 36, 581 | 37, 37, 19, 37 582 | }; 583 | 584 | /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ 585 | static const yytype_uint8 yyr1[] = 586 | { 587 | 0, 22, 23, 25, 24, 26, 26, 27, 27, 28, 588 | 28, 29, 29, 31, 30, 32, 32, 33, 33, 34, 589 | 34, 35, 35, 36, 36, 37, 37, 37, 37, 37, 590 | 37, 37, 37, 37, 37, 37 591 | }; 592 | 593 | /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ 594 | static const yytype_uint8 yyr2[] = 595 | { 596 | 0, 2, 2, 0, 4, 1, 1, 0, 2, 3, 597 | 5, 0, 1, 0, 4, 1, 1, 0, 2, 1, 598 | 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 599 | 1, 1, 1, 1, 1, 1 600 | }; 601 | 602 | 603 | #define yyerrok (yyerrstatus = 0) 604 | #define yyclearin (yychar = YYEMPTY) 605 | #define YYEMPTY (-2) 606 | #define YYEOF 0 607 | 608 | #define YYACCEPT goto yyacceptlab 609 | #define YYABORT goto yyabortlab 610 | #define YYERROR goto yyerrorlab 611 | 612 | 613 | #define YYRECOVERING() (!!yyerrstatus) 614 | 615 | #define YYBACKUP(Token, Value) \ 616 | do \ 617 | if (yychar == YYEMPTY) \ 618 | { \ 619 | yychar = (Token); \ 620 | yylval = (Value); \ 621 | YYPOPSTACK (yylen); \ 622 | yystate = *yyssp; \ 623 | goto yybackup; \ 624 | } \ 625 | else \ 626 | { \ 627 | yyerror (parser, YY_("syntax error: cannot back up")); \ 628 | YYERROR; \ 629 | } \ 630 | while (0) 631 | 632 | /* Error token number */ 633 | #define YYTERROR 1 634 | #define YYERRCODE 256 635 | 636 | 637 | 638 | /* Enable debugging if requested. */ 639 | #if ZUA_YYDEBUG 640 | 641 | # ifndef YYFPRINTF 642 | # include /* INFRINGES ON USER NAME SPACE */ 643 | # define YYFPRINTF fprintf 644 | # endif 645 | 646 | # define YYDPRINTF(Args) \ 647 | do { \ 648 | if (yydebug) \ 649 | YYFPRINTF Args; \ 650 | } while (0) 651 | 652 | /* This macro is provided for backward compatibility. */ 653 | #ifndef YY_LOCATION_PRINT 654 | # define YY_LOCATION_PRINT(File, Loc) ((void) 0) 655 | #endif 656 | 657 | 658 | # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ 659 | do { \ 660 | if (yydebug) \ 661 | { \ 662 | YYFPRINTF (stderr, "%s ", Title); \ 663 | yy_symbol_print (stderr, \ 664 | Type, Value, parser); \ 665 | YYFPRINTF (stderr, "\n"); \ 666 | } \ 667 | } while (0) 668 | 669 | 670 | /*-----------------------------------. 671 | | Print this symbol's value on YYO. | 672 | `-----------------------------------*/ 673 | 674 | static void 675 | yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, zua_json_parser *parser) 676 | { 677 | FILE *yyoutput = yyo; 678 | YYUSE (yyoutput); 679 | YYUSE (parser); 680 | if (!yyvaluep) 681 | return; 682 | # ifdef YYPRINT 683 | if (yytype < YYNTOKENS) 684 | YYPRINT (yyo, yytoknum[yytype], *yyvaluep); 685 | # endif 686 | YYUSE (yytype); 687 | } 688 | 689 | 690 | /*---------------------------. 691 | | Print this symbol on YYO. | 692 | `---------------------------*/ 693 | 694 | static void 695 | yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, zua_json_parser *parser) 696 | { 697 | YYFPRINTF (yyo, "%s %s (", 698 | yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); 699 | 700 | yy_symbol_value_print (yyo, yytype, yyvaluep, parser); 701 | YYFPRINTF (yyo, ")"); 702 | } 703 | 704 | /*------------------------------------------------------------------. 705 | | yy_stack_print -- Print the state stack from its BOTTOM up to its | 706 | | TOP (included). | 707 | `------------------------------------------------------------------*/ 708 | 709 | static void 710 | yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) 711 | { 712 | YYFPRINTF (stderr, "Stack now"); 713 | for (; yybottom <= yytop; yybottom++) 714 | { 715 | int yybot = *yybottom; 716 | YYFPRINTF (stderr, " %d", yybot); 717 | } 718 | YYFPRINTF (stderr, "\n"); 719 | } 720 | 721 | # define YY_STACK_PRINT(Bottom, Top) \ 722 | do { \ 723 | if (yydebug) \ 724 | yy_stack_print ((Bottom), (Top)); \ 725 | } while (0) 726 | 727 | 728 | /*------------------------------------------------. 729 | | Report that the YYRULE is going to be reduced. | 730 | `------------------------------------------------*/ 731 | 732 | static void 733 | yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, zua_json_parser *parser) 734 | { 735 | unsigned long yylno = yyrline[yyrule]; 736 | int yynrhs = yyr2[yyrule]; 737 | int yyi; 738 | YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", 739 | yyrule - 1, yylno); 740 | /* The symbols being reduced. */ 741 | for (yyi = 0; yyi < yynrhs; yyi++) 742 | { 743 | YYFPRINTF (stderr, " $%d = ", yyi + 1); 744 | yy_symbol_print (stderr, 745 | yystos[yyssp[yyi + 1 - yynrhs]], 746 | &yyvsp[(yyi + 1) - (yynrhs)] 747 | , parser); 748 | YYFPRINTF (stderr, "\n"); 749 | } 750 | } 751 | 752 | # define YY_REDUCE_PRINT(Rule) \ 753 | do { \ 754 | if (yydebug) \ 755 | yy_reduce_print (yyssp, yyvsp, Rule, parser); \ 756 | } while (0) 757 | 758 | /* Nonzero means print parse trace. It is left uninitialized so that 759 | multiple parsers can coexist. */ 760 | int yydebug; 761 | #else /* !ZUA_YYDEBUG */ 762 | # define YYDPRINTF(Args) 763 | # define YY_SYMBOL_PRINT(Title, Type, Value, Location) 764 | # define YY_STACK_PRINT(Bottom, Top) 765 | # define YY_REDUCE_PRINT(Rule) 766 | #endif /* !ZUA_YYDEBUG */ 767 | 768 | 769 | /* YYINITDEPTH -- initial size of the parser's stacks. */ 770 | #ifndef YYINITDEPTH 771 | # define YYINITDEPTH 200 772 | #endif 773 | 774 | /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only 775 | if the built-in stack extension method is used). 776 | 777 | Do not make this value too large; the results are undefined if 778 | YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) 779 | evaluated with infinite-precision integer arithmetic. */ 780 | 781 | #ifndef YYMAXDEPTH 782 | # define YYMAXDEPTH 10000 783 | #endif 784 | 785 | 786 | #if YYERROR_VERBOSE 787 | 788 | # ifndef yystrlen 789 | # if defined __GLIBC__ && defined _STRING_H 790 | # define yystrlen strlen 791 | # else 792 | /* Return the length of YYSTR. */ 793 | static YYSIZE_T 794 | yystrlen (const char *yystr) 795 | { 796 | YYSIZE_T yylen; 797 | for (yylen = 0; yystr[yylen]; yylen++) 798 | continue; 799 | return yylen; 800 | } 801 | # endif 802 | # endif 803 | 804 | # ifndef yystpcpy 805 | # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE 806 | # define yystpcpy stpcpy 807 | # else 808 | /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in 809 | YYDEST. */ 810 | static char * 811 | yystpcpy (char *yydest, const char *yysrc) 812 | { 813 | char *yyd = yydest; 814 | const char *yys = yysrc; 815 | 816 | while ((*yyd++ = *yys++) != '\0') 817 | continue; 818 | 819 | return yyd - 1; 820 | } 821 | # endif 822 | # endif 823 | 824 | # ifndef yytnamerr 825 | /* Copy to YYRES the contents of YYSTR after stripping away unnecessary 826 | quotes and backslashes, so that it's suitable for yyerror. The 827 | heuristic is that double-quoting is unnecessary unless the string 828 | contains an apostrophe, a comma, or backslash (other than 829 | backslash-backslash). YYSTR is taken from yytname. If YYRES is 830 | null, do not copy; instead, return the length of what the result 831 | would have been. */ 832 | static YYSIZE_T 833 | yytnamerr (char *yyres, const char *yystr) 834 | { 835 | if (*yystr == '"') 836 | { 837 | YYSIZE_T yyn = 0; 838 | char const *yyp = yystr; 839 | 840 | for (;;) 841 | switch (*++yyp) 842 | { 843 | case '\'': 844 | case ',': 845 | goto do_not_strip_quotes; 846 | 847 | case '\\': 848 | if (*++yyp != '\\') 849 | goto do_not_strip_quotes; 850 | else 851 | goto append; 852 | 853 | append: 854 | default: 855 | if (yyres) 856 | yyres[yyn] = *yyp; 857 | yyn++; 858 | break; 859 | 860 | case '"': 861 | if (yyres) 862 | yyres[yyn] = '\0'; 863 | return yyn; 864 | } 865 | do_not_strip_quotes: ; 866 | } 867 | 868 | if (! yyres) 869 | return yystrlen (yystr); 870 | 871 | return (YYSIZE_T) (yystpcpy (yyres, yystr) - yyres); 872 | } 873 | # endif 874 | 875 | /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message 876 | about the unexpected token YYTOKEN for the state stack whose top is 877 | YYSSP. 878 | 879 | Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is 880 | not large enough to hold the message. In that case, also set 881 | *YYMSG_ALLOC to the required number of bytes. Return 2 if the 882 | required number of bytes is too large to store. */ 883 | static int 884 | yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, 885 | yytype_int16 *yyssp, int yytoken) 886 | { 887 | YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); 888 | YYSIZE_T yysize = yysize0; 889 | enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; 890 | /* Internationalized format string. */ 891 | const char *yyformat = YY_NULLPTR; 892 | /* Arguments of yyformat. */ 893 | char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; 894 | /* Number of reported tokens (one for the "unexpected", one per 895 | "expected"). */ 896 | int yycount = 0; 897 | 898 | /* There are many possibilities here to consider: 899 | - If this state is a consistent state with a default action, then 900 | the only way this function was invoked is if the default action 901 | is an error action. In that case, don't check for expected 902 | tokens because there are none. 903 | - The only way there can be no lookahead present (in yychar) is if 904 | this state is a consistent state with a default action. Thus, 905 | detecting the absence of a lookahead is sufficient to determine 906 | that there is no unexpected or expected token to report. In that 907 | case, just report a simple "syntax error". 908 | - Don't assume there isn't a lookahead just because this state is a 909 | consistent state with a default action. There might have been a 910 | previous inconsistent state, consistent state with a non-default 911 | action, or user semantic action that manipulated yychar. 912 | - Of course, the expected token list depends on states to have 913 | correct lookahead information, and it depends on the parser not 914 | to perform extra reductions after fetching a lookahead from the 915 | scanner and before detecting a syntax error. Thus, state merging 916 | (from LALR or IELR) and default reductions corrupt the expected 917 | token list. However, the list is correct for canonical LR with 918 | one exception: it will still contain any token that will not be 919 | accepted due to an error action in a later state. 920 | */ 921 | if (yytoken != YYEMPTY) 922 | { 923 | int yyn = yypact[*yyssp]; 924 | yyarg[yycount++] = yytname[yytoken]; 925 | if (!yypact_value_is_default (yyn)) 926 | { 927 | /* Start YYX at -YYN if negative to avoid negative indexes in 928 | YYCHECK. In other words, skip the first -YYN actions for 929 | this state because they are default actions. */ 930 | int yyxbegin = yyn < 0 ? -yyn : 0; 931 | /* Stay within bounds of both yycheck and yytname. */ 932 | int yychecklim = YYLAST - yyn + 1; 933 | int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; 934 | int yyx; 935 | 936 | for (yyx = yyxbegin; yyx < yyxend; ++yyx) 937 | if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR 938 | && !yytable_value_is_error (yytable[yyx + yyn])) 939 | { 940 | if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) 941 | { 942 | yycount = 1; 943 | yysize = yysize0; 944 | break; 945 | } 946 | yyarg[yycount++] = yytname[yyx]; 947 | { 948 | YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); 949 | if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) 950 | yysize = yysize1; 951 | else 952 | return 2; 953 | } 954 | } 955 | } 956 | } 957 | 958 | switch (yycount) 959 | { 960 | # define YYCASE_(N, S) \ 961 | case N: \ 962 | yyformat = S; \ 963 | break 964 | default: /* Avoid compiler warnings. */ 965 | YYCASE_(0, YY_("syntax error")); 966 | YYCASE_(1, YY_("syntax error, unexpected %s")); 967 | YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); 968 | YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); 969 | YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); 970 | YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); 971 | # undef YYCASE_ 972 | } 973 | 974 | { 975 | YYSIZE_T yysize1 = yysize + yystrlen (yyformat); 976 | if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) 977 | yysize = yysize1; 978 | else 979 | return 2; 980 | } 981 | 982 | if (*yymsg_alloc < yysize) 983 | { 984 | *yymsg_alloc = 2 * yysize; 985 | if (! (yysize <= *yymsg_alloc 986 | && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) 987 | *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; 988 | return 1; 989 | } 990 | 991 | /* Avoid sprintf, as that infringes on the user's name space. 992 | Don't have undefined behavior even if the translation 993 | produced a string with the wrong number of "%s"s. */ 994 | { 995 | char *yyp = *yymsg; 996 | int yyi = 0; 997 | while ((*yyp = *yyformat) != '\0') 998 | if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) 999 | { 1000 | yyp += yytnamerr (yyp, yyarg[yyi++]); 1001 | yyformat += 2; 1002 | } 1003 | else 1004 | { 1005 | yyp++; 1006 | yyformat++; 1007 | } 1008 | } 1009 | return 0; 1010 | } 1011 | #endif /* YYERROR_VERBOSE */ 1012 | 1013 | /*-----------------------------------------------. 1014 | | Release the memory associated to this symbol. | 1015 | `-----------------------------------------------*/ 1016 | 1017 | static void 1018 | yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, zua_json_parser *parser) 1019 | { 1020 | YYUSE (yyvaluep); 1021 | YYUSE (parser); 1022 | if (!yymsg) 1023 | yymsg = "Deleting"; 1024 | YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); 1025 | 1026 | YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN 1027 | switch (yytype) 1028 | { 1029 | case 3: /* ZUA_JSON_T_NUL */ 1030 | 1031 | { zval_free_nogc(&((*yyvaluep).value)); } 1032 | 1033 | break; 1034 | 1035 | case 4: /* ZUA_JSON_T_NAN */ 1036 | 1037 | { zval_free_nogc(&((*yyvaluep).value)); } 1038 | 1039 | break; 1040 | 1041 | case 5: /* ZUA_JSON_T_INFINITY */ 1042 | 1043 | { zval_free_nogc(&((*yyvaluep).value)); } 1044 | 1045 | break; 1046 | 1047 | case 6: /* ZUA_JSON_T_NEGATIVE_INFINITY */ 1048 | 1049 | { zval_free_nogc(&((*yyvaluep).value)); } 1050 | 1051 | break; 1052 | 1053 | case 7: /* ZUA_JSON_T_TRUE */ 1054 | 1055 | { zval_free_nogc(&((*yyvaluep).value)); } 1056 | 1057 | break; 1058 | 1059 | case 8: /* ZUA_JSON_T_FALSE */ 1060 | 1061 | { zval_free_nogc(&((*yyvaluep).value)); } 1062 | 1063 | break; 1064 | 1065 | case 9: /* ZUA_JSON_T_INT */ 1066 | 1067 | { zval_free_nogc(&((*yyvaluep).value)); } 1068 | 1069 | break; 1070 | 1071 | case 10: /* ZUA_JSON_T_DOUBLE */ 1072 | 1073 | { zval_free_nogc(&((*yyvaluep).value)); } 1074 | 1075 | break; 1076 | 1077 | case 11: /* ZUA_JSON_T_STRING */ 1078 | 1079 | { zval_free_nogc(&((*yyvaluep).value)); } 1080 | 1081 | break; 1082 | 1083 | case 12: /* ZUA_JSON_T_ETRING */ 1084 | 1085 | { zval_free_nogc(&((*yyvaluep).value)); } 1086 | 1087 | break; 1088 | 1089 | case 23: /* start */ 1090 | 1091 | { zval_free_nogc(&((*yyvaluep).value)); } 1092 | 1093 | break; 1094 | 1095 | case 24: /* object */ 1096 | 1097 | { zval_free_nogc(&((*yyvaluep).value)); } 1098 | 1099 | break; 1100 | 1101 | case 27: /* members */ 1102 | 1103 | { zval_free_nogc(&((*yyvaluep).value)); } 1104 | 1105 | break; 1106 | 1107 | case 28: /* member */ 1108 | 1109 | { zval_free_nogc(&((*yyvaluep).value)); } 1110 | 1111 | break; 1112 | 1113 | case 30: /* array */ 1114 | 1115 | { zval_free_nogc(&((*yyvaluep).value)); } 1116 | 1117 | break; 1118 | 1119 | case 33: /* elements */ 1120 | 1121 | { zval_free_nogc(&((*yyvaluep).value)); } 1122 | 1123 | break; 1124 | 1125 | case 34: /* element */ 1126 | 1127 | { zval_free_nogc(&((*yyvaluep).value)); } 1128 | 1129 | break; 1130 | 1131 | case 36: /* key */ 1132 | 1133 | { zval_free_nogc(&((*yyvaluep).value)); } 1134 | 1135 | break; 1136 | 1137 | case 37: /* value */ 1138 | 1139 | { zval_free_nogc(&((*yyvaluep).value)); } 1140 | 1141 | break; 1142 | 1143 | default: 1144 | break; 1145 | } 1146 | YY_IGNORE_MAYBE_UNINITIALIZED_END 1147 | } 1148 | 1149 | 1150 | 1151 | 1152 | /*----------. 1153 | | yyparse. | 1154 | `----------*/ 1155 | 1156 | int 1157 | yyparse (zua_json_parser *parser) 1158 | { 1159 | /* The lookahead symbol. */ 1160 | int yychar; 1161 | 1162 | 1163 | /* The semantic value of the lookahead symbol. */ 1164 | /* Default value used for initialization, for pacifying older GCCs 1165 | or non-GCC compilers. */ 1166 | YY_INITIAL_VALUE (static YYSTYPE yyval_default;) 1167 | YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); 1168 | 1169 | /* Number of syntax errors so far. */ 1170 | int yynerrs; 1171 | 1172 | int yystate; 1173 | /* Number of tokens to shift before error messages enabled. */ 1174 | int yyerrstatus; 1175 | 1176 | /* The stacks and their tools: 1177 | 'yyss': related to states. 1178 | 'yyvs': related to semantic values. 1179 | 1180 | Refer to the stacks through separate pointers, to allow yyoverflow 1181 | to reallocate them elsewhere. */ 1182 | 1183 | /* The state stack. */ 1184 | yytype_int16 yyssa[YYINITDEPTH]; 1185 | yytype_int16 *yyss; 1186 | yytype_int16 *yyssp; 1187 | 1188 | /* The semantic value stack. */ 1189 | YYSTYPE yyvsa[YYINITDEPTH]; 1190 | YYSTYPE *yyvs; 1191 | YYSTYPE *yyvsp; 1192 | 1193 | YYSIZE_T yystacksize; 1194 | 1195 | int yyn; 1196 | int yyresult; 1197 | /* Lookahead token as an internal (translated) token number. */ 1198 | int yytoken = 0; 1199 | /* The variables used to return semantic value and location from the 1200 | action routines. */ 1201 | YYSTYPE yyval; 1202 | 1203 | #if YYERROR_VERBOSE 1204 | /* Buffer for error messages, and its allocated size. */ 1205 | char yymsgbuf[128]; 1206 | char *yymsg = yymsgbuf; 1207 | YYSIZE_T yymsg_alloc = sizeof yymsgbuf; 1208 | #endif 1209 | 1210 | #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) 1211 | 1212 | /* The number of symbols on the RHS of the reduced rule. 1213 | Keep to zero when no symbol should be popped. */ 1214 | int yylen = 0; 1215 | 1216 | yyssp = yyss = yyssa; 1217 | yyvsp = yyvs = yyvsa; 1218 | yystacksize = YYINITDEPTH; 1219 | 1220 | YYDPRINTF ((stderr, "Starting parse\n")); 1221 | 1222 | yystate = 0; 1223 | yyerrstatus = 0; 1224 | yynerrs = 0; 1225 | yychar = YYEMPTY; /* Cause a token to be read. */ 1226 | goto yysetstate; 1227 | 1228 | 1229 | /*------------------------------------------------------------. 1230 | | yynewstate -- push a new state, which is found in yystate. | 1231 | `------------------------------------------------------------*/ 1232 | yynewstate: 1233 | /* In all cases, when you get here, the value and location stacks 1234 | have just been pushed. So pushing a state here evens the stacks. */ 1235 | yyssp++; 1236 | 1237 | 1238 | /*--------------------------------------------------------------------. 1239 | | yynewstate -- set current state (the top of the stack) to yystate. | 1240 | `--------------------------------------------------------------------*/ 1241 | yysetstate: 1242 | *yyssp = (yytype_int16) yystate; 1243 | 1244 | if (yyss + yystacksize - 1 <= yyssp) 1245 | #if !defined yyoverflow && !defined YYSTACK_RELOCATE 1246 | goto yyexhaustedlab; 1247 | #else 1248 | { 1249 | /* Get the current used size of the three stacks, in elements. */ 1250 | YYSIZE_T yysize = (YYSIZE_T) (yyssp - yyss + 1); 1251 | 1252 | # if defined yyoverflow 1253 | { 1254 | /* Give user a chance to reallocate the stack. Use copies of 1255 | these so that the &'s don't force the real ones into 1256 | memory. */ 1257 | YYSTYPE *yyvs1 = yyvs; 1258 | yytype_int16 *yyss1 = yyss; 1259 | 1260 | /* Each stack pointer address is followed by the size of the 1261 | data in use in that stack, in bytes. This used to be a 1262 | conditional around just the two extra args, but that might 1263 | be undefined if yyoverflow is a macro. */ 1264 | yyoverflow (YY_("memory exhausted"), 1265 | &yyss1, yysize * sizeof (*yyssp), 1266 | &yyvs1, yysize * sizeof (*yyvsp), 1267 | &yystacksize); 1268 | yyss = yyss1; 1269 | yyvs = yyvs1; 1270 | } 1271 | # else /* defined YYSTACK_RELOCATE */ 1272 | /* Extend the stack our own way. */ 1273 | if (YYMAXDEPTH <= yystacksize) 1274 | goto yyexhaustedlab; 1275 | yystacksize *= 2; 1276 | if (YYMAXDEPTH < yystacksize) 1277 | yystacksize = YYMAXDEPTH; 1278 | 1279 | { 1280 | yytype_int16 *yyss1 = yyss; 1281 | union yyalloc *yyptr = 1282 | (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); 1283 | if (! yyptr) 1284 | goto yyexhaustedlab; 1285 | YYSTACK_RELOCATE (yyss_alloc, yyss); 1286 | YYSTACK_RELOCATE (yyvs_alloc, yyvs); 1287 | # undef YYSTACK_RELOCATE 1288 | if (yyss1 != yyssa) 1289 | YYSTACK_FREE (yyss1); 1290 | } 1291 | # endif 1292 | 1293 | yyssp = yyss + yysize - 1; 1294 | yyvsp = yyvs + yysize - 1; 1295 | 1296 | YYDPRINTF ((stderr, "Stack size increased to %lu\n", 1297 | (unsigned long) yystacksize)); 1298 | 1299 | if (yyss + yystacksize - 1 <= yyssp) 1300 | YYABORT; 1301 | } 1302 | #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ 1303 | 1304 | YYDPRINTF ((stderr, "Entering state %d\n", yystate)); 1305 | 1306 | if (yystate == YYFINAL) 1307 | YYACCEPT; 1308 | 1309 | goto yybackup; 1310 | 1311 | 1312 | /*-----------. 1313 | | yybackup. | 1314 | `-----------*/ 1315 | yybackup: 1316 | /* Do appropriate processing given the current state. Read a 1317 | lookahead token if we need one and don't already have one. */ 1318 | 1319 | /* First try to decide what to do without reference to lookahead token. */ 1320 | yyn = yypact[yystate]; 1321 | if (yypact_value_is_default (yyn)) 1322 | goto yydefault; 1323 | 1324 | /* Not known => get a lookahead token if don't already have one. */ 1325 | 1326 | /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ 1327 | if (yychar == YYEMPTY) 1328 | { 1329 | YYDPRINTF ((stderr, "Reading a token: ")); 1330 | yychar = yylex (&yylval, parser); 1331 | } 1332 | 1333 | if (yychar <= YYEOF) 1334 | { 1335 | yychar = yytoken = YYEOF; 1336 | YYDPRINTF ((stderr, "Now at end of input.\n")); 1337 | } 1338 | else 1339 | { 1340 | yytoken = YYTRANSLATE (yychar); 1341 | YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); 1342 | } 1343 | 1344 | /* If the proper action on seeing token YYTOKEN is to reduce or to 1345 | detect an error, take that action. */ 1346 | yyn += yytoken; 1347 | if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) 1348 | goto yydefault; 1349 | yyn = yytable[yyn]; 1350 | if (yyn <= 0) 1351 | { 1352 | if (yytable_value_is_error (yyn)) 1353 | goto yyerrlab; 1354 | yyn = -yyn; 1355 | goto yyreduce; 1356 | } 1357 | 1358 | /* Count tokens shifted since error; after three, turn off error 1359 | status. */ 1360 | if (yyerrstatus) 1361 | yyerrstatus--; 1362 | 1363 | /* Shift the lookahead token. */ 1364 | YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); 1365 | 1366 | /* Discard the shifted token. */ 1367 | yychar = YYEMPTY; 1368 | 1369 | yystate = yyn; 1370 | YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN 1371 | *++yyvsp = yylval; 1372 | YY_IGNORE_MAYBE_UNINITIALIZED_END 1373 | 1374 | goto yynewstate; 1375 | 1376 | 1377 | /*-----------------------------------------------------------. 1378 | | yydefault -- do the default action for the current state. | 1379 | `-----------------------------------------------------------*/ 1380 | yydefault: 1381 | yyn = yydefact[yystate]; 1382 | if (yyn == 0) 1383 | goto yyerrlab; 1384 | goto yyreduce; 1385 | 1386 | 1387 | /*-----------------------------. 1388 | | yyreduce -- do a reduction. | 1389 | `-----------------------------*/ 1390 | yyreduce: 1391 | /* yyn is the number of a rule to reduce with. */ 1392 | yylen = yyr2[yyn]; 1393 | 1394 | /* If YYLEN is nonzero, implement the default value of the action: 1395 | '$$ = $1'. 1396 | 1397 | Otherwise, the following line sets YYVAL to garbage. 1398 | This behavior is undocumented and Bison 1399 | users should not rely upon it. Assigning to YYVAL 1400 | unconditionally makes the parser a bit smaller, and it avoids a 1401 | GCC warning that YYVAL may be used uninitialized. */ 1402 | yyval = yyvsp[1-yylen]; 1403 | 1404 | 1405 | YY_REDUCE_PRINT (yyn); 1406 | switch (yyn) 1407 | { 1408 | case 2: 1409 | 1410 | { 1411 | ZUA_COPY_VALUE(&(yyval.value), &(yyvsp[-1].value)); 1412 | ZUA_COPY_VALUE(parser->return_value, &(yyvsp[-1].value)); 1413 | YYACCEPT; 1414 | } 1415 | 1416 | break; 1417 | 1418 | case 3: 1419 | 1420 | { 1421 | } 1422 | 1423 | break; 1424 | 1425 | case 4: 1426 | 1427 | { 1428 | ZUA_COPY_VALUE(&(yyval.value), &(yyvsp[-1].value)); 1429 | } 1430 | 1431 | break; 1432 | 1433 | case 6: 1434 | 1435 | { 1436 | parser->scanner.errcode = ZUA_JSON_BRACKET_MISMATCH; 1437 | YYERROR; 1438 | } 1439 | 1440 | break; 1441 | 1442 | case 7: 1443 | 1444 | { 1445 | object_init(&(yyval.value)); 1446 | } 1447 | 1448 | break; 1449 | 1450 | case 9: 1451 | 1452 | { 1453 | object_init(&(yyval.value)); 1454 | zua_hash_str_add_or_update(&(yyval.value), ZSTRL(Z_STR((yyvsp[-2].value))), &(yyvsp[0].value)); 1455 | zua_string_free(Z_STR((yyvsp[-2].value))); 1456 | } 1457 | 1458 | break; 1459 | 1460 | case 10: 1461 | 1462 | { 1463 | zua_hash_str_add_or_update(&(yyvsp[-4].value), ZSTRL(Z_STR((yyvsp[-2].value))), &(yyvsp[0].value)); 1464 | ZUA_COPY_VALUE(&(yyval.value), &(yyvsp[-4].value)); 1465 | zua_string_free(Z_STR((yyvsp[-2].value))); 1466 | } 1467 | 1468 | break; 1469 | 1470 | case 13: 1471 | 1472 | { 1473 | } 1474 | 1475 | break; 1476 | 1477 | case 14: 1478 | 1479 | { 1480 | ZUA_COPY_VALUE(&(yyval.value), &(yyvsp[-1].value)); 1481 | } 1482 | 1483 | break; 1484 | 1485 | case 16: 1486 | 1487 | { 1488 | parser->scanner.errcode = ZUA_JSON_BRACKET_MISMATCH; 1489 | YYERROR; 1490 | } 1491 | 1492 | break; 1493 | 1494 | case 17: 1495 | 1496 | { 1497 | array_init(&(yyval.value)); 1498 | } 1499 | 1500 | break; 1501 | 1502 | case 19: 1503 | 1504 | { 1505 | array_init(&(yyval.value)); 1506 | zua_hash_index_add(&(yyval.value), &(yyvsp[0].value)); 1507 | } 1508 | 1509 | break; 1510 | 1511 | case 20: 1512 | 1513 | { 1514 | zua_hash_index_add(&(yyvsp[-2].value), &(yyvsp[0].value)); 1515 | ZUA_COPY_VALUE(&(yyval.value), &(yyvsp[-2].value)); 1516 | } 1517 | 1518 | break; 1519 | 1520 | 1521 | 1522 | default: break; 1523 | } 1524 | /* User semantic actions sometimes alter yychar, and that requires 1525 | that yytoken be updated with the new translation. We take the 1526 | approach of translating immediately before every use of yytoken. 1527 | One alternative is translating here after every semantic action, 1528 | but that translation would be missed if the semantic action invokes 1529 | YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or 1530 | if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an 1531 | incorrect destructor might then be invoked immediately. In the 1532 | case of YYERROR or YYBACKUP, subsequent parser actions might lead 1533 | to an incorrect destructor call or verbose syntax error message 1534 | before the lookahead is translated. */ 1535 | YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); 1536 | 1537 | YYPOPSTACK (yylen); 1538 | yylen = 0; 1539 | YY_STACK_PRINT (yyss, yyssp); 1540 | 1541 | *++yyvsp = yyval; 1542 | 1543 | /* Now 'shift' the result of the reduction. Determine what state 1544 | that goes to, based on the state we popped back to and the rule 1545 | number reduced by. */ 1546 | { 1547 | const int yylhs = yyr1[yyn] - YYNTOKENS; 1548 | const int yyi = yypgoto[yylhs] + *yyssp; 1549 | yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp 1550 | ? yytable[yyi] 1551 | : yydefgoto[yylhs]); 1552 | } 1553 | 1554 | goto yynewstate; 1555 | 1556 | 1557 | /*--------------------------------------. 1558 | | yyerrlab -- here on detecting error. | 1559 | `--------------------------------------*/ 1560 | yyerrlab: 1561 | /* Make sure we have latest lookahead translation. See comments at 1562 | user semantic actions for why this is necessary. */ 1563 | yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); 1564 | 1565 | /* If not already recovering from an error, report this error. */ 1566 | if (!yyerrstatus) 1567 | { 1568 | ++yynerrs; 1569 | #if ! YYERROR_VERBOSE 1570 | yyerror (parser, YY_("syntax error")); 1571 | #else 1572 | # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ 1573 | yyssp, yytoken) 1574 | { 1575 | char const *yymsgp = YY_("syntax error"); 1576 | int yysyntax_error_status; 1577 | yysyntax_error_status = YYSYNTAX_ERROR; 1578 | if (yysyntax_error_status == 0) 1579 | yymsgp = yymsg; 1580 | else if (yysyntax_error_status == 1) 1581 | { 1582 | if (yymsg != yymsgbuf) 1583 | YYSTACK_FREE (yymsg); 1584 | yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); 1585 | if (!yymsg) 1586 | { 1587 | yymsg = yymsgbuf; 1588 | yymsg_alloc = sizeof yymsgbuf; 1589 | yysyntax_error_status = 2; 1590 | } 1591 | else 1592 | { 1593 | yysyntax_error_status = YYSYNTAX_ERROR; 1594 | yymsgp = yymsg; 1595 | } 1596 | } 1597 | yyerror (parser, yymsgp); 1598 | if (yysyntax_error_status == 2) 1599 | goto yyexhaustedlab; 1600 | } 1601 | # undef YYSYNTAX_ERROR 1602 | #endif 1603 | } 1604 | 1605 | 1606 | 1607 | if (yyerrstatus == 3) 1608 | { 1609 | /* If just tried and failed to reuse lookahead token after an 1610 | error, discard it. */ 1611 | 1612 | if (yychar <= YYEOF) 1613 | { 1614 | /* Return failure if at end of input. */ 1615 | if (yychar == YYEOF) 1616 | YYABORT; 1617 | } 1618 | else 1619 | { 1620 | yydestruct ("Error: discarding", 1621 | yytoken, &yylval, parser); 1622 | yychar = YYEMPTY; 1623 | } 1624 | } 1625 | 1626 | /* Else will try to reuse lookahead token after shifting the error 1627 | token. */ 1628 | goto yyerrlab1; 1629 | 1630 | 1631 | /*---------------------------------------------------. 1632 | | yyerrorlab -- error raised explicitly by YYERROR. | 1633 | `---------------------------------------------------*/ 1634 | yyerrorlab: 1635 | /* Pacify compilers when the user code never invokes YYERROR and the 1636 | label yyerrorlab therefore never appears in user code. */ 1637 | if (0) 1638 | YYERROR; 1639 | 1640 | /* Do not reclaim the symbols of the rule whose action triggered 1641 | this YYERROR. */ 1642 | YYPOPSTACK (yylen); 1643 | yylen = 0; 1644 | YY_STACK_PRINT (yyss, yyssp); 1645 | yystate = *yyssp; 1646 | goto yyerrlab1; 1647 | 1648 | 1649 | /*-------------------------------------------------------------. 1650 | | yyerrlab1 -- common code for both syntax error and YYERROR. | 1651 | `-------------------------------------------------------------*/ 1652 | yyerrlab1: 1653 | yyerrstatus = 3; /* Each real token shifted decrements this. */ 1654 | 1655 | for (;;) 1656 | { 1657 | yyn = yypact[yystate]; 1658 | if (!yypact_value_is_default (yyn)) 1659 | { 1660 | yyn += YYTERROR; 1661 | if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) 1662 | { 1663 | yyn = yytable[yyn]; 1664 | if (0 < yyn) 1665 | break; 1666 | } 1667 | } 1668 | 1669 | /* Pop the current state because it cannot handle the error token. */ 1670 | if (yyssp == yyss) 1671 | YYABORT; 1672 | 1673 | 1674 | yydestruct ("Error: popping", 1675 | yystos[yystate], yyvsp, parser); 1676 | YYPOPSTACK (1); 1677 | yystate = *yyssp; 1678 | YY_STACK_PRINT (yyss, yyssp); 1679 | } 1680 | 1681 | YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN 1682 | *++yyvsp = yylval; 1683 | YY_IGNORE_MAYBE_UNINITIALIZED_END 1684 | 1685 | 1686 | /* Shift the error token. */ 1687 | YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); 1688 | 1689 | yystate = yyn; 1690 | goto yynewstate; 1691 | 1692 | 1693 | /*-------------------------------------. 1694 | | yyacceptlab -- YYACCEPT comes here. | 1695 | `-------------------------------------*/ 1696 | yyacceptlab: 1697 | yyresult = 0; 1698 | goto yyreturn; 1699 | 1700 | 1701 | /*-----------------------------------. 1702 | | yyabortlab -- YYABORT comes here. | 1703 | `-----------------------------------*/ 1704 | yyabortlab: 1705 | yyresult = 1; 1706 | goto yyreturn; 1707 | 1708 | 1709 | #if !defined yyoverflow || YYERROR_VERBOSE 1710 | /*-------------------------------------------------. 1711 | | yyexhaustedlab -- memory exhaustion comes here. | 1712 | `-------------------------------------------------*/ 1713 | yyexhaustedlab: 1714 | yyerror (parser, YY_("memory exhausted")); 1715 | yyresult = 2; 1716 | /* Fall through. */ 1717 | #endif 1718 | 1719 | 1720 | /*-----------------------------------------------------. 1721 | | yyreturn -- parsing is finished, return the result. | 1722 | `-----------------------------------------------------*/ 1723 | yyreturn: 1724 | if (yychar != YYEMPTY) 1725 | { 1726 | /* Make sure we have latest lookahead translation. See comments at 1727 | user semantic actions for why this is necessary. */ 1728 | yytoken = YYTRANSLATE (yychar); 1729 | yydestruct ("Cleanup: discarding lookahead", 1730 | yytoken, &yylval, parser); 1731 | } 1732 | /* Do not reclaim the symbols of the rule whose action triggered 1733 | this YYABORT or YYACCEPT. */ 1734 | YYPOPSTACK (yylen); 1735 | YY_STACK_PRINT (yyss, yyssp); 1736 | while (yyssp != yyss) 1737 | { 1738 | yydestruct ("Cleanup: popping", 1739 | yystos[*yyssp], yyvsp, parser); 1740 | YYPOPSTACK (1); 1741 | } 1742 | #ifndef yyoverflow 1743 | if (yyss != yyssa) 1744 | YYSTACK_FREE (yyss); 1745 | #endif 1746 | #if YYERROR_VERBOSE 1747 | if (yymsg != yymsgbuf) 1748 | YYSTACK_FREE (yymsg); 1749 | #endif 1750 | return yyresult; 1751 | } 1752 | 1753 | 1754 | 1755 | void zua_json_parser_init( zua_json_parser *parser, zval *return_value, const char *str, size_t str_len, int options, int max_depth ) { 1756 | memset(parser, 0, sizeof(zua_json_parser)); 1757 | zua_json_scanner_init(&parser->scanner, str, str_len, options); 1758 | parser->depth = 1; 1759 | parser->max_depth = max_depth; 1760 | parser->return_value = return_value; 1761 | } 1762 | 1763 | static void zua_yyerror( zua_json_parser *parser, const char *str ) 1764 | { 1765 | parser->scanner.errcode = ZUA_JSON_SYNTAX_ERROR; 1766 | } 1767 | 1768 | static int zua_yylex(ZUA_YYSTYPE *val, zua_json_parser *parser) 1769 | { 1770 | int token = zua_json_scan(&parser->scanner); 1771 | val->value = parser->scanner.value; 1772 | return token; 1773 | } 1774 | 1775 | 1776 | -------------------------------------------------------------------------------- /zua_parser.h: -------------------------------------------------------------------------------- 1 | /* A Bison parser, made by GNU Bison 3.3.2. */ 2 | 3 | /* Bison interface for Yacc-like parsers in C 4 | 5 | Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation, 6 | Inc. 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . */ 20 | 21 | /* As a special exception, you may create a larger work that contains 22 | part or all of the Bison parser skeleton and distribute that work 23 | under terms of your choice, so long as that work isn't itself a 24 | parser generator using the skeleton or a modified version thereof 25 | as a parser skeleton. Alternatively, if you modify or redistribute 26 | the parser skeleton itself, you may (at your option) remove this 27 | special exception, which will cause the skeleton and the resulting 28 | Bison output files to be licensed under the GNU General Public 29 | License without this special exception. 30 | 31 | This special exception was added by the Free Software Foundation in 32 | version 2.2 of Bison. */ 33 | 34 | /* Undocumented macros, especially those whose name start with YY_, 35 | are private implementation details. Do not rely on them. */ 36 | 37 | #ifndef YY_ZUA_YY_ZUA_PARSER_H_INCLUDED 38 | # define YY_ZUA_YY_ZUA_PARSER_H_INCLUDED 39 | /* Debug traces. */ 40 | #ifndef ZUA_YYDEBUG 41 | # if defined YYDEBUG 42 | #if YYDEBUG 43 | # define ZUA_YYDEBUG 1 44 | # else 45 | # define ZUA_YYDEBUG 0 46 | # endif 47 | # else /* ! defined YYDEBUG */ 48 | # define ZUA_YYDEBUG 0 49 | # endif /* ! defined YYDEBUG */ 50 | #endif /* ! defined ZUA_YYDEBUG */ 51 | #if ZUA_YYDEBUG 52 | extern int zua_yydebug; 53 | #endif 54 | /* "%code requires" blocks. */ 55 | 56 | 57 | #include "zua_type.h" 58 | #include "zua_parser_defs.h" 59 | 60 | 61 | 62 | /* Token type. */ 63 | #ifndef ZUA_YYTOKENTYPE 64 | # define ZUA_YYTOKENTYPE 65 | enum zua_yytokentype 66 | { 67 | ZUA_JSON_T_NUL = 258, 68 | ZUA_JSON_T_NAN = 259, 69 | ZUA_JSON_T_INFINITY = 260, 70 | ZUA_JSON_T_NEGATIVE_INFINITY = 261, 71 | ZUA_JSON_T_TRUE = 262, 72 | ZUA_JSON_T_FALSE = 263, 73 | ZUA_JSON_T_INT = 264, 74 | ZUA_JSON_T_DOUBLE = 265, 75 | ZUA_JSON_T_STRING = 266, 76 | ZUA_JSON_T_ETRING = 267, 77 | ZUA_JSON_T_EOI = 268, 78 | ZUA_JSON_T_ERROR = 269, 79 | ZUA_JSON_T_COMMENT_NOT_CLOSED = 270 80 | }; 81 | #endif 82 | 83 | /* Value type. */ 84 | #if ! defined ZUA_YYSTYPE && ! defined ZUA_YYSTYPE_IS_DECLARED 85 | 86 | union ZUA_YYSTYPE 87 | { 88 | 89 | 90 | zval value; 91 | 92 | 93 | }; 94 | 95 | typedef union ZUA_YYSTYPE ZUA_YYSTYPE; 96 | # define ZUA_YYSTYPE_IS_TRIVIAL 1 97 | # define ZUA_YYSTYPE_IS_DECLARED 1 98 | #endif 99 | 100 | 101 | 102 | int zua_yyparse (zua_json_parser *parser); 103 | 104 | #endif /* !YY_ZUA_YY_ZUA_PARSER_H_INCLUDED */ 105 | -------------------------------------------------------------------------------- /zua_parser.y: -------------------------------------------------------------------------------- 1 | %require "3.0" 2 | 3 | %code requires { 4 | #include "zua_type.h" 5 | #include "zua_parser_defs.h" 6 | } 7 | 8 | %code top { 9 | /* bison --defines -l zua_parser.y -o zua_parser.c */ 10 | #include 11 | #include "zua_scanner.h" 12 | 13 | #define YYDEBUG 1 14 | #define YYERROR_VERBOSE 1 15 | } 16 | 17 | %code { 18 | static int zua_yylex(ZUA_YYSTYPE *, zua_json_parser *parser); 19 | static void zua_yyerror(zua_json_parser *parser, const char *str); 20 | } 21 | 22 | %union { 23 | zval value; 24 | } 25 | 26 | %define api.prefix {zua_yy} 27 | %define api.pure full 28 | %param {zua_json_parser *parser} 29 | %destructor { zval_free_nogc(&$$); } 30 | 31 | %token ZUA_JSON_T_NUL 32 | %token ZUA_JSON_T_NAN 33 | %token ZUA_JSON_T_INFINITY 34 | %token ZUA_JSON_T_NEGATIVE_INFINITY 35 | %token ZUA_JSON_T_TRUE 36 | %token ZUA_JSON_T_FALSE 37 | %token ZUA_JSON_T_INT 38 | %token ZUA_JSON_T_DOUBLE 39 | %token ZUA_JSON_T_STRING 40 | %token ZUA_JSON_T_ETRING 41 | %token ZUA_JSON_T_EOI 42 | %token ZUA_JSON_T_ERROR 43 | %token ZUA_JSON_T_COMMENT_NOT_CLOSED 44 | 45 | 46 | %type start object array key value 47 | %type members member elements element 48 | 49 | %% 50 | 51 | start: 52 | value ZUA_JSON_T_EOI 53 | { 54 | ZUA_COPY_VALUE(&$$, &$1); 55 | ZUA_COPY_VALUE(parser->return_value, &$1); 56 | YYACCEPT; 57 | } 58 | ; 59 | 60 | 61 | object: 62 | '{' 63 | { 64 | } 65 | members object_end 66 | { 67 | ZUA_COPY_VALUE(&$$, &$3); 68 | } 69 | ; 70 | 71 | 72 | object_end: 73 | '}' 74 | | ']' 75 | { 76 | parser->scanner.errcode = ZUA_JSON_BRACKET_MISMATCH; 77 | YYERROR; 78 | } 79 | ; 80 | 81 | members: 82 | %empty 83 | { 84 | object_init(&$$); 85 | } 86 | | member member_end 87 | ; 88 | 89 | 90 | member: 91 | key ':' value 92 | { 93 | object_init(&$$); 94 | zua_hash_str_add_or_update(&$$, ZSTRL(Z_STR($1)), &$3); 95 | zua_string_free(Z_STR($1)); 96 | } 97 | | member ',' key ':' value 98 | { 99 | zua_hash_str_add_or_update(&$1, ZSTRL(Z_STR($3)), &$5); 100 | ZUA_COPY_VALUE(&$$, &$1); 101 | zua_string_free(Z_STR($3)); 102 | } 103 | ; 104 | 105 | member_end: 106 | %empty 107 | | ',' 108 | ; 109 | 110 | 111 | array: 112 | '[' 113 | { 114 | } 115 | elements array_end 116 | { 117 | ZUA_COPY_VALUE(&$$, &$3); 118 | } 119 | ; 120 | 121 | array_end: 122 | ']' 123 | | '}' 124 | { 125 | parser->scanner.errcode = ZUA_JSON_BRACKET_MISMATCH; 126 | YYERROR; 127 | } 128 | ; 129 | 130 | elements: 131 | %empty 132 | { 133 | array_init(&$$); 134 | } 135 | | element element_end 136 | ; 137 | 138 | 139 | element: 140 | value 141 | { 142 | array_init(&$$); 143 | zua_hash_index_add(&$$, &$1); 144 | } 145 | | element ',' value 146 | { 147 | zua_hash_index_add(&$1, &$3); 148 | ZUA_COPY_VALUE(&$$, &$1); 149 | } 150 | ; 151 | 152 | element_end: 153 | %empty 154 | | ',' 155 | ; 156 | 157 | key: 158 | ZUA_JSON_T_STRING 159 | | ZUA_JSON_T_ETRING 160 | ; 161 | 162 | 163 | value: 164 | object 165 | | array 166 | | ZUA_JSON_T_NUL 167 | | ZUA_JSON_T_NAN 168 | | ZUA_JSON_T_INFINITY 169 | | ZUA_JSON_T_NEGATIVE_INFINITY 170 | | ZUA_JSON_T_TRUE 171 | | ZUA_JSON_T_FALSE 172 | | ZUA_JSON_T_INT 173 | | ZUA_JSON_T_DOUBLE 174 | | ZUA_JSON_T_STRING 175 | ; 176 | 177 | %% 178 | 179 | void zua_json_parser_init( zua_json_parser *parser, zval *return_value, const char *str, size_t str_len, int options, int max_depth ) { 180 | memset(parser, 0, sizeof(zua_json_parser)); 181 | zua_json_scanner_init(&parser->scanner, str, str_len, options); 182 | parser->depth = 1; 183 | parser->max_depth = max_depth; 184 | parser->return_value = return_value; 185 | } 186 | 187 | static void zua_yyerror( zua_json_parser *parser, const char *str ) 188 | { 189 | parser->scanner.errcode = ZUA_JSON_SYNTAX_ERROR; 190 | } 191 | 192 | static int zua_yylex(ZUA_YYSTYPE *val, zua_json_parser *parser) 193 | { 194 | int token = zua_json_scan(&parser->scanner); 195 | val->value = parser->scanner.value; 196 | return token; 197 | } 198 | 199 | 200 | -------------------------------------------------------------------------------- /zua_parser_defs.h: -------------------------------------------------------------------------------- 1 | #ifndef ZUA_ZUA_PARSER_DEFS_H 2 | #define ZUA_ZUA_PARSER_DEFS_H 3 | 4 | #include "zua_scanner.h" 5 | 6 | typedef struct _zua_json_parser zua_json_parser; 7 | 8 | struct _zua_json_parser { 9 | zua_json_scanner scanner; 10 | zval *return_value; 11 | int depth; 12 | int max_depth; 13 | }; 14 | 15 | void zua_json_parser_init( 16 | zua_json_parser *parser, 17 | zval *return_value, 18 | const char *str, 19 | size_t str_len, 20 | int options, 21 | int max_depth); 22 | 23 | 24 | #endif /* ZUA_ZUA_PARSER_DEFS_H */ 25 | -------------------------------------------------------------------------------- /zua_scanner.c: -------------------------------------------------------------------------------- 1 | /* Generated by re2c 2.1.1 */ 2 | /* 3 | * re2c -t zua_scanner_defs.h -bci -o zua_scanner.c --no-generation-date zua_scanner.re 4 | */ 5 | #include 6 | #include "zua_scanner.h" 7 | #include "zua_scanner_defs.h" 8 | #include "zua_parser.h" 9 | #include "zua_type.h" 10 | #include 11 | #include 12 | 13 | #define YYCTYPE zua_json_ctype 14 | #define YYCURSOR s->cursor 15 | #define YYLIMIT s->limit 16 | #define YYMARKER s->marker 17 | #define YYCTXMARKER s->ctxmarker 18 | 19 | #define YYGETCONDITION() s->state 20 | #define YYSETCONDITION(yystate) s->state = yystate 21 | 22 | #define YYFILL(n) 23 | 24 | #define ZUA_JSON_CONDITION_SET(condition) YYSETCONDITION(yyc##condition) 25 | #define ZUA_JSON_CONDITION_GOTO(condition) goto yyc_##condition 26 | #define ZUA_JSON_CONDITION_SET_AND_GOTO(condition) \ 27 | ZUA_JSON_CONDITION_SET(condition); \ 28 | ZUA_JSON_CONDITION_GOTO(condition) 29 | 30 | void zua_json_scanner_init(zua_json_scanner *s, const char *str, uint32_t str_len, int options) { 31 | s->cursor = (zua_json_ctype *)str; 32 | s->limit = (zua_json_ctype *)str + str_len; 33 | s->options = options; 34 | ZUA_JSON_CONDITION_SET(JS); 35 | } 36 | 37 | 38 | int zua_json_scan(zua_json_scanner *s) { 39 | ZVAL_NULL(&s->value); 40 | 41 | std: 42 | s->token = s->cursor; 43 | 44 | 45 | { 46 | YYCTYPE yych; 47 | unsigned int yyaccept = 0; 48 | if (YYGETCONDITION() < 2) { 49 | if (YYGETCONDITION() < 1) { 50 | goto yyc_JS; 51 | } else { 52 | goto yyc_STR_P2; 53 | } 54 | } else { 55 | if (YYGETCONDITION() < 3) { 56 | goto yyc_COMMENTS; 57 | } else { 58 | goto yyc_STR_P1; 59 | } 60 | } 61 | /* *********************************** */ 62 | yyc_JS: 63 | { 64 | static const unsigned char yybm[] = { 65 | 0, 0, 0, 0, 0, 0, 0, 0, 66 | 0, 16, 0, 0, 0, 16, 0, 0, 67 | 0, 0, 0, 0, 0, 0, 0, 0, 68 | 0, 0, 0, 0, 0, 0, 0, 0, 69 | 16, 0, 0, 0, 0, 0, 0, 0, 70 | 0, 0, 0, 0, 0, 0, 0, 0, 71 | 96, 96, 96, 96, 96, 96, 96, 96, 72 | 96, 96, 0, 0, 0, 0, 0, 0, 73 | 0, 192, 192, 192, 192, 192, 192, 64, 74 | 64, 64, 64, 64, 64, 64, 64, 64, 75 | 64, 64, 64, 64, 64, 64, 64, 64, 76 | 64, 64, 64, 0, 0, 0, 0, 64, 77 | 0, 192, 192, 192, 192, 192, 192, 64, 78 | 64, 64, 64, 64, 64, 64, 64, 64, 79 | 64, 64, 64, 64, 64, 64, 64, 64, 80 | 64, 64, 64, 0, 0, 0, 0, 0, 81 | 64, 64, 64, 64, 64, 64, 64, 64, 82 | 64, 64, 64, 64, 64, 64, 64, 64, 83 | 64, 64, 64, 64, 64, 64, 64, 64, 84 | 64, 64, 64, 64, 64, 64, 64, 64, 85 | 64, 64, 64, 64, 64, 64, 64, 64, 86 | 64, 64, 64, 64, 64, 64, 64, 64, 87 | 64, 64, 64, 64, 64, 64, 64, 64, 88 | 64, 64, 64, 64, 64, 64, 64, 64, 89 | 64, 64, 64, 64, 64, 64, 64, 64, 90 | 64, 64, 64, 64, 64, 64, 64, 64, 91 | 64, 64, 64, 64, 64, 64, 64, 64, 92 | 64, 64, 64, 64, 64, 64, 64, 64, 93 | 64, 64, 64, 64, 64, 64, 64, 64, 94 | 64, 64, 64, 64, 64, 64, 64, 64, 95 | 64, 64, 64, 64, 64, 64, 64, 64, 96 | 64, 64, 64, 64, 64, 64, 64, 64, 97 | }; 98 | yych = *YYCURSOR; 99 | switch (yych) { 100 | case 0x00: goto yy2; 101 | case 0x01: 102 | case 0x02: 103 | case 0x03: 104 | case 0x04: 105 | case 0x05: 106 | case 0x06: 107 | case 0x07: 108 | case 0x08: 109 | case '\v': 110 | case '\f': 111 | case 0x0E: 112 | case 0x0F: 113 | case 0x10: 114 | case 0x11: 115 | case 0x12: 116 | case 0x13: 117 | case 0x14: 118 | case 0x15: 119 | case 0x16: 120 | case 0x17: 121 | case 0x18: 122 | case 0x19: 123 | case 0x1A: 124 | case 0x1B: 125 | case 0x1C: 126 | case 0x1D: 127 | case 0x1E: 128 | case 0x1F: 129 | case '!': 130 | case '#': 131 | case '$': 132 | case '%': 133 | case '&': 134 | case '(': 135 | case ')': 136 | case '*': 137 | case ';': 138 | case '<': 139 | case '=': 140 | case '>': 141 | case '?': 142 | case '\\': 143 | case '^': 144 | case '`': 145 | case '|': 146 | case '~': 147 | case 0x7F: goto yy4; 148 | case '\t': 149 | case ' ': goto yy6; 150 | case '\n': goto yy9; 151 | case '\r': goto yy10; 152 | case '"': 153 | case '\'': goto yy11; 154 | case '+': goto yy13; 155 | case ',': goto yy14; 156 | case '-': goto yy16; 157 | case '.': goto yy17; 158 | case '/': goto yy20; 159 | case '0': goto yy21; 160 | case '1': 161 | case '2': 162 | case '3': 163 | case '4': 164 | case '5': 165 | case '6': 166 | case '7': 167 | case '8': 168 | case '9': goto yy23; 169 | case ':': goto yy25; 170 | case '@': goto yy27; 171 | case 'I': goto yy31; 172 | case 'N': goto yy32; 173 | case '[': goto yy33; 174 | case ']': goto yy35; 175 | case 'f': goto yy37; 176 | case 'n': goto yy38; 177 | case 't': goto yy39; 178 | case '{': goto yy40; 179 | case '}': goto yy42; 180 | default: goto yy28; 181 | } 182 | yy2: 183 | ++YYCURSOR; 184 | { 185 | if (s->limit < s->cursor) { 186 | return ZUA_JSON_T_EOI; 187 | } else { 188 | s->errcode = 1; 189 | return ZUA_JSON_T_ERROR; 190 | } 191 | } 192 | yy4: 193 | ++YYCURSOR; 194 | yy5: 195 | { 196 | return ZUA_JSON_T_ERROR; 197 | } 198 | yy6: 199 | yych = *++YYCURSOR; 200 | yy7: 201 | if (yybm[0+yych] & 16) { 202 | goto yy6; 203 | } 204 | yy8: 205 | { goto std; } 206 | yy9: 207 | ++YYCURSOR; 208 | goto yy8; 209 | yy10: 210 | yych = *++YYCURSOR; 211 | if (yych == '\n') goto yy9; 212 | goto yy7; 213 | yy11: 214 | ++YYCURSOR; 215 | { 216 | char c = s->token[0]; 217 | s->str_start = s->cursor; 218 | uint32_t i = 0, j = 0; 219 | zua_string *str = NULL; 220 | for (; ; i++) { 221 | if (YYCURSOR < YYLIMIT) { 222 | if (*YYCURSOR == c) break; 223 | if (*YYCURSOR++ == '\\') { 224 | if (str == NULL) { 225 | str = zua_string_create(s->str_start, i - j); 226 | } else { 227 | str = zua_string_append(str, s->str_start+j, i - j); 228 | } 229 | while (isspace(*YYCURSOR)) { 230 | YYCURSOR++; 231 | i++; 232 | } 233 | j = i + 1; 234 | } 235 | } else { 236 | zua_string_free(str); 237 | return ZUA_JSON_T_ERROR; 238 | } 239 | } 240 | str = zua_string_append(str, s->str_start+j, i - j); 241 | s->cursor++; 242 | Z_STR_P(&s->value) = str; 243 | Z_TYPE_P(&s->value) = IS_STRING; 244 | return ZUA_JSON_T_STRING; 245 | } 246 | yy13: 247 | yych = *++YYCURSOR; 248 | if (yych <= '/') goto yy5; 249 | if (yych <= '0') goto yy44; 250 | if (yych <= '9') goto yy23; 251 | goto yy5; 252 | yy14: 253 | ++YYCURSOR; 254 | { return ','; } 255 | yy16: 256 | yyaccept = 0; 257 | yych = *(YYMARKER = ++YYCURSOR); 258 | if (yych <= '9') { 259 | if (yych <= '/') goto yy5; 260 | if (yych <= '0') goto yy44; 261 | goto yy23; 262 | } else { 263 | if (yych == 'I') goto yy45; 264 | goto yy5; 265 | } 266 | yy17: 267 | yyaccept = 1; 268 | yych = *(YYMARKER = ++YYCURSOR); 269 | if (yybm[0+yych] & 32) { 270 | goto yy17; 271 | } 272 | if (yych == 'E') goto yy47; 273 | if (yych == 'e') goto yy47; 274 | yy19: 275 | { 276 | ZVAL_DOUBLE(&s->value, strtod((char *) s->token, NULL)); 277 | return ZUA_JSON_T_DOUBLE; 278 | } 279 | yy20: 280 | yych = *++YYCURSOR; 281 | if (yych == '*') goto yy48; 282 | if (yych == '/') goto yy50; 283 | goto yy5; 284 | yy21: 285 | yyaccept = 2; 286 | yych = *(YYMARKER = ++YYCURSOR); 287 | if (yych <= 'W') { 288 | if (yych <= '.') { 289 | if (yych >= '.') goto yy17; 290 | } else { 291 | if (yych == 'E') goto yy47; 292 | } 293 | } else { 294 | if (yych <= 'e') { 295 | if (yych <= 'X') goto yy52; 296 | if (yych >= 'e') goto yy47; 297 | } else { 298 | if (yych == 'x') goto yy52; 299 | } 300 | } 301 | yy22: 302 | { 303 | ZVAL_LONG(&s->value, strtol((char *)s->token, NULL, 10)); 304 | return ZUA_JSON_T_INT; 305 | } 306 | yy23: 307 | yyaccept = 2; 308 | yych = *(YYMARKER = ++YYCURSOR); 309 | if (yych <= '9') { 310 | if (yych == '.') goto yy17; 311 | if (yych <= '/') goto yy22; 312 | goto yy23; 313 | } else { 314 | if (yych <= 'E') { 315 | if (yych <= 'D') goto yy22; 316 | goto yy47; 317 | } else { 318 | if (yych == 'e') goto yy47; 319 | goto yy22; 320 | } 321 | } 322 | yy25: 323 | ++YYCURSOR; 324 | { return ':'; } 325 | yy27: 326 | yych = *++YYCURSOR; 327 | if (yych == '"') goto yy53; 328 | if (yych == '\'') goto yy55; 329 | goto yy5; 330 | yy28: 331 | yych = *++YYCURSOR; 332 | yy29: 333 | if (yybm[0+yych] & 64) { 334 | goto yy28; 335 | } 336 | { 337 | ZVAL_STRINGL(&s->value, s->token, s->cursor - s->token); 338 | ZUA_JSON_CONDITION_SET(JS); 339 | return ZUA_JSON_T_ETRING; 340 | } 341 | yy31: 342 | yych = *++YYCURSOR; 343 | if (yych == 'n') goto yy57; 344 | goto yy29; 345 | yy32: 346 | yych = *++YYCURSOR; 347 | if (yych == 'a') goto yy58; 348 | goto yy29; 349 | yy33: 350 | ++YYCURSOR; 351 | { return '['; } 352 | yy35: 353 | ++YYCURSOR; 354 | { return ']'; } 355 | yy37: 356 | yych = *++YYCURSOR; 357 | if (yych == 'a') goto yy59; 358 | goto yy29; 359 | yy38: 360 | yych = *++YYCURSOR; 361 | if (yych == 'u') goto yy60; 362 | goto yy29; 363 | yy39: 364 | yych = *++YYCURSOR; 365 | if (yych == 'r') goto yy61; 366 | goto yy29; 367 | yy40: 368 | ++YYCURSOR; 369 | { return '{'; } 370 | yy42: 371 | ++YYCURSOR; 372 | { return '}'; } 373 | yy44: 374 | yyaccept = 2; 375 | yych = *(YYMARKER = ++YYCURSOR); 376 | if (yych <= 'D') { 377 | if (yych == '.') goto yy17; 378 | goto yy22; 379 | } else { 380 | if (yych <= 'E') goto yy47; 381 | if (yych == 'e') goto yy47; 382 | goto yy22; 383 | } 384 | yy45: 385 | yych = *++YYCURSOR; 386 | if (yych == 'n') goto yy62; 387 | yy46: 388 | YYCURSOR = YYMARKER; 389 | if (yyaccept <= 1) { 390 | if (yyaccept == 0) { 391 | goto yy5; 392 | } else { 393 | goto yy19; 394 | } 395 | } else { 396 | goto yy22; 397 | } 398 | yy47: 399 | yych = *++YYCURSOR; 400 | if (yych <= ',') { 401 | if (yych == '+') goto yy63; 402 | goto yy46; 403 | } else { 404 | if (yych <= '-') goto yy63; 405 | if (yych <= '/') goto yy46; 406 | if (yych <= '9') goto yy64; 407 | goto yy46; 408 | } 409 | yy48: 410 | ++YYCURSOR; 411 | { 412 | while(YYCURSOR < YYLIMIT) { 413 | if (*YYCURSOR++ == '*' && *YYCURSOR == '/') { 414 | break; 415 | } 416 | } 417 | if (YYCURSOR < YYLIMIT) { 418 | YYCURSOR++; 419 | } else { 420 | return ZUA_JSON_T_COMMENT_NOT_CLOSED; 421 | } 422 | goto std; 423 | } 424 | yy50: 425 | ++YYCURSOR; 426 | { 427 | ZUA_JSON_CONDITION_SET_AND_GOTO(COMMENTS); 428 | } 429 | yy52: 430 | yych = *++YYCURSOR; 431 | if (yybm[0+yych] & 128) { 432 | goto yy66; 433 | } 434 | goto yy46; 435 | yy53: 436 | ++YYCURSOR; 437 | { 438 | s->str_start = s->cursor; 439 | s->str_esc = 0; 440 | s->utf8_invalid = 0; 441 | s->utf8_invalid_count = 0; 442 | ZUA_JSON_CONDITION_SET_AND_GOTO(STR_P1); 443 | } 444 | yy55: 445 | ++YYCURSOR; 446 | { 447 | s->str_start = s->cursor; 448 | s->str_esc = 0; 449 | s->utf8_invalid = 0; 450 | s->utf8_invalid_count = 0; 451 | ZUA_JSON_CONDITION_SET_AND_GOTO(STR_P2); 452 | } 453 | yy57: 454 | yych = *++YYCURSOR; 455 | if (yych == 'f') goto yy69; 456 | goto yy29; 457 | yy58: 458 | yych = *++YYCURSOR; 459 | if (yych == 'N') goto yy70; 460 | goto yy29; 461 | yy59: 462 | yych = *++YYCURSOR; 463 | if (yych == 'l') goto yy72; 464 | goto yy29; 465 | yy60: 466 | yych = *++YYCURSOR; 467 | if (yych == 'l') goto yy73; 468 | goto yy29; 469 | yy61: 470 | yych = *++YYCURSOR; 471 | if (yych == 'u') goto yy74; 472 | goto yy29; 473 | yy62: 474 | yych = *++YYCURSOR; 475 | if (yych == 'f') goto yy75; 476 | goto yy46; 477 | yy63: 478 | yych = *++YYCURSOR; 479 | if (yych <= '/') goto yy46; 480 | if (yych >= ':') goto yy46; 481 | yy64: 482 | yych = *++YYCURSOR; 483 | if (yych <= '/') goto yy19; 484 | if (yych <= '9') goto yy64; 485 | goto yy19; 486 | yy66: 487 | yych = *++YYCURSOR; 488 | if (yybm[0+yych] & 128) { 489 | goto yy66; 490 | } 491 | { 492 | ZVAL_LONG(&s->value, strtol((char *)s->token, NULL, 16)); 493 | return ZUA_JSON_T_INT; 494 | } 495 | yy69: 496 | yych = *++YYCURSOR; 497 | if (yych == 'i') goto yy76; 498 | goto yy29; 499 | yy70: 500 | yych = *++YYCURSOR; 501 | if (yybm[0+yych] & 64) { 502 | goto yy28; 503 | } 504 | { 505 | ZVAL_NAN(&s->value); 506 | return ZUA_JSON_T_NAN; 507 | } 508 | yy72: 509 | yych = *++YYCURSOR; 510 | if (yych == 's') goto yy77; 511 | goto yy29; 512 | yy73: 513 | yych = *++YYCURSOR; 514 | if (yych == 'l') goto yy78; 515 | goto yy29; 516 | yy74: 517 | yych = *++YYCURSOR; 518 | if (yych == 'e') goto yy80; 519 | goto yy29; 520 | yy75: 521 | yych = *++YYCURSOR; 522 | if (yych == 'i') goto yy82; 523 | goto yy46; 524 | yy76: 525 | yych = *++YYCURSOR; 526 | if (yych == 'n') goto yy83; 527 | goto yy29; 528 | yy77: 529 | yych = *++YYCURSOR; 530 | if (yych == 'e') goto yy84; 531 | goto yy29; 532 | yy78: 533 | yych = *++YYCURSOR; 534 | if (yybm[0+yych] & 64) { 535 | goto yy28; 536 | } 537 | { 538 | ZVAL_NULL(&s->value); 539 | return ZUA_JSON_T_NUL; 540 | } 541 | yy80: 542 | yych = *++YYCURSOR; 543 | if (yybm[0+yych] & 64) { 544 | goto yy28; 545 | } 546 | { 547 | ZVAL_TRUE(&s->value); 548 | return ZUA_JSON_T_TRUE; 549 | } 550 | yy82: 551 | yych = *++YYCURSOR; 552 | if (yych == 'n') goto yy86; 553 | goto yy46; 554 | yy83: 555 | yych = *++YYCURSOR; 556 | if (yych == 'i') goto yy87; 557 | goto yy29; 558 | yy84: 559 | yych = *++YYCURSOR; 560 | if (yybm[0+yych] & 64) { 561 | goto yy28; 562 | } 563 | { 564 | ZVAL_FALSE(&s->value); 565 | return ZUA_JSON_T_FALSE; 566 | } 567 | yy86: 568 | yych = *++YYCURSOR; 569 | if (yych == 'i') goto yy88; 570 | goto yy46; 571 | yy87: 572 | yych = *++YYCURSOR; 573 | if (yych == 't') goto yy89; 574 | goto yy29; 575 | yy88: 576 | yych = *++YYCURSOR; 577 | if (yych == 't') goto yy90; 578 | goto yy46; 579 | yy89: 580 | yych = *++YYCURSOR; 581 | if (yych == 'y') goto yy91; 582 | goto yy29; 583 | yy90: 584 | yych = *++YYCURSOR; 585 | if (yych == 'y') goto yy93; 586 | goto yy46; 587 | yy91: 588 | yych = *++YYCURSOR; 589 | if (yybm[0+yych] & 64) { 590 | goto yy28; 591 | } 592 | { 593 | ZVAL_INFINITY(&s->value); 594 | return ZUA_JSON_T_INFINITY; 595 | } 596 | yy93: 597 | ++YYCURSOR; 598 | { 599 | ZVAL_NINFINITY(&s->value); 600 | return ZUA_JSON_T_NEGATIVE_INFINITY; 601 | } 602 | } 603 | /* *********************************** */ 604 | yyc_STR_P2: 605 | { 606 | static const unsigned char yybm[] = { 607 | 128, 128, 128, 128, 128, 128, 128, 128, 608 | 128, 128, 128, 128, 128, 128, 128, 128, 609 | 128, 128, 128, 128, 128, 128, 128, 128, 610 | 128, 128, 128, 128, 128, 128, 128, 128, 611 | 128, 128, 128, 128, 128, 128, 128, 0, 612 | 128, 128, 128, 128, 128, 128, 128, 128, 613 | 128, 128, 128, 128, 128, 128, 128, 128, 614 | 128, 128, 128, 128, 128, 128, 128, 128, 615 | 128, 128, 128, 128, 128, 128, 128, 128, 616 | 128, 128, 128, 128, 128, 128, 128, 128, 617 | 128, 128, 128, 128, 128, 128, 128, 128, 618 | 128, 128, 128, 128, 128, 128, 128, 128, 619 | 128, 128, 128, 128, 128, 128, 128, 128, 620 | 128, 128, 128, 128, 128, 128, 128, 128, 621 | 128, 128, 128, 128, 128, 128, 128, 128, 622 | 128, 128, 128, 128, 128, 128, 128, 128, 623 | 128, 128, 128, 128, 128, 128, 128, 128, 624 | 128, 128, 128, 128, 128, 128, 128, 128, 625 | 128, 128, 128, 128, 128, 128, 128, 128, 626 | 128, 128, 128, 128, 128, 128, 128, 128, 627 | 128, 128, 128, 128, 128, 128, 128, 128, 628 | 128, 128, 128, 128, 128, 128, 128, 128, 629 | 128, 128, 128, 128, 128, 128, 128, 128, 630 | 128, 128, 128, 128, 128, 128, 128, 128, 631 | 128, 128, 128, 128, 128, 128, 128, 128, 632 | 128, 128, 128, 128, 128, 128, 128, 128, 633 | 128, 128, 128, 128, 128, 128, 128, 128, 634 | 128, 128, 128, 128, 128, 128, 128, 128, 635 | 128, 128, 128, 128, 128, 128, 128, 128, 636 | 128, 128, 128, 128, 128, 128, 128, 128, 637 | 128, 128, 128, 128, 128, 128, 128, 128, 638 | 128, 128, 128, 128, 128, 128, 128, 128, 639 | }; 640 | yych = *YYCURSOR; 641 | if (yybm[0+yych] & 128) { 642 | goto yy97; 643 | } 644 | goto yy100; 645 | yy97: 646 | yych = *++YYCURSOR; 647 | if (yybm[0+yych] & 128) { 648 | goto yy97; 649 | } 650 | { ZUA_JSON_CONDITION_GOTO(STR_P2); } 651 | yy100: 652 | ++YYCURSOR; 653 | { 654 | size_t len = s->cursor - s->str_start - s->str_esc - 1 + s->utf8_invalid_count; 655 | ZVAL_STRINGL(&s->value, s->str_start, len); 656 | ZUA_JSON_CONDITION_SET(JS); 657 | return ZUA_JSON_T_STRING; 658 | } 659 | } 660 | /* *********************************** */ 661 | yyc_COMMENTS: 662 | yych = *YYCURSOR; 663 | if (yych == '\n') goto yy106; 664 | ++YYCURSOR; 665 | { 666 | if (YYCURSOR >= YYLIMIT) { 667 | return ZUA_JSON_T_ERROR; 668 | } 669 | ZUA_JSON_CONDITION_SET_AND_GOTO(COMMENTS); 670 | } 671 | yy106: 672 | ++YYCURSOR; 673 | { ZUA_JSON_CONDITION_SET_AND_GOTO(JS); } 674 | /* *********************************** */ 675 | yyc_STR_P1: 676 | { 677 | static const unsigned char yybm[] = { 678 | 128, 128, 128, 128, 128, 128, 128, 128, 679 | 128, 128, 128, 128, 128, 128, 128, 128, 680 | 128, 128, 128, 128, 128, 128, 128, 128, 681 | 128, 128, 128, 128, 128, 128, 128, 128, 682 | 128, 128, 0, 128, 128, 128, 128, 128, 683 | 128, 128, 128, 128, 128, 128, 128, 128, 684 | 128, 128, 128, 128, 128, 128, 128, 128, 685 | 128, 128, 128, 128, 128, 128, 128, 128, 686 | 128, 128, 128, 128, 128, 128, 128, 128, 687 | 128, 128, 128, 128, 128, 128, 128, 128, 688 | 128, 128, 128, 128, 128, 128, 128, 128, 689 | 128, 128, 128, 128, 128, 128, 128, 128, 690 | 128, 128, 128, 128, 128, 128, 128, 128, 691 | 128, 128, 128, 128, 128, 128, 128, 128, 692 | 128, 128, 128, 128, 128, 128, 128, 128, 693 | 128, 128, 128, 128, 128, 128, 128, 128, 694 | 128, 128, 128, 128, 128, 128, 128, 128, 695 | 128, 128, 128, 128, 128, 128, 128, 128, 696 | 128, 128, 128, 128, 128, 128, 128, 128, 697 | 128, 128, 128, 128, 128, 128, 128, 128, 698 | 128, 128, 128, 128, 128, 128, 128, 128, 699 | 128, 128, 128, 128, 128, 128, 128, 128, 700 | 128, 128, 128, 128, 128, 128, 128, 128, 701 | 128, 128, 128, 128, 128, 128, 128, 128, 702 | 128, 128, 128, 128, 128, 128, 128, 128, 703 | 128, 128, 128, 128, 128, 128, 128, 128, 704 | 128, 128, 128, 128, 128, 128, 128, 128, 705 | 128, 128, 128, 128, 128, 128, 128, 128, 706 | 128, 128, 128, 128, 128, 128, 128, 128, 707 | 128, 128, 128, 128, 128, 128, 128, 128, 708 | 128, 128, 128, 128, 128, 128, 128, 128, 709 | 128, 128, 128, 128, 128, 128, 128, 128, 710 | }; 711 | yych = *YYCURSOR; 712 | if (yybm[0+yych] & 128) { 713 | goto yy110; 714 | } 715 | goto yy113; 716 | yy110: 717 | yych = *++YYCURSOR; 718 | if (yybm[0+yych] & 128) { 719 | goto yy110; 720 | } 721 | { ZUA_JSON_CONDITION_GOTO(STR_P1); } 722 | yy113: 723 | ++YYCURSOR; 724 | { 725 | size_t len = s->cursor - s->str_start - s->str_esc - 1 + s->utf8_invalid_count; 726 | ZVAL_STRINGL(&s->value, s->str_start, len); 727 | ZUA_JSON_CONDITION_SET(JS); 728 | return ZUA_JSON_T_STRING; 729 | } 730 | } 731 | } 732 | 733 | } -------------------------------------------------------------------------------- /zua_scanner.h: -------------------------------------------------------------------------------- 1 | #ifndef ZUA_ZUA_SCANNER_H 2 | #define ZUA_ZUA_SCANNER_H 3 | 4 | #include "zua_type.h" 5 | 6 | typedef char zua_json_ctype; 7 | 8 | enum { 9 | ZUA_JSON_SYNTAX_ERROR = 1 << 6, 10 | ZUA_JSON_BRACKET_MISMATCH, 11 | }; 12 | 13 | typedef struct _zua_json_scanner { 14 | zua_json_ctype *cursor; /* cursor position */ 15 | zua_json_ctype *token; /* token position */ 16 | zua_json_ctype *limit; /* the last read character + 1 position */ 17 | zua_json_ctype *marker; /* marker position for backtracking */ 18 | zua_json_ctype *ctxmarker; /* marker position for context backtracking */ 19 | zua_json_ctype *str_start; /* start position of the string */ 20 | zua_json_ctype *pstr; /* string pointer for escapes conversion */ 21 | zval value; /* value */ 22 | int str_esc; /* number of extra characters for escaping */ 23 | int state; /* condition state */ 24 | int options; /* options */ 25 | int errcode; /* error type if there is an error */ 26 | int utf8_invalid; /* whether utf8 is invalid */ 27 | int utf8_invalid_count; /* number of extra character for invalid utf8 */ 28 | } zua_json_scanner; 29 | 30 | 31 | void zua_json_scanner_init(zua_json_scanner *scanner, const char *str, uint32_t str_len, int options); 32 | int zua_json_scan(zua_json_scanner *s); 33 | 34 | #endif /* ZUA_ZUA_SCANNER_H */ 35 | -------------------------------------------------------------------------------- /zua_scanner.re: -------------------------------------------------------------------------------- 1 | /* 2 | * re2c -t zua_scanner_defs.h -bci -o zua_scanner.c --no-generation-date zua_scanner.re 3 | */ 4 | #include 5 | #include "zua_scanner.h" 6 | #include "zua_scanner_defs.h" 7 | #include "zua_parser.h" 8 | #include "zua_type.h" 9 | #include 10 | #include 11 | 12 | #define YYCTYPE zua_json_ctype 13 | #define YYCURSOR s->cursor 14 | #define YYLIMIT s->limit 15 | #define YYMARKER s->marker 16 | #define YYCTXMARKER s->ctxmarker 17 | 18 | #define YYGETCONDITION() s->state 19 | #define YYSETCONDITION(yystate) s->state = yystate 20 | 21 | #define YYFILL(n) 22 | 23 | #define ZUA_JSON_CONDITION_SET(condition) YYSETCONDITION(yyc##condition) 24 | #define ZUA_JSON_CONDITION_GOTO(condition) goto yyc_##condition 25 | #define ZUA_JSON_CONDITION_SET_AND_GOTO(condition) \ 26 | ZUA_JSON_CONDITION_SET(condition); \ 27 | ZUA_JSON_CONDITION_GOTO(condition) 28 | 29 | void zua_json_scanner_init(zua_json_scanner *s, const char *str, uint32_t str_len, int options) { 30 | s->cursor = (zua_json_ctype *)str; 31 | s->limit = (zua_json_ctype *)str + str_len; 32 | s->options = options; 33 | ZUA_JSON_CONDITION_SET(JS); 34 | } 35 | 36 | 37 | int zua_json_scan(zua_json_scanner *s) { 38 | ZVAL_NULL(&s->value); 39 | 40 | std: 41 | s->token = s->cursor; 42 | 43 | /*!re2c 44 | re2c:indent:top = 1; 45 | re2c:yyfill:enable = 0; 46 | 47 | DIGIT = [0-9]; 48 | DIGITNZ = [1-9]; 49 | UINT = "0" | (DIGITNZ DIGIT*); 50 | INT = ("-"|"+")? UINT ; 51 | FLOAT = (INT) ? "." DIGIT* ; 52 | EXP = ( INT | FLOAT ) [eE] [+-]? DIGIT+ ; 53 | NL = "\r"? "\n"; 54 | HEX = "0"[xX][a-fA-F]+; 55 | WS = [ \t\r]+; 56 | EOI = "\000"; 57 | UTF8T = [\x80-\xBF] ; 58 | UTF8_1 = [\x00-\x7F] ; 59 | UTF8_2 = [\xC2-\xDF] UTF8T ; 60 | UTF8_3A = "\xE0" [\xA0-\xBF] UTF8T ; 61 | UTF8_3B = [\xE1-\xEC] UTF8T{2} ; 62 | UTF8_3C = "\xED" [\x80-\x9F] UTF8T ; 63 | UTF8_3D = [\xEE-\xEF] UTF8T{2} ; 64 | UTF8_3 = UTF8_3A | UTF8_3B | UTF8_3C | UTF8_3D ; 65 | UTF8_4A = "\xF0"[\x90-\xBF] UTF8T{2} ; 66 | UTF8_4B = [\xF1-\xF3] UTF8T{3} ; 67 | UTF8_4C = "\xF4" [\x80-\x8F] UTF8T{2} ; 68 | UTF8_4 = UTF8_4A | UTF8_4B | UTF8_4C ; 69 | UTF8 = UTF8_1 | UTF8_2 | UTF8_3 | UTF8_4; 70 | ANY = [^]; 71 | ESCPREF = "\\" ; 72 | ESCSYM = ( "\"" | "\\" | "/" | [bfnrt] ) ; 73 | ESC = ESCPREF ESCSYM ; 74 | UTFSYM = "u" ; 75 | UTFPREF = ESCPREF UTFSYM ; 76 | LABEL = [a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*; 77 | 78 | 79 | "{" { return '{'; } 80 | "}" { return '}'; } 81 | "[" { return '['; } 82 | "]" { return ']'; } 83 | ":" { return ':'; } 84 | "," { return ','; } 85 | "null" { 86 | ZVAL_NULL(&s->value); 87 | return ZUA_JSON_T_NUL; 88 | } 89 | "true" { 90 | ZVAL_TRUE(&s->value); 91 | return ZUA_JSON_T_TRUE; 92 | } 93 | "false" { 94 | ZVAL_FALSE(&s->value); 95 | return ZUA_JSON_T_FALSE; 96 | } 97 | "NaN" { 98 | ZVAL_NAN(&s->value); 99 | return ZUA_JSON_T_NAN; 100 | } 101 | "Infinity" { 102 | ZVAL_INFINITY(&s->value); 103 | return ZUA_JSON_T_INFINITY; 104 | } 105 | "-Infinity" { 106 | ZVAL_NINFINITY(&s->value); 107 | return ZUA_JSON_T_NEGATIVE_INFINITY; 108 | } 109 | INT { 110 | ZVAL_LONG(&s->value, strtol((char *)s->token, NULL, 10)); 111 | return ZUA_JSON_T_INT; 112 | } 113 | HEX { 114 | ZVAL_LONG(&s->value, strtol((char *)s->token, NULL, 16)); 115 | return ZUA_JSON_T_INT; 116 | } 117 | FLOAT|EXP { 118 | ZVAL_DOUBLE(&s->value, strtod((char *) s->token, NULL)); 119 | return ZUA_JSON_T_DOUBLE; 120 | } 121 | NL|WS { goto std; } 122 | EOI { 123 | if (s->limit < s->cursor) { 124 | return ZUA_JSON_T_EOI; 125 | } else { 126 | s->errcode = 1; 127 | return ZUA_JSON_T_ERROR; 128 | } 129 | } 130 | LABEL { 131 | ZVAL_STRINGL(&s->value, s->token, s->cursor - s->token); 132 | ZUA_JSON_CONDITION_SET(JS); 133 | return ZUA_JSON_T_ETRING; 134 | } 135 | "@'" { 136 | s->str_start = s->cursor; 137 | s->str_esc = 0; 138 | s->utf8_invalid = 0; 139 | s->utf8_invalid_count = 0; 140 | ZUA_JSON_CONDITION_SET_AND_GOTO(STR_P2); 141 | } 142 | [^']* { ZUA_JSON_CONDITION_GOTO(STR_P2); } 143 | ['] { 144 | size_t len = s->cursor - s->str_start - s->str_esc - 1 + s->utf8_invalid_count; 145 | ZVAL_STRINGL(&s->value, s->str_start, len); 146 | ZUA_JSON_CONDITION_SET(JS); 147 | return ZUA_JSON_T_STRING; 148 | } 149 | "@\"" { 150 | s->str_start = s->cursor; 151 | s->str_esc = 0; 152 | s->utf8_invalid = 0; 153 | s->utf8_invalid_count = 0; 154 | ZUA_JSON_CONDITION_SET_AND_GOTO(STR_P1); 155 | } 156 | ["'] { 157 | char c = s->token[0]; 158 | s->str_start = s->cursor; 159 | uint32_t i = 0, j = 0; 160 | zua_string *str = NULL; 161 | for (; ; i++) { 162 | if (YYCURSOR < YYLIMIT) { 163 | if (*YYCURSOR == c) break; 164 | if (*YYCURSOR++ == '\\') { 165 | if (str == NULL) { 166 | str = zua_string_create(s->str_start, i - j); 167 | } else { 168 | str = zua_string_append(str, s->str_start+j, i - j); 169 | } 170 | while (isspace(*YYCURSOR)) { 171 | YYCURSOR++; 172 | i++; 173 | } 174 | j = i + 1; 175 | } 176 | } else { 177 | zua_string_free(str); 178 | return ZUA_JSON_T_ERROR; 179 | } 180 | } 181 | str = zua_string_append(str, s->str_start+j, i - j); 182 | s->cursor++; 183 | Z_STR_P(&s->value) = str; 184 | Z_TYPE_P(&s->value) = IS_STRING; 185 | return ZUA_JSON_T_STRING; 186 | } 187 | "//" { 188 | ZUA_JSON_CONDITION_SET_AND_GOTO(COMMENTS); 189 | } 190 | "/*" { 191 | while(YYCURSOR < YYLIMIT) { 192 | if (*YYCURSOR++ == '*' && *YYCURSOR == '/') { 193 | break; 194 | } 195 | } 196 | if (YYCURSOR < YYLIMIT) { 197 | YYCURSOR++; 198 | } else { 199 | return ZUA_JSON_T_COMMENT_NOT_CLOSED; 200 | } 201 | goto std; 202 | } 203 | 204 | [^\n] { 205 | if (YYCURSOR >= YYLIMIT) { 206 | return ZUA_JSON_T_ERROR; 207 | } 208 | ZUA_JSON_CONDITION_SET_AND_GOTO(COMMENTS); 209 | } 210 | [\n] { ZUA_JSON_CONDITION_SET_AND_GOTO(JS); } 211 | 212 | [^"]* { ZUA_JSON_CONDITION_GOTO(STR_P1); } 213 | ["] { 214 | size_t len = s->cursor - s->str_start - s->str_esc - 1 + s->utf8_invalid_count; 215 | ZVAL_STRINGL(&s->value, s->str_start, len); 216 | ZUA_JSON_CONDITION_SET(JS); 217 | return ZUA_JSON_T_STRING; 218 | } 219 | <*>ANY { 220 | return ZUA_JSON_T_ERROR; 221 | } 222 | */ 223 | } -------------------------------------------------------------------------------- /zua_scanner_defs.h: -------------------------------------------------------------------------------- 1 | /* Generated by re2c 2.1.1 */ 2 | 3 | enum YYCONDTYPE { 4 | yycJS, 5 | yycSTR_P2, 6 | yycCOMMENTS, 7 | yycSTR_P1, 8 | }; 9 | -------------------------------------------------------------------------------- /zua_type.c: -------------------------------------------------------------------------------- 1 | #include "zua_type.h" 2 | #include "zua_parser_defs.h" 3 | #include "zua_parser.h" 4 | 5 | zua_string *zua_string_create(const char *str, uint32_t str_len) { 6 | zua_string *r = zua_malloc(zua_string_size(str_len)); 7 | bzero(r, zua_string_size(str_len)); 8 | bcopy(str, ZSTR_VAL(r), sizeof(char) * str_len); 9 | ZSTR_LEN(r) = str_len; 10 | return r; 11 | } 12 | 13 | zua_string *zua_string_append(zua_string *r, const char *str, uint32_t str_len) { 14 | if (r == NULL) return zua_string_create(str, str_len); 15 | uint32_t new_str_len = zua_string_size(ZSTR_LEN(r) + str_len); 16 | zua_string *t = zua_malloc(new_str_len); 17 | bzero(t, new_str_len); 18 | bcopy(ZSTR_VAL(r), ZSTR_VAL(t), ZSTR_LEN(r)); 19 | bcopy(str, ZSTR_VAL(t) + ZSTR_LEN(r), sizeof(char) * str_len); 20 | ZSTR_LEN(t) = ZSTR_LEN(r) + str_len; 21 | zua_string_free(r); 22 | return t; 23 | } 24 | 25 | zua_string *zua_string_addslashes(zua_string *r) { 26 | uint32_t i = 0, j = 0; 27 | zua_string *str = NULL; 28 | for (; i < ZSTR_LEN(r); i++) { 29 | if (ZSTR_VAL(r)[i] == '"') { 30 | if (str == NULL) { 31 | str = zua_string_create(ZSTR_VAL(r), i - j); 32 | } else { 33 | str = zua_string_append(str, ZSTR_VAL(r)+j, i - j); 34 | } 35 | str = zua_string_append(str, ZUA_STR("\\\"")); 36 | j = i+1; 37 | } 38 | } 39 | str = zua_string_append(str, ZSTR_VAL(r)+j, i - j); 40 | return str; 41 | } 42 | 43 | ZUA_API zval *zval_init() { 44 | zval *v1 = zua_malloc(sizeof(zval)); 45 | memset(v1, 0, sizeof(zval)); 46 | return v1; 47 | } 48 | 49 | void object_init(zval *v) { 50 | Z_OBJ_P(v) = zua_hashmap_init(); 51 | assert(0 == hashmap_create(HASHMAP_DEFAULT_SIZE, Z_OBJ_P(v))); 52 | Z_TYPE_P(v) = IS_OBJECT; 53 | } 54 | 55 | 56 | void array_init(zval *v) { 57 | Z_ARR_P(v) = zua_hashmap_init(); 58 | assert(0 == hashmap_create(HASHMAP_DEFAULT_SIZE, Z_ARR_P(v))); 59 | Z_TYPE_P(v) = IS_ARRAY; 60 | } 61 | 62 | int _array_object_free_hashmap(void * const context, zua_hashmap_ele *const ele) { 63 | zua_free(ele->key); 64 | zval_free(ele->data); 65 | return 0; 66 | } 67 | 68 | void zval_free_by_type(zval *v, uint32_t gc) { 69 | switch (Z_TYPE_P(v)) { 70 | case IS_ARRAY: 71 | { 72 | hashmap_iterate_pairs(Z_ARR_P(v), _array_object_free_hashmap, NULL); 73 | hashmap_destroy(Z_ARR_P(v)); 74 | zua_free(Z_ARR_P(v)); 75 | break; 76 | } 77 | case IS_OBJECT: 78 | { 79 | hashmap_iterate_pairs(Z_OBJ_P(v), _array_object_free_hashmap, NULL); 80 | hashmap_destroy(Z_OBJ_P(v)); 81 | zua_free(Z_OBJ_P(v)); 82 | break; 83 | } 84 | case IS_STRING: 85 | { 86 | zua_free(Z_STR_P(v)); 87 | break; 88 | } 89 | case IS_TRUE: 90 | case IS_FALSE: 91 | case IS_NULL: 92 | case IS_NAN: 93 | case IS_NEGATIVE_INFINITY: 94 | case IS_INFINITY: 95 | break; 96 | } 97 | if (gc) zua_free(v); 98 | } 99 | 100 | void zval_free(zval *v) { 101 | zval_free_by_type(v, 1); 102 | } 103 | 104 | void zval_free_nogc(zval *v) { 105 | zval_free_by_type(v, 0); 106 | } 107 | 108 | ZUA_API void zua_hash_str_add_or_update(zval *h, const char *key, uint32_t key_len, zval *v2) { 109 | if ( h == NULL || Z_ARR_P(h) == NULL || Z_OBJ_P(h) == NULL) return ; 110 | if ( Z_TYPE_P(h) != IS_OBJECT ) return ; 111 | 112 | zval *v1 = NULL; 113 | char *k = zua_malloc(sizeof(char) * key_len); 114 | bzero(k, sizeof(char) * key_len); 115 | memcpy(k, key, sizeof(char) * key_len); 116 | 117 | v1 = zua_malloc(sizeof(zval)); 118 | ZUA_COPY_VALUE(v1, v2); 119 | 120 | switch (Z_TYPE_P(h)) { 121 | case IS_ARRAY: 122 | { 123 | zval *v = hashmap_get(Z_ARR_P(h), k, key_len); 124 | if (v != HASHMAP_NULL) { 125 | zval_free(v); 126 | } 127 | hashmap_put(Z_ARR_P(h), k, key_len, v1); 128 | break; 129 | } 130 | case IS_OBJECT: 131 | { 132 | zval *v = hashmap_get(Z_OBJ_P(h), k, key_len); 133 | if (v != HASHMAP_NULL) { 134 | zval_free(v); 135 | } 136 | hashmap_put(Z_OBJ_P(h), k, key_len, v1); 137 | break; 138 | } 139 | } 140 | } 141 | 142 | ZUA_API void zua_hash_index_add(zval *h, zval *value) { 143 | if ( h == NULL || Z_ARR_P(h) == NULL || Z_OBJ_P(h) == NULL) return ; 144 | if ( Z_TYPE_P(h) != IS_ARRAY ) return ; 145 | 146 | char *keyBuf = zua_malloc(sizeof(char) * MAX_STRING_KEY); 147 | bzero(keyBuf, sizeof(char) * MAX_STRING_KEY); 148 | sprintf(keyBuf, "%d", hashmap_num_entries(Z_ARR_P(h))); 149 | 150 | zval *v1 = zua_malloc(sizeof(zval)); 151 | ZUA_COPY_VALUE(v1, value); 152 | 153 | hashmap_put(Z_ARR_P(h), keyBuf, strlen(keyBuf), v1); 154 | } 155 | 156 | ZUA_API zval *json_decode(const char *str, uint32_t str_len) { 157 | zval *val = zua_malloc(sizeof(zval)); 158 | zua_json_parser parser; 159 | zua_json_parser_init(&parser, val, str, str_len, 0, 0); 160 | 161 | zua_yyparse(&parser); 162 | val->u2.errcode = parser.scanner.errcode; 163 | return val; 164 | } 165 | 166 | ZUA_API zval *zua_get_value(zval *v, const char *key, uint32_t key_len) { 167 | zua_hashmap *map = NULL; 168 | if (Z_TYPE_P(v) == IS_OBJECT) { 169 | map = Z_OBJ_P(v); 170 | } else if (Z_TYPE_P(v) == IS_ARRAY) { 171 | map = Z_ARR_P(v); 172 | } else { 173 | return NULL; 174 | } 175 | return hashmap_get(map, key, key_len); 176 | } 177 | 178 | ZUA_API zval *zua_get_value_by_index(zval *v, uint32_t index) { 179 | zval *ret = NULL; 180 | char keyBuf[MAX_STRING_KEY]; 181 | if (Z_TYPE_P(v) == IS_ARRAY) { 182 | bzero(keyBuf, sizeof(char) * MAX_STRING_KEY); 183 | sprintf(keyBuf, "%d", index); 184 | ret = hashmap_get(Z_ARR_P(v), keyBuf, strlen(keyBuf)); 185 | } 186 | return ret; 187 | } 188 | 189 | ZUA_API zua_string *json_encode(zval *v) { 190 | if (Z_TYPE_P(v) == 0) return NULL; 191 | 192 | char str[MAX_STRING_KEY]; 193 | 194 | switch(Z_TYPE_P(v)) { 195 | case IS_LONG: 196 | { 197 | memset(str, 0, sizeof(str)); 198 | sprintf(str, "%ld", Z_LVAL_P(v)); 199 | return zua_string_create(str, strlen(str)); 200 | } 201 | case IS_TRUE: 202 | { 203 | memset(str, 0, sizeof(str)); 204 | sprintf(str, "true"); 205 | return zua_string_create(str, strlen(str)); 206 | } 207 | case IS_FALSE: 208 | { 209 | memset(str, 0, sizeof(str)); 210 | sprintf(str, "false"); 211 | return zua_string_create(str, strlen(str)); 212 | } 213 | case IS_NULL: 214 | { 215 | memset(str, 0, sizeof(str)); 216 | sprintf(str, "null"); 217 | return zua_string_create(str, strlen(str)); 218 | } 219 | case IS_NAN: 220 | { 221 | memset(str, 0, sizeof(str)); 222 | sprintf(str, "NaN"); 223 | return zua_string_create(str, strlen(str)); 224 | } 225 | case IS_INFINITY: 226 | { 227 | memset(str, 0, sizeof(str)); 228 | sprintf(str, "Infinity"); 229 | return zua_string_create(str, strlen(str)); 230 | } 231 | case IS_NEGATIVE_INFINITY: 232 | { 233 | memset(str, 0, sizeof(str)); 234 | sprintf(str, "-Infinity"); 235 | return zua_string_create(str, strlen(str)); 236 | } 237 | case IS_STRING: 238 | { 239 | return zua_string_create(ZSTRL(Z_STR_P(v))); 240 | } 241 | case IS_DOUBLE: 242 | { 243 | memset(str, 0, sizeof(str)); 244 | sprintf(str, "%f", Z_DVAL_P(v)); 245 | return zua_string_create(str, strlen(str)); 246 | } 247 | } 248 | 249 | zua_string *r = zua_string_create(Z_TYPE_P(v) == IS_ARRAY ? "[" : "{", 1); 250 | zua_hashmap *map = NULL; 251 | if (Z_TYPE_P(v) == IS_ARRAY) { 252 | map = Z_ARR_P(v); 253 | } else { 254 | map = Z_OBJ_P(v); 255 | } 256 | zua_hashmap_ele *e = NULL; 257 | zua_string *t = NULL; 258 | zua_string *s = NULL; 259 | unsigned int i; 260 | 261 | ZUA_HASHMAP_FOREACH_ELE(map, i, e) { 262 | zval *val = e->data; 263 | if (Z_TYPE_P(v) == IS_OBJECT) { 264 | r = zua_string_append( r, ZUA_STR("\"") ); 265 | t = zua_string_create(e->key, e->key_len); 266 | s = zua_string_addslashes(t); 267 | r = zua_string_append( r, ZSTR_VAL(s), ZSTR_LEN(s) ); 268 | zua_string_free(s); 269 | zua_string_free(t); 270 | r = zua_string_append( r, ZUA_STR("\":") ); 271 | } 272 | switch(Z_TYPE_P(val)) { 273 | case IS_STRING: 274 | r = zua_string_append(r, ZUA_STR("\"") ); 275 | s = zua_string_addslashes(Z_STR_P(val)); 276 | r = zua_string_append(r, ZSTRL(s) ); 277 | zua_string_free(s); 278 | r = zua_string_append(r, ZUA_STR("\"") ); 279 | break; 280 | case IS_DOUBLE: 281 | memset(str, 0, sizeof(str)); 282 | sprintf(str, "%f", Z_DVAL_P(val)); 283 | r = zua_string_append(r, str, strlen(str)); 284 | break; 285 | case IS_FALSE: 286 | r = zua_string_append(r, ZUA_STR("false") ); 287 | break; 288 | case IS_TRUE: 289 | r = zua_string_append(r, ZUA_STR("true") ); 290 | break; 291 | case IS_NULL: 292 | r = zua_string_append(r, ZUA_STR("null") ); 293 | break; 294 | case IS_NAN: 295 | r = zua_string_append(r, ZUA_STR("NaN") ); 296 | break; 297 | case IS_INFINITY: 298 | r = zua_string_append(r, ZUA_STR("Infinity") ); 299 | break; 300 | case IS_NEGATIVE_INFINITY: 301 | r = zua_string_append(r, ZUA_STR("-Infinity") ); 302 | break; 303 | case IS_LONG: 304 | memset(str, 0, sizeof(str)); 305 | sprintf(str, "%ld", Z_LVAL_P(val)); 306 | r = zua_string_append(r, str, strlen(str)); 307 | break; 308 | case IS_OBJECT: 309 | case IS_ARRAY: 310 | t = json_encode(val); 311 | r = zua_string_append(r, ZSTRL(t)); 312 | zua_string_free(t); 313 | break; 314 | } 315 | if ( i < (map->table_size - 1) ) r = zua_string_append(r, ZUA_STR(",")); 316 | } ZUA_HASHMAP_FOREACH_END(); 317 | if (ZSTR_VAL(r)[ZSTR_LEN(r) - 1] == ',') ZSTR_LEN(r)--; 318 | r = zua_string_append(r, Z_TYPE_P(v) == IS_ARRAY ? "]" : "}", 1); 319 | return r; 320 | } 321 | 322 | static inline zua_string *json_encode_pretty_with_indent(zval *v, const char *indent_str, uint32_t indent_str_len, const char *raw_indent_str, uint32_t initial_indent_str_len) { 323 | if (Z_TYPE_P(v) == 0) return NULL; 324 | 325 | char str[MAX_STRING_KEY]; 326 | 327 | switch(Z_TYPE_P(v)) { 328 | case IS_LONG: 329 | { 330 | memset(str, 0, sizeof(str)); 331 | sprintf(str, "%ld", Z_LVAL_P(v)); 332 | return zua_string_create(str, strlen(str)); 333 | } 334 | case IS_TRUE: 335 | { 336 | memset(str, 0, sizeof(str)); 337 | sprintf(str, "true"); 338 | return zua_string_create(str, strlen(str)); 339 | } 340 | case IS_FALSE: 341 | { 342 | memset(str, 0, sizeof(str)); 343 | sprintf(str, "false"); 344 | return zua_string_create(str, strlen(str)); 345 | } 346 | case IS_NULL: 347 | { 348 | memset(str, 0, sizeof(str)); 349 | sprintf(str, "null"); 350 | return zua_string_create(str, strlen(str)); 351 | } 352 | case IS_NAN: 353 | { 354 | memset(str, 0, sizeof(str)); 355 | sprintf(str, "NaN"); 356 | return zua_string_create(str, strlen(str)); 357 | } 358 | case IS_INFINITY: 359 | { 360 | memset(str, 0, sizeof(str)); 361 | sprintf(str, "Infinity"); 362 | return zua_string_create(str, strlen(str)); 363 | } 364 | case IS_NEGATIVE_INFINITY: 365 | { 366 | memset(str, 0, sizeof(str)); 367 | sprintf(str, "-Infinity"); 368 | return zua_string_create(str, strlen(str)); 369 | } 370 | case IS_STRING: 371 | { 372 | return zua_string_create(ZSTRL(Z_STR_P(v))); 373 | } 374 | case IS_DOUBLE: 375 | { 376 | memset(str, 0, sizeof(str)); 377 | sprintf(str, "%f", Z_DVAL_P(v)); 378 | return zua_string_create(str, strlen(str)); 379 | } 380 | } 381 | 382 | uint32_t i; 383 | zua_string *r = NULL; 384 | zua_string *t = NULL; 385 | zua_string *s = NULL; 386 | zua_string *indent = NULL; 387 | zua_hashmap_ele *e = NULL; 388 | zua_hashmap *map = NULL; 389 | if (Z_TYPE_P(v) == IS_ARRAY) { 390 | map = Z_ARR_P( v ); 391 | r = zua_string_create(ZUA_STR("[\n")); 392 | } else if (Z_TYPE_P(v) == IS_OBJECT) { 393 | map = Z_OBJ_P( v ); 394 | r = zua_string_create(ZUA_STR( "{\n")); 395 | } 396 | 397 | indent = zua_string_create(indent_str, indent_str_len); 398 | 399 | ZUA_HASHMAP_FOREACH_ELE(map, i, e) { 400 | zval *val = e->data; 401 | r = zua_string_append(r, ZSTRL(indent)); 402 | if (Z_TYPE_P(v) == IS_OBJECT) { 403 | r = zua_string_append( r, ZUA_STR("\"") ); 404 | t = zua_string_create(e->key, e->key_len); 405 | s = zua_string_addslashes(t); 406 | r = zua_string_append( r, ZSTRL(s) ); 407 | zua_string_free(t); 408 | zua_string_free(s); 409 | r = zua_string_append( r, ZUA_STR("\":") ); 410 | } 411 | switch(Z_TYPE_P(val)) { 412 | case IS_STRING: 413 | r = zua_string_append(r, ZUA_STR("\"") ); 414 | s = zua_string_addslashes(Z_STR_P(val)); 415 | r = zua_string_append(r, ZSTRL(s) ); 416 | zua_string_free(s); 417 | r = zua_string_append(r, ZUA_STR("\"") ); 418 | break; 419 | case IS_DOUBLE: 420 | memset(str, 0, sizeof(str)); 421 | sprintf(str, "%f", Z_DVAL_P(val)); 422 | r = zua_string_append(r, str, strlen(str)); 423 | break; 424 | case IS_FALSE: 425 | r = zua_string_append(r, ZUA_STR("false") ); 426 | break; 427 | case IS_TRUE: 428 | r = zua_string_append(r, ZUA_STR("true") ); 429 | break; 430 | case IS_NULL: 431 | r = zua_string_append(r, ZUA_STR("null") ); 432 | break; 433 | case IS_NAN: 434 | r = zua_string_append(r, ZUA_STR("NaN") ); 435 | break; 436 | case IS_INFINITY: 437 | r = zua_string_append(r, ZUA_STR("Infinity") ); 438 | break; 439 | case IS_NEGATIVE_INFINITY: 440 | r = zua_string_append(r, ZUA_STR("-Infinity") ); 441 | break; 442 | case IS_LONG: 443 | memset(str, 0, sizeof(str)); 444 | sprintf(str, "%ld", Z_LVAL_P(val)); 445 | r = zua_string_append(r, str, strlen(str)); 446 | break; 447 | case IS_OBJECT: 448 | case IS_ARRAY: 449 | indent = zua_string_append(indent, raw_indent_str, initial_indent_str_len); 450 | t = json_encode_pretty_with_indent(val, ZSTRL(indent), raw_indent_str, initial_indent_str_len); 451 | r = zua_string_append(r, ZSTRL(t)); 452 | ZSTRL(indent) -= initial_indent_str_len; 453 | zua_string_free(t); 454 | break; 455 | } 456 | if ( i < (map->table_size - 1) ) r = zua_string_append(r, ZUA_STR(",\n")); 457 | } ZUA_HASHMAP_FOREACH_END(); 458 | 459 | if (ZSTR_VAL(r)[ZSTR_LEN(r) - 1] == '\n' && ZSTR_VAL(r)[ZSTR_LEN(r) - 2] == ',') ZSTR_LEN(r)-=2; 460 | 461 | ZSTRL(indent) -= initial_indent_str_len; 462 | r = zua_string_append(r, ZUA_STR("\n")); 463 | r = zua_string_append(r, ZSTRL(indent)); 464 | 465 | if (Z_TYPE_P(v) == IS_ARRAY) { 466 | r = zua_string_append(r, ZUA_STR("]")); 467 | } else if (Z_TYPE_P(v) == IS_OBJECT) { 468 | r = zua_string_append(r, ZUA_STR("}")); 469 | } 470 | 471 | zua_string_free(indent); 472 | return r; 473 | } 474 | 475 | ZUA_API zua_string *json_encode_pretty(zval *v) { 476 | return json_encode_pretty_with_indent(v, ZUA_STR2(" ")); 477 | } 478 | 479 | ZUA_API zval *zua_get_value_by_path(zval *r, const char *str, uint32_t str_len) { 480 | uint32_t i = 0, j = 0; 481 | 482 | zval *t = NULL; 483 | zua_hashmap *map = NULL; 484 | 485 | if (Z_TYPE_P(r) == IS_ARRAY) { 486 | map = Z_ARR_P(r); 487 | } else if (Z_TYPE_P(r) == IS_OBJECT) { 488 | map = Z_OBJ_P(r); 489 | } 490 | 491 | for (; i < str_len; i++) { 492 | if (str[i] == '.') { 493 | t = hashmap_get(map, str + j, i - j); 494 | if (Z_TYPE_P(t) == IS_ARRAY) { 495 | map = Z_ARR_P(t); 496 | } else if (Z_TYPE_P(t) == IS_OBJECT) { 497 | map = Z_OBJ_P(t); 498 | } else { 499 | return t; 500 | } 501 | j = i + 1; 502 | } 503 | } 504 | 505 | return hashmap_get(map, str + j, i - j); 506 | } 507 | 508 | ZUA_API bool zua_in_array(zval *r, zval *value) { 509 | zua_hashmap *map = NULL; 510 | if (Z_TYPE_P(r) == IS_OBJECT) { 511 | map = Z_OBJ_P(r); 512 | } else if (Z_TYPE_P(r) == IS_ARRAY) { 513 | map = Z_ARR_P(r); 514 | } 515 | 516 | uint32_t i; 517 | zval *v = NULL; 518 | zua_hashmap_ele *e; 519 | ZUA_HASHMAP_FOREACH_ELE(map, i, e) { 520 | v = e->data; 521 | 522 | switch ( Z_TYPE_P(value) ) { 523 | case IS_NAN: 524 | { 525 | if (Z_TYPE_P(v) == IS_NAN) return TRUE; 526 | break; 527 | } 528 | case IS_NEGATIVE_INFINITY: 529 | { 530 | if (Z_TYPE_P(v) == IS_NEGATIVE_INFINITY) return TRUE; 531 | break; 532 | } 533 | case IS_INFINITY: 534 | { 535 | if (Z_TYPE_P(v) == IS_INFINITY) return TRUE; 536 | break; 537 | } 538 | case IS_ARRAY: 539 | case IS_OBJECT: 540 | { 541 | return FALSE; 542 | } 543 | case IS_DOUBLE: 544 | { 545 | if(Z_TYPE_P(v) == IS_DOUBLE && (Z_DVAL_P(v) - Z_DVAL_P(value) <= 0)) return TRUE; 546 | break; 547 | } 548 | case IS_STRING: 549 | { 550 | if(Z_TYPE_P(v) == IS_STRING && ( ZSTR_LEN(Z_STR_P(v)) == ZSTR_LEN(Z_STR_P(value)) ) && 551 | (0 == strncasecmp(ZSTR_VAL(Z_STR_P(value)), ZSTR_VAL(Z_STR_P(v)), ZSTR_LEN(Z_STR_P(v))))) return TRUE; 552 | break; 553 | } 554 | case IS_NULL: 555 | { 556 | if(Z_TYPE_P(v) == IS_NULL) return TRUE; 557 | break; 558 | } 559 | case IS_FALSE: 560 | { 561 | if(Z_TYPE_P(v) == IS_FALSE) return TRUE; 562 | break; 563 | } 564 | case IS_TRUE: 565 | { 566 | if(Z_TYPE_P(v) == IS_TRUE) return TRUE; 567 | break; 568 | } 569 | case IS_LONG: 570 | { 571 | if(Z_TYPE_P(v) == IS_LONG && Z_LVAL_P(v) == Z_LVAL_P(value)) return TRUE; 572 | break; 573 | } 574 | default: 575 | return FALSE; 576 | } 577 | } ZUA_HASHMAP_FOREACH_END(); 578 | 579 | return FALSE; 580 | } 581 | 582 | ZUA_API zua_string *zua_file_gets(const char *file_name) { 583 | zua_string *r = NULL; 584 | FILE *f = fopen(file_name, "r"); 585 | char buf[MAX_STRING_KEY]; 586 | while(f && !feof(f)) { 587 | if (ferror(f)) break; 588 | memset(buf, 0, sizeof(buf)); 589 | size_t n = fread(buf, sizeof(char), MAX_STRING_KEY - 1, f); 590 | if (n >= 1) 591 | r = zua_string_append(r, buf, strlen(buf)); 592 | } 593 | fclose(f); 594 | return r; 595 | } -------------------------------------------------------------------------------- /zua_type.h: -------------------------------------------------------------------------------- 1 | #ifndef ZUA_ZUA_TYPE_H 2 | #define ZUA_ZUA_TYPE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "hashmap.h" 8 | #include 9 | #include 10 | 11 | typedef union _zua_value zua_value; 12 | typedef struct _zua_struct zval; 13 | typedef struct hashmap_s zua_hashmap; 14 | typedef struct hashmap_element_s zua_hashmap_ele; 15 | typedef struct hashmap_s zua_array; 16 | typedef struct hashmap_s zua_object; 17 | #define zua_free free 18 | #define zua_malloc malloc 19 | #define ZUA_API 20 | typedef int bool; 21 | #define TRUE 1 22 | #define FALSE 0 23 | 24 | typedef struct _zua_string { 25 | uint32_t len; 26 | char v[1]; 27 | } zua_string; 28 | 29 | #define ZUA_STR(s) (s), (sizeof(s)-1) 30 | #define ZUA_STR2(s) (s), (sizeof(s)-1), (s), (sizeof(s)-1) 31 | #define ZSTR_LEN(s) (s)->len 32 | #define ZSTR_VAL(s) (s)->v 33 | #define ZSTRL(s) ZSTR_VAL(s), ZSTR_LEN(s) 34 | 35 | static inline uint32_t zua_string_size(uint32_t length) { 36 | return sizeof(zua_string) - sizeof(char) + sizeof(char) * length; 37 | } 38 | 39 | static inline void zua_string_free(zua_string *r) { 40 | if (r != NULL) zua_free(r); 41 | } 42 | 43 | static inline void *zua_hashmap_init() { 44 | return zua_malloc(sizeof(zua_hashmap)); 45 | } 46 | 47 | zua_string *zua_string_create(const char *str, uint32_t str_len); 48 | zua_string *zua_string_append(zua_string *r, const char *str, uint32_t str_len); 49 | zua_string *zua_string_addslashes(zua_string *r); 50 | 51 | enum { 52 | IS_NULL = 1 << 5, 53 | IS_FALSE, 54 | IS_TRUE, 55 | IS_LONG, 56 | IS_DOUBLE, 57 | IS_STRING, 58 | IS_ARRAY, 59 | IS_OBJECT, 60 | IS_NAN, /* JSON5 NaN */ 61 | IS_INFINITY, /* JSON Infinity */ 62 | IS_NEGATIVE_INFINITY, /* JSON -Infinity */ 63 | }; 64 | 65 | union _zua_value { 66 | long lval; 67 | double dval; 68 | zua_string *str; 69 | zua_array *arr; 70 | zua_object *obj; 71 | struct { 72 | uint32_t w1; 73 | uint32_t w2; 74 | } ww; 75 | }; 76 | 77 | struct _zua_struct { 78 | zua_value value; 79 | union { 80 | uint32_t type; 81 | } u1; 82 | union { 83 | uint32_t lineno; 84 | uint32_t errcode; /* Used for JSON parse error */ 85 | } u2; 86 | }; 87 | 88 | #define Z_LVAL(z) (z).value.lval 89 | #define Z_LVAL_P(z) Z_LVAL(*(z)) 90 | 91 | #define Z_DVAL(z) (z).value.dval 92 | #define Z_DVAL_P(z) Z_DVAL(*(z)) 93 | 94 | #define Z_STR(z) (z).value.str 95 | #define Z_STR_P(z) Z_STR(*(z)) 96 | 97 | #define Z_ARR(z) (z).value.arr 98 | #define Z_ARR_P(z) Z_ARR(*(z)) 99 | 100 | #define Z_OBJ(z) (z).value.obj 101 | #define Z_OBJ_P(z) Z_OBJ(*(z)) 102 | 103 | #define Z_TYPE(z) (z).u1.type 104 | #define Z_TYPE_P(z) Z_TYPE(*(z)) 105 | 106 | #define Z_LINENO(z) (z).u2.lineno 107 | #define Z_LINENO_P(z) Z_LINENO(*(z)) 108 | 109 | #define ZVAL_LONG(z, l) { \ 110 | zval *_z = (z); \ 111 | Z_LVAL_P(_z) = l; \ 112 | Z_TYPE_P(_z) = IS_LONG; \ 113 | } 114 | 115 | #define ZVAL_NULL(z) { \ 116 | Z_TYPE_P(z) = IS_NULL; \ 117 | } 118 | 119 | #define ZVAL_NAN(z) { \ 120 | Z_TYPE_P(z) = IS_NAN; \ 121 | } 122 | 123 | #define ZVAL_INFINITY(z) { \ 124 | Z_TYPE_P(z) = IS_INFINITY; \ 125 | } 126 | 127 | #define ZVAL_NINFINITY(z) { \ 128 | Z_TYPE_P(z) = IS_NEGATIVE_INFINITY; \ 129 | } 130 | 131 | #define ZVAL_NULL(z) { \ 132 | Z_TYPE_P(z) = IS_NULL; \ 133 | } 134 | 135 | #define ZVAL_TRUE(z) { \ 136 | Z_TYPE_P(z) = IS_TRUE; \ 137 | } 138 | 139 | #define ZVAL_FALSE(z) { \ 140 | Z_TYPE_P(z) = IS_FALSE; \ 141 | } 142 | 143 | #define ZVAL_DOUBLE(z, d) { \ 144 | zval *_z = (z); \ 145 | Z_DVAL_P(_z) = d; \ 146 | Z_TYPE_P(_z) = IS_DOUBLE; \ 147 | } 148 | 149 | #define ZVAL_STRINGL(z, s, l) { \ 150 | zval *_z = (z); \ 151 | Z_STR_P(_z) = zua_string_create(s, l); \ 152 | Z_TYPE_P(_z) = IS_STRING; \ 153 | } 154 | 155 | #define ZVAL_STRING(z, s) { \ 156 | ZVAL_STRINGL(z, s, strlen(s)); \ 157 | } 158 | 159 | #define ZUA_COPY_VALUE(z, v) \ 160 | do { \ 161 | zval *z1 = (z); \ 162 | const zval *z2 = (v); \ 163 | Z_TYPE_P(z1) = Z_TYPE_P(z2); \ 164 | Z_LINENO_P(z1) = Z_LINENO_P(z2); \ 165 | z1->value.ww.w1 = z2->value.ww.w1; \ 166 | z1->value.ww.w2 = z2->value.ww.w2; \ 167 | } while(0) 168 | 169 | #define HASHMAP_DEFAULT_SIZE 256 170 | 171 | ZUA_API zval *zval_init(); 172 | ZUA_API void object_init(zval *v); 173 | ZUA_API void array_init(zval *v); 174 | ZUA_API void zval_free(zval *v); 175 | void zval_free_nogc(zval *v); 176 | 177 | 178 | ZUA_API void zua_hash_str_add_or_update(zval *h, const char *key, uint32_t key_len, zval *value); 179 | ZUA_API void zua_hash_index_add(zval *h, zval *value); 180 | 181 | #define MAX_STRING_KEY 256 182 | 183 | #define ZUA_HASHMAP_FOREACH_ELE(s, i, ele)\ 184 | do { \ 185 | for (i = 0; i < s->table_size; i++) { \ 186 | ele = &s->data[i]; \ 187 | if (ele->in_use) { 188 | 189 | 190 | #define ZUA_HASHMAP_FOREACH_END() \ 191 | }} \ 192 | } while(0) 193 | 194 | ZUA_API zua_string *json_encode(zval *v); 195 | ZUA_API zua_string *json_encode_pretty(zval *v); 196 | 197 | ZUA_API zval *json_decode(const char *str, uint32_t str_len); 198 | 199 | ZUA_API zval *zua_get_value(zval *v, const char *key, uint32_t key_len); 200 | ZUA_API zval *zua_get_value_by_index(zval *v, uint32_t index); 201 | ZUA_API zval *zua_get_value_by_path(zval *r, const char *str, uint32_t str_len); 202 | ZUA_API bool zua_in_array(zval *r, zval *value); 203 | 204 | ZUA_API zua_string *zua_file_gets(const char *file_name); 205 | 206 | #endif 207 | --------------------------------------------------------------------------------