-#include <command.h>
-#include <vector.h>
+/*
+ * Command DFA module.
+ * Provides a DFA data structure and associated functions for manipulating it.
+ * Used to match user command line input.
+ *
+ * @author Quentin Young <qlyoung@cumulusnetworks.com>
+ */
-enum tree_node_type
-{
- WORD_TN,
- IPV4_TN,
- IPV4_PREFIX_TN,
- IPV6_TN,
- IPV6_PREFIX_TN,
- VARIABLE_TN,
- RANGE_TN,
- NUMBER_TN,
- SELECTOR_TN,
- OPTION_TN
-}
-
-struct tree_node
-{
- enum tree_node_type type;
- vector children;
- int leaf;
- (int) (*func(struct cmd_info *, struct vty *, int, const char *[]));
-}
+#include "memory.h"
+#include "cmdtree.h"
-void add_node(struct tree_node *parent, struct tree_node *child)
+struct graph_node *
+add_node(struct graph_node *parent, struct graph_node *child)
{
+ int index;
+ struct graph_node *p_child;
+ for (index = 0; index < vector_active(parent->children); index++)
+ {
+ *p_child = vector_slot(parent->children, index);
+ if (cmp_node(child, p_child))
+ return p_child;
+ }
+ vector_set(parent->children, child);
+ return child;
}
-// checks nodes for equivalence; definition of equivalence depends
-// on node type (WORD_TN strcmps words, etc)
-int cmp_node(struct tree_node *first, struct tree_node *second)
+int
+cmp_node(struct graph_node *first, struct graph_node *second)
{
-
}
-int merge_tree(struct tree_node *first, struct tree_node *second)
+struct graph_node *
+new_node(enum graph_node_type type)
{
+ struct graph_node *node = XMALLOC(MTYPE_TMP, sizeof(graph_node));
+ node->type = type;
+ node->children = vector_init(VECTOR_MIN_SIZE);
+ node->is_leaf = 0;
+ node->is_root = 0;
+ node->func = NULL;
+ return node;
}
--- /dev/null
+#include "vector.h"
+
+enum graph_node_type
+{
+ WORD_GN,
+ IPV4_GN,
+ IPV4_PREFIX_GN,
+ IPV6_GN,
+ IPV6_PREFIX_GN,
+ VARIABLE_GN,
+ RANGE_GN,
+ NUMBER_GN,
+ SELECTOR_GN,
+ OPTION_GN,
+ NUL_GN
+};
+
+struct graph_node
+{
+ enum graph_node_type type;
+ vector children;
+ int is_leaf, is_root;
+ // int (*func(struct cmd_info *, struct vty *, int, const char *[]));
+};
+
+/*
+ * Adds a child to a node. If the node already has the exact same
+ * child, nothing is done.
+ */
+struct graph_node *
+add_node(struct graph_node *, struct graph_node *);
+
+/*
+ * Compares two nodes for equivalence.
+ * What exactly constitutes two nodes being equal depends on the
+ * node type.
+ * @return 0 if equal, nonzero otherwise.
+ */
+int
+cmp_node(struct graph_node *first, struct graph_node *second);
+
+struct graph_node *
+new_node(enum graph_node_type type);
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include "cmdtree.h"
extern int yylex(void);
-extern void yyerror(const char *);
+void yyerror(const char *);
+
+// turn on debug
+#define YYDEBUG 1
%}
%union{
int integer;
char *string;
+ struct graph_node *node;
}
-%token <string> WORD
-%token <string> IPV4
-%token <string> IPV4_PREFIX
-%token <string> IPV6
-%token <string> IPV6_PREFIX
-%token <string> VARIABLE
-%token <string> RANGE
-%token <integer> NUMBER
+%{
+// last top-level node
+struct graph_node *topnode,
+//
+ *optnode,
+ *selnode;
+%}
+
+%token <string> WORD
+%token <string> IPV4
+%token <string> IPV4_PREFIX
+%token <string> IPV6
+%token <string> IPV6_PREFIX
+%token <string> VARIABLE
+%token <string> RANGE
+%token <integer> NUMBER
+
+%type <node> start
+%type <node> sentence_root
+%type <node> cmd_token
+%type <node> literal_token
+%type <node> placeholder_token
+%type <node> option_token
+%type <node> selector_token
+%type <node> option
+%type <node> selector
+%type <node> selector_token_seq
+%type <node> option_token_seq
+
+%output "command.c"
+%defines
/* grammar proper */
%%
-start: sentence_root {printf("Matched sentence root\n");}
- cmd_token_seq {printf("Matched sentence\n");};
+start: sentence_root
+ cmd_token_seq;
-sentence_root: WORD {printf("Sentence root: %s\n", $1);};
+sentence_root: WORD {
+ currnode = new_node(WORD_GN);
+ currnode->is_root = 1;
+ };
/* valid top level tokens */
-cmd_token: placeholder_token
- | literal_token
- | selector
- | option
- ;
-cmd_token_seq: /* empty */
- | cmd_token_seq cmd_token;
-
-placeholder_token: IPV4 {printf("Matched placeholder\n");}
- | IPV4_PREFIX {printf("Matched placeholder\n");}
- | IPV6 {printf("Matched placeholder\n");}
- | IPV6_PREFIX {printf("Matched placeholder\n");}
- | VARIABLE {printf("Matched placeholder\n");}
- | RANGE {printf("Matched placeholder\n");}
-
-literal_token: WORD
- | NUMBER
- ;
-/* range: '(' NUMBER '-' NUMBER ')' {printf("Matched range\n");}; */
+cmd_token:
+ placeholder_token
+| literal_token
+| selector
+| option
+;
+cmd_token_seq:
+ %empty
+| cmd_token_seq cmd_token
+;
+
+placeholder_token:
+ IPV4 {$$ = new_node(IPV4_GN);}
+| IPV4_PREFIX {$$ = new_node(IPV4_PREFIX_GN);}
+| IPV6 {$$ = new_node(IPV6_GN);}
+| IPV6_PREFIX {$$ = new_node(IPV6_PREFIX_GN);}
+| VARIABLE {$$ = new_node(VARIABLE_GN);}
+| RANGE {$$ = new_node(RANGE_GN);}
+;
+
+literal_token:
+ WORD {$$ = new_node(WORD_GN);}
+| NUMBER {$$ = new_node(NUMBER_GN);}
+;
/* <selector|token> productions */
-selector: '<' selector_part '|'
- selector_element '>' {printf("Matched selector\n");};
-selector_part: selector_part '|'
- selector_element
- | selector_element
- {printf("Matched selector part\n");};
-selector_element: WORD
- selector_token_seq
-selector_token_seq: /* empty */
- | selector_token_seq
- selector_token
- ;
-selector_token: literal_token
- | placeholder_token
- | option
- ;
+selector:
+ '<' selector_part '|'
+ selector_element '>' {
+ //$$ = new_node(SELECTOR_GN);
+ //add_node($$, $4);
+ };
+
+selector_part:
+ selector_part '|' selector_element
+| selector_element
+;
+
+selector_element:
+ WORD selector_token_seq;
+
+selector_token_seq:
+ %empty
+| selector_token_seq selector_token {
+ //add_node(currnode, $2);
+ //currnode = $2;
+ }
+;
+
+selector_token:
+ literal_token
+| placeholder_token
+| option
+;
/* [option|set] productions */
-option: '[' option_part ']' {printf("Matched option\n");};
-option_part: option_part '|'
- option_element_seq
- | option_element_seq
- ;
-option_element_seq: option_token
- | option_element_seq
- option_token
- ;
-option_token: literal_token
- | placeholder_token
- ;
+option: '[' option_part ']';
+
+option_part:
+ option_part '|' option_token_seq
+| option_token_seq
+;
+
+option_token_seq:
+ option_token
+| option_token_seq option_token
+;
+
+option_token:
+ literal_token
+| placeholder_token
+;
+
%%
int
main (void)
{
- return yyparse ();
+ yydebug = 1;
+ const char* input = "show [random conf NAME] thing";
+ printf("Parsing:\n\t%s\n", input);
+ return cmd_parse_format(input, "description");
}
void yyerror(char const *message) {
printf("Grammar error: %s\n", message);
exit(EXIT_FAILURE);
}
+
+int
+cmd_parse_format(const char *string, const char *desc)
+{
+ yy_scan_string(string);
+ yyparse();
+ return 0;
+}
+
+