lib: parser: add pre-merge varname propagation step

Fills token->varname based on context.  WORD tokens use the WORD - if it
isn't actually "WORD".  Other than that, a preceding constant token is
used as name.

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
David Lamparter 2017-03-22 06:56:17 +01:00 committed by Quentin Young
parent 5894e76da7
commit c09c46ae3c
3 changed files with 133 additions and 1 deletions

View File

@ -341,6 +341,7 @@ install_element (enum node_type ntype, struct cmd_element *cmd)
graph_new_node (graph, token, (void (*)(void *)) &cmd_token_del); graph_new_node (graph, token, (void (*)(void *)) &cmd_token_del);
cmd_graph_parse (graph, cmd); cmd_graph_parse (graph, cmd);
cmd_graph_names (graph);
cmd_graph_merge (cnode->cmdgraph, graph, +1); cmd_graph_merge (cnode->cmdgraph, graph, +1);
graph_delete_graph (graph); graph_delete_graph (graph);
@ -387,6 +388,7 @@ uninstall_element (enum node_type ntype, struct cmd_element *cmd)
graph_new_node (graph, token, (void (*)(void *)) &cmd_token_del); graph_new_node (graph, token, (void (*)(void *)) &cmd_token_del);
cmd_graph_parse (graph, cmd); cmd_graph_parse (graph, cmd);
cmd_graph_names (graph);
cmd_graph_merge (cnode->cmdgraph, graph, -1); cmd_graph_merge (cnode->cmdgraph, graph, -1);
graph_delete_graph (graph); graph_delete_graph (graph);

View File

@ -81,7 +81,28 @@ cmd_token_dup (struct cmd_token *token)
void cmd_token_varname_set(struct cmd_token *token, const char *varname) void cmd_token_varname_set(struct cmd_token *token, const char *varname)
{ {
XFREE (MTYPE_CMD_VAR, token->varname); XFREE (MTYPE_CMD_VAR, token->varname);
token->varname = varname ? XSTRDUP (MTYPE_CMD_VAR, varname) : NULL; if (!varname)
{
token->varname = NULL;
return;
}
size_t len = strlen (varname), i;
token->varname = XMALLOC (MTYPE_CMD_VAR, len + 1);
for (i = 0; i < len; i++)
switch (varname[i])
{
case '-':
case '+':
case '*':
case ':':
token->varname[i] = '_';
break;
default:
token->varname[i] = tolower (varname[i]);
}
token->varname[len] = '\0';
} }
static bool static bool
@ -162,6 +183,10 @@ cmd_nodes_equal (struct graph_node *ga, struct graph_node *gb)
/* one a ..., the other not. */ /* one a ..., the other not. */
if (cmd_nodes_link (ga, ga) != cmd_nodes_link (gb, gb)) if (cmd_nodes_link (ga, ga) != cmd_nodes_link (gb, gb))
return false; return false;
if (!a->varname != !b->varname)
return false;
if (a->varname && strcmp (a->varname, b->varname))
return false;
switch (a->type) switch (a->type)
{ {
@ -349,3 +374,107 @@ cmd_graph_merge (struct graph *old, struct graph *new, int direction)
vector_slot (old->nodes, 0), vector_slot (new->nodes, 0), vector_slot (old->nodes, 0), vector_slot (new->nodes, 0),
direction); direction);
} }
static void
cmd_node_names (struct graph_node *gn, struct graph_node *join,
const char *prevname)
{
size_t i;
struct cmd_token *tok = gn->data, *jointok;
struct graph_node *stop = cmd_loopstop (gn);
switch (tok->type)
{
case WORD_TKN:
prevname = tok->text;
break;
case VARIABLE_TKN:
if (!tok->varname
&& strcmp (tok->text, "WORD")
&& strcmp (tok->text, "NAME"))
cmd_token_varname_set (tok, tok->text);
/* fallthrough */
case RANGE_TKN:
case IPV4_TKN:
case IPV4_PREFIX_TKN:
case IPV6_TKN:
case IPV6_PREFIX_TKN:
if (!tok->varname && prevname)
cmd_token_varname_set (tok, prevname);
prevname = NULL;
break;
case START_TKN:
case END_TKN:
case JOIN_TKN:
/* "<foo|bar> WORD" -> word is not "bar" or "foo" */
prevname = NULL;
break;
case FORK_TKN:
/* apply "<A.B.C.D|X:X::X:X>$name" */
jointok = tok->forkjoin->data;
if (!jointok->varname)
break;
for (i = 0; i < vector_active (tok->forkjoin->from); i++)
{
struct graph_node *tail = vector_slot (tok->forkjoin->from, i);
struct cmd_token *tailtok = tail->data;
if (tail == gn || tailtok->varname)
continue;
cmd_token_varname_set (tailtok, jointok->varname);
}
break;
}
for (i = 0; i < vector_active (gn->to); i++)
{
struct graph_node *next = vector_slot (gn->to, i);
if (next == stop || next == join)
continue;
cmd_node_names (next, join, prevname);
}
if (tok->type == FORK_TKN && tok->forkjoin != join)
cmd_node_names (tok->forkjoin, join, NULL);
}
void
cmd_graph_names (struct graph *graph)
{
struct graph_node *start;
assert (vector_active (graph->nodes) >= 1);
start = vector_slot (graph->nodes, 0);
/* apply varname on initial "[no]" */
do
{
if (vector_active (start->to) != 1)
break;
struct graph_node *first = vector_slot (start->to, 0);
struct cmd_token *tok = first->data;
/* looking for an option with 2 choices, nothing or "no" */
if (tok->type != FORK_TKN || vector_active (first->to) != 2)
break;
struct graph_node *next0 = vector_slot (first->to, 0);
struct graph_node *next1 = vector_slot (first->to, 1);
/* one needs to be empty */
if (next0 != tok->forkjoin && next1 != tok->forkjoin)
break;
struct cmd_token *tok0 = next0->data;
struct cmd_token *tok1 = next1->data;
/* the other one needs to be "no" (only one will match here) */
if ((tok0->type == WORD_TKN && !strcmp(tok0->text, "no")))
cmd_token_varname_set (tok0, "no");
if ((tok1->type == WORD_TKN && !strcmp(tok1->text, "no")))
cmd_token_varname_set (tok1, "no");
}
while (0);
cmd_node_names (start, NULL, NULL);
}

View File

@ -111,6 +111,7 @@ extern void cmd_token_del (struct cmd_token *);
extern void cmd_token_varname_set(struct cmd_token *token, const char *varname); extern void cmd_token_varname_set(struct cmd_token *token, const char *varname);
extern void cmd_graph_parse (struct graph *graph, struct cmd_element *cmd); extern void cmd_graph_parse (struct graph *graph, struct cmd_element *cmd);
extern void cmd_graph_names (struct graph *graph);
extern void cmd_graph_merge (struct graph *old, struct graph *new, int direction); extern void cmd_graph_merge (struct graph *old, struct graph *new, int direction);
#endif /* _FRR_COMMAND_GRAPH_H */ #endif /* _FRR_COMMAND_GRAPH_H */