mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-12 11:18:59 +00:00
lib: Implement node comparison function
Implement comparator for nodes, some miscellaneous cleanup. Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
This commit is contained in:
parent
4b0abf2434
commit
340a2b4ac0
@ -13,12 +13,11 @@
|
|||||||
struct graph_node *
|
struct graph_node *
|
||||||
add_node(struct graph_node *parent, struct graph_node *child)
|
add_node(struct graph_node *parent, struct graph_node *child)
|
||||||
{
|
{
|
||||||
unsigned int index;
|
|
||||||
struct graph_node *p_child;
|
struct graph_node *p_child;
|
||||||
|
|
||||||
for (index = 0; index < vector_active(parent->children); index++)
|
for (unsigned int i = 0; i < vector_active(parent->children); i++)
|
||||||
{
|
{
|
||||||
p_child = vector_slot(parent->children, index);
|
p_child = vector_slot(parent->children, i);
|
||||||
if (cmp_node(child, p_child))
|
if (cmp_node(child, p_child))
|
||||||
return p_child;
|
return p_child;
|
||||||
}
|
}
|
||||||
@ -29,7 +28,36 @@ add_node(struct graph_node *parent, struct graph_node *child)
|
|||||||
int
|
int
|
||||||
cmp_node(struct graph_node *first, struct graph_node *second)
|
cmp_node(struct graph_node *first, struct graph_node *second)
|
||||||
{
|
{
|
||||||
|
// compare types
|
||||||
|
if (first->type != second->type) return 0;
|
||||||
|
|
||||||
|
switch (first->type) {
|
||||||
|
case WORD_GN: // words and variables are equal if their
|
||||||
|
case VARIABLE_GN: // text value is equal
|
||||||
|
if (first->text && second->text) {
|
||||||
|
if (strcmp(first->text, second->text)) return 0;
|
||||||
|
}
|
||||||
|
else if (first->text != second->text) return 0;
|
||||||
|
break;
|
||||||
|
case RANGE_GN: // ranges are equal if their bounds are equal
|
||||||
|
if (first->min != second->min || first->max != second->max)
|
||||||
return 0;
|
return 0;
|
||||||
|
break;
|
||||||
|
case NUMBER_GN: // numbers are equal if their values are equal
|
||||||
|
if (first->value != second->value) return 0;
|
||||||
|
break;
|
||||||
|
/* selectors and options should be equal if all paths are equal,
|
||||||
|
* but the graph isomorphism problem is not solvable in polynomial
|
||||||
|
* time so we consider selectors and options inequal in all cases
|
||||||
|
*/
|
||||||
|
case SELECTOR_GN:
|
||||||
|
case OPTION_GN:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct graph_node *
|
struct graph_node *
|
||||||
@ -40,6 +68,11 @@ new_node(enum graph_node_type type)
|
|||||||
node->children = vector_init(VECTOR_MIN_SIZE);
|
node->children = vector_init(VECTOR_MIN_SIZE);
|
||||||
node->is_leaf = 0;
|
node->is_leaf = 0;
|
||||||
node->is_root = 0;
|
node->is_root = 0;
|
||||||
|
node->end = NULL;
|
||||||
|
node->text = NULL;
|
||||||
|
node->value = 0;
|
||||||
|
node->min = 0;
|
||||||
|
node->max = 0;
|
||||||
node->func = NULL;
|
node->func = NULL;
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
@ -77,22 +110,24 @@ walk_graph(struct graph_node *start, int level)
|
|||||||
fprintf(stderr, "[%d] ", vector_active(start->children));
|
fprintf(stderr, "[%d] ", vector_active(start->children));
|
||||||
|
|
||||||
if (vector_active(start->children))
|
if (vector_active(start->children))
|
||||||
for (unsigned int i = 0; i < vector_active(start->children); i++) {
|
for (unsigned int i = 0; i < vector_active(start->children); i++)
|
||||||
|
{
|
||||||
struct graph_node *r = vector_slot(start->children, i);
|
struct graph_node *r = vector_slot(start->children, i);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
fprintf(stderr, "Child seems null?\n");
|
fprintf(stderr, "Child seems null?\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (start->type == OPTION_GN || start->type == SELECTOR_GN) {
|
if (vector_active(start->children) > 1) {
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
for (int i = 0; i < level+1; i++)
|
for (int i = 0; i < level+1; i++)
|
||||||
fprintf(stderr, "\t");
|
fprintf(stderr, " ");
|
||||||
}
|
|
||||||
walk_graph(r, level+1);
|
walk_graph(r, level+1);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
walk_graph(r, level);
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
|
if (level == 0)
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -22,18 +22,21 @@ struct graph_node
|
|||||||
vector children;
|
vector children;
|
||||||
int is_root; // true if first token in command
|
int is_root; // true if first token in command
|
||||||
int is_leaf; // true if last token in command
|
int is_leaf; // true if last token in command
|
||||||
|
struct graph_node * end; // pointer to end for selector & option
|
||||||
|
|
||||||
int (*func)(struct vty *, int, const char *[]);
|
int (*func)(struct vty *, int, const char *[]);
|
||||||
|
|
||||||
/* various data fields for nodes */
|
/* various data fields for nodes */
|
||||||
char* text; // for words and variables
|
char* text; // for words and variables
|
||||||
int value; // for numbers
|
int value; // for numbers
|
||||||
int start, end; // for ranges
|
int min, max; // for ranges
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adds a child to a node. If the node already has the exact same
|
* Adds a child to a node.
|
||||||
* child, nothing is done.
|
* If the node already has the exact same child, nothing is done. This is
|
||||||
|
* decided with cmp_node.
|
||||||
|
*
|
||||||
* @param[in] parent node
|
* @param[in] parent node
|
||||||
* @param[in] child node
|
* @param[in] child node
|
||||||
* @return the new child, or the existing child if the parent already has the
|
* @return the new child, or the existing child if the parent already has the
|
||||||
@ -43,16 +46,35 @@ extern struct graph_node *
|
|||||||
add_node(struct graph_node *, struct graph_node *);
|
add_node(struct graph_node *, struct graph_node *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compares two nodes for equivalence.
|
* Compares two nodes for parsing equivalence.
|
||||||
* What exactly constitutes two nodes being equal depends on the
|
* Equivalence in this case means that a single user input token
|
||||||
* node type.
|
* should be able to unambiguously match one of the two nodes.
|
||||||
* @return 0 if equal, nonzero otherwise.
|
* For example, two nodes which have all fields equal except their
|
||||||
|
* function pointers would be considered equal.
|
||||||
|
*
|
||||||
|
* @param[in] first node to compare
|
||||||
|
* @param[in] second node to compare
|
||||||
|
* @return 1 if equal, zero otherwise.
|
||||||
*/
|
*/
|
||||||
extern int
|
extern int
|
||||||
cmp_node(struct graph_node *first, struct graph_node *second);
|
cmp_node(struct graph_node *, struct graph_node *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new node.
|
||||||
|
* Initializes all fields to default values and sets the node type.
|
||||||
|
*
|
||||||
|
* @param[in] node type
|
||||||
|
* @return pointer to the newly allocated node
|
||||||
|
*/
|
||||||
extern struct graph_node *
|
extern struct graph_node *
|
||||||
new_node(enum graph_node_type type);
|
new_node(enum graph_node_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walks a command DFA, printing structure to stdout.
|
||||||
|
* For debugging.
|
||||||
|
*
|
||||||
|
* @param[in] start node of graph to walk
|
||||||
|
* @param[in] graph depth for recursion, caller passes 0
|
||||||
|
*/
|
||||||
extern void
|
extern void
|
||||||
walk_graph(struct graph_node *, int);
|
walk_graph(struct graph_node *, int);
|
||||||
|
@ -48,7 +48,7 @@ struct graph_node *selnode_start, // start node for selector set
|
|||||||
%type <node> option_token
|
%type <node> option_token
|
||||||
%type <node> option_token_seq
|
%type <node> option_token_seq
|
||||||
%type <node> selector
|
%type <node> selector
|
||||||
%type <node> selector_root
|
%type <node> selector_element_root
|
||||||
%type <node> selector_token
|
%type <node> selector_token
|
||||||
%type <node> selector_token_seq
|
%type <node> selector_token_seq
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ sentence_root: WORD
|
|||||||
|
|
||||||
currnode = $$;
|
currnode = $$;
|
||||||
currnode->is_root = 1;
|
currnode->is_root = 1;
|
||||||
add_node(startnode, currnode);
|
currnode = add_node(startnode, currnode);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* valid top level tokens */
|
/* valid top level tokens */
|
||||||
@ -132,9 +132,9 @@ placeholder_token:
|
|||||||
|
|
||||||
// get the numbers out
|
// get the numbers out
|
||||||
strsep(&yylval.string, "(-)");
|
strsep(&yylval.string, "(-)");
|
||||||
$$->start = atoi( strsep(&yylval.string, "(-)") );
|
$$->min = atoi( strsep(&yylval.string, "(-)") );
|
||||||
strsep(&yylval.string, "(-)");
|
strsep(&yylval.string, "(-)");
|
||||||
$$->end = atoi( strsep(&yylval.string, "(-)") );
|
$$->max = atoi( strsep(&yylval.string, "(-)") );
|
||||||
|
|
||||||
// we could do this a variety of ways with either
|
// we could do this a variety of ways with either
|
||||||
// the lexer or the parser, but this is the simplest
|
// the lexer or the parser, but this is the simplest
|
||||||
@ -172,13 +172,14 @@ selector_part:
|
|||||||
;
|
;
|
||||||
|
|
||||||
selector_element:
|
selector_element:
|
||||||
selector_root selector_token_seq
|
selector_element_root selector_token_seq
|
||||||
{
|
{
|
||||||
// if the selector start and end do not exist, create them
|
// if the selector start and end do not exist, create them
|
||||||
if (!selnode_start || !selnode_end) { // if one is null
|
if (!selnode_start || !selnode_end) { // if one is null
|
||||||
assert(!selnode_start && !selnode_end); // both should be null
|
assert(!selnode_start && !selnode_end); // both should be null
|
||||||
selnode_start = new_node(SELECTOR_GN); // diverging node
|
selnode_start = new_node(SELECTOR_GN); // diverging node
|
||||||
selnode_end = new_node(NUL_GN); // converging node
|
selnode_end = new_node(NUL_GN); // converging node
|
||||||
|
selnode_start->end = selnode_end; // duh
|
||||||
}
|
}
|
||||||
|
|
||||||
// add element head as a child of the selector
|
// add element head as a child of the selector
|
||||||
@ -210,13 +211,13 @@ selector_token_seq:
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
selector_root:
|
selector_element_root:
|
||||||
literal_token
|
literal_token
|
||||||
| placeholder_token
|
| placeholder_token
|
||||||
;
|
;
|
||||||
|
|
||||||
selector_token:
|
selector_token:
|
||||||
selector_root
|
selector_element_root
|
||||||
| option
|
| option
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
#define GRAMMAR_STR "CLI grammar sandbox\n"
|
#define GRAMMAR_STR "CLI grammar sandbox\n"
|
||||||
|
|
||||||
|
struct graph_node * nodegraph;
|
||||||
|
|
||||||
DEFUN (grammar_test,
|
DEFUN (grammar_test,
|
||||||
grammar_test_cmd,
|
grammar_test_cmd,
|
||||||
"grammar .COMMAND",
|
"grammar parse .COMMAND",
|
||||||
GRAMMAR_STR
|
GRAMMAR_STR
|
||||||
"command to pass to new parser\n")
|
"command to pass to new parser\n")
|
||||||
{
|
{
|
||||||
@ -22,17 +24,28 @@ DEFUN (grammar_test,
|
|||||||
strcat(cat, " ");
|
strcat(cat, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct graph_node *result = new_node(NUL_GN);
|
//struct graph_node *result = new_node(NUL_GN);
|
||||||
/* cmd_parse_format_new((const char*) cat, "lol", result);*/
|
cmd_parse_format_new((const char*) cat, "lol", nodegraph);
|
||||||
cmd_parse_format_new ("test <command|options> lol", "lol", result);
|
walk_graph(nodegraph, 0);
|
||||||
cmd_parse_format_new ("test <command|options> lol", "lol", result);
|
|
||||||
walk_graph(result, 0);
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN (grammar_test_show,
|
||||||
|
grammar_test_show_cmd,
|
||||||
|
"grammar tree",
|
||||||
|
GRAMMAR_STR
|
||||||
|
"print current accumulated DFA\n")
|
||||||
|
{
|
||||||
|
walk_graph(nodegraph, 0);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void grammar_sandbox_init(void);
|
void grammar_sandbox_init(void);
|
||||||
void grammar_sandbox_init() {
|
void grammar_sandbox_init() {
|
||||||
|
fprintf(stderr, "reinitializing graph\n");
|
||||||
|
nodegraph = new_node(NUL_GN);
|
||||||
install_element (ENABLE_NODE, &grammar_test_cmd);
|
install_element (ENABLE_NODE, &grammar_test_cmd);
|
||||||
|
install_element (ENABLE_NODE, &grammar_test_show_cmd);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user