/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following functions.
- yyparse
- filtererror
- yyerror
- syntax_error
- yywrap
- yy_input
- main
1 %{
2 /*
3 filename: filter.y
4
5 description:
6 Defines the grammar for an RPSL filter attribute. It was mostly
7 stolen from the IRRToolSet, simplified by removing ability to parse
8 things defined by a dictionary (we use XML for extensibility rather
9 than a dictionary).
10
11 notes:
12 Defines tokens for the associated lexer, filter.l.
13 */
14 %}
15
16 %union {
17 char *sval;
18 }
19
20 %token OP_OR OP_AND OP_NOT OP_MS OP_EQUAL OP_APPEND OP_COMPARE
21 %token KEYW_ANY KEYW_PEERAS
22 %token KEYW_IGP_COST KEYW_PREPEND KEYW_APPEND KEYW_DELETE KEYW_CONTAINS
23 %token KEYW_INTERNET KEYW_NO_EXPORT KEYW_NO_ADVERTISE KEYW_SELF
24 %token ASPATH_POSTFIX
25 %token TKN_FLTRNAME TKN_ASNO TKN_RSNAME TKN_ASNAME TKN_PRFXV4 TKN_PRFXV4RNG
26 %token TKN_PREF TKN_MED TKN_DPA TKN_ASPATH TKN_COMMUNITY
27 %token TKN_COMM_NO TKN_NEXT_HOP TKN_IPV4 TKN_COST
28 %token <sval> TKN_INT
29
30 %{
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include <stdlib.h>
34
35 int yyerror(const char *s);
36
37 /* defines for unit testing */
38 #ifdef UNIT_TEST
39 int main();
40 #endif /* UNIT_TEST */
41 %}
42
43 %%
/* [<][>][^][v][top][bottom][index][help] */
44
45 filter: filter OP_OR filter_term
46 | filter filter_term %prec OP_OR
47 | filter_term
48 ;
49
50 filter_term : filter_term OP_AND filter_factor
51 | filter_factor
52 ;
53
54 filter_factor : OP_NOT filter_factor
55 | '(' filter ')'
56 | filter_operand
57 ;
58
59 filter_operand: KEYW_ANY
60 | '<' filter_aspath '>'
61 | rp_attribute
62 | TKN_FLTRNAME
63 | filter_prefix
64 ;
65
66 filter_prefix: filter_prefix_operand OP_MS
67 | filter_prefix_operand
68 ;
69
70 filter_prefix_operand: TKN_ASNO
71 | KEYW_PEERAS
72 | TKN_ASNAME
73 | TKN_RSNAME
74 | '{' opt_filter_prefix_list '}'
75 ;
76
77 opt_filter_prefix_list:
78 | filter_prefix_list
79 ;
80
81 filter_prefix_list: filter_prefix_list_prefix
82 | filter_prefix_list ',' filter_prefix_list_prefix
83 ;
84
85 filter_prefix_list_prefix: TKN_PRFXV4
86 | TKN_PRFXV4RNG
87 ;
88
89 filter_aspath: filter_aspath '|' filter_aspath_term
90 | filter_aspath_term
91 ;
92
93 filter_aspath_term: filter_aspath_term filter_aspath_closure
94 | filter_aspath_closure
95 ;
96
97 filter_aspath_closure: filter_aspath_closure '*'
98 | filter_aspath_closure '?'
99 | filter_aspath_closure '+'
100 | filter_aspath_closure ASPATH_POSTFIX
101 | filter_aspath_factor
102 ;
103
104 filter_aspath_factor: '^'
105 | '$'
106 | '(' filter_aspath ')'
107 | filter_aspath_no
108 ;
109
110 filter_aspath_no: TKN_ASNO
111 | KEYW_PEERAS
112 | TKN_ASNAME
113 | '.'
114 | '[' filter_aspath_range ']'
115 | '[' '^' filter_aspath_range ']'
116 ;
117
118 filter_aspath_range:
119 | filter_aspath_range TKN_ASNO
120 | filter_aspath_range KEYW_PEERAS
121 | filter_aspath_range '.'
122 | filter_aspath_range TKN_ASNO '-' TKN_ASNO
123 | filter_aspath_range TKN_ASNAME
124 ;
125
126 action: rp_attribute ';'
127 | action rp_attribute ';'
128 ;
129
130 rp_attribute: pref
131 | med
132 | dpa
133 | aspath
134 | community
135 | next_hop
136 | cost
137 ;
138
139 pref: TKN_PREF OP_EQUAL TKN_INT {
140 long int val;
141 char *s, *p;
142 p = $3;
143 val = strtol(p, &s, 10);
144 if ((val < 0) || (val > 65535)) {
145 syntax_error("pref value \"%s\" is not between 0 and 65535", p);
146 }
147 }
148 ;
149
150 med: TKN_MED OP_EQUAL TKN_INT {
151 long int val;
152 char *s, *p;
153 p = $3;
154 val = strtol(p, &s, 10);
155 if ((val < 0) || (val > 65535)) {
156 syntax_error("med value \"%s\" is not between 0 and 65535", p);
157 }
158 }
159 | TKN_MED OP_EQUAL KEYW_IGP_COST
160 ;
161
162 dpa: TKN_DPA OP_EQUAL TKN_INT {
163 long int val;
164 char *s, *p;
165 p = $3;
166 val = strtol(p, &s, 10);
167 if ((val < 0) || (val > 65535)) {
168 syntax_error("dpa value \"%s\" is not between 0 and 65535", p);
169 }
170 }
171 ;
172
173 aspath: TKN_ASPATH '.' KEYW_PREPEND '(' asno_list ')'
174 ;
175
176 asno_list: TKN_ASNO
177 | asno_list ',' TKN_ASNO
178 ;
179
180 community: TKN_COMMUNITY OP_EQUAL community_list
181 | TKN_COMMUNITY OP_APPEND community_list
182 | TKN_COMMUNITY '.' KEYW_APPEND '(' community_elm_list ')'
183 | TKN_COMMUNITY '.' KEYW_DELETE '(' community_elm_list ')'
184 | TKN_COMMUNITY '.' KEYW_CONTAINS '(' community_elm_list ')'
185 | TKN_COMMUNITY '(' community_elm_list ')'
186 | TKN_COMMUNITY OP_COMPARE community_list
187 ;
188
189 community_list: '{' community_elm_list '}'
190 ;
191
192 community_elm_list: community_elm
193 | community_elm_list ',' community_elm
194 ;
195
196 community_elm: KEYW_INTERNET
197 | KEYW_NO_EXPORT
198 | KEYW_NO_ADVERTISE
199 | TKN_INT {
200 unsigned long int val;
201 char *s, *p;
202 p = $1;
203 val = strtoul(p, &s, 10);
204 if ((val < 1) || (val > 4294967295UL) || (*s != '\0')) {
205 syntax_error("community element \"%s\" is not between 1 and 4294967295",
206 p);
207 }
208 }
209 | TKN_COMM_NO
210 ;
211
212 next_hop: TKN_NEXT_HOP OP_EQUAL TKN_IPV4
213 | TKN_NEXT_HOP OP_EQUAL KEYW_SELF
214 ;
215
216 cost: TKN_COST OP_EQUAL TKN_INT {
217 long int val;
218 char *s, *p;
219 p = $3;
220 val = strtol(p, &s, 10);
221 if ((val < 0) || (val > 65535)) {
222 syntax_error("cost value \"%s\" is not between 0 and 65535", p);
223 }
224 }
225 ;
226
227
228 %%
229
230 /* define a unit test that simply returns "yes" or "no" for filter input */
231 #ifndef UNIT_TEST
232
233 #undef filtererror
234 #undef yyerror
235
236 int
237 filtererror (const char *s)
/* [<][>][^][v][top][bottom][index][help] */
238 {
239 yyerror(s);
240 return 0;
241 }
242 #else /* UNIT_TEST */
243
244 int parse_error_count;
245
246 /* parse error */
247 void
248 yyerror(const char *s)
/* [<][>][^][v][top][bottom][index][help] */
249 {
250 fputs(s, stderr);
251 putc('\n', stderr);
252 parse_error_count++;
253 }
254
255 /* syntax error */
256 void
257 syntax_error(const char *fmt, ...)
/* [<][>][^][v][top][bottom][index][help] */
258 {
259 va_list args;
260 char buf[1024];
261
262 va_start(args, fmt);
263 vsnprintf(buf, sizeof(buf), fmt, args);
264 va_end(args);
265 yyerror(buf);
266 }
267
268 int
269 yywrap()
/* [<][>][^][v][top][bottom][index][help] */
270 {
271 return 1;
272 }
273
274 /* taken from _lex & yacc_ p.157, by Levine, Mason, & Brown (corrected) */
275 char *myinputptr;
276 char *myinputlim;
277
278 #undef min
279 #define min(a, b) (((a) < (b)) ? (a) : (b))
280
281 void
282 yy_input(char *buf, int *result, int max_size)
/* [<][>][^][v][top][bottom][index][help] */
283 {
284 int n = min(max_size, myinputlim - myinputptr);
285
286 if (n > 0) {
287 memcpy(buf, myinputptr, n);
288 myinputptr += n;
289 }
290 *result = n;
291 }
292
293 /* program entry point */
294 int
295 main()
/* [<][>][^][v][top][bottom][index][help] */
296 {
297 char buf[4096];
298
299 setbuf(stdout, NULL);
300 for (;;) {
301 printf("filter> ");
302 if (gets(buf) == NULL) {
303 printf("\n");
304 return(0);
305 }
306 parse_error_count = 0;
307 myinputptr = buf;
308 myinputlim = buf + strlen(buf);
309 filterparse();
310 printf("%d parse errors\n", parse_error_count);
311 }
312 }
313 #endif /* UNIT_TEST */