Initial commit
[project/jsonpath.git] / parser.y
1 %{
2 /*
3  * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include <stdarg.h>
19 #include <libubox/utils.h>
20
21 #include "lexer.h"
22 #include "parser.h"
23
24 static struct jp_opcode *op_pool = NULL;
25 static struct jp_opcode *append_op(struct jp_opcode *a, struct jp_opcode *b);
26
27 int yyparse(struct jp_opcode **tree, const char **error);
28 void yyerror(struct jp_opcode **expr, const char **error, const char *msg);
29
30 %}
31
32 %output  "parser.c"
33 %defines "parser.h"
34
35 %parse-param { struct jp_opcode **expr }
36 %parse-param { const char **error }
37
38 %code provides {
39
40 #ifndef JP_OPCODE
41 # define JP_OPCODE
42         struct jp_opcode {
43                 int type;
44                 struct jp_opcode *next;
45                 struct jp_opcode *down;
46                 struct jp_opcode *sibling;
47                 char *str;
48                 int num;
49         };
50 #endif
51
52 struct jp_opcode *_jp_alloc_op(int type, int num, char *str, ...);
53 #define jp_alloc_op(type, num, str, ...) _jp_alloc_op(type, num, str, ##__VA_ARGS__, NULL)
54
55 struct jp_opcode *jp_parse(const char *expr, const char **error);
56 void jp_free(void);
57
58 }
59
60 %union {
61         struct jp_opcode *op;
62 }
63
64
65 %token T_ROOT T_THIS T_DOT T_BROPEN T_BRCLOSE
66 %token T_OR T_AND T_LT T_LE T_GT T_GE T_EQ T_NE T_POPEN T_PCLOSE T_NOT
67
68 %token <op> T_BOOL T_NUMBER T_STRING T_LABEL T_WILDCARD
69
70 %type <op> expr path segments segment or_exps or_exp and_exps and_exp cmp_exp unary_exp
71
72 %error-verbose
73
74 %%
75
76 input
77         : expr                                                  { *expr = $1; }
78         ;
79
80 expr
81         : T_LABEL T_EQ path                             { $1->down = $3; $$ = $1; }
82         | path                                                  { $$ = $1; }
83         ;
84
85 path
86         : T_ROOT segments                               { $$ = jp_alloc_op(T_ROOT, 0, NULL, $2); }
87         | T_THIS segments                               { $$ = jp_alloc_op(T_THIS, 0, NULL, $2); }
88         ;
89
90 segments
91         : segments segment                              { $$ = append_op($1, $2); }
92         | segment                                               { $$ = $1; }
93         ;
94
95 segment
96         : T_DOT T_LABEL                                 { $$ = $2; }
97         | T_DOT T_WILDCARD                              { $$ = $2; }
98         | T_BROPEN or_exps T_BRCLOSE    { $$ = $2; }
99         ;
100
101 or_exps
102         : or_exp                                                { $$ = $1->sibling ? jp_alloc_op(T_OR, 0, NULL, $1) : $1; }
103         ;
104
105 or_exp
106         : or_exp T_OR and_exps                  { $$ = append_op($1, $3); }
107         | and_exps                                              { $$ = $1; }
108         ;
109
110 and_exps
111         : and_exp                                               { $$ = $1->sibling ? jp_alloc_op(T_AND, 0, NULL, $1) : $1; }
112         ;
113
114 and_exp
115         : and_exp T_AND cmp_exp                 { $$ = append_op($1, $3); }
116         | cmp_exp                                               { $$ = $1; }
117         ;
118
119 cmp_exp
120         : unary_exp T_LT unary_exp              { $$ = jp_alloc_op(T_LT, 0, NULL, $1, $3); }
121         | unary_exp T_LE unary_exp              { $$ = jp_alloc_op(T_LE, 0, NULL, $1, $3); }
122         | unary_exp T_GT unary_exp              { $$ = jp_alloc_op(T_GT, 0, NULL, $1, $3); }
123         | unary_exp T_GE unary_exp              { $$ = jp_alloc_op(T_GE, 0, NULL, $1, $3); }
124         | unary_exp T_EQ unary_exp              { $$ = jp_alloc_op(T_EQ, 0, NULL, $1, $3); }
125         | unary_exp T_NE unary_exp              { $$ = jp_alloc_op(T_NE, 0, NULL, $1, $3); }
126         | unary_exp                                             { $$ = $1; }
127         ;
128
129 unary_exp
130         : T_BOOL                                                { $$ = $1; }
131         | T_NUMBER                                              { $$ = $1; }
132         | T_STRING                                              { $$ = $1; }
133         | T_WILDCARD                                    { $$ = $1; }
134         | T_POPEN or_exps T_PCLOSE              { $$ = $2; }
135         | T_NOT unary_exp                               { $$ = jp_alloc_op(T_NOT, 0, NULL, $2); }
136         | path                                                  { $$ = $1; }
137         ;
138
139 %%
140
141 void
142 yyerror(struct jp_opcode **expr, const char **error, const char *msg)
143 {
144         *error = msg;
145         jp_free();
146 }
147
148 static struct jp_opcode *
149 append_op(struct jp_opcode *a, struct jp_opcode *b)
150 {
151         struct jp_opcode *tail = a;
152
153         while (tail->sibling)
154                 tail = tail->sibling;
155
156         tail->sibling = b;
157
158         return a;
159 }
160
161 struct jp_opcode *
162 _jp_alloc_op(int type, int num, char *str, ...)
163 {
164         va_list ap;
165         char *ptr;
166         struct jp_opcode *newop, *child;
167
168         newop = calloc_a(sizeof(*newop),
169                          str ? &ptr : NULL, str ? strlen(str) + 1 : 0);
170
171         if (!newop)
172         {
173                 fprintf(stderr, "Out of memory\n");
174                 exit(1);
175         }
176
177         newop->type = type;
178         newop->num = num;
179
180         if (str)
181                 newop->str = strcpy(ptr, str);
182
183         va_start(ap, str);
184
185         while ((child = va_arg(ap, void *)) != NULL)
186                 if (!newop->down)
187                         newop->down = child;
188                 else
189                         append_op(newop->down, child);
190
191         va_end(ap);
192
193         newop->next = op_pool;
194         op_pool = newop;
195
196         return newop;
197 }
198
199 struct jp_opcode *
200 jp_parse(const char *expr, const char **error)
201 {
202         void *buf;
203         struct jp_opcode *tree;
204
205         buf = yy_scan_string(expr);
206
207         if (yyparse(&tree, error))
208                 tree = NULL;
209         else
210                 *error = NULL;
211
212         yy_delete_buffer(buf);
213         yylex_destroy();
214
215         return tree;
216 }
217
218 void
219 jp_free(void)
220 {
221         struct jp_opcode *op, *tmp;
222
223         for (op = op_pool; op;)
224         {
225                 tmp = op->next;
226                 free(op);
227                 op = tmp;
228         }
229
230         op_pool = NULL;
231 }