75c33407586d39864d597a75d368a0bd8993cebc
[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 <stdio.h>
19 #include <stdlib.h>
20 #include <stdarg.h>
21 #include <string.h>
22
23 #include <libubox/utils.h>
24
25 #include "parser.h"
26
27 static struct jp_opcode *append_op(struct jp_opcode *a, struct jp_opcode *b);
28
29 int yylex(struct jp_state *s);
30 void *yy_scan_string (const char *str);
31 int yylex_destroy(void);
32
33 int yyparse(struct jp_state *s);
34 void yyerror(struct jp_state *s, const char *msg);
35
36 %}
37
38 %output "parser.c"
39 %defines "parser.h"
40
41 %parse-param { struct jp_state *s }
42 %lex-param { struct jp_state *s }
43
44 %code requires {
45
46 #ifndef __PARSER_H_
47 #define __PARSER_H_
48
49 struct jp_opcode {
50 int type;
51 struct jp_opcode *next;
52 struct jp_opcode *down;
53 struct jp_opcode *sibling;
54 char *str;
55 int num;
56 };
57
58 struct jp_state {
59 struct jp_opcode *pool;
60 struct jp_opcode *path;
61 const char *error;
62 char str_quote;
63 char str_buf[128];
64 char *str_ptr;
65 };
66
67 struct jp_opcode *_jp_alloc_op(struct jp_state *s, int type, int num, char *str, ...);
68 #define jp_alloc_op(type, num, str, ...) _jp_alloc_op(s, type, num, str, ##__VA_ARGS__, NULL)
69
70 struct jp_state *jp_parse(const char *expr);
71 void jp_free(struct jp_state *s);
72
73 #endif
74
75 }
76
77 %union {
78 struct jp_opcode *op;
79 }
80
81
82 %token T_ROOT T_THIS T_DOT T_BROPEN T_BRCLOSE
83 %token T_OR T_AND T_LT T_LE T_GT T_GE T_EQ T_NE T_POPEN T_PCLOSE T_NOT
84
85 %token <op> T_BOOL T_NUMBER T_STRING T_LABEL T_WILDCARD
86
87 %type <op> expr path segments segment or_exps or_exp and_exps and_exp cmp_exp unary_exp
88
89 %error-verbose
90
91 %%
92
93 input
94 : expr { s->path = $1; }
95 ;
96
97 expr
98 : T_LABEL T_EQ path { $1->down = $3; $$ = $1; }
99 | path { $$ = $1; }
100 ;
101
102 path
103 : T_ROOT segments { $$ = jp_alloc_op(T_ROOT, 0, NULL, $2); }
104 | T_THIS segments { $$ = jp_alloc_op(T_THIS, 0, NULL, $2); }
105 ;
106
107 segments
108 : segments segment { $$ = append_op($1, $2); }
109 | segment { $$ = $1; }
110 ;
111
112 segment
113 : T_DOT T_LABEL { $$ = $2; }
114 | T_DOT T_WILDCARD { $$ = $2; }
115 | T_BROPEN or_exps T_BRCLOSE { $$ = $2; }
116 ;
117
118 or_exps
119 : or_exp { $$ = $1->sibling ? jp_alloc_op(T_OR, 0, NULL, $1) : $1; }
120 ;
121
122 or_exp
123 : or_exp T_OR and_exps { $$ = append_op($1, $3); }
124 | and_exps { $$ = $1; }
125 ;
126
127 and_exps
128 : and_exp { $$ = $1->sibling ? jp_alloc_op(T_AND, 0, NULL, $1) : $1; }
129 ;
130
131 and_exp
132 : and_exp T_AND cmp_exp { $$ = append_op($1, $3); }
133 | cmp_exp { $$ = $1; }
134 ;
135
136 cmp_exp
137 : unary_exp T_LT unary_exp { $$ = jp_alloc_op(T_LT, 0, NULL, $1, $3); }
138 | unary_exp T_LE unary_exp { $$ = jp_alloc_op(T_LE, 0, NULL, $1, $3); }
139 | unary_exp T_GT unary_exp { $$ = jp_alloc_op(T_GT, 0, NULL, $1, $3); }
140 | unary_exp T_GE unary_exp { $$ = jp_alloc_op(T_GE, 0, NULL, $1, $3); }
141 | unary_exp T_EQ unary_exp { $$ = jp_alloc_op(T_EQ, 0, NULL, $1, $3); }
142 | unary_exp T_NE unary_exp { $$ = jp_alloc_op(T_NE, 0, NULL, $1, $3); }
143 | unary_exp { $$ = $1; }
144 ;
145
146 unary_exp
147 : T_BOOL { $$ = $1; }
148 | T_NUMBER { $$ = $1; }
149 | T_STRING { $$ = $1; }
150 | T_WILDCARD { $$ = $1; }
151 | T_POPEN or_exps T_PCLOSE { $$ = $2; }
152 | T_NOT unary_exp { $$ = jp_alloc_op(T_NOT, 0, NULL, $2); }
153 | path { $$ = $1; }
154 ;
155
156 %%
157
158 void
159 yyerror(struct jp_state *s, const char *msg)
160 {
161 s->error = msg;
162 }
163
164 static struct jp_opcode *
165 append_op(struct jp_opcode *a, struct jp_opcode *b)
166 {
167 struct jp_opcode *tail = a;
168
169 while (tail->sibling)
170 tail = tail->sibling;
171
172 tail->sibling = b;
173
174 return a;
175 }
176
177 struct jp_opcode *
178 _jp_alloc_op(struct jp_state *s, int type, int num, char *str, ...)
179 {
180 va_list ap;
181 char *ptr;
182 struct jp_opcode *newop, *child;
183
184 newop = calloc_a(sizeof(*newop),
185 str ? &ptr : NULL, str ? strlen(str) + 1 : 0);
186
187 if (!newop)
188 {
189 fprintf(stderr, "Out of memory\n");
190 exit(127);
191 }
192
193 newop->type = type;
194 newop->num = num;
195
196 if (str)
197 newop->str = strcpy(ptr, str);
198
199 va_start(ap, str);
200
201 while ((child = va_arg(ap, void *)) != NULL)
202 if (!newop->down)
203 newop->down = child;
204 else
205 append_op(newop->down, child);
206
207 va_end(ap);
208
209 newop->next = s->pool;
210 s->pool = newop;
211
212 return newop;
213 }
214
215 struct jp_state *
216 jp_parse(const char *expr)
217 {
218 struct jp_state *s;
219
220 s = calloc(1, sizeof(*s));
221
222 if (!s)
223 return NULL;
224
225 yy_scan_string(expr);
226
227 if (yyparse(s))
228 s->path = NULL;
229
230 yylex_destroy();
231
232 return s;
233 }
234
235 void
236 jp_free(struct jp_state *s)
237 {
238 struct jp_opcode *op, *tmp;
239
240 for (op = s->pool; op;)
241 {
242 tmp = op->next;
243 free(op);
244 op = tmp;
245 }
246
247 free(s);
248 }