/* define api.prefix {cmd_yy} */
/* names for generated header and parser files */
-%defines "command_parse.h"
-%output "command_parse.c"
+%defines "lib/command_parse.h"
+%output "lib/command_parse.c"
/* note: code blocks are output in order, to both .c and .h:
* 1. %code requires
* struct parser_ctx is needed for the bison forward decls.
*/
%code requires {
- #include "stdlib.h"
- #include "string.h"
- #include "memory.h"
- #include "command.h"
+ #include "config.h"
+
+ #include <stdlib.h>
+ #include <string.h>
+ #include <ctype.h>
+
+ #include "command_graph.h"
#include "log.h"
- #include "graph.h"
DECLARE_MTYPE(LEX)
%token <string> IPV6_PREFIX
%token <string> VARIABLE
%token <string> RANGE
+%token <string> MAC
+%token <string> MAC_PREFIX
/* union types for parsed rules */
%type <node> start
%type <node> literal_token
%type <node> placeholder_token
+%type <node> placeholder_token_real
%type <node> simple_token
%type <subgraph> selector
%type <subgraph> selector_token
%type <subgraph> selector_token_seq
%type <subgraph> selector_seq_seq
+%type <string> varname_token
+
%code {
/* bison declarations */
}
;
+varname_token: '$' WORD
+{
+ $$ = $2;
+}
+| /* empty */
+{
+ $$ = NULL;
+}
+;
+
cmd_token_seq:
/* empty */
| cmd_token_seq cmd_token
| placeholder_token
;
-literal_token: WORD
+literal_token: WORD varname_token
{
$$ = new_token_node (ctx, WORD_TKN, $1, doc_next(ctx));
+ cmd_token_varname_set ($$->data, $2);
+ XFREE (MTYPE_LEX, $2);
XFREE (MTYPE_LEX, $1);
}
;
-placeholder_token:
+placeholder_token_real:
IPV4
{
$$ = new_token_node (ctx, IPV4_TKN, $1, doc_next(ctx));
XFREE (MTYPE_LEX, $1);
}
+| MAC
+{
+ $$ = new_token_node (ctx, MAC_TKN, $1, doc_next(ctx));
+ XFREE (MTYPE_LEX, $1);
+}
+| MAC_PREFIX
+{
+ $$ = new_token_node (ctx, MAC_PREFIX_TKN, $1, doc_next(ctx));
+ XFREE (MTYPE_LEX, $1);
+}
+
+placeholder_token:
+ placeholder_token_real varname_token
+{
+ struct cmd_token *token = $$->data;
+ $$ = $1;
+ cmd_token_varname_set (token, $2);
+ XFREE (MTYPE_LEX, $2);
+};
+
/* <selector|set> productions */
-selector: '<' selector_seq_seq '>'
+selector: '<' selector_seq_seq '>' varname_token
{
$$ = $2;
+ cmd_token_varname_set ($2.end->data, $4);
+ XFREE (MTYPE_LEX, $4);
};
selector_seq_seq:
;
/* {keyword} productions */
-selector: '{' selector_seq_seq '}'
+selector: '{' selector_seq_seq '}' varname_token
{
$$ = $2;
graph_add_edge ($$.end, $$.start);
* loop-avoidal fails to handle
* just use [{a|b}] if neccessary, that will work perfectly fine, and reason
* #1 is good enough to keep it this way. */
+
+ cmd_token_varname_set ($2.end->data, $4);
+ XFREE (MTYPE_LEX, $4);
};
;
/* [option] productions */
-selector: '[' selector_seq_seq ']'
+selector: '[' selector_seq_seq ']' varname_token
{
$$ = $2;
graph_add_edge ($$.start, $$.end);
+ cmd_token_varname_set ($2.end->data, $4);
+ XFREE (MTYPE_LEX, $4);
}
;
DEFINE_MTYPE(LIB, LEX, "Lexer token (temporary)")
void
-command_parse_format (struct graph *graph, struct cmd_element *cmd)
+cmd_graph_parse (struct graph *graph, struct cmd_element *cmd)
{
struct parser_ctx ctx = { .graph = graph, .el = cmd };
char spacing[256];
int lineno = 0;
- zlog_err ("%s: FATAL parse error: %s", __func__, msg);
- zlog_err ("%s: %d:%d-%d of this command definition:", __func__, loc->first_line, loc->first_column, loc->last_column);
+ zlog_notice ("%s: FATAL parse error: %s", __func__, msg);
+ zlog_notice ("%s: %d:%d-%d of this command definition:", __func__, loc->first_line, loc->first_column, loc->last_column);
line = tmpstr;
do {
if (eol)
*eol++ = '\0';
- zlog_err ("%s: | %s", __func__, line);
+ zlog_notice ("%s: | %s", __func__, line);
if (lineno == loc->first_line && lineno == loc->last_line
&& loc->first_column < (int)sizeof(spacing) - 1
&& loc->last_column < (int)sizeof(spacing) - 1) {
memset(spacing, ' ', loc->first_column - 1);
memset(spacing + loc->first_column - 1, '^', len);
spacing[loc->first_column - 1 + len] = '\0';
- zlog_err ("%s: | %s", __func__, spacing);
+ zlog_notice ("%s: | %s", __func__, spacing);
}
} while ((line = eol));
free(tmpstr);
struct graph_node *end_element_node =
graph_new_node (ctx->graph, element, NULL);
+ if (ctx->docstr && strlen (ctx->docstr) > 1) {
+ zlog_debug ("Excessive docstring while parsing '%s'", ctx->el->string);
+ zlog_debug ("----------");
+ while (ctx->docstr && ctx->docstr[1] != '\0')
+ zlog_debug ("%s", strsep(&ctx->docstr, "\n"));
+ zlog_debug ("----------\n");
+ }
+
graph_add_edge (finalnode, end_token_node);
graph_add_edge (end_token_node, end_element_node);
}
new_token_node (struct parser_ctx *ctx, enum cmd_token_type type,
const char *text, const char *doc)
{
- struct cmd_token *token = new_cmd_token (type, ctx->el->attr, text, doc);
- return graph_new_node (ctx->graph, token, (void (*)(void *)) &del_cmd_token);
+ struct cmd_token *token = cmd_token_new (type, ctx->el->attr, text, doc);
+ return graph_new_node (ctx->graph, token, (void (*)(void *)) &cmd_token_del);
}