/* 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 "config.h"
+
+ #include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
struct parser_ctx {
yyscan_t scanner;
- struct cmd_element *el;
+ const struct cmd_element *el;
struct graph *graph;
struct graph_node *currnode;
%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
static void
cleanup (struct parser_ctx *ctx);
+ static void loopcheck(struct parser_ctx *ctx, struct subgraph *sg);
+
#define scanner ctx->scanner
}
varname_token: '$' WORD
{
- $$ = XSTRDUP (MTYPE_LEX, $2);
+ $$ = $2;
}
| /* empty */
{
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
* just use [{a|b}] if neccessary, that will work perfectly fine, and reason
* #1 is good enough to keep it this way. */
+ loopcheck(ctx, &$$);
cmd_token_varname_set ($2.end->data, $4);
XFREE (MTYPE_LEX, $4);
};
DEFINE_MTYPE(LIB, LEX, "Lexer token (temporary)")
void
-cmd_graph_parse (struct graph *graph, struct cmd_element *cmd)
+cmd_graph_parse (struct graph *graph, const struct cmd_element *cmd)
{
struct parser_ctx ctx = { .graph = graph, .el = cmd };
/* parser helper functions */
+static bool loopcheck_inner(struct graph_node *start, struct graph_node *node,
+ struct graph_node *end, size_t depth)
+{
+ size_t i;
+ bool ret;
+
+ /* safety check */
+ if (depth++ == 64)
+ return true;
+
+ for (i = 0; i < vector_active(node->to); i++) {
+ struct graph_node *next = vector_slot(node->to, i);
+ struct cmd_token *tok = next->data;
+
+ if (next == end || next == start)
+ return true;
+ if (tok->type < SPECIAL_TKN)
+ continue;
+ ret = loopcheck_inner(start, next, end, depth);
+ if (ret)
+ return true;
+ }
+ return false;
+}
+
+static void loopcheck(struct parser_ctx *ctx, struct subgraph *sg)
+{
+ if (loopcheck_inner(sg->start, sg->start, sg->end, 0))
+ zlog_err("FATAL: '%s': {} contains an empty path! Use [{...}]",
+ ctx->el->string);
+}
+
void
yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
{
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);
{
// end of graph should look like this
// * -> finalnode -> END_TKN -> cmd_element
- struct cmd_element *element = ctx->el;
+ const struct cmd_element *element = ctx->el;
struct graph_node *end_token_node =
new_token_node (ctx, END_TKN, CMD_CR_TEXT, "");
struct graph_node *end_element_node =
- graph_new_node (ctx->graph, element, NULL);
+ graph_new_node (ctx->graph, (void *)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);