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
+ case WORD_GN:
+ case VARIABLE_GN:
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
+ case RANGE_GN:
if (first->min != second->min || first->max != second->max)
return 0;
break;
- case NUMBER_GN: // numbers are equal if their values are equal
+ case NUMBER_GN:
if (first->value != second->value) return 0;
break;
/* selectors and options should be equal if all paths are equal,
case SELECTOR_GN:
case OPTION_GN:
return 0;
- // end nodes are always considered equal, since each node may only
- // have one at a time
+ /* end nodes are always considered equal, since each node may only
+ * have one at a time
+ */
+ case START_GN:
case END_GN:
default:
break;
struct graph_node *
new_node(enum graph_node_type type)
{
- struct graph_node *node = malloc(sizeof(struct graph_node));
+ struct graph_node *node =
+ XMALLOC(MTYPE_CMD_TOKENS, sizeof(struct graph_node));
+
node->type = type;
node->children = vector_init(VECTOR_MIN_SIZE);
- node->is_root = 0;
- node->end = NULL;
- node->text = NULL;
- node->value = 0;
- node->min = 0;
- node->max = 0;
- node->element = NULL;
+ node->is_start = 0;
+ node->end = NULL;
+ node->text = NULL;
+ node->value = 0;
+ node->min = 0;
+ node->max = 0;
+ node->element = NULL;
return node;
}
+void
+free_node (struct graph_node *node)
+{
+ if (!node) return;
+ free_node (node->end);
+ vector_free (node->children);
+ free (node->text);
+ free (node->arg);
+ free (node->element);
+ free (node);
+}
+
char *
describe_node(struct graph_node *node, char* buffer, unsigned int bufsize)
{
case END_GN:
snprintf(buffer, bufsize, "END");
break;
+ case START_GN:
+ snprintf(buffer, bufsize, "START");
+ break;
default:
snprintf(buffer, bufsize, "ERROR");
}
else
fprintf(stderr, "\n");
}
+
SELECTOR_GN,
OPTION_GN,
NUL_GN,
+ START_GN,
END_GN
};
vector children; // this node's children
struct graph_node * end; // pointer to end for SELECTOR_GN & OPTION_GN
- char* text; // for WORD_GN and VARIABLE_GN
- long value; // for NUMBER_GN
- long min, max; // for RANGE_GN
+ char* text; // for WORD_GN and VARIABLE_GN
+ long value; // for NUMBER_GN
+ long min, max; // for RANGE_GN
/* cmd_element struct pointer, only valid for END_GN */
struct cmd_element *element;
};
/*
- * Adds a child to a node.
- * If the node already has the exact same child, nothing is done. This is
- * decided with cmp_node.
+ * Adds a node as a child of another node.
+ * If the new parent has a child that is equal to the prospective child, as
+ * determined by cmp_node, then a pointer to the existing node is returned and
+ * the prospective child is not added. Otherwise the return value is NULL.
*
* @param[in] parent node
* @param[in] child node
- * @return the new child, or the existing child if the parent already has the
- * new child
+ * @return pointer to child if it is added, pointer to existing child otherwise
*/
extern struct graph_node *
add_node(struct graph_node *, struct graph_node *);
%code requires {
#include "command.h"
#include "command_graph.h"
+ #include "memory.h"
}
%code provides {
extern void
struct cmd_element *command; // command we're parsing
%}
-%token <node> WORD
-%token <node> IPV4
-%token <node> IPV4_PREFIX
-%token <node> IPV6
-%token <node> IPV6_PREFIX
-%token <node> VARIABLE
-%token <node> RANGE
-%token <node> NUMBER
+%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
start: sentence_root
cmd_token_seq
{
- // this should never happen...
- if (currnode->type == END_GN)
- yyerror("Unexpected leaf");
-
- // create function pointer node
+ // create leaf node
struct graph_node *end = new_node(END_GN);
end->element = command;
- // ensure there are no END_GN children
- for (unsigned int i = 0; i < vector_active(currnode->children); i++)
+ // add node
+ if (add_node(currnode, end) != end)
{
- struct graph_node *child = vector_slot(currnode->children, i);
- if (child->type == END_GN)
- yyerror("Duplicate command.");
+ yyerror("Duplicate command.");
+ YYABORT;
}
-
- // add node
- end = add_node(currnode, end);
}
sentence_root: WORD
{
- $$ = new_node(WORD_GN);
- $$->text = strdup(yylval.string);
- fprintf(stderr, ">>>>>>>> YYLVAL.STRING: %s\n", yylval.string);
- fprintf(stderr, ">>>>>>>> TEXT: %s\n", $$->text);
+ struct graph_node *root = new_node(WORD_GN);
+ root->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
+
+ currnode = add_node(startnode, root);
+ if (currnode != root)
+ free (root);
- currnode = $$;
- currnode->is_root = 1;
- currnode = add_node(startnode, currnode);
+ free ($1);
+ $$ = currnode;
};
/* valid top level tokens */
cmd_token:
placeholder_token
-{ currnode = add_node(currnode, $1); }
+{
+ currnode = add_node(currnode, $1);
+ if (currnode != $1)
+ free_node ($1);
+}
| literal_token
-{ currnode = add_node(currnode, $1); }
+{
+ currnode = add_node(currnode, $1);
+ if (currnode != $1)
+ free_node ($1);
+}
/* selectors and options are subgraphs with start and end nodes */
| selector
{
IPV4
{
$$ = new_node(IPV4_GN);
- $$->text = strdup(yylval.string);
+ $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
+ free ($1);
}
| IPV4_PREFIX
{
$$ = new_node(IPV4_PREFIX_GN);
- $$->text = strdup(yylval.string);
+ $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
+ free ($1);
}
| IPV6
{
$$ = new_node(IPV6_GN);
- $$->text = strdup(yylval.string);
+ $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
+ free ($1);
}
| IPV6_PREFIX
{
$$ = new_node(IPV6_PREFIX_GN);
- $$->text = strdup(yylval.string);
+ $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
+ free ($1);
}
| VARIABLE
{
$$ = new_node(VARIABLE_GN);
- $$->text = strdup(yylval.string);
+ $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
+ free ($1);
}
| RANGE
{
$$ = new_node(RANGE_GN);
- $$->text = strdup(yylval.string);
+ $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
// get the numbers out
strsep(&yylval.string, "(-)");
$$->min = atoi( strsep(&yylval.string, "(-)") );
$$->max = atoi( strsep(&yylval.string, "(-)") );
+
+ free ($1);
}
;
WORD
{
$$ = new_node(WORD_GN);
- $$->text = strdup(yylval.string);
- fprintf(stderr, ">>>>>>>> YYLVAL.STRING: %s\n", yylval.string);
- fprintf(stderr, ">>>>>>>> TEXT: %s\n", $$->text);
+ $$->text = XSTRDUP(MTYPE_CMD_TOKENS, $1);
+ free ($1);
}
| NUMBER
{
void yyerror(char const *message) {
// fail on bad parse
- printf("Grammar error: %s\n", message);
- exit(EXIT_FAILURE);
+ fprintf(stderr, "Grammar error: %s\n", message);
}
struct graph_node *
fprintf(stderr, "parsing: %s\n", cmd->string);
/* clear state pointers */
- startnode = currnode = seqhead = NULL;
+ startnode = start;
+ currnode = seqhead = NULL;
selnode_start = selnode_end = NULL;
optnode_start = optnode_end = NULL;
command = cmd;
// make flex read from a string
set_buffer_string(command->string);
- // initialize the start node of this command dfa
- startnode = start;
// parse command into DFA
yyparse();
// startnode points to command DFA