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