├── 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 |  as Lexer generator
18 |
19 |  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 |
--------------------------------------------------------------------------------