├── test ├── jsonchecker │ ├── fail29.json │ ├── fail30.json │ ├── fail16.json │ ├── fail31.json │ ├── fail33.json │ ├── fail34.json │ ├── fail02.json │ ├── fail04.json │ ├── fail08.json │ ├── fail23.json │ ├── fail24.json │ ├── fail27.json │ ├── fail28.json │ ├── fail05.json │ ├── fail09.json │ ├── fail19.json │ ├── fail20.json │ ├── fail35.json │ ├── fail06.json │ ├── fail07.json │ ├── fail11.json │ ├── fail25.json │ ├── fail12.json │ ├── fail14.json │ ├── fail15.json │ ├── fail17.json │ ├── fail21.json │ ├── fail22.json │ ├── fail03.json │ ├── fail26.json │ ├── fail32.json │ ├── fail13.json │ ├── pass02.json │ ├── fail10.json │ ├── fail18_EXCLUDE.json │ ├── fail01_EXCLUDE.json │ ├── pass03.json │ ├── readme.txt │ └── pass01.json ├── test.pro └── main.c ├── json-parser.pro ├── json-parser ├── parser.h ├── json-parser.pro ├── private │ └── private.h ├── parser.y ├── json-primitives.c ├── json-parser.h ├── lexer.rl ├── lexer.c └── parser.c └── README.md /test/jsonchecker/fail29.json: -------------------------------------------------------------------------------- 1 | [0e] -------------------------------------------------------------------------------- /test/jsonchecker/fail30.json: -------------------------------------------------------------------------------- 1 | [0e+] -------------------------------------------------------------------------------- /test/jsonchecker/fail16.json: -------------------------------------------------------------------------------- 1 | [\naked] -------------------------------------------------------------------------------- /test/jsonchecker/fail31.json: -------------------------------------------------------------------------------- 1 | [0e+-1] -------------------------------------------------------------------------------- /test/jsonchecker/fail33.json: -------------------------------------------------------------------------------- 1 | ["mismatch"} -------------------------------------------------------------------------------- /test/jsonchecker/fail34.json: -------------------------------------------------------------------------------- 1 | ["\u123 "] 2 | -------------------------------------------------------------------------------- /test/jsonchecker/fail02.json: -------------------------------------------------------------------------------- 1 | ["Unclosed array" -------------------------------------------------------------------------------- /test/jsonchecker/fail04.json: -------------------------------------------------------------------------------- 1 | ["extra comma",] -------------------------------------------------------------------------------- /test/jsonchecker/fail08.json: -------------------------------------------------------------------------------- 1 | ["Extra close"]] -------------------------------------------------------------------------------- /test/jsonchecker/fail23.json: -------------------------------------------------------------------------------- 1 | ["Bad value", truth] -------------------------------------------------------------------------------- /test/jsonchecker/fail24.json: -------------------------------------------------------------------------------- 1 | ['single quote'] -------------------------------------------------------------------------------- /test/jsonchecker/fail27.json: -------------------------------------------------------------------------------- 1 | ["line 2 | break"] -------------------------------------------------------------------------------- /test/jsonchecker/fail28.json: -------------------------------------------------------------------------------- 1 | ["line\ 2 | break"] -------------------------------------------------------------------------------- /test/jsonchecker/fail05.json: -------------------------------------------------------------------------------- 1 | ["double extra comma",,] -------------------------------------------------------------------------------- /test/jsonchecker/fail09.json: -------------------------------------------------------------------------------- 1 | {"Extra comma": true,} -------------------------------------------------------------------------------- /test/jsonchecker/fail19.json: -------------------------------------------------------------------------------- 1 | {"Missing colon" null} -------------------------------------------------------------------------------- /test/jsonchecker/fail20.json: -------------------------------------------------------------------------------- 1 | {"Double colon":: null} -------------------------------------------------------------------------------- /test/jsonchecker/fail35.json: -------------------------------------------------------------------------------- 1 | ["something\ hello"] 2 | -------------------------------------------------------------------------------- /test/jsonchecker/fail06.json: -------------------------------------------------------------------------------- 1 | [ , "<-- missing value"] -------------------------------------------------------------------------------- /test/jsonchecker/fail07.json: -------------------------------------------------------------------------------- 1 | ["Comma after the close"], -------------------------------------------------------------------------------- /test/jsonchecker/fail11.json: -------------------------------------------------------------------------------- 1 | {"Illegal expression": 1 + 2} -------------------------------------------------------------------------------- /test/jsonchecker/fail25.json: -------------------------------------------------------------------------------- 1 | [" tab character in string "] -------------------------------------------------------------------------------- /test/jsonchecker/fail12.json: -------------------------------------------------------------------------------- 1 | {"Illegal invocation": alert()} -------------------------------------------------------------------------------- /test/jsonchecker/fail14.json: -------------------------------------------------------------------------------- 1 | {"Numbers cannot be hex": 0x14} -------------------------------------------------------------------------------- /test/jsonchecker/fail15.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \x15"] -------------------------------------------------------------------------------- /test/jsonchecker/fail17.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \017"] -------------------------------------------------------------------------------- /test/jsonchecker/fail21.json: -------------------------------------------------------------------------------- 1 | {"Comma instead of colon", null} -------------------------------------------------------------------------------- /test/jsonchecker/fail22.json: -------------------------------------------------------------------------------- 1 | ["Colon instead of comma": false] -------------------------------------------------------------------------------- /test/jsonchecker/fail03.json: -------------------------------------------------------------------------------- 1 | {unquoted_key: "keys must be quoted"} -------------------------------------------------------------------------------- /test/jsonchecker/fail26.json: -------------------------------------------------------------------------------- 1 | ["tab\ character\ in\ string\ "] -------------------------------------------------------------------------------- /test/jsonchecker/fail32.json: -------------------------------------------------------------------------------- 1 | {"Comma instead if closing brace": true, -------------------------------------------------------------------------------- /test/jsonchecker/fail13.json: -------------------------------------------------------------------------------- 1 | {"Numbers cannot have leading zeroes": 013} -------------------------------------------------------------------------------- /test/jsonchecker/pass02.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /test/jsonchecker/fail10.json: -------------------------------------------------------------------------------- 1 | {"Extra value after close": true} "misplaced quoted value" -------------------------------------------------------------------------------- /test/jsonchecker/fail18_EXCLUDE.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /json-parser.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | json-parser \ 5 | test 6 | -------------------------------------------------------------------------------- /test/jsonchecker/fail01_EXCLUDE.json: -------------------------------------------------------------------------------- 1 | "A JSON payload should be an object or array, not a string." -------------------------------------------------------------------------------- /test/jsonchecker/pass03.json: -------------------------------------------------------------------------------- 1 | { 2 | "JSON Test Pattern pass3": { 3 | "The outermost value": "must be an object or array.", 4 | "In this test": "It is an object." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/jsonchecker/readme.txt: -------------------------------------------------------------------------------- 1 | Test suite from http://json.org/JSON_checker/. 2 | 3 | If the JSON_checker is working correctly, it must accept all of the pass*.json files and reject all of the fail*.json files. 4 | -------------------------------------------------------------------------------- /json-parser/parser.h: -------------------------------------------------------------------------------- 1 | #define JSON_TOK_STRING 1 2 | #define JSON_TOK_COL 2 3 | #define JSON_TOK_COMMA 3 4 | #define JSON_TOK_LBRACK 4 5 | #define JSON_TOK_RBRACK 5 6 | #define JSON_TOK_LSQB 6 7 | #define JSON_TOK_RSQB 7 8 | #define JSON_TOK_NUMBER 8 9 | #define JSON_TOK_BOOLEAN 9 10 | #define JSON_TOK_NONE 10 11 | -------------------------------------------------------------------------------- /json-parser/json-parser.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2015-06-07T16:28:28 4 | # 5 | #------------------------------------------------- 6 | 7 | QT -= core gui 8 | 9 | TARGET = json-parser 10 | TEMPLATE = lib 11 | CONFIG += staticlib 12 | 13 | QMAKE_CFLAGS += -std=c99 14 | 15 | lexer.target = lexer.c 16 | lexer.commands = ragel -C -o $$PWD/lexer.c $$PWD/lexer.rl 17 | lexer.depends = 18 | 19 | parser.target = parser.c 20 | parser.commands = lemon $$PWD/parser.y 21 | 22 | QMAKE_EXTRA_TARGETS += lexer parser 23 | 24 | PRE_TARGETDEPS += parser.c lexer.c 25 | 26 | SOURCES += \ 27 | lexer.c \ 28 | parser.c \ 29 | json-primitives.c 30 | 31 | HEADERS += \ 32 | json-parser.h \ 33 | parser.h \ 34 | private/private.h 35 | 36 | unix { 37 | target.path = /usr/lib 38 | INSTALLS += target 39 | } 40 | 41 | DISTFILES += \ 42 | lexer.rl \ 43 | parser.y 44 | -------------------------------------------------------------------------------- /test/jsonchecker/pass01.json: -------------------------------------------------------------------------------- 1 | [ 2 | "JSON Test Pattern pass1", 3 | {"object with 1 member":["array with 1 element"]}, 4 | {}, 5 | [], 6 | -42, 7 | true, 8 | false, 9 | null, 10 | { 11 | "integer": 1234567890, 12 | "real": -9876.543210, 13 | "e": 0.123456789e-12, 14 | "E": 1.234567890E+34, 15 | "": 23456789012E66, 16 | "zero": 0, 17 | "one": 1, 18 | "space": " ", 19 | "quote": "\"", 20 | "backslash": "\\", 21 | "controls": "\b\f\n\r\t", 22 | "slash": "/ & \/", 23 | "alpha": "abcdefghijklmnopqrstuvwyz", 24 | "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", 25 | "digit": "0123456789", 26 | "0123456789": "digit", 27 | "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", 28 | "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", 29 | "true": true, 30 | "false": false, 31 | "null": null, 32 | "array":[ ], 33 | "object":{ }, 34 | "address": "50 St. James Street", 35 | "url": "http://www.JSON.org/", 36 | "comment": "// /* */": " ", 38 | " s p a c e d " :[1,2 , 3 39 | 40 | , 41 | 42 | 4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], 43 | "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", 44 | "quotes": "" \u0022 %22 0x22 034 "", 45 | "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" 46 | : "A key can be any string" 47 | }, 48 | 0.5 ,98.6 49 | , 50 | 99.44 51 | , 52 | 53 | 1066, 54 | 1e1, 55 | 0.1e1, 56 | 1e-1, 57 | 1e00,2e+00,2e-00 58 | ,"rosebud"] -------------------------------------------------------------------------------- /json-parser/private/private.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** json-parser Copyright 2015(c) Wael El Oraiby. All Rights Reserved 3 | ** 4 | ** This library is distributed in the hope that it will be useful, 5 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 6 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 7 | ** GNU General Public License for more details. 8 | ** 9 | ** Under Section 7 of GPL version 3, you are granted additional 10 | ** permissions described in the GCC Runtime Library Exception, version 11 | ** 3.1, as published by the Free Software Foundation. 12 | ** 13 | ** You should have received a copy of the GNU General Public License and 14 | ** a copy of the GCC Runtime Library Exception along with this program; 15 | ** see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 16 | ** . 17 | ** 18 | */ 19 | #ifndef JSON_PRIVATE_H 20 | #define JSON_PRIVATE_H 21 | 22 | #include "../json-parser.h" 23 | #include "../parser.h" 24 | 25 | typedef struct { 26 | int tok_type; 27 | union { 28 | double number; 29 | bool boolean; 30 | string_t string; 31 | }; 32 | } token_t; 33 | 34 | 35 | typedef struct { 36 | const char* token_start; 37 | const char* token_end; 38 | int token_line; 39 | int error_code; /* 0 : no error */ 40 | 41 | json_value_t* root; 42 | } json_parser_t; 43 | 44 | 45 | json_pair_t json_pair (token_t key, json_value_t* value); 46 | json_value_t* json_add_pair (json_pair_t, json_value_t* /* object */); 47 | json_value_t* json_add_element (json_value_t* /* value */, json_value_t* /* array */); 48 | 49 | json_value_t* json_object (); 50 | json_value_t* json_array (); 51 | json_value_t* json_boolean (bool); 52 | json_value_t* json_number (double); 53 | json_value_t* json_string (string_t); 54 | json_value_t* json_none (); 55 | 56 | #endif // JSON_PRIVATE_H 57 | 58 | -------------------------------------------------------------------------------- /test/test.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2015-06-08T20:32:52 4 | # 5 | #------------------------------------------------- 6 | 7 | QT -= core gui 8 | 9 | TARGET = test 10 | CONFIG += console 11 | CONFIG -= app_bundle 12 | 13 | TEMPLATE = app 14 | 15 | QMAKE_CFLAGS += -std=c99 16 | 17 | SOURCES += \ 18 | main.c 19 | 20 | win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../json-parser/release/ -ljson-parser 21 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../json-parser/debug/ -ljson-parser 22 | else:unix: LIBS += -L$$OUT_PWD/../json-parser/ -ljson-parser 23 | 24 | INCLUDEPATH += $$PWD/../json-parser 25 | DEPENDPATH += $$PWD/../json-parser 26 | 27 | OTHER_FILES += \ 28 | jsonchecker/fail34.json \ 29 | jsonchecker/fail01_EXCLUDE.json \ 30 | jsonchecker/fail02.json \ 31 | jsonchecker/fail03.json \ 32 | jsonchecker/fail04.json \ 33 | jsonchecker/fail05.json \ 34 | jsonchecker/fail06.json \ 35 | jsonchecker/fail07.json \ 36 | jsonchecker/fail08.json \ 37 | jsonchecker/fail09.json \ 38 | jsonchecker/fail10.json \ 39 | jsonchecker/fail11.json \ 40 | jsonchecker/fail12.json \ 41 | jsonchecker/fail13.json \ 42 | jsonchecker/fail14.json \ 43 | jsonchecker/fail15.json \ 44 | jsonchecker/fail16.json \ 45 | jsonchecker/fail17.json \ 46 | jsonchecker/fail18_EXCLUDE.json \ 47 | jsonchecker/fail19.json \ 48 | jsonchecker/fail20.json \ 49 | jsonchecker/fail21.json \ 50 | jsonchecker/fail22.json \ 51 | jsonchecker/fail23.json \ 52 | jsonchecker/fail24.json \ 53 | jsonchecker/fail25.json \ 54 | jsonchecker/fail26.json \ 55 | jsonchecker/fail27.json \ 56 | jsonchecker/fail28.json \ 57 | jsonchecker/fail29.json \ 58 | jsonchecker/fail30.json \ 59 | jsonchecker/fail31.json \ 60 | jsonchecker/fail32.json \ 61 | jsonchecker/fail33.json \ 62 | jsonchecker/pass01.json \ 63 | jsonchecker/pass02.json \ 64 | jsonchecker/pass03.json \ 65 | jsonchecker/readme.txt \ 66 | jsonchecker/fail35.json 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rl-json-parser 2 | 3 | A small, lightweight C99 Ragel/Lemon based json parser, easy to use and customize. 4 | 5 | Why ? 6 | ----- 7 | Needed a high performance (no string copy and fewer allocations) and easily customizable json-parser (one that has a grammar). Ended up using ragel and lemon. Both have their advantages and inconvenience, but overall, they present a good solution. 8 | 9 | Testing 10 | ------- 11 | The parser was tested against the JsonChecker and nativejson-benchmark tests. I added another test for unicode (\uXXXX). It was valgrinded for memory leaks during the tests! 12 | 13 | Dependencies 14 | ------------ 15 | On windows, download: 16 | 17 | ![ragel](https://github.com/eloraiby/ragel-windows) as Lexer generator 18 | 19 | ![lemon](https://github.com/eloraiby/lemon-windows) as Parser generator 20 | 21 | Both should be in your system path. 22 | 23 | 24 | On *Nix based system both can be downloaded using the default package manager or can be built from source. 25 | 26 | For simplicity, I use qmake/Qt Creator as the cross platform build system/IDE. The code can be easily ported to other systems. 27 | 28 | 29 | Usage 30 | ----- 31 | Just include ```json-parser.h``` and call: 32 | 33 | ```C 34 | json_return_t json_parse(const char* str); 35 | ``` 36 | where 37 | ```C 38 | typedef struct { 39 | JSON_STATUS status; 40 | json_value_t* value; 41 | } json_return_t; 42 | ``` 43 | 44 | In case of error, ```value``` will be ```NULL```, otherwise you'll have the json object/array. 45 | 46 | To free, just call: 47 | ```C 48 | void json_free(json_value_t*); 49 | ``` 50 | 51 | For the structure details, look at ```json-parser.h``` file. 52 | 53 | Important Note 54 | -------------- 55 | The string parameter you pass to ```json_parse``` **SHOULD NOT** be freed untill ```json_free``` is called. The **json-parser** will not create or copy any string and will only reference the substrings within the passed string. This was done to improve performance and reduce the stress on memory! 56 | 57 | License 58 | ------- 59 | ``` 60 | json-parser Copyright 2015(c) Wael El Oraiby. All Rights Reserved 61 | 62 | This library is distributed in the hope that it will be useful, 63 | but WITHOUT ANY WARRANTY; without even the implied warranty of 64 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 65 | GNU General Public License for more details. 66 | 67 | Under Section 7 of GPL version 3, you are granted additional 68 | permissions described in the GCC Runtime Library Exception, version 69 | 3.1, as published by the Free Software Foundation. 70 | 71 | You should have received a copy of the GNU General Public License and 72 | a copy of the GCC Runtime Library Exception along with this program; 73 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 74 | . 75 | ``` 76 | 77 | Roughly speaking: it means that you can statically link with the code but you are obliged to make open your bug fixes and/or enhancement to the rl-json-parser code. 78 | 79 | Tests come from JsonChecker and nativejson-benchmark. They are copyrighted to their respective authors. 80 | 81 | -------------------------------------------------------------------------------- /json-parser/parser.y: -------------------------------------------------------------------------------- 1 | /* 2 | ** json-parser Copyright 2015(c) Wael El Oraiby. All Rights Reserved 3 | ** 4 | ** This library is distributed in the hope that it will be useful, 5 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 6 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 7 | ** GNU General Public License for more details. 8 | ** 9 | ** Under Section 7 of GPL version 3, you are granted additional 10 | ** permissions described in the GCC Runtime Library Exception, version 11 | ** 3.1, as published by the Free Software Foundation. 12 | ** 13 | ** You should have received a copy of the GNU General Public License and 14 | ** a copy of the GCC Runtime Library Exception along with this program; 15 | ** see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 16 | ** . 17 | ** 18 | */ 19 | /* 20 | grammar parser: using Lemon, not YACC nor BISON 21 | */ 22 | 23 | /* the grammar is based on json.org */ 24 | 25 | %name parser 26 | 27 | /*%token_type { void* }*/ 28 | %extra_argument { json_parser_t* pret } 29 | 30 | %include { 31 | #include 32 | #include 33 | #include 34 | 35 | #include "private/private.h" 36 | 37 | #define PUSH(A) json_insert_before(A, pret->head); pret->head = A; 38 | #define POP(A) if( A == pret->head ) { assert(pret->head->prev == NULL); pret->head = A->next; } json_dereference(A) 39 | } 40 | 41 | %parse_failure { 42 | pret->error_code = 2; 43 | } 44 | 45 | %syntax_error { 46 | pret->error_code = 1; 47 | } 48 | 49 | %token_type { token_t } 50 | 51 | %type pair { json_pair_t } 52 | %type members { json_value_t* } 53 | %type elements { json_value_t* } 54 | %type object { json_value_t* } 55 | %type array { json_value_t* } 56 | %type value { json_value_t* } 57 | 58 | %destructor pair { json_free($$.value); } 59 | %destructor members { json_free($$); } 60 | %destructor elements { json_free($$); } 61 | %destructor object { json_free($$); } 62 | %destructor array { json_free($$); } 63 | %destructor value { json_free($$); } 64 | 65 | 66 | %start_symbol root 67 | 68 | /* a json file is either an object or an array */ 69 | root ::= object(B). { pret->root = B; } 70 | root ::= array(B). { pret->root = B; } 71 | 72 | pair(A) ::= JSON_TOK_STRING(B) JSON_TOK_COL value(C). { A = json_pair(B, C); } 73 | 74 | members(A) ::= pair(B). { A = json_object(); json_add_pair(B, A); } 75 | members(A) ::= members(B) JSON_TOK_COMMA pair(C). { A = json_add_pair(C, B); } 76 | 77 | object(A) ::= JSON_TOK_LBRACK JSON_TOK_RBRACK. { A = json_object(); } 78 | object(A) ::= JSON_TOK_LBRACK members(B) JSON_TOK_RBRACK. { A = B; } 79 | 80 | array(A) ::= JSON_TOK_LSQB JSON_TOK_RSQB. { A = json_array(); } 81 | array(A) ::= JSON_TOK_LSQB elements(B) JSON_TOK_RSQB. { A = B; } 82 | 83 | elements(A) ::= value(B). { A = json_array(); json_add_element(B, A); } 84 | elements(A) ::= elements(B) JSON_TOK_COMMA value(C).{ A = json_add_element(C, B); } 85 | 86 | value(A) ::= JSON_TOK_STRING(B). { A = json_string(B.string); } 87 | value(A) ::= JSON_TOK_NUMBER(B). { A = json_number(B.number); } 88 | value(A) ::= JSON_TOK_BOOLEAN(B). { A = json_boolean(B.boolean); } 89 | value(A) ::= JSON_TOK_NONE. { A = json_none(); } 90 | value(A) ::= object(B). { A = B; } 91 | value(A) ::= array(B). { A = B; } 92 | 93 | -------------------------------------------------------------------------------- /json-parser/json-primitives.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** json-parser Copyright 2015(c) Wael El Oraiby. All Rights Reserved 3 | ** 4 | ** This library is distributed in the hope that it will be useful, 5 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 6 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 7 | ** GNU General Public License for more details. 8 | ** 9 | ** Under Section 7 of GPL version 3, you are granted additional 10 | ** permissions described in the GCC Runtime Library Exception, version 11 | ** 3.1, as published by the Free Software Foundation. 12 | ** 13 | ** You should have received a copy of the GNU General Public License and 14 | ** a copy of the GCC Runtime Library Exception along with this program; 15 | ** see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 16 | ** . 17 | ** 18 | */ 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "./private/private.h" 25 | 26 | static inline json_value_t* 27 | json_alloc() { 28 | json_value_t* v = (json_value_t*)malloc(sizeof(json_value_t)); 29 | memset(v, 0, sizeof(json_value_t)); 30 | return v; 31 | } 32 | 33 | json_pair_t 34 | json_pair (token_t key, json_value_t* value) { 35 | json_pair_t pair; 36 | pair.key = key.string; 37 | pair.value = value; 38 | return pair; 39 | } 40 | 41 | 42 | json_value_t* 43 | json_object () { 44 | json_value_t* object = json_alloc(); 45 | object->tag = JSON_OBJECT; 46 | object->members = json_pair_array_new(); 47 | return object; 48 | } 49 | 50 | json_value_t* 51 | json_add_pair (json_pair_t p, json_value_t* v) { 52 | assert(v->tag == JSON_OBJECT); 53 | json_pair_array_push(&(v->members), p); 54 | return v; 55 | } 56 | 57 | json_value_t* 58 | json_array () { 59 | json_value_t* arr = json_alloc(); 60 | arr->tag = JSON_ARRAY; 61 | arr->array = json_value_array_new(); 62 | 63 | return arr; 64 | } 65 | 66 | json_value_t* 67 | json_add_element (json_value_t* e, json_value_t* v) { 68 | assert(v->tag == JSON_ARRAY); 69 | json_value_array_push(&(v->array), e); 70 | return v; 71 | } 72 | 73 | json_value_t* 74 | json_boolean (bool b) { 75 | json_value_t* ret = json_alloc(); 76 | ret->tag = JSON_BOOLEAN; 77 | ret->boolean = b; 78 | return ret; 79 | } 80 | 81 | json_value_t* 82 | json_number (double n) { 83 | json_value_t* ret = json_alloc(); 84 | ret->tag = JSON_NUMBER; 85 | ret->number = n; 86 | return ret; 87 | } 88 | 89 | json_value_t* 90 | json_string (string_t str) { 91 | json_value_t* ret = json_alloc(); 92 | ret->tag = JSON_STRING; 93 | ret->string = str; 94 | 95 | return ret; 96 | } 97 | 98 | json_value_t* 99 | json_none () { 100 | json_value_t* ret = json_alloc(); 101 | ret->tag = JSON_NONE; 102 | return ret; 103 | } 104 | 105 | void 106 | json_free(json_value_t* v) { 107 | if( v ) { 108 | switch( v->tag ) { 109 | case JSON_STRING: 110 | break; 111 | 112 | case JSON_NUMBER: 113 | break; 114 | 115 | case JSON_OBJECT: 116 | for( size_t c = 0; c < v->members.count; ++c ) { 117 | json_free(v->members.array[c].value); 118 | } 119 | json_pair_array_release(&(v->members)); 120 | break; 121 | 122 | case JSON_ARRAY: 123 | for( size_t c = 0; c < v->array.count; ++c ) { 124 | json_free(v->array.array[c]); 125 | } 126 | json_value_array_release(&(v->array)); 127 | break; 128 | 129 | case JSON_BOOLEAN: 130 | break; 131 | 132 | case JSON_NONE: 133 | break; 134 | } 135 | 136 | free(v); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /json-parser/json-parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** json-parser Copyright 2015(c) Wael El Oraiby. All Rights Reserved 3 | ** 4 | ** This library is distributed in the hope that it will be useful, 5 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 6 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 7 | ** GNU General Public License for more details. 8 | ** 9 | ** Under Section 7 of GPL version 3, you are granted additional 10 | ** permissions described in the GCC Runtime Library Exception, version 11 | ** 3.1, as published by the Free Software Foundation. 12 | ** 13 | ** You should have received a copy of the GNU General Public License and 14 | ** a copy of the GCC Runtime Library Exception along with this program; 15 | ** see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 16 | ** . 17 | ** 18 | */ 19 | #ifndef JSON_PARSER__H 20 | #define JSON_PARSER__H 21 | 22 | #ifndef __cplusplus 23 | # ifndef bool 24 | # define bool char 25 | # endif 26 | 27 | # ifndef false 28 | # define false 0 29 | # endif 30 | 31 | # ifndef true 32 | # define true (!false) 33 | # endif 34 | #endif 35 | 36 | #ifndef MIN 37 | # define MIN(a, b) ((a) < (b) ? (a) : (b)) 38 | #endif 39 | 40 | #include 41 | 42 | #define DECLARE_ARRAY(NAME, TYPE) \ 43 | typedef struct { \ 44 | size_t count; \ 45 | size_t capacity; \ 46 | TYPE* array; \ 47 | } NAME ## _t; \ 48 | static inline NAME ## _t NAME ## _new() { NAME ## _t v; v.count = 0; v.capacity = 0; v.array = NULL; return v; } \ 49 | static inline void NAME ## _release(NAME ## _t* v) { v->count = 0; v->capacity = 0; free(v->array); v->array = NULL; } \ 50 | static inline TYPE NAME ## _get(NAME ## _t* v, size_t idx) { return v->array[idx]; } \ 51 | static inline void NAME ## _set(NAME ## _t* v, size_t idx, TYPE t) { v->array[idx] = t; } \ 52 | static inline TYPE NAME ## _pop(NAME ## _t* v) { TYPE t = v->array[--(v->count)]; return t; } \ 53 | static inline void NAME ## _push(NAME ## _t* v, TYPE e) { if( v->count == v->capacity ) { \ 54 | v->capacity = v->capacity ? (v->capacity) << 1 : 2; \ 55 | v->array = (TYPE*)realloc(v->array, sizeof(TYPE) * v->capacity); \ 56 | } \ 57 | v->array[(v->count)++] = e; \ 58 | } \ 59 | static inline NAME ## _t NAME ## _copy(NAME ## _t* orig) { NAME ## _t dest; \ 60 | dest.count = orig->count; \ 61 | dest.capacity = orig->capacity; \ 62 | dest.array = (TYPE*)malloc(sizeof(TYPE) * orig->capacity); \ 63 | memcpy(dest.array, orig->array, sizeof(TYPE) * orig->capacity); \ 64 | return dest; \ 65 | } \ 66 | static inline void NAME ## _resize(NAME ## _t* v, size_t s) { v->capacity = s; v->count = MIN(v->count, s); v->array = (TYPE*)realloc(v->array, sizeof(TYPE) * s); } 67 | 68 | 69 | 70 | #ifdef __cplusplus 71 | extern "C" { 72 | #endif 73 | 74 | typedef enum { 75 | JSON_SUCCESS, 76 | JSON_INVALID_INPUT, 77 | JSON_ERROR_SYNTAX_ERROR, 78 | JSON_INVALID_CHARACTER, 79 | JSON_INVALID_NUMBER, 80 | JSON_INVALID_STRING, 81 | } JSON_STATUS; 82 | 83 | typedef enum { 84 | JSON_STRING, 85 | JSON_NUMBER, 86 | JSON_OBJECT, 87 | JSON_ARRAY, 88 | JSON_BOOLEAN, 89 | JSON_NONE 90 | } JSON_TYPE; 91 | 92 | struct json_value_s; 93 | 94 | typedef struct { 95 | const char* start; 96 | size_t len; 97 | } string_t; 98 | 99 | typedef struct { 100 | string_t key; 101 | struct json_value_s* value; 102 | } json_pair_t; 103 | 104 | 105 | 106 | DECLARE_ARRAY(json_pair_array, json_pair_t) 107 | DECLARE_ARRAY(json_value_array, struct json_value_s*) 108 | 109 | typedef struct json_value_s { 110 | JSON_TYPE tag; 111 | 112 | union { 113 | bool boolean; 114 | double number; 115 | string_t string; 116 | json_pair_t pair; 117 | json_pair_array_t members; 118 | json_value_array_t array; 119 | }; 120 | 121 | } json_value_t; 122 | 123 | typedef struct { 124 | JSON_STATUS status; 125 | json_value_t* value; 126 | } json_return_t; 127 | 128 | extern json_return_t json_parse(const char* str); 129 | extern void json_free(json_value_t*); 130 | #ifdef __cplusplus 131 | } 132 | #endif 133 | 134 | #endif // JSON_PARSER__H 135 | 136 | -------------------------------------------------------------------------------- /test/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "json-parser.h" 7 | 8 | void print_level(int level, const char* str, ...) { 9 | va_list args; 10 | for( int i = 0; i < level; ++i ) { 11 | printf(" "); 12 | } 13 | 14 | va_start(args, str); 15 | vprintf(str, args); 16 | va_end(args); 17 | } 18 | 19 | void 20 | dump(json_value_t* v, int level) { 21 | switch( v->tag ) { 22 | case JSON_ARRAY: 23 | print_level(level, "["); 24 | for( size_t i = 0; i < v->array.count; ++i ) { 25 | dump(v->array.array[i], 0); 26 | 27 | if( i < v->array.count - 1) { 28 | printf(", "); 29 | } 30 | } 31 | 32 | print_level(level, "]\n"); 33 | break; 34 | 35 | case JSON_BOOLEAN: 36 | if( v->boolean ) { 37 | print_level(level, "true"); 38 | } else { 39 | print_level(level, "false"); 40 | } 41 | break; 42 | 43 | case JSON_NONE: print_level(level, "none"); break; 44 | 45 | case JSON_NUMBER: print_level(level, "%lf", v->number); break; 46 | 47 | case JSON_OBJECT: 48 | print_level(level, "{\n"); 49 | for( size_t i = 0; i < v->members.count; ++i ) { 50 | print_level(0, "\""); 51 | for( size_t s = 0; s < v->members.array[i].key.len; ++s ) { 52 | printf("%c", v->members.array[i].key.start[s]); 53 | } 54 | printf("\""); 55 | 56 | printf(" : "); 57 | dump(v->members.array[i].value, 0); 58 | 59 | 60 | if( i < v->members.count - 1) { 61 | printf(", "); 62 | } 63 | } 64 | 65 | print_level(level, "\n}"); 66 | break; 67 | 68 | case JSON_STRING: 69 | print_level(level, "\""); 70 | for( size_t s = 0; s < v->string.len; ++s ) { 71 | printf("%c", v->string.start[s]); 72 | } 73 | printf("\""); 74 | break; 75 | 76 | default: break; 77 | } 78 | } 79 | 80 | void 81 | test_simple_object() { 82 | const char* json_str = "{\n\"key\":\"value\"\n}"; 83 | json_value_t* val = json_parse(json_str).value; 84 | dump(val, 0); 85 | printf("\n"); 86 | json_free(val); 87 | } 88 | 89 | void 90 | test_simple_object2() { 91 | const char* json_str = "{\n\"key\":\"value\",\n\"key2\":\"value2\"\n,\"key3\":23.4}"; 92 | json_value_t* val = json_parse(json_str).value; 93 | dump(val, 0); 94 | printf("\n"); 95 | json_free(val); 96 | } 97 | 98 | char* 99 | load_file(const char* filename) { 100 | FILE* f = fopen(filename, "rb"); 101 | if( f ) { 102 | fseek(f, 0, SEEK_END); 103 | size_t size = ftell(f); 104 | fseek(f, 0, SEEK_SET); 105 | char* buffer = (char*)malloc(size + 1); 106 | fread(buffer, 1, size, f); 107 | buffer[size] = '\0'; 108 | fclose(f); 109 | return buffer; 110 | } else { 111 | return NULL; 112 | } 113 | } 114 | 115 | static const char* 116 | pass_tests[] = { 117 | "twitter.json", 118 | "canada.json", 119 | "citm_catalog.json", 120 | }; 121 | 122 | void 123 | test_pass() { 124 | for( size_t t = 0; t < sizeof(pass_tests) / sizeof(char*); ++t ) { 125 | char* test = load_file(pass_tests[t]); 126 | json_value_t* val = json_parse(test).value; 127 | if(val != NULL) { 128 | fprintf(stderr, "test %s is passing\n", pass_tests[t]); 129 | json_free(val); 130 | } else { 131 | fprintf(stderr, "test %s failing!\n", pass_tests[t]); 132 | } 133 | free(test); 134 | } 135 | } 136 | 137 | 138 | static const char* 139 | fail_tests[] = { 140 | "jsonchecker/fail01_EXCLUDE.json", 141 | "jsonchecker/fail02.json", 142 | "jsonchecker/fail03.json", 143 | "jsonchecker/fail04.json", 144 | "jsonchecker/fail05.json", 145 | "jsonchecker/fail06.json", 146 | "jsonchecker/fail07.json", 147 | "jsonchecker/fail08.json", 148 | "jsonchecker/fail09.json", 149 | "jsonchecker/fail10.json", 150 | "jsonchecker/fail11.json", 151 | "jsonchecker/fail12.json", 152 | "jsonchecker/fail13.json", 153 | "jsonchecker/fail14.json", 154 | "jsonchecker/fail15.json", 155 | "jsonchecker/fail16.json", 156 | "jsonchecker/fail17.json", 157 | "jsonchecker/fail18_EXCLUDE.json", 158 | "jsonchecker/fail19.json", 159 | "jsonchecker/fail20.json", 160 | "jsonchecker/fail21.json", 161 | "jsonchecker/fail22.json", 162 | "jsonchecker/fail23.json", 163 | "jsonchecker/fail24.json", 164 | "jsonchecker/fail25.json", 165 | "jsonchecker/fail26.json", 166 | "jsonchecker/fail27.json", 167 | "jsonchecker/fail28.json", 168 | "jsonchecker/fail29.json", 169 | "jsonchecker/fail30.json", 170 | "jsonchecker/fail31.json", 171 | "jsonchecker/fail32.json", 172 | "jsonchecker/fail33.json", 173 | "jsonchecker/fail34.json", 174 | "jsonchecker/fail35.json", 175 | 176 | }; 177 | 178 | 179 | void 180 | test_fail() { 181 | for( size_t t = 0; t < sizeof(fail_tests) / sizeof(char*); ++t ) { 182 | char* test = load_file(fail_tests[t]); 183 | json_value_t* val = json_parse(test).value; 184 | if(val != NULL) { 185 | fprintf(stderr, "test %s is passing! should be failing!\n", fail_tests[t]); 186 | json_free(val); 187 | } else { 188 | fprintf(stderr, "test %s is passing by failing\n", fail_tests[t]); 189 | } 190 | free(test); 191 | } 192 | } 193 | 194 | int 195 | main(int argc, char* argv[]) { 196 | test_simple_object(); 197 | test_simple_object2(); 198 | test_pass(); 199 | test_fail(); 200 | return 0; 201 | } 202 | -------------------------------------------------------------------------------- /json-parser/lexer.rl: -------------------------------------------------------------------------------- 1 | /* 2 | ** json-parser Copyright 2015(c) Wael El Oraiby. All Rights Reserved 3 | ** 4 | ** This library is distributed in the hope that it will be useful, 5 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 6 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 7 | ** GNU General Public License for more details. 8 | ** 9 | ** Under Section 7 of GPL version 3, you are granted additional 10 | ** permissions described in the GCC Runtime Library Exception, version 11 | ** 3.1, as published by the Free Software Foundation. 12 | ** 13 | ** You should have received a copy of the GNU General Public License and 14 | ** a copy of the GCC Runtime Library Exception along with this program; 15 | ** see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 16 | ** . 17 | ** 18 | */ 19 | /* 20 | grammar parser: using Lemon, not YACC nor BISON 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "private/private.h" 28 | 29 | extern void* parserAlloc(void *(*mallocProc)(size_t)); 30 | extern void parserFree(void *p, void (*freeProc)(void*)); 31 | extern void parser(void *yyp, int yymajor, token_t yyminor, json_parser_t* s); 32 | 33 | 34 | #define ADVANCE(A, T) if( parser_.error_code == 0) { \ 35 | parser_.token_start = ts; \ 36 | parser_.token_end = te; \ 37 | parser_.token_line = line; \ 38 | copy_token(ts, te, tmp); \ 39 | token_t tmpc = token_to_##A(tmp); \ 40 | parser(yyparser, T, tmpc, &parser_); \ 41 | } else cs = scanner_error 42 | 43 | #define ADVANCE_STRING(T) if( parser_.error_code == 0) { \ 44 | parser_.token_start = string_s; \ 45 | parser_.token_end = string_e; \ 46 | parser_.token_line = line; \ 47 | token_t tmpc = token_to_string(string_s, string_e); \ 48 | parser(yyparser, T, tmpc, &parser_); \ 49 | } else cs = scanner_error 50 | 51 | #define ADVANCE_TOKEN(A) if( parser_.error_code == 0) { token_t t; t.tok_type = A; parser(yyparser, A, t, &parser_); } else p = pe - 1 52 | 53 | /* EOF char used to flush out that last token. This should be a whitespace 54 | * token. */ 55 | 56 | #define LAST_CHAR 0 57 | 58 | 59 | %%{ 60 | machine scanner; 61 | write data nofinal; 62 | 63 | # Floating literals. 64 | fract_const = ([0] | digit+) '.' digit+ | digit+ '.'; 65 | exponent = [eE] [+\-]? digit+; 66 | 67 | action inc_line { ++line; } 68 | 69 | c_comment := (any | '\n'@inc_line)* :>> '*/' @{ fgoto main; }; 70 | 71 | ju = [0-9a-fA-F]; 72 | 73 | j_string := |* 74 | ('\\' ('"' | '\\' | '/' | 'b' | 'f' | 'n' | 'r' | 't')) { }; 75 | ('\\u' ju ju ju ju) { }; 76 | (cntrl) { 77 | ret.status = JSON_INVALID_STRING; 78 | cs = scanner_error; 79 | }; 80 | '"' @{ string_e = ts; ADVANCE_STRING(JSON_TOK_STRING); string_s = NULL; string_e = NULL; fgoto main; }; 81 | '\n' | '\\' { 82 | ret.status = JSON_INVALID_STRING; 83 | cs = scanner_error; 84 | }; 85 | any { }; 86 | *|; 87 | 88 | main := |* 89 | 'true' { ADVANCE( boolean, JSON_TOK_BOOLEAN );}; 90 | 'false' { ADVANCE( boolean, JSON_TOK_BOOLEAN );}; 91 | 'null' { ADVANCE( none, JSON_TOK_NONE );}; 92 | 93 | # string. 94 | '"' { string_s = te; fgoto j_string; }; 95 | 96 | 97 | # Integer decimal. Leading part buffered by float. 98 | ( [+\-]? ( '0' | [1-9] [0-9]* ) ) { ADVANCE( number, JSON_TOK_NUMBER ); }; 99 | 100 | ( [+\-]? ( '0' | [1-9] [0-9]* ) [a-zA-Z_]+ ) { 101 | ret.status = JSON_INVALID_NUMBER; 102 | cs = scanner_error; 103 | }; 104 | 105 | # Floating literals. 106 | ( [+\-]? fract_const exponent? | [+\-]? digit+ exponent ) { ADVANCE( number, JSON_TOK_NUMBER );}; 107 | 108 | # Only buffer the second item, first buffered by symbol. */ 109 | '{' { ADVANCE_TOKEN( JSON_TOK_LBRACK );}; 110 | '}' { ADVANCE_TOKEN( JSON_TOK_RBRACK );}; 111 | '[' { ADVANCE_TOKEN( JSON_TOK_LSQB );}; 112 | ']' { ADVANCE_TOKEN( JSON_TOK_RSQB );}; 113 | ':' { ADVANCE_TOKEN( JSON_TOK_COL );}; 114 | ',' { ADVANCE_TOKEN( JSON_TOK_COMMA );}; 115 | 116 | '\n' { ++line; }; 117 | 118 | # Single char symbols. 119 | ( punct - [_"'] ) { ret.status = JSON_INVALID_CHARACTER; cs = scanner_error; }; 120 | 121 | # Comments and whitespace. 122 | '/*' { fgoto c_comment; }; 123 | '//' [^\n]* '\n'@inc_line; 124 | ( any - 33..126 )+; 125 | *|; 126 | }%% 127 | 128 | static int 129 | copy_token(const char* ts, const char *te, char* dst) { 130 | int index = 0; 131 | while( ts < te ) { 132 | dst[index++] = *ts; 133 | ++ts; 134 | } 135 | dst[index] = '\0'; 136 | return index; 137 | } 138 | 139 | static token_t 140 | token_to_boolean(const char* b) { 141 | token_t t; 142 | t.tok_type = JSON_TOK_BOOLEAN; 143 | if( !strcmp(b, "true") ) { 144 | t.boolean = true; 145 | } else { 146 | t.boolean = false; 147 | } 148 | return t; 149 | } 150 | 151 | static token_t 152 | token_to_number(const char* r) { 153 | token_t t; 154 | double v = 0.0; 155 | t.tok_type = JSON_TOK_NUMBER; 156 | sscanf(r, "%lf", &v); 157 | /* TODO: check limit */ 158 | t.number = v; 159 | return t; 160 | } 161 | 162 | static token_t 163 | token_to_none(const char* str) { 164 | token_t t; 165 | t.tok_type = JSON_TOK_NONE; 166 | return t; 167 | } 168 | 169 | static token_t 170 | token_to_string(const char* ts, const char* te) { 171 | token_t t; 172 | t.tok_type = JSON_TOK_STRING; 173 | t.string.start = ts; 174 | t.string.len = te - ts; 175 | return t; 176 | } 177 | 178 | 179 | json_return_t 180 | json_parse(const char* str) 181 | { 182 | json_parser_t parser_; 183 | json_return_t ret; 184 | ret.status = JSON_INVALID_INPUT; 185 | ret.value = NULL; 186 | 187 | void* yyparser; 188 | size_t line = 1; 189 | const char* ts = str; 190 | const char* te = str; 191 | const char* i = NULL; 192 | const char* string_s = NULL; 193 | const char* string_e = NULL; 194 | 195 | const char* p = str; 196 | const char* pe = p + strlen(str) + 1; 197 | const char* eof = NULL; 198 | 199 | int act = 0; 200 | int cs = 0; 201 | char tmp[4096]; 202 | 203 | token_t dummy; 204 | dummy.tok_type = 0; 205 | 206 | parser_.root = NULL; 207 | parser_.error_code = 0; 208 | parser_.token_start = ts; 209 | parser_.token_end = te; 210 | parser_.token_line = line; 211 | 212 | yyparser = parserAlloc(malloc); 213 | 214 | memset(tmp, 0, sizeof(tmp)); 215 | 216 | %% write init; 217 | 218 | %% write exec; 219 | 220 | /* Check if we failed. */ 221 | if ( cs == scanner_error ) { 222 | /* Machine failed before finding a token. */ 223 | parser_.error_code = 1; 224 | } 225 | 226 | parser(yyparser, 0, dummy, &parser_); 227 | 228 | if( parser_.error_code == 1 ) { 229 | while( parser_.error_code == 1 ) 230 | parser(yyparser, 0, dummy, &parser_); 231 | } 232 | 233 | if( parser_.error_code != 0 ) { 234 | ret.status = JSON_ERROR_SYNTAX_ERROR; 235 | 236 | parserFree(yyparser, free); 237 | 238 | if( parser_.root ) { 239 | json_free(parser_.root); 240 | } 241 | 242 | return ret; 243 | } 244 | 245 | parserFree(yyparser, free); 246 | ret.status = JSON_SUCCESS; 247 | ret.value = parser_.root; 248 | return ret; 249 | } 250 | 251 | -------------------------------------------------------------------------------- /json-parser/lexer.c: -------------------------------------------------------------------------------- 1 | 2 | #line 1 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 3 | /* 4 | ** json-parser Copyright 2015(c) Wael El Oraiby. All Rights Reserved 5 | ** 6 | ** This library is distributed in the hope that it will be useful, 7 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | ** GNU General Public License for more details. 10 | ** 11 | ** Under Section 7 of GPL version 3, you are granted additional 12 | ** permissions described in the GCC Runtime Library Exception, version 13 | ** 3.1, as published by the Free Software Foundation. 14 | ** 15 | ** You should have received a copy of the GNU General Public License and 16 | ** a copy of the GCC Runtime Library Exception along with this program; 17 | ** see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 18 | ** . 19 | ** 20 | */ 21 | /* 22 | grammar parser: using Lemon, not YACC nor BISON 23 | */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "private/private.h" 30 | 31 | extern void* parserAlloc(void *(*mallocProc)(size_t)); 32 | extern void parserFree(void *p, void (*freeProc)(void*)); 33 | extern void parser(void *yyp, int yymajor, token_t yyminor, json_parser_t* s); 34 | 35 | 36 | #define ADVANCE(A, T) if( parser_.error_code == 0) { \ 37 | parser_.token_start = ts; \ 38 | parser_.token_end = te; \ 39 | parser_.token_line = line; \ 40 | copy_token(ts, te, tmp); \ 41 | token_t tmpc = token_to_##A(tmp); \ 42 | parser(yyparser, T, tmpc, &parser_); \ 43 | } else cs = scanner_error 44 | 45 | #define ADVANCE_STRING(T) if( parser_.error_code == 0) { \ 46 | parser_.token_start = string_s; \ 47 | parser_.token_end = string_e; \ 48 | parser_.token_line = line; \ 49 | token_t tmpc = token_to_string(string_s, string_e); \ 50 | parser(yyparser, T, tmpc, &parser_); \ 51 | } else cs = scanner_error 52 | 53 | #define ADVANCE_TOKEN(A) if( parser_.error_code == 0) { token_t t; t.tok_type = A; parser(yyparser, A, t, &parser_); } else p = pe - 1 54 | 55 | /* EOF char used to flush out that last token. This should be a whitespace 56 | * token. */ 57 | 58 | #define LAST_CHAR 0 59 | 60 | 61 | 62 | #line 63 "/home/wael/projects/rl-json-parser/json-parser/lexer.c" 63 | static const char _scanner_actions[] = { 64 | 0, 1, 0, 1, 1, 1, 3, 1, 65 | 4, 1, 5, 1, 6, 1, 7, 1, 66 | 8, 1, 10, 1, 11, 1, 12, 1, 67 | 18, 1, 19, 1, 20, 1, 21, 1, 68 | 22, 1, 23, 1, 24, 1, 25, 1, 69 | 26, 1, 27, 1, 28, 1, 29, 1, 70 | 31, 1, 32, 1, 33, 1, 34, 1, 71 | 35, 1, 36, 1, 37, 2, 0, 30, 72 | 2, 2, 9, 2, 5, 13, 2, 5, 73 | 14, 2, 5, 15, 2, 5, 16, 2, 74 | 5, 17 75 | }; 76 | 77 | static const unsigned char _scanner_key_offsets[] = { 78 | 0, 0, 4, 6, 11, 12, 13, 14, 79 | 15, 16, 17, 18, 19, 20, 21, 22, 80 | 24, 27, 33, 39, 45, 51, 80, 82, 81 | 85, 95, 99, 101, 106, 115, 125, 127, 82 | 127, 132 83 | }; 84 | 85 | static const char _scanner_trans_keys[] = { 86 | 43, 45, 48, 57, 48, 57, 46, 69, 87 | 101, 48, 57, 10, 97, 108, 115, 101, 88 | 117, 108, 108, 114, 117, 101, 10, 42, 89 | 10, 42, 47, 48, 57, 65, 70, 97, 90 | 102, 48, 57, 65, 70, 97, 102, 48, 91 | 57, 65, 70, 97, 102, 48, 57, 65, 92 | 70, 97, 102, 10, 34, 39, 43, 44, 93 | 45, 47, 48, 58, 91, 92, 93, 94, 94 | 96, 102, 110, 116, 123, 125, 33, 46, 95 | 49, 57, 59, 64, 65, 122, 124, 126, 96 | 33, 126, 48, 49, 57, 46, 69, 95, 97 | 101, 48, 57, 65, 90, 97, 122, 69, 98 | 101, 48, 57, 48, 57, 95, 65, 90, 99 | 97, 122, 43, 45, 95, 48, 57, 65, 100 | 90, 97, 122, 46, 69, 95, 101, 48, 101 | 57, 65, 90, 97, 122, 42, 47, 34, 102 | 92, 127, 0, 31, 34, 47, 92, 98, 103 | 102, 110, 114, 116, 117, 0 104 | }; 105 | 106 | static const char _scanner_single_lengths[] = { 107 | 0, 2, 0, 3, 1, 1, 1, 1, 108 | 1, 1, 1, 1, 1, 1, 1, 2, 109 | 3, 0, 0, 0, 0, 19, 0, 1, 110 | 4, 2, 0, 1, 3, 4, 2, 0, 111 | 3, 9 112 | }; 113 | 114 | static const char _scanner_range_lengths[] = { 115 | 0, 1, 1, 1, 0, 0, 0, 0, 116 | 0, 0, 0, 0, 0, 0, 0, 0, 117 | 0, 3, 3, 3, 3, 5, 1, 1, 118 | 3, 1, 1, 2, 3, 3, 0, 0, 119 | 1, 0 120 | }; 121 | 122 | static const unsigned char _scanner_index_offsets[] = { 123 | 0, 0, 4, 6, 11, 13, 15, 17, 124 | 19, 21, 23, 25, 27, 29, 31, 33, 125 | 36, 40, 44, 48, 52, 56, 81, 83, 126 | 86, 94, 98, 100, 104, 111, 119, 122, 127 | 123, 128 128 | }; 129 | 130 | static const char _scanner_indicies[] = { 131 | 1, 1, 2, 0, 2, 0, 4, 6, 132 | 6, 5, 3, 9, 8, 10, 11, 12, 133 | 11, 13, 11, 14, 11, 15, 11, 16, 134 | 11, 17, 11, 18, 11, 19, 11, 20, 135 | 11, 22, 23, 21, 22, 23, 24, 21, 136 | 26, 26, 26, 25, 27, 27, 27, 25, 137 | 28, 28, 28, 25, 29, 29, 29, 25, 138 | 31, 33, 11, 34, 35, 34, 36, 37, 139 | 39, 40, 32, 41, 32, 32, 42, 43, 140 | 44, 45, 46, 32, 38, 32, 11, 32, 141 | 30, 0, 30, 37, 38, 47, 4, 50, 142 | 49, 50, 5, 49, 49, 48, 6, 6, 143 | 4, 51, 2, 51, 49, 49, 49, 52, 144 | 1, 1, 49, 2, 49, 49, 52, 4, 145 | 50, 49, 50, 38, 49, 49, 48, 53, 146 | 8, 47, 11, 56, 57, 55, 55, 54, 147 | 59, 59, 59, 59, 59, 59, 59, 59, 148 | 60, 58, 0 149 | }; 150 | 151 | static const char _scanner_trans_targs[] = { 152 | 21, 2, 26, 21, 25, 3, 1, 21, 153 | 4, 21, 6, 0, 7, 8, 21, 10, 154 | 11, 21, 13, 14, 21, 15, 15, 16, 155 | 31, 32, 18, 19, 20, 32, 22, 22, 156 | 21, 21, 23, 21, 30, 24, 29, 21, 157 | 21, 21, 5, 9, 12, 21, 21, 21, 158 | 21, 27, 28, 21, 21, 21, 32, 32, 159 | 32, 33, 32, 32, 17 160 | }; 161 | 162 | static const char _scanner_trans_actions[] = { 163 | 59, 0, 0, 55, 73, 0, 0, 57, 164 | 0, 61, 0, 0, 0, 0, 25, 0, 165 | 0, 27, 0, 0, 23, 0, 1, 0, 166 | 3, 21, 0, 0, 0, 13, 79, 76, 167 | 43, 29, 0, 41, 9, 67, 0, 39, 168 | 35, 37, 0, 0, 0, 31, 33, 53, 169 | 47, 0, 70, 51, 49, 45, 17, 15, 170 | 64, 9, 19, 11, 0 171 | }; 172 | 173 | static const char _scanner_to_state_actions[] = { 174 | 0, 0, 0, 0, 0, 0, 0, 0, 175 | 0, 0, 0, 0, 0, 0, 0, 5, 176 | 0, 0, 0, 0, 0, 5, 0, 0, 177 | 0, 0, 0, 0, 0, 0, 0, 0, 178 | 5, 0 179 | }; 180 | 181 | static const char _scanner_from_state_actions[] = { 182 | 0, 0, 0, 0, 0, 0, 0, 0, 183 | 0, 0, 0, 0, 0, 0, 0, 0, 184 | 0, 0, 0, 0, 0, 7, 0, 0, 185 | 0, 0, 0, 0, 0, 0, 0, 0, 186 | 7, 0 187 | }; 188 | 189 | static const unsigned char _scanner_eof_trans[] = { 190 | 0, 1, 1, 4, 8, 0, 0, 0, 191 | 0, 0, 0, 0, 0, 0, 0, 0, 192 | 0, 26, 26, 26, 26, 0, 1, 48, 193 | 49, 52, 52, 53, 53, 49, 48, 0, 194 | 0, 59 195 | }; 196 | 197 | static const int scanner_start = 21; 198 | static const int scanner_error = 0; 199 | 200 | static const int scanner_en_c_comment = 15; 201 | static const int scanner_en_j_string = 32; 202 | static const int scanner_en_main = 21; 203 | 204 | 205 | #line 126 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 206 | 207 | 208 | static int 209 | copy_token(const char* ts, const char *te, char* dst) { 210 | int index = 0; 211 | while( ts < te ) { 212 | dst[index++] = *ts; 213 | ++ts; 214 | } 215 | dst[index] = '\0'; 216 | return index; 217 | } 218 | 219 | static token_t 220 | token_to_boolean(const char* b) { 221 | token_t t; 222 | t.tok_type = JSON_TOK_BOOLEAN; 223 | if( !strcmp(b, "true") ) { 224 | t.boolean = true; 225 | } else { 226 | t.boolean = false; 227 | } 228 | return t; 229 | } 230 | 231 | static token_t 232 | token_to_number(const char* r) { 233 | token_t t; 234 | double v = 0.0; 235 | t.tok_type = JSON_TOK_NUMBER; 236 | sscanf(r, "%lf", &v); 237 | /* TODO: check limit */ 238 | t.number = v; 239 | return t; 240 | } 241 | 242 | static token_t 243 | token_to_none(const char* str) { 244 | token_t t; 245 | t.tok_type = JSON_TOK_NONE; 246 | return t; 247 | } 248 | 249 | static token_t 250 | token_to_string(const char* ts, const char* te) { 251 | token_t t; 252 | t.tok_type = JSON_TOK_STRING; 253 | t.string.start = ts; 254 | t.string.len = te - ts; 255 | return t; 256 | } 257 | 258 | 259 | json_return_t 260 | json_parse(const char* str) 261 | { 262 | json_parser_t parser_; 263 | json_return_t ret; 264 | ret.status = JSON_INVALID_INPUT; 265 | ret.value = NULL; 266 | 267 | void* yyparser; 268 | size_t line = 1; 269 | const char* ts = str; 270 | const char* te = str; 271 | const char* i = NULL; 272 | const char* string_s = NULL; 273 | const char* string_e = NULL; 274 | 275 | const char* p = str; 276 | const char* pe = p + strlen(str) + 1; 277 | const char* eof = NULL; 278 | 279 | int act = 0; 280 | int cs = 0; 281 | char tmp[4096]; 282 | 283 | token_t dummy; 284 | dummy.tok_type = 0; 285 | 286 | parser_.root = NULL; 287 | parser_.error_code = 0; 288 | parser_.token_start = ts; 289 | parser_.token_end = te; 290 | parser_.token_line = line; 291 | 292 | yyparser = parserAlloc(malloc); 293 | 294 | memset(tmp, 0, sizeof(tmp)); 295 | 296 | 297 | #line 298 "/home/wael/projects/rl-json-parser/json-parser/lexer.c" 298 | { 299 | cs = scanner_start; 300 | ts = 0; 301 | te = 0; 302 | act = 0; 303 | } 304 | 305 | #line 217 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 306 | 307 | 308 | #line 309 "/home/wael/projects/rl-json-parser/json-parser/lexer.c" 309 | { 310 | int _klen; 311 | unsigned int _trans; 312 | const char *_acts; 313 | unsigned int _nacts; 314 | const char *_keys; 315 | 316 | if ( p == pe ) 317 | goto _test_eof; 318 | if ( cs == 0 ) 319 | goto _out; 320 | _resume: 321 | _acts = _scanner_actions + _scanner_from_state_actions[cs]; 322 | _nacts = (unsigned int) *_acts++; 323 | while ( _nacts-- > 0 ) { 324 | switch ( *_acts++ ) { 325 | case 4: 326 | #line 1 "NONE" 327 | {ts = p;} 328 | break; 329 | #line 330 "/home/wael/projects/rl-json-parser/json-parser/lexer.c" 330 | } 331 | } 332 | 333 | _keys = _scanner_trans_keys + _scanner_key_offsets[cs]; 334 | _trans = _scanner_index_offsets[cs]; 335 | 336 | _klen = _scanner_single_lengths[cs]; 337 | if ( _klen > 0 ) { 338 | const char *_lower = _keys; 339 | const char *_mid; 340 | const char *_upper = _keys + _klen - 1; 341 | while (1) { 342 | if ( _upper < _lower ) 343 | break; 344 | 345 | _mid = _lower + ((_upper-_lower) >> 1); 346 | if ( (*p) < *_mid ) 347 | _upper = _mid - 1; 348 | else if ( (*p) > *_mid ) 349 | _lower = _mid + 1; 350 | else { 351 | _trans += (unsigned int)(_mid - _keys); 352 | goto _match; 353 | } 354 | } 355 | _keys += _klen; 356 | _trans += _klen; 357 | } 358 | 359 | _klen = _scanner_range_lengths[cs]; 360 | if ( _klen > 0 ) { 361 | const char *_lower = _keys; 362 | const char *_mid; 363 | const char *_upper = _keys + (_klen<<1) - 2; 364 | while (1) { 365 | if ( _upper < _lower ) 366 | break; 367 | 368 | _mid = _lower + (((_upper-_lower) >> 1) & ~1); 369 | if ( (*p) < _mid[0] ) 370 | _upper = _mid - 2; 371 | else if ( (*p) > _mid[1] ) 372 | _lower = _mid + 2; 373 | else { 374 | _trans += (unsigned int)((_mid - _keys)>>1); 375 | goto _match; 376 | } 377 | } 378 | _trans += _klen; 379 | } 380 | 381 | _match: 382 | _trans = _scanner_indicies[_trans]; 383 | _eof_trans: 384 | cs = _scanner_trans_targs[_trans]; 385 | 386 | if ( _scanner_trans_actions[_trans] == 0 ) 387 | goto _again; 388 | 389 | _acts = _scanner_actions + _scanner_trans_actions[_trans]; 390 | _nacts = (unsigned int) *_acts++; 391 | while ( _nacts-- > 0 ) 392 | { 393 | switch ( *_acts++ ) 394 | { 395 | case 0: 396 | #line 67 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 397 | { ++line; } 398 | break; 399 | case 1: 400 | #line 69 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 401 | { {cs = 21;goto _again;} } 402 | break; 403 | case 2: 404 | #line 80 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 405 | { string_e = ts; ADVANCE_STRING(JSON_TOK_STRING); string_s = NULL; string_e = NULL; {cs = 21;goto _again;} } 406 | break; 407 | case 5: 408 | #line 1 "NONE" 409 | {te = p+1;} 410 | break; 411 | case 6: 412 | #line 74 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 413 | {te = p+1;{ }} 414 | break; 415 | case 7: 416 | #line 75 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 417 | {te = p+1;{ }} 418 | break; 419 | case 8: 420 | #line 76 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 421 | {te = p+1;{ 422 | ret.status = JSON_INVALID_STRING; 423 | cs = scanner_error; 424 | }} 425 | break; 426 | case 9: 427 | #line 80 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 428 | {te = p+1;} 429 | break; 430 | case 10: 431 | #line 85 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 432 | {te = p+1;{ }} 433 | break; 434 | case 11: 435 | #line 81 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 436 | {te = p;p--;{ 437 | ret.status = JSON_INVALID_STRING; 438 | cs = scanner_error; 439 | }} 440 | break; 441 | case 12: 442 | #line 81 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 443 | {{p = ((te))-1;}{ 444 | ret.status = JSON_INVALID_STRING; 445 | cs = scanner_error; 446 | }} 447 | break; 448 | case 13: 449 | #line 98 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 450 | {act = 11;} 451 | break; 452 | case 14: 453 | #line 100 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 454 | {act = 12;} 455 | break; 456 | case 15: 457 | #line 106 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 458 | {act = 13;} 459 | break; 460 | case 16: 461 | #line 116 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 462 | {act = 20;} 463 | break; 464 | case 17: 465 | #line 124 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 466 | {act = 24;} 467 | break; 468 | case 18: 469 | #line 89 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 470 | {te = p+1;{ ADVANCE( boolean, JSON_TOK_BOOLEAN );}} 471 | break; 472 | case 19: 473 | #line 90 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 474 | {te = p+1;{ ADVANCE( boolean, JSON_TOK_BOOLEAN );}} 475 | break; 476 | case 20: 477 | #line 91 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 478 | {te = p+1;{ ADVANCE( none, JSON_TOK_NONE );}} 479 | break; 480 | case 21: 481 | #line 94 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 482 | {te = p+1;{ string_s = te; {cs = 32;goto _again;} }} 483 | break; 484 | case 22: 485 | #line 109 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 486 | {te = p+1;{ ADVANCE_TOKEN( JSON_TOK_LBRACK );}} 487 | break; 488 | case 23: 489 | #line 110 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 490 | {te = p+1;{ ADVANCE_TOKEN( JSON_TOK_RBRACK );}} 491 | break; 492 | case 24: 493 | #line 111 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 494 | {te = p+1;{ ADVANCE_TOKEN( JSON_TOK_LSQB );}} 495 | break; 496 | case 25: 497 | #line 112 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 498 | {te = p+1;{ ADVANCE_TOKEN( JSON_TOK_RSQB );}} 499 | break; 500 | case 26: 501 | #line 113 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 502 | {te = p+1;{ ADVANCE_TOKEN( JSON_TOK_COL );}} 503 | break; 504 | case 27: 505 | #line 114 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 506 | {te = p+1;{ ADVANCE_TOKEN( JSON_TOK_COMMA );}} 507 | break; 508 | case 28: 509 | #line 119 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 510 | {te = p+1;{ ret.status = JSON_INVALID_CHARACTER; cs = scanner_error; }} 511 | break; 512 | case 29: 513 | #line 122 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 514 | {te = p+1;{ {cs = 15;goto _again;} }} 515 | break; 516 | case 30: 517 | #line 123 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 518 | {te = p+1;} 519 | break; 520 | case 31: 521 | #line 98 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 522 | {te = p;p--;{ ADVANCE( number, JSON_TOK_NUMBER ); }} 523 | break; 524 | case 32: 525 | #line 100 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 526 | {te = p;p--;{ 527 | ret.status = JSON_INVALID_NUMBER; 528 | cs = scanner_error; 529 | }} 530 | break; 531 | case 33: 532 | #line 106 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 533 | {te = p;p--;{ ADVANCE( number, JSON_TOK_NUMBER );}} 534 | break; 535 | case 34: 536 | #line 119 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 537 | {te = p;p--;{ ret.status = JSON_INVALID_CHARACTER; cs = scanner_error; }} 538 | break; 539 | case 35: 540 | #line 98 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 541 | {{p = ((te))-1;}{ ADVANCE( number, JSON_TOK_NUMBER ); }} 542 | break; 543 | case 36: 544 | #line 119 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 545 | {{p = ((te))-1;}{ ret.status = JSON_INVALID_CHARACTER; cs = scanner_error; }} 546 | break; 547 | case 37: 548 | #line 1 "NONE" 549 | { switch( act ) { 550 | case 11: 551 | {{p = ((te))-1;} ADVANCE( number, JSON_TOK_NUMBER ); } 552 | break; 553 | case 12: 554 | {{p = ((te))-1;} 555 | ret.status = JSON_INVALID_NUMBER; 556 | cs = scanner_error; 557 | } 558 | break; 559 | case 13: 560 | {{p = ((te))-1;} ADVANCE( number, JSON_TOK_NUMBER );} 561 | break; 562 | case 20: 563 | {{p = ((te))-1;} ++line; } 564 | break; 565 | default: 566 | {{p = ((te))-1;}} 567 | break; 568 | } 569 | } 570 | break; 571 | #line 572 "/home/wael/projects/rl-json-parser/json-parser/lexer.c" 572 | } 573 | } 574 | 575 | _again: 576 | _acts = _scanner_actions + _scanner_to_state_actions[cs]; 577 | _nacts = (unsigned int) *_acts++; 578 | while ( _nacts-- > 0 ) { 579 | switch ( *_acts++ ) { 580 | case 3: 581 | #line 1 "NONE" 582 | {ts = 0;} 583 | break; 584 | #line 585 "/home/wael/projects/rl-json-parser/json-parser/lexer.c" 585 | } 586 | } 587 | 588 | if ( cs == 0 ) 589 | goto _out; 590 | if ( ++p != pe ) 591 | goto _resume; 592 | _test_eof: {} 593 | if ( p == eof ) 594 | { 595 | if ( _scanner_eof_trans[cs] > 0 ) { 596 | _trans = _scanner_eof_trans[cs] - 1; 597 | goto _eof_trans; 598 | } 599 | } 600 | 601 | _out: {} 602 | } 603 | 604 | #line 219 "/home/wael/projects/rl-json-parser/json-parser/lexer.rl" 605 | 606 | /* Check if we failed. */ 607 | if ( cs == scanner_error ) { 608 | /* Machine failed before finding a token. */ 609 | parser_.error_code = 1; 610 | } 611 | 612 | parser(yyparser, 0, dummy, &parser_); 613 | 614 | if( parser_.error_code == 1 ) { 615 | while( parser_.error_code == 1 ) 616 | parser(yyparser, 0, dummy, &parser_); 617 | } 618 | 619 | if( parser_.error_code != 0 ) { 620 | ret.status = JSON_ERROR_SYNTAX_ERROR; 621 | 622 | parserFree(yyparser, free); 623 | 624 | if( parser_.root ) { 625 | json_free(parser_.root); 626 | } 627 | 628 | return ret; 629 | } 630 | 631 | parserFree(yyparser, free); 632 | ret.status = JSON_SUCCESS; 633 | ret.value = parser_.root; 634 | return ret; 635 | } 636 | 637 | -------------------------------------------------------------------------------- /json-parser/parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** 2000-05-29 3 | ** 4 | ** The author disclaims copyright to this source code. In place of 5 | ** a legal notice, here is a blessing: 6 | ** 7 | ** May you do good and not evil. 8 | ** May you find forgiveness for yourself and forgive others. 9 | ** May you share freely, never taking more than you give. 10 | ** 11 | ************************************************************************* 12 | ** Driver template for the LEMON parser generator. 13 | ** 14 | ** The "lemon" program processes an LALR(1) input grammar file, then uses 15 | ** this template to construct a parser. The "lemon" program inserts text 16 | ** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the 17 | ** interstitial "-" characters) contained in this template is changed into 18 | ** the value of the %name directive from the grammar. Otherwise, the content 19 | ** of this template is copied straight through into the generate parser 20 | ** source file. 21 | ** 22 | ** The following is the concatenation of all %include directives from the 23 | ** input grammar file: 24 | */ 25 | #include 26 | /************ Begin %include sections from the grammar ************************/ 27 | #line 30 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include "private/private.h" 34 | 35 | #define PUSH(A) json_insert_before(A, pret->head); pret->head = A; 36 | #define POP(A) if( A == pret->head ) { assert(pret->head->prev == NULL); pret->head = A->next; } json_dereference(A) 37 | #line 38 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 38 | /**************** End of %include directives **********************************/ 39 | /* These constants specify the various numeric values for terminal symbols 40 | ** in a format understandable to "makeheaders". This section is blank unless 41 | ** "lemon" is run with the "-m" command-line option. 42 | ***************** Begin makeheaders token definitions *************************/ 43 | /**************** End makeheaders token definitions ***************************/ 44 | 45 | /* The next sections is a series of control #defines. 46 | ** various aspects of the generated parser. 47 | ** YYCODETYPE is the data type used to store the integer codes 48 | ** that represent terminal and non-terminal symbols. 49 | ** "unsigned char" is used if there are fewer than 50 | ** 256 symbols. Larger types otherwise. 51 | ** YYNOCODE is a number of type YYCODETYPE that is not used for 52 | ** any terminal or nonterminal symbol. 53 | ** YYFALLBACK If defined, this indicates that one or more tokens 54 | ** (also known as: "terminal symbols") have fall-back 55 | ** values which should be used if the original symbol 56 | ** would not parse. This permits keywords to sometimes 57 | ** be used as identifiers, for example. 58 | ** YYACTIONTYPE is the data type used for "action codes" - numbers 59 | ** that indicate what to do in response to the next 60 | ** token. 61 | ** parserTOKENTYPE is the data type used for minor type for terminal 62 | ** symbols. Background: A "minor type" is a semantic 63 | ** value associated with a terminal or non-terminal 64 | ** symbols. For example, for an "ID" terminal symbol, 65 | ** the minor type might be the name of the identifier. 66 | ** Each non-terminal can have a different minor type. 67 | ** Terminal symbols all have the same minor type, though. 68 | ** This macros defines the minor type for terminal 69 | ** symbols. 70 | ** YYMINORTYPE is the data type used for all minor types. 71 | ** This is typically a union of many types, one of 72 | ** which is parserTOKENTYPE. The entry in the union 73 | ** for terminal symbols is called "yy0". 74 | ** YYSTACKDEPTH is the maximum depth of the parser's stack. If 75 | ** zero the stack is dynamically sized using realloc() 76 | ** parserARG_SDECL A static variable declaration for the %extra_argument 77 | ** parserARG_PDECL A parameter declaration for the %extra_argument 78 | ** parserARG_STORE Code to store %extra_argument into yypParser 79 | ** parserARG_FETCH Code to extract %extra_argument from yypParser 80 | ** YYERRORSYMBOL is the code number of the error symbol. If not 81 | ** defined, then do no error processing. 82 | ** YYNSTATE the combined number of states. 83 | ** YYNRULE the number of rules in the grammar 84 | ** YYNTOKEN Number of terminal symbols 85 | ** YY_MAX_SHIFT Maximum value for shift actions 86 | ** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions 87 | ** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions 88 | ** YY_ERROR_ACTION The yy_action[] code for syntax error 89 | ** YY_ACCEPT_ACTION The yy_action[] code for accept 90 | ** YY_NO_ACTION The yy_action[] code for no-op 91 | ** YY_MIN_REDUCE Minimum value for reduce actions 92 | ** YY_MAX_REDUCE Maximum value for reduce actions 93 | */ 94 | #ifndef INTERFACE 95 | # define INTERFACE 1 96 | #endif 97 | /************* Begin control #defines *****************************************/ 98 | #define YYCODETYPE unsigned char 99 | #define YYNOCODE 20 100 | #define YYACTIONTYPE unsigned char 101 | #define parserTOKENTYPE token_t 102 | typedef union { 103 | int yyinit; 104 | parserTOKENTYPE yy0; 105 | json_pair_t yy13; 106 | json_value_t* yy14; 107 | } YYMINORTYPE; 108 | #ifndef YYSTACKDEPTH 109 | #define YYSTACKDEPTH 100 110 | #endif 111 | #define parserARG_SDECL json_parser_t* pret ; 112 | #define parserARG_PDECL , json_parser_t* pret 113 | #define parserARG_FETCH json_parser_t* pret = yypParser->pret 114 | #define parserARG_STORE yypParser->pret = pret 115 | #define YYNSTATE 11 116 | #define YYNRULE 17 117 | #define YYNTOKEN 11 118 | #define YY_MAX_SHIFT 10 119 | #define YY_MIN_SHIFTREDUCE 26 120 | #define YY_MAX_SHIFTREDUCE 42 121 | #define YY_ERROR_ACTION 43 122 | #define YY_ACCEPT_ACTION 44 123 | #define YY_NO_ACTION 45 124 | #define YY_MIN_REDUCE 46 125 | #define YY_MAX_REDUCE 62 126 | /************* End control #defines *******************************************/ 127 | 128 | /* Define the yytestcase() macro to be a no-op if is not already defined 129 | ** otherwise. 130 | ** 131 | ** Applications can choose to define yytestcase() in the %include section 132 | ** to a macro that can assist in verifying code coverage. For production 133 | ** code the yytestcase() macro should be turned off. But it is useful 134 | ** for testing. 135 | */ 136 | #ifndef yytestcase 137 | # define yytestcase(X) 138 | #endif 139 | 140 | 141 | /* Next are the tables used to determine what action to take based on the 142 | ** current state and lookahead token. These tables are used to implement 143 | ** functions that take a state number and lookahead value and return an 144 | ** action integer. 145 | ** 146 | ** Suppose the action integer is N. Then the action is determined as 147 | ** follows 148 | ** 149 | ** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead 150 | ** token onto the stack and goto state N. 151 | ** 152 | ** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then 153 | ** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. 154 | ** 155 | ** N == YY_ERROR_ACTION A syntax error has occurred. 156 | ** 157 | ** N == YY_ACCEPT_ACTION The parser accepts its input. 158 | ** 159 | ** N == YY_NO_ACTION No such action. Denotes unused 160 | ** slots in the yy_action[] table. 161 | ** 162 | ** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE 163 | ** and YY_MAX_REDUCE 164 | ** 165 | ** The action table is constructed as a single large table named yy_action[]. 166 | ** Given state S and lookahead X, the action is computed as either: 167 | ** 168 | ** (A) N = yy_action[ yy_shift_ofst[S] + X ] 169 | ** (B) N = yy_default[S] 170 | ** 171 | ** The (A) formula is preferred. The B formula is used instead if 172 | ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X. 173 | ** 174 | ** The formulas above are for computing the action when the lookahead is 175 | ** a terminal symbol. If the lookahead is a non-terminal (as occurs after 176 | ** a reduce action) then the yy_reduce_ofst[] array is used in place of 177 | ** the yy_shift_ofst[] array. 178 | ** 179 | ** The following are the tables generated in this section: 180 | ** 181 | ** yy_action[] A single table containing all actions. 182 | ** yy_lookahead[] A table containing the lookahead for each entry in 183 | ** yy_action. Used to detect hash collisions. 184 | ** yy_shift_ofst[] For each state, the offset into yy_action for 185 | ** shifting terminals. 186 | ** yy_reduce_ofst[] For each state, the offset into yy_action for 187 | ** shifting non-terminals after a reduce. 188 | ** yy_default[] Default action for each state. 189 | ** 190 | *********** Begin parsing tables **********************************************/ 191 | #define YY_ACTTAB_COUNT (41) 192 | static const YYACTIONTYPE yy_action[] = { 193 | /* 0 */ 50, 37, 10, 9, 4, 44, 1, 33, 38, 39, 194 | /* 10 */ 40, 37, 47, 4, 4, 1, 1, 8, 38, 39, 195 | /* 20 */ 40, 7, 61, 62, 55, 8, 61, 62, 56, 31, 196 | /* 30 */ 61, 62, 48, 49, 6, 5, 2, 32, 3, 46, 197 | /* 40 */ 34, 198 | }; 199 | static const YYCODETYPE yy_lookahead[] = { 200 | /* 0 */ 12, 1, 15, 16, 4, 18, 6, 7, 8, 9, 201 | /* 10 */ 10, 1, 0, 4, 4, 6, 6, 1, 8, 9, 202 | /* 20 */ 10, 14, 15, 16, 17, 1, 15, 16, 17, 5, 203 | /* 30 */ 15, 16, 17, 12, 13, 3, 3, 5, 2, 0, 204 | /* 40 */ 7, 19, 19, 19, 19, 19, 19, 19, 19, 19, 205 | /* 50 */ 19, 206 | }; 207 | #define YY_SHIFT_COUNT (10) 208 | #define YY_SHIFT_MIN (0) 209 | #define YY_SHIFT_MAX (39) 210 | static const unsigned char yy_shift_ofst[] = { 211 | /* 0 */ 9, 0, 10, 10, 24, 16, 32, 33, 36, 12, 212 | /* 10 */ 39, 213 | }; 214 | #define YY_REDUCE_COUNT (5) 215 | #define YY_REDUCE_MIN (-13) 216 | #define YY_REDUCE_MAX (21) 217 | static const signed char yy_reduce_ofst[] = { 218 | /* 0 */ -13, 7, 11, 15, 21, -12, 219 | }; 220 | static const YYACTIONTYPE yy_default[] = { 221 | /* 0 */ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 222 | /* 10 */ 43, 223 | }; 224 | /********** End of lemon-generated parsing tables *****************************/ 225 | 226 | /* The next table maps tokens (terminal symbols) into fallback tokens. 227 | ** If a construct like the following: 228 | ** 229 | ** %fallback ID X Y Z. 230 | ** 231 | ** appears in the grammar, then ID becomes a fallback token for X, Y, 232 | ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser 233 | ** but it does not parse, the type of the token is changed to ID and 234 | ** the parse is retried before an error is thrown. 235 | ** 236 | ** This feature can be used, for example, to cause some keywords in a language 237 | ** to revert to identifiers if they keyword does not apply in the context where 238 | ** it appears. 239 | */ 240 | #ifdef YYFALLBACK 241 | static const YYCODETYPE yyFallback[] = { 242 | }; 243 | #endif /* YYFALLBACK */ 244 | 245 | /* The following structure represents a single element of the 246 | ** parser's stack. Information stored includes: 247 | ** 248 | ** + The state number for the parser at this level of the stack. 249 | ** 250 | ** + The value of the token stored at this level of the stack. 251 | ** (In other words, the "major" token.) 252 | ** 253 | ** + The semantic value stored at this level of the stack. This is 254 | ** the information used by the action routines in the grammar. 255 | ** It is sometimes called the "minor" token. 256 | ** 257 | ** After the "shift" half of a SHIFTREDUCE action, the stateno field 258 | ** actually contains the reduce action for the second half of the 259 | ** SHIFTREDUCE. 260 | */ 261 | struct yyStackEntry { 262 | YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ 263 | YYCODETYPE major; /* The major token value. This is the code 264 | ** number for the token at this stack level */ 265 | YYMINORTYPE minor; /* The user-supplied minor token value. This 266 | ** is the value of the token */ 267 | }; 268 | typedef struct yyStackEntry yyStackEntry; 269 | 270 | /* The state of the parser is completely contained in an instance of 271 | ** the following structure */ 272 | struct yyParser { 273 | yyStackEntry *yytos; /* Pointer to top element of the stack */ 274 | #ifdef YYTRACKMAXSTACKDEPTH 275 | int yyhwm; /* High-water mark of the stack */ 276 | #endif 277 | #ifndef YYNOERRORRECOVERY 278 | int yyerrcnt; /* Shifts left before out of the error */ 279 | #endif 280 | parserARG_SDECL /* A place to hold %extra_argument */ 281 | #if YYSTACKDEPTH<=0 282 | int yystksz; /* Current side of the stack */ 283 | yyStackEntry *yystack; /* The parser's stack */ 284 | yyStackEntry yystk0; /* First stack entry */ 285 | #else 286 | yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ 287 | yyStackEntry *yystackEnd; /* Last entry in the stack */ 288 | #endif 289 | }; 290 | typedef struct yyParser yyParser; 291 | 292 | #ifndef NDEBUG 293 | #include 294 | static FILE *yyTraceFILE = 0; 295 | static char *yyTracePrompt = 0; 296 | #endif /* NDEBUG */ 297 | 298 | #ifndef NDEBUG 299 | /* 300 | ** Turn parser tracing on by giving a stream to which to write the trace 301 | ** and a prompt to preface each trace message. Tracing is turned off 302 | ** by making either argument NULL 303 | ** 304 | ** Inputs: 305 | **
    306 | **
  • A FILE* to which trace output should be written. 307 | ** If NULL, then tracing is turned off. 308 | **
  • A prefix string written at the beginning of every 309 | ** line of trace output. If NULL, then tracing is 310 | ** turned off. 311 | **
312 | ** 313 | ** Outputs: 314 | ** None. 315 | */ 316 | void parserTrace(FILE *TraceFILE, char *zTracePrompt){ 317 | yyTraceFILE = TraceFILE; 318 | yyTracePrompt = zTracePrompt; 319 | if( yyTraceFILE==0 ) yyTracePrompt = 0; 320 | else if( yyTracePrompt==0 ) yyTraceFILE = 0; 321 | } 322 | #endif /* NDEBUG */ 323 | 324 | #if defined(YYCOVERAGE) || !defined(NDEBUG) 325 | /* For tracing shifts, the names of all terminals and nonterminals 326 | ** are required. The following table supplies these names */ 327 | static const char *const yyTokenName[] = { 328 | /* 0 */ "$", 329 | /* 1 */ "JSON_TOK_STRING", 330 | /* 2 */ "JSON_TOK_COL", 331 | /* 3 */ "JSON_TOK_COMMA", 332 | /* 4 */ "JSON_TOK_LBRACK", 333 | /* 5 */ "JSON_TOK_RBRACK", 334 | /* 6 */ "JSON_TOK_LSQB", 335 | /* 7 */ "JSON_TOK_RSQB", 336 | /* 8 */ "JSON_TOK_NUMBER", 337 | /* 9 */ "JSON_TOK_BOOLEAN", 338 | /* 10 */ "JSON_TOK_NONE", 339 | /* 11 */ "error", 340 | /* 12 */ "pair", 341 | /* 13 */ "members", 342 | /* 14 */ "elements", 343 | /* 15 */ "object", 344 | /* 16 */ "array", 345 | /* 17 */ "value", 346 | /* 18 */ "root", 347 | }; 348 | #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ 349 | 350 | #ifndef NDEBUG 351 | /* For tracing reduce actions, the names of all rules are required. 352 | */ 353 | static const char *const yyRuleName[] = { 354 | /* 0 */ "root ::= object", 355 | /* 1 */ "root ::= array", 356 | /* 2 */ "pair ::= JSON_TOK_STRING JSON_TOK_COL value", 357 | /* 3 */ "members ::= pair", 358 | /* 4 */ "members ::= members JSON_TOK_COMMA pair", 359 | /* 5 */ "object ::= JSON_TOK_LBRACK JSON_TOK_RBRACK", 360 | /* 6 */ "object ::= JSON_TOK_LBRACK members JSON_TOK_RBRACK", 361 | /* 7 */ "array ::= JSON_TOK_LSQB JSON_TOK_RSQB", 362 | /* 8 */ "array ::= JSON_TOK_LSQB elements JSON_TOK_RSQB", 363 | /* 9 */ "elements ::= value", 364 | /* 10 */ "elements ::= elements JSON_TOK_COMMA value", 365 | /* 11 */ "value ::= JSON_TOK_STRING", 366 | /* 12 */ "value ::= JSON_TOK_NUMBER", 367 | /* 13 */ "value ::= JSON_TOK_BOOLEAN", 368 | /* 14 */ "value ::= JSON_TOK_NONE", 369 | /* 15 */ "value ::= object", 370 | /* 16 */ "value ::= array", 371 | }; 372 | #endif /* NDEBUG */ 373 | 374 | 375 | #if YYSTACKDEPTH<=0 376 | /* 377 | ** Try to increase the size of the parser stack. Return the number 378 | ** of errors. Return 0 on success. 379 | */ 380 | static int yyGrowStack(yyParser *p){ 381 | int newSize; 382 | int idx; 383 | yyStackEntry *pNew; 384 | 385 | newSize = p->yystksz*2 + 100; 386 | idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; 387 | if( p->yystack==&p->yystk0 ){ 388 | pNew = malloc(newSize*sizeof(pNew[0])); 389 | if( pNew ) pNew[0] = p->yystk0; 390 | }else{ 391 | pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); 392 | } 393 | if( pNew ){ 394 | p->yystack = pNew; 395 | p->yytos = &p->yystack[idx]; 396 | #ifndef NDEBUG 397 | if( yyTraceFILE ){ 398 | fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", 399 | yyTracePrompt, p->yystksz, newSize); 400 | } 401 | #endif 402 | p->yystksz = newSize; 403 | } 404 | return pNew==0; 405 | } 406 | #endif 407 | 408 | /* Datatype of the argument to the memory allocated passed as the 409 | ** second argument to parserAlloc() below. This can be changed by 410 | ** putting an appropriate #define in the %include section of the input 411 | ** grammar. 412 | */ 413 | #ifndef YYMALLOCARGTYPE 414 | # define YYMALLOCARGTYPE size_t 415 | #endif 416 | 417 | /* Initialize a new parser that has already been allocated. 418 | */ 419 | void parserInit(void *yypParser){ 420 | yyParser *pParser = (yyParser*)yypParser; 421 | #ifdef YYTRACKMAXSTACKDEPTH 422 | pParser->yyhwm = 0; 423 | #endif 424 | #if YYSTACKDEPTH<=0 425 | pParser->yytos = NULL; 426 | pParser->yystack = NULL; 427 | pParser->yystksz = 0; 428 | if( yyGrowStack(pParser) ){ 429 | pParser->yystack = &pParser->yystk0; 430 | pParser->yystksz = 1; 431 | } 432 | #endif 433 | #ifndef YYNOERRORRECOVERY 434 | pParser->yyerrcnt = -1; 435 | #endif 436 | pParser->yytos = pParser->yystack; 437 | pParser->yystack[0].stateno = 0; 438 | pParser->yystack[0].major = 0; 439 | #if YYSTACKDEPTH>0 440 | pParser->yystackEnd = &pParser->yystack[YYSTACKDEPTH-1]; 441 | #endif 442 | } 443 | 444 | #ifndef parser_ENGINEALWAYSONSTACK 445 | /* 446 | ** This function allocates a new parser. 447 | ** The only argument is a pointer to a function which works like 448 | ** malloc. 449 | ** 450 | ** Inputs: 451 | ** A pointer to the function used to allocate memory. 452 | ** 453 | ** Outputs: 454 | ** A pointer to a parser. This pointer is used in subsequent calls 455 | ** to parser and parserFree. 456 | */ 457 | void *parserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ 458 | yyParser *pParser; 459 | pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); 460 | if( pParser ) parserInit(pParser); 461 | return pParser; 462 | } 463 | #endif /* parser_ENGINEALWAYSONSTACK */ 464 | 465 | 466 | /* The following function deletes the "minor type" or semantic value 467 | ** associated with a symbol. The symbol can be either a terminal 468 | ** or nonterminal. "yymajor" is the symbol code, and "yypminor" is 469 | ** a pointer to the value to be deleted. The code used to do the 470 | ** deletions is derived from the %destructor and/or %token_destructor 471 | ** directives of the input grammar. 472 | */ 473 | static void yy_destructor( 474 | yyParser *yypParser, /* The parser */ 475 | YYCODETYPE yymajor, /* Type code for object to destroy */ 476 | YYMINORTYPE *yypminor /* The object to be destroyed */ 477 | ){ 478 | parserARG_FETCH; 479 | switch( yymajor ){ 480 | /* Here is inserted the actions which take place when a 481 | ** terminal or non-terminal is destroyed. This can happen 482 | ** when the symbol is popped from the stack during a 483 | ** reduce or during error processing or when a parser is 484 | ** being destroyed before it is finished parsing. 485 | ** 486 | ** Note: during a reduce, the only symbols destroyed are those 487 | ** which appear on the RHS of the rule, but which are *not* used 488 | ** inside the C code. 489 | */ 490 | /********* Begin destructor definitions ***************************************/ 491 | case 12: /* pair */ 492 | { 493 | #line 58 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 494 | json_free((yypminor->yy13).value); 495 | #line 496 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 496 | } 497 | break; 498 | case 13: /* members */ 499 | case 14: /* elements */ 500 | case 15: /* object */ 501 | case 16: /* array */ 502 | case 17: /* value */ 503 | { 504 | #line 59 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 505 | json_free((yypminor->yy14)); 506 | #line 507 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 507 | } 508 | break; 509 | /********* End destructor definitions *****************************************/ 510 | default: break; /* If no destructor action specified: do nothing */ 511 | } 512 | } 513 | 514 | /* 515 | ** Pop the parser's stack once. 516 | ** 517 | ** If there is a destructor routine associated with the token which 518 | ** is popped from the stack, then call it. 519 | */ 520 | static void yy_pop_parser_stack(yyParser *pParser){ 521 | yyStackEntry *yytos; 522 | assert( pParser->yytos!=0 ); 523 | assert( pParser->yytos > pParser->yystack ); 524 | yytos = pParser->yytos--; 525 | #ifndef NDEBUG 526 | if( yyTraceFILE ){ 527 | fprintf(yyTraceFILE,"%sPopping %s\n", 528 | yyTracePrompt, 529 | yyTokenName[yytos->major]); 530 | } 531 | #endif 532 | yy_destructor(pParser, yytos->major, &yytos->minor); 533 | } 534 | 535 | /* 536 | ** Clear all secondary memory allocations from the parser 537 | */ 538 | void parserFinalize(void *p){ 539 | yyParser *pParser = (yyParser*)p; 540 | while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); 541 | #if YYSTACKDEPTH<=0 542 | if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); 543 | #endif 544 | } 545 | 546 | #ifndef parser_ENGINEALWAYSONSTACK 547 | /* 548 | ** Deallocate and destroy a parser. Destructors are called for 549 | ** all stack elements before shutting the parser down. 550 | ** 551 | ** If the YYPARSEFREENEVERNULL macro exists (for example because it 552 | ** is defined in a %include section of the input grammar) then it is 553 | ** assumed that the input pointer is never NULL. 554 | */ 555 | void parserFree( 556 | void *p, /* The parser to be deleted */ 557 | void (*freeProc)(void*) /* Function used to reclaim memory */ 558 | ){ 559 | #ifndef YYPARSEFREENEVERNULL 560 | if( p==0 ) return; 561 | #endif 562 | parserFinalize(p); 563 | (*freeProc)(p); 564 | } 565 | #endif /* parser_ENGINEALWAYSONSTACK */ 566 | 567 | /* 568 | ** Return the peak depth of the stack for a parser. 569 | */ 570 | #ifdef YYTRACKMAXSTACKDEPTH 571 | int parserStackPeak(void *p){ 572 | yyParser *pParser = (yyParser*)p; 573 | return pParser->yyhwm; 574 | } 575 | #endif 576 | 577 | /* This array of booleans keeps track of the parser statement 578 | ** coverage. The element yycoverage[X][Y] is set when the parser 579 | ** is in state X and has a lookahead token Y. In a well-tested 580 | ** systems, every element of this matrix should end up being set. 581 | */ 582 | #if defined(YYCOVERAGE) 583 | static unsigned char yycoverage[YYNSTATE][YYNTOKEN]; 584 | #endif 585 | 586 | /* 587 | ** Write into out a description of every state/lookahead combination that 588 | ** 589 | ** (1) has not been used by the parser, and 590 | ** (2) is not a syntax error. 591 | ** 592 | ** Return the number of missed state/lookahead combinations. 593 | */ 594 | #if defined(YYCOVERAGE) 595 | int parserCoverage(FILE *out){ 596 | int stateno, iLookAhead, i; 597 | int nMissed = 0; 598 | for(stateno=0; statenoyytos->stateno; 624 | 625 | if( stateno>YY_MAX_SHIFT ) return stateno; 626 | assert( stateno <= YY_SHIFT_COUNT ); 627 | #if defined(YYCOVERAGE) 628 | yycoverage[stateno][iLookAhead] = 1; 629 | #endif 630 | do{ 631 | i = yy_shift_ofst[stateno]; 632 | assert( i>=0 && i+YYNTOKEN<=sizeof(yy_lookahead)/sizeof(yy_lookahead[0]) ); 633 | assert( iLookAhead!=YYNOCODE ); 634 | assert( iLookAhead < YYNTOKEN ); 635 | i += iLookAhead; 636 | if( yy_lookahead[i]!=iLookAhead ){ 637 | #ifdef YYFALLBACK 638 | YYCODETYPE iFallback; /* Fallback token */ 639 | if( iLookAhead %s\n", 644 | yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); 645 | } 646 | #endif 647 | assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ 648 | iLookAhead = iFallback; 649 | continue; 650 | } 651 | #endif 652 | #ifdef YYWILDCARD 653 | { 654 | int j = i - iLookAhead + YYWILDCARD; 655 | if( 656 | #if YY_SHIFT_MIN+YYWILDCARD<0 657 | j>=0 && 658 | #endif 659 | #if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT 660 | j0 663 | ){ 664 | #ifndef NDEBUG 665 | if( yyTraceFILE ){ 666 | fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", 667 | yyTracePrompt, yyTokenName[iLookAhead], 668 | yyTokenName[YYWILDCARD]); 669 | } 670 | #endif /* NDEBUG */ 671 | return yy_action[j]; 672 | } 673 | } 674 | #endif /* YYWILDCARD */ 675 | return yy_default[stateno]; 676 | }else{ 677 | return yy_action[i]; 678 | } 679 | }while(1); 680 | } 681 | 682 | /* 683 | ** Find the appropriate action for a parser given the non-terminal 684 | ** look-ahead token iLookAhead. 685 | */ 686 | static int yy_find_reduce_action( 687 | int stateno, /* Current state number */ 688 | YYCODETYPE iLookAhead /* The look-ahead token */ 689 | ){ 690 | int i; 691 | #ifdef YYERRORSYMBOL 692 | if( stateno>YY_REDUCE_COUNT ){ 693 | return yy_default[stateno]; 694 | } 695 | #else 696 | assert( stateno<=YY_REDUCE_COUNT ); 697 | #endif 698 | i = yy_reduce_ofst[stateno]; 699 | assert( iLookAhead!=YYNOCODE ); 700 | i += iLookAhead; 701 | #ifdef YYERRORSYMBOL 702 | if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ 703 | return yy_default[stateno]; 704 | } 705 | #else 706 | assert( i>=0 && iyytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); 723 | /* Here code is inserted which will execute if the parser 724 | ** stack every overflows */ 725 | /******** Begin %stack_overflow code ******************************************/ 726 | /******** End %stack_overflow code ********************************************/ 727 | parserARG_STORE; /* Suppress warning about unused %extra_argument var */ 728 | } 729 | 730 | /* 731 | ** Print tracing information for a SHIFT action 732 | */ 733 | #ifndef NDEBUG 734 | static void yyTraceShift(yyParser *yypParser, int yyNewState, const char *zTag){ 735 | if( yyTraceFILE ){ 736 | if( yyNewStateyytos->major], 739 | yyNewState); 740 | }else{ 741 | fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n", 742 | yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major], 743 | yyNewState - YY_MIN_REDUCE); 744 | } 745 | } 746 | } 747 | #else 748 | # define yyTraceShift(X,Y,Z) 749 | #endif 750 | 751 | /* 752 | ** Perform a shift action. 753 | */ 754 | static void yy_shift( 755 | yyParser *yypParser, /* The parser to be shifted */ 756 | int yyNewState, /* The new state to shift in */ 757 | int yyMajor, /* The major token to shift in */ 758 | parserTOKENTYPE yyMinor /* The minor token to shift in */ 759 | ){ 760 | yyStackEntry *yytos; 761 | yypParser->yytos++; 762 | #ifdef YYTRACKMAXSTACKDEPTH 763 | if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ 764 | yypParser->yyhwm++; 765 | assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); 766 | } 767 | #endif 768 | #if YYSTACKDEPTH>0 769 | if( yypParser->yytos>yypParser->yystackEnd ){ 770 | yypParser->yytos--; 771 | yyStackOverflow(yypParser); 772 | return; 773 | } 774 | #else 775 | if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ 776 | if( yyGrowStack(yypParser) ){ 777 | yypParser->yytos--; 778 | yyStackOverflow(yypParser); 779 | return; 780 | } 781 | } 782 | #endif 783 | if( yyNewState > YY_MAX_SHIFT ){ 784 | yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; 785 | } 786 | yytos = yypParser->yytos; 787 | yytos->stateno = (YYACTIONTYPE)yyNewState; 788 | yytos->major = (YYCODETYPE)yyMajor; 789 | yytos->minor.yy0 = yyMinor; 790 | yyTraceShift(yypParser, yyNewState, "Shift"); 791 | } 792 | 793 | /* The following table contains information about every rule that 794 | ** is used during the reduce. 795 | */ 796 | static const struct { 797 | YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ 798 | signed char nrhs; /* Negative of the number of RHS symbols in the rule */ 799 | } yyRuleInfo[] = { 800 | { 18, -1 }, /* (0) root ::= object */ 801 | { 18, -1 }, /* (1) root ::= array */ 802 | { 12, -3 }, /* (2) pair ::= JSON_TOK_STRING JSON_TOK_COL value */ 803 | { 13, -1 }, /* (3) members ::= pair */ 804 | { 13, -3 }, /* (4) members ::= members JSON_TOK_COMMA pair */ 805 | { 15, -2 }, /* (5) object ::= JSON_TOK_LBRACK JSON_TOK_RBRACK */ 806 | { 15, -3 }, /* (6) object ::= JSON_TOK_LBRACK members JSON_TOK_RBRACK */ 807 | { 16, -2 }, /* (7) array ::= JSON_TOK_LSQB JSON_TOK_RSQB */ 808 | { 16, -3 }, /* (8) array ::= JSON_TOK_LSQB elements JSON_TOK_RSQB */ 809 | { 14, -1 }, /* (9) elements ::= value */ 810 | { 14, -3 }, /* (10) elements ::= elements JSON_TOK_COMMA value */ 811 | { 17, -1 }, /* (11) value ::= JSON_TOK_STRING */ 812 | { 17, -1 }, /* (12) value ::= JSON_TOK_NUMBER */ 813 | { 17, -1 }, /* (13) value ::= JSON_TOK_BOOLEAN */ 814 | { 17, -1 }, /* (14) value ::= JSON_TOK_NONE */ 815 | { 17, -1 }, /* (15) value ::= object */ 816 | { 17, -1 }, /* (16) value ::= array */ 817 | }; 818 | 819 | static void yy_accept(yyParser*); /* Forward Declaration */ 820 | 821 | /* 822 | ** Perform a reduce action and the shift that must immediately 823 | ** follow the reduce. 824 | ** 825 | ** The yyLookahead and yyLookaheadToken parameters provide reduce actions 826 | ** access to the lookahead token (if any). The yyLookahead will be YYNOCODE 827 | ** if the lookahead token has already been consumed. As this procedure is 828 | ** only called from one place, optimizing compilers will in-line it, which 829 | ** means that the extra parameters have no performance impact. 830 | */ 831 | static void yy_reduce( 832 | yyParser *yypParser, /* The parser */ 833 | unsigned int yyruleno, /* Number of the rule by which to reduce */ 834 | int yyLookahead, /* Lookahead token, or YYNOCODE if none */ 835 | parserTOKENTYPE yyLookaheadToken /* Value of the lookahead token */ 836 | ){ 837 | int yygoto; /* The next state */ 838 | int yyact; /* The next action */ 839 | yyStackEntry *yymsp; /* The top of the parser's stack */ 840 | int yysize; /* Amount to pop the stack */ 841 | parserARG_FETCH; 842 | (void)yyLookahead; 843 | (void)yyLookaheadToken; 844 | yymsp = yypParser->yytos; 845 | #ifndef NDEBUG 846 | if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ 847 | yysize = yyRuleInfo[yyruleno].nrhs; 848 | if( yysize ){ 849 | fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n", 850 | yyTracePrompt, 851 | yyruleno, yyRuleName[yyruleno], yymsp[yysize].stateno); 852 | }else{ 853 | fprintf(yyTraceFILE, "%sReduce %d [%s].\n", 854 | yyTracePrompt, yyruleno, yyRuleName[yyruleno]); 855 | } 856 | } 857 | #endif /* NDEBUG */ 858 | 859 | /* Check that the stack is large enough to grow by a single entry 860 | ** if the RHS of the rule is empty. This ensures that there is room 861 | ** enough on the stack to push the LHS value */ 862 | if( yyRuleInfo[yyruleno].nrhs==0 ){ 863 | #ifdef YYTRACKMAXSTACKDEPTH 864 | if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ 865 | yypParser->yyhwm++; 866 | assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); 867 | } 868 | #endif 869 | #if YYSTACKDEPTH>0 870 | if( yypParser->yytos>=yypParser->yystackEnd ){ 871 | yyStackOverflow(yypParser); 872 | return; 873 | } 874 | #else 875 | if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ 876 | if( yyGrowStack(yypParser) ){ 877 | yyStackOverflow(yypParser); 878 | return; 879 | } 880 | yymsp = yypParser->yytos; 881 | } 882 | #endif 883 | } 884 | 885 | switch( yyruleno ){ 886 | /* Beginning here are the reduction cases. A typical example 887 | ** follows: 888 | ** case 0: 889 | ** #line 890 | ** { ... } // User supplied code 891 | ** #line 892 | ** break; 893 | */ 894 | /********** Begin reduce actions **********************************************/ 895 | YYMINORTYPE yylhsminor; 896 | case 0: /* root ::= object */ 897 | case 1: /* root ::= array */ yytestcase(yyruleno==1); 898 | #line 69 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 899 | { pret->root = yymsp[0].minor.yy14; } 900 | #line 901 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 901 | break; 902 | case 2: /* pair ::= JSON_TOK_STRING JSON_TOK_COL value */ 903 | #line 72 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 904 | { yylhsminor.yy13 = json_pair(yymsp[-2].minor.yy0, yymsp[0].minor.yy14); } 905 | #line 906 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 906 | yymsp[-2].minor.yy13 = yylhsminor.yy13; 907 | break; 908 | case 3: /* members ::= pair */ 909 | #line 74 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 910 | { yylhsminor.yy14 = json_object(); json_add_pair(yymsp[0].minor.yy13, yylhsminor.yy14); } 911 | #line 912 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 912 | yymsp[0].minor.yy14 = yylhsminor.yy14; 913 | break; 914 | case 4: /* members ::= members JSON_TOK_COMMA pair */ 915 | #line 75 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 916 | { yylhsminor.yy14 = json_add_pair(yymsp[0].minor.yy13, yymsp[-2].minor.yy14); } 917 | #line 918 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 918 | yymsp[-2].minor.yy14 = yylhsminor.yy14; 919 | break; 920 | case 5: /* object ::= JSON_TOK_LBRACK JSON_TOK_RBRACK */ 921 | #line 77 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 922 | { yymsp[-1].minor.yy14 = json_object(); } 923 | #line 924 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 924 | break; 925 | case 6: /* object ::= JSON_TOK_LBRACK members JSON_TOK_RBRACK */ 926 | case 8: /* array ::= JSON_TOK_LSQB elements JSON_TOK_RSQB */ yytestcase(yyruleno==8); 927 | #line 78 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 928 | { yymsp[-2].minor.yy14 = yymsp[-1].minor.yy14; } 929 | #line 930 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 930 | break; 931 | case 7: /* array ::= JSON_TOK_LSQB JSON_TOK_RSQB */ 932 | #line 80 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 933 | { yymsp[-1].minor.yy14 = json_array(); } 934 | #line 935 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 935 | break; 936 | case 9: /* elements ::= value */ 937 | #line 83 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 938 | { yylhsminor.yy14 = json_array(); json_add_element(yymsp[0].minor.yy14, yylhsminor.yy14); } 939 | #line 940 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 940 | yymsp[0].minor.yy14 = yylhsminor.yy14; 941 | break; 942 | case 10: /* elements ::= elements JSON_TOK_COMMA value */ 943 | #line 84 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 944 | { yylhsminor.yy14 = json_add_element(yymsp[0].minor.yy14, yymsp[-2].minor.yy14); } 945 | #line 946 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 946 | yymsp[-2].minor.yy14 = yylhsminor.yy14; 947 | break; 948 | case 11: /* value ::= JSON_TOK_STRING */ 949 | #line 86 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 950 | { yylhsminor.yy14 = json_string(yymsp[0].minor.yy0.string); } 951 | #line 952 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 952 | yymsp[0].minor.yy14 = yylhsminor.yy14; 953 | break; 954 | case 12: /* value ::= JSON_TOK_NUMBER */ 955 | #line 87 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 956 | { yylhsminor.yy14 = json_number(yymsp[0].minor.yy0.number); } 957 | #line 958 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 958 | yymsp[0].minor.yy14 = yylhsminor.yy14; 959 | break; 960 | case 13: /* value ::= JSON_TOK_BOOLEAN */ 961 | #line 88 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 962 | { yylhsminor.yy14 = json_boolean(yymsp[0].minor.yy0.boolean); } 963 | #line 964 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 964 | yymsp[0].minor.yy14 = yylhsminor.yy14; 965 | break; 966 | case 14: /* value ::= JSON_TOK_NONE */ 967 | #line 89 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 968 | { yymsp[0].minor.yy14 = json_none(); } 969 | #line 970 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 970 | break; 971 | case 15: /* value ::= object */ 972 | case 16: /* value ::= array */ yytestcase(yyruleno==16); 973 | #line 90 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 974 | { yylhsminor.yy14 = yymsp[0].minor.yy14; } 975 | #line 976 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 976 | yymsp[0].minor.yy14 = yylhsminor.yy14; 977 | break; 978 | default: 979 | break; 980 | /********** End reduce actions ************************************************/ 981 | }; 982 | assert( yyrulenoYY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) ); 990 | 991 | /* It is not possible for a REDUCE to be followed by an error */ 992 | assert( yyact!=YY_ERROR_ACTION ); 993 | 994 | yymsp += yysize+1; 995 | yypParser->yytos = yymsp; 996 | yymsp->stateno = (YYACTIONTYPE)yyact; 997 | yymsp->major = (YYCODETYPE)yygoto; 998 | yyTraceShift(yypParser, yyact, "... then shift"); 999 | } 1000 | 1001 | /* 1002 | ** The following code executes when the parse fails 1003 | */ 1004 | #ifndef YYNOERRORRECOVERY 1005 | static void yy_parse_failed( 1006 | yyParser *yypParser /* The parser */ 1007 | ){ 1008 | parserARG_FETCH; 1009 | #ifndef NDEBUG 1010 | if( yyTraceFILE ){ 1011 | fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); 1012 | } 1013 | #endif 1014 | while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); 1015 | /* Here code is inserted which will be executed whenever the 1016 | ** parser fails */ 1017 | /************ Begin %parse_failure code ***************************************/ 1018 | #line 41 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 1019 | 1020 | pret->error_code = 2; 1021 | #line 1022 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 1022 | /************ End %parse_failure code *****************************************/ 1023 | parserARG_STORE; /* Suppress warning about unused %extra_argument variable */ 1024 | } 1025 | #endif /* YYNOERRORRECOVERY */ 1026 | 1027 | /* 1028 | ** The following code executes when a syntax error first occurs. 1029 | */ 1030 | static void yy_syntax_error( 1031 | yyParser *yypParser, /* The parser */ 1032 | int yymajor, /* The major type of the error token */ 1033 | parserTOKENTYPE yyminor /* The minor type of the error token */ 1034 | ){ 1035 | parserARG_FETCH; 1036 | #define TOKEN yyminor 1037 | /************ Begin %syntax_error code ****************************************/ 1038 | #line 45 "/home/wael/projects/rl-json-parser/json-parser/parser.y" 1039 | 1040 | pret->error_code = 1; 1041 | #line 1042 "/home/wael/projects/rl-json-parser/json-parser/parser.c" 1042 | /************ End %syntax_error code ******************************************/ 1043 | parserARG_STORE; /* Suppress warning about unused %extra_argument variable */ 1044 | } 1045 | 1046 | /* 1047 | ** The following is executed when the parser accepts 1048 | */ 1049 | static void yy_accept( 1050 | yyParser *yypParser /* The parser */ 1051 | ){ 1052 | parserARG_FETCH; 1053 | #ifndef NDEBUG 1054 | if( yyTraceFILE ){ 1055 | fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); 1056 | } 1057 | #endif 1058 | #ifndef YYNOERRORRECOVERY 1059 | yypParser->yyerrcnt = -1; 1060 | #endif 1061 | assert( yypParser->yytos==yypParser->yystack ); 1062 | /* Here code is inserted which will be executed whenever the 1063 | ** parser accepts */ 1064 | /*********** Begin %parse_accept code *****************************************/ 1065 | /*********** End %parse_accept code *******************************************/ 1066 | parserARG_STORE; /* Suppress warning about unused %extra_argument variable */ 1067 | } 1068 | 1069 | /* The main parser program. 1070 | ** The first argument is a pointer to a structure obtained from 1071 | ** "parserAlloc" which describes the current state of the parser. 1072 | ** The second argument is the major token number. The third is 1073 | ** the minor token. The fourth optional argument is whatever the 1074 | ** user wants (and specified in the grammar) and is available for 1075 | ** use by the action routines. 1076 | ** 1077 | ** Inputs: 1078 | **
    1079 | **
  • A pointer to the parser (an opaque structure.) 1080 | **
  • The major token number. 1081 | **
  • The minor token number. 1082 | **
  • An option argument of a grammar-specified type. 1083 | **
1084 | ** 1085 | ** Outputs: 1086 | ** None. 1087 | */ 1088 | void parser( 1089 | void *yyp, /* The parser */ 1090 | int yymajor, /* The major token code number */ 1091 | parserTOKENTYPE yyminor /* The value for the token */ 1092 | parserARG_PDECL /* Optional %extra_argument parameter */ 1093 | ){ 1094 | YYMINORTYPE yyminorunion; 1095 | unsigned int yyact; /* The parser action. */ 1096 | #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) 1097 | int yyendofinput; /* True if we are at the end of input */ 1098 | #endif 1099 | #ifdef YYERRORSYMBOL 1100 | int yyerrorhit = 0; /* True if yymajor has invoked an error */ 1101 | #endif 1102 | yyParser *yypParser; /* The parser */ 1103 | 1104 | yypParser = (yyParser*)yyp; 1105 | assert( yypParser->yytos!=0 ); 1106 | #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) 1107 | yyendofinput = (yymajor==0); 1108 | #endif 1109 | parserARG_STORE; 1110 | 1111 | #ifndef NDEBUG 1112 | if( yyTraceFILE ){ 1113 | int stateno = yypParser->yytos->stateno; 1114 | if( stateno < YY_MIN_REDUCE ){ 1115 | fprintf(yyTraceFILE,"%sInput '%s' in state %d\n", 1116 | yyTracePrompt,yyTokenName[yymajor],stateno); 1117 | }else{ 1118 | fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n", 1119 | yyTracePrompt,yyTokenName[yymajor],stateno-YY_MIN_REDUCE); 1120 | } 1121 | } 1122 | #endif 1123 | 1124 | do{ 1125 | yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); 1126 | if( yyact >= YY_MIN_REDUCE ){ 1127 | yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor,yyminor); 1128 | }else if( yyact <= YY_MAX_SHIFTREDUCE ){ 1129 | yy_shift(yypParser,yyact,yymajor,yyminor); 1130 | #ifndef YYNOERRORRECOVERY 1131 | yypParser->yyerrcnt--; 1132 | #endif 1133 | yymajor = YYNOCODE; 1134 | }else if( yyact==YY_ACCEPT_ACTION ){ 1135 | yypParser->yytos--; 1136 | yy_accept(yypParser); 1137 | return; 1138 | }else{ 1139 | assert( yyact == YY_ERROR_ACTION ); 1140 | yyminorunion.yy0 = yyminor; 1141 | #ifdef YYERRORSYMBOL 1142 | int yymx; 1143 | #endif 1144 | #ifndef NDEBUG 1145 | if( yyTraceFILE ){ 1146 | fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); 1147 | } 1148 | #endif 1149 | #ifdef YYERRORSYMBOL 1150 | /* A syntax error has occurred. 1151 | ** The response to an error depends upon whether or not the 1152 | ** grammar defines an error token "ERROR". 1153 | ** 1154 | ** This is what we do if the grammar does define ERROR: 1155 | ** 1156 | ** * Call the %syntax_error function. 1157 | ** 1158 | ** * Begin popping the stack until we enter a state where 1159 | ** it is legal to shift the error symbol, then shift 1160 | ** the error symbol. 1161 | ** 1162 | ** * Set the error count to three. 1163 | ** 1164 | ** * Begin accepting and shifting new tokens. No new error 1165 | ** processing will occur until three tokens have been 1166 | ** shifted successfully. 1167 | ** 1168 | */ 1169 | if( yypParser->yyerrcnt<0 ){ 1170 | yy_syntax_error(yypParser,yymajor,yyminor); 1171 | } 1172 | yymx = yypParser->yytos->major; 1173 | if( yymx==YYERRORSYMBOL || yyerrorhit ){ 1174 | #ifndef NDEBUG 1175 | if( yyTraceFILE ){ 1176 | fprintf(yyTraceFILE,"%sDiscard input token %s\n", 1177 | yyTracePrompt,yyTokenName[yymajor]); 1178 | } 1179 | #endif 1180 | yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); 1181 | yymajor = YYNOCODE; 1182 | }else{ 1183 | while( yypParser->yytos >= yypParser->yystack 1184 | && yymx != YYERRORSYMBOL 1185 | && (yyact = yy_find_reduce_action( 1186 | yypParser->yytos->stateno, 1187 | YYERRORSYMBOL)) >= YY_MIN_REDUCE 1188 | ){ 1189 | yy_pop_parser_stack(yypParser); 1190 | } 1191 | if( yypParser->yytos < yypParser->yystack || yymajor==0 ){ 1192 | yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); 1193 | yy_parse_failed(yypParser); 1194 | #ifndef YYNOERRORRECOVERY 1195 | yypParser->yyerrcnt = -1; 1196 | #endif 1197 | yymajor = YYNOCODE; 1198 | }else if( yymx!=YYERRORSYMBOL ){ 1199 | yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); 1200 | } 1201 | } 1202 | yypParser->yyerrcnt = 3; 1203 | yyerrorhit = 1; 1204 | #elif defined(YYNOERRORRECOVERY) 1205 | /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to 1206 | ** do any kind of error recovery. Instead, simply invoke the syntax 1207 | ** error routine and continue going as if nothing had happened. 1208 | ** 1209 | ** Applications can set this macro (for example inside %include) if 1210 | ** they intend to abandon the parse upon the first syntax error seen. 1211 | */ 1212 | yy_syntax_error(yypParser,yymajor, yyminor); 1213 | yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); 1214 | yymajor = YYNOCODE; 1215 | 1216 | #else /* YYERRORSYMBOL is not defined */ 1217 | /* This is what we do if the grammar does not define ERROR: 1218 | ** 1219 | ** * Report an error message, and throw away the input token. 1220 | ** 1221 | ** * If the input token is $, then fail the parse. 1222 | ** 1223 | ** As before, subsequent error messages are suppressed until 1224 | ** three input tokens have been successfully shifted. 1225 | */ 1226 | if( yypParser->yyerrcnt<=0 ){ 1227 | yy_syntax_error(yypParser,yymajor, yyminor); 1228 | } 1229 | yypParser->yyerrcnt = 3; 1230 | yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); 1231 | if( yyendofinput ){ 1232 | yy_parse_failed(yypParser); 1233 | #ifndef YYNOERRORRECOVERY 1234 | yypParser->yyerrcnt = -1; 1235 | #endif 1236 | } 1237 | yymajor = YYNOCODE; 1238 | #endif 1239 | } 1240 | }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack ); 1241 | #ifndef NDEBUG 1242 | if( yyTraceFILE ){ 1243 | yyStackEntry *i; 1244 | char cDiv = '['; 1245 | fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); 1246 | for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ 1247 | fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); 1248 | cDiv = ' '; 1249 | } 1250 | fprintf(yyTraceFILE,"]\n"); 1251 | } 1252 | #endif 1253 | return; 1254 | } 1255 | --------------------------------------------------------------------------------