]> git.proxmox.com Git - mirror_frr.git/blame - lib/command_parse.y
lib: Fix OOB range parses, variable matches
[mirror_frr.git] / lib / command_parse.y
CommitLineData
9d0662e0
QY
1/*
2 * Command format string parser.
3 *
4 * Turns a command definition into a DFA that together with the functions
5 * provided in command_match.c may be used to map command line input to a
6 * function.
7 *
8 * @author Quentin Young <qlyoung@cumulusnetworks.com>
9 */
10
92055a92 11%{
92055a92 12extern int yylex(void);
2a23ca6e 13extern void yyerror(const char *);
782d9789 14
2a23ca6e 15// compile with debugging facilities
782d9789 16#define YYDEBUG 1
92055a92 17%}
eceb1066
QY
18%code requires {
19 #include "command.h"
20 #include "command_graph.h"
5a5d576b 21 #include "memory.h"
eceb1066 22}
478bdaeb 23%code provides {
eceb1066
QY
24 extern void
25 set_buffer_string(const char *);
26 struct graph_node *
27 parse_command_format(struct graph_node *, struct cmd_element *);
478bdaeb 28}
92055a92 29
eceb1066 30
9d0662e0 31/* valid types for tokens */
92055a92 32%union{
e648e61a 33 signed long long integer;
92055a92 34 char *string;
782d9789 35 struct graph_node *node;
92055a92
QY
36}
37
9d0662e0 38/* some helpful state variables */
782d9789 39%{
478bdaeb
QY
40struct graph_node *startnode, // command root node
41 *currnode, // current node
478bdaeb
QY
42 *seqhead; // sequence head
43
2a23ca6e 44
4b0abf24
QY
45struct graph_node *optnode_start, // start node for option set
46 *optnode_end; // end node for option set
2a23ca6e 47
4b0abf24
QY
48struct graph_node *selnode_start, // start node for selector set
49 *selnode_end; // end node for selector set
880e24a1 50
eceb1066 51struct cmd_element *command; // command we're parsing
782d9789
QY
52%}
53
5a5d576b
QY
54%token <string> WORD
55%token <string> IPV4
56%token <string> IPV4_PREFIX
57%token <string> IPV6
58%token <string> IPV6_PREFIX
59%token <string> VARIABLE
60%token <string> RANGE
61%token <integer> NUMBER
782d9789
QY
62
63%type <node> start
64%type <node> sentence_root
782d9789
QY
65%type <node> literal_token
66%type <node> placeholder_token
782d9789 67%type <node> option
478bdaeb
QY
68%type <node> option_token
69%type <node> option_token_seq
782d9789 70%type <node> selector
340a2b4a 71%type <node> selector_element_root
478bdaeb 72%type <node> selector_token
782d9789 73%type <node> selector_token_seq
782d9789 74
2a23ca6e
QY
75%defines "command_parse.h"
76%output "command_parse.c"
92055a92
QY
77
78/* grammar proper */
79%%
80
782d9789 81start: sentence_root
880e24a1
QY
82 cmd_token_seq
83{
5a5d576b 84 // create leaf node
880e24a1 85 struct graph_node *end = new_node(END_GN);
a53fbbf5 86 end->element = command;
880e24a1 87
5a5d576b
QY
88 // add node
89 if (add_node(currnode, end) != end)
eceb1066 90 {
5a5d576b
QY
91 yyerror("Duplicate command.");
92 YYABORT;
eceb1066 93 }
e648e61a 94 fprintf(stderr, "Parsed full command successfully.\n");
880e24a1 95}
92055a92 96
2a23ca6e 97sentence_root: WORD
478bdaeb 98{
5a5d576b
QY
99 struct graph_node *root = new_node(WORD_GN);
100 root->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
101
102 currnode = add_node(startnode, root);
103 if (currnode != root)
104 free (root);
4b0abf24 105
5a5d576b
QY
106 free ($1);
107 $$ = currnode;
478bdaeb 108};
92055a92
QY
109
110/* valid top level tokens */
782d9789
QY
111cmd_token:
112 placeholder_token
5a5d576b
QY
113{
114 currnode = add_node(currnode, $1);
115 if (currnode != $1)
116 free_node ($1);
117}
782d9789 118| literal_token
5a5d576b
QY
119{
120 currnode = add_node(currnode, $1);
121 if (currnode != $1)
122 free_node ($1);
123}
478bdaeb 124/* selectors and options are subgraphs with start and end nodes */
782d9789 125| selector
478bdaeb
QY
126{
127 add_node(currnode, $1);
128 currnode = selnode_end;
129 selnode_start = selnode_end = NULL;
130}
782d9789 131| option
478bdaeb
QY
132{
133 add_node(currnode, $1);
134 currnode = optnode_end;
135 optnode_start = optnode_end = NULL;
136}
782d9789 137;
92055a92 138
782d9789
QY
139cmd_token_seq:
140 %empty
141| cmd_token_seq cmd_token
142;
143
144placeholder_token:
478bdaeb 145 IPV4
4b0abf24
QY
146{
147 $$ = new_node(IPV4_GN);
5a5d576b
QY
148 $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
149 free ($1);
4b0abf24 150}
478bdaeb 151| IPV4_PREFIX
340a2b4a 152{
4b0abf24 153 $$ = new_node(IPV4_PREFIX_GN);
5a5d576b
QY
154 $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
155 free ($1);
4b0abf24 156}
478bdaeb 157| IPV6
340a2b4a 158{
4b0abf24 159 $$ = new_node(IPV6_GN);
5a5d576b
QY
160 $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
161 free ($1);
4b0abf24 162}
478bdaeb 163| IPV6_PREFIX
340a2b4a 164{
4b0abf24 165 $$ = new_node(IPV6_PREFIX_GN);
5a5d576b
QY
166 $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
167 free ($1);
4b0abf24 168}
478bdaeb 169| VARIABLE
340a2b4a 170{
4b0abf24 171 $$ = new_node(VARIABLE_GN);
5a5d576b
QY
172 $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
173 free ($1);
4b0abf24 174}
478bdaeb
QY
175| RANGE
176{
177 $$ = new_node(RANGE_GN);
5a5d576b 178 $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
478bdaeb
QY
179
180 // get the numbers out
181 strsep(&yylval.string, "(-)");
e648e61a
QY
182 char *endptr;
183 $$->min = strtoll( strsep(&yylval.string, "(-)"), &endptr, 10 );
184 $$->max = strtoll( strsep(&yylval.string, "(-)"), &endptr, 10 );
5a5d576b
QY
185
186 free ($1);
478bdaeb 187}
782d9789
QY
188;
189
190literal_token:
478bdaeb
QY
191 WORD
192{
193 $$ = new_node(WORD_GN);
5a5d576b
QY
194 $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
195 free ($1);
478bdaeb
QY
196}
197| NUMBER
198{
199 $$ = new_node(NUMBER_GN);
200 $$->value = yylval.integer;
201}
782d9789 202;
92055a92 203
4b0abf24 204/* <selector|set> productions */
782d9789 205selector:
478bdaeb 206 '<' selector_part '|' selector_element '>'
2a23ca6e 207{
478bdaeb
QY
208 // all the graph building is done in selector_element,
209 // so just return the selector subgraph head
210 $$ = selnode_start;
2a23ca6e 211};
782d9789
QY
212
213selector_part:
2a23ca6e 214 selector_part '|' selector_element
782d9789
QY
215| selector_element
216;
217
218selector_element:
340a2b4a 219 selector_element_root selector_token_seq
478bdaeb
QY
220{
221 // if the selector start and end do not exist, create them
222 if (!selnode_start || !selnode_end) { // if one is null
223 assert(!selnode_start && !selnode_end); // both should be null
224 selnode_start = new_node(SELECTOR_GN); // diverging node
225 selnode_end = new_node(NUL_GN); // converging node
340a2b4a 226 selnode_start->end = selnode_end; // duh
478bdaeb
QY
227 }
228
229 // add element head as a child of the selector
230 add_node(selnode_start, $1);
231
232 if ($2->type != NUL_GN) {
233 add_node($1, seqhead);
234 add_node($2, selnode_end);
235 }
236 else
237 add_node($1, selnode_end);
238
239 seqhead = NULL;
240}
782d9789
QY
241
242selector_token_seq:
478bdaeb 243 %empty { $$ = new_node(NUL_GN); }
2a23ca6e
QY
244| selector_token_seq selector_token
245{
478bdaeb
QY
246 // if the sequence component is NUL_GN, this is a sequence start
247 if ($1->type == NUL_GN) {
248 assert(!seqhead); // sequence head should always be null here
249 seqhead = $2;
250 }
251 else // chain on new node
252 add_node($1, $2);
253
254 $$ = $2;
2a23ca6e 255}
782d9789
QY
256;
257
340a2b4a 258selector_element_root:
782d9789
QY
259 literal_token
260| placeholder_token
478bdaeb
QY
261;
262
263selector_token:
340a2b4a 264 selector_element_root
782d9789
QY
265| option
266;
92055a92
QY
267
268/* [option|set] productions */
2a23ca6e 269option: '[' option_part ']'
4b0abf24
QY
270{
271 // add null path
272 struct graph_node *nullpath = new_node(NUL_GN);
273 add_node(optnode_start, nullpath);
274 add_node(nullpath, optnode_end);
275
276 $$ = optnode_start;
277};
782d9789
QY
278
279option_part:
478bdaeb
QY
280 option_part '|' option_element
281| option_element
782d9789
QY
282;
283
478bdaeb
QY
284option_element:
285 option_token_seq
2a23ca6e 286{
478bdaeb
QY
287 if (!optnode_start || !optnode_end) {
288 assert(!optnode_start && !optnode_end);
289 optnode_start = new_node(OPTION_GN);
290 optnode_end = new_node(NUL_GN);
291 }
292
293 add_node(optnode_start, seqhead);
294 add_node($1, optnode_end);
2a23ca6e 295}
478bdaeb
QY
296
297option_token_seq:
298 option_token
299{ $$ = seqhead = $1; }
300| option_token_seq option_token
301{ $$ = add_node($1, $2); }
782d9789
QY
302;
303
304option_token:
305 literal_token
306| placeholder_token
307;
308
92055a92 309%%
4b0abf24 310
92055a92 311void yyerror(char const *message) {
880e24a1 312 // fail on bad parse
5a5d576b 313 fprintf(stderr, "Grammar error: %s\n", message);
1a8c390d
QY
314 fprintf(stderr, "Token on error: ");
315 if (yylval.string) fprintf(stderr, "%s\n", yylval.string);
316 else if (yylval.node) fprintf(stderr, "%s\n", yylval.node->text);
e648e61a 317 else fprintf(stderr, "%lld\n", yylval.integer);
1a8c390d 318
92055a92 319}
782d9789 320
478bdaeb 321struct graph_node *
eceb1066 322parse_command_format(struct graph_node *start, struct cmd_element *cmd)
782d9789 323{
eceb1066 324 fprintf(stderr, "parsing: %s\n", cmd->string);
478bdaeb 325
4b0abf24 326 /* clear state pointers */
5a5d576b
QY
327 startnode = start;
328 currnode = seqhead = NULL;
4b0abf24
QY
329 selnode_start = selnode_end = NULL;
330 optnode_start = optnode_end = NULL;
331
332 // trace parser
de9d7e4f 333 yydebug = 0;
a53fbbf5
QY
334 // command string
335 command = cmd;
2a23ca6e 336 // make flex read from a string
eceb1066 337 set_buffer_string(command->string);
2a23ca6e 338 // parse command into DFA
782d9789 339 yyparse();
478bdaeb
QY
340 // startnode points to command DFA
341 return startnode;
782d9789 342}