mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 17:27:42 +00:00
lib: parser: add error location reporting
flex+bison have nice capabilities to track the location that is currently being processed; let's enable these and get better warnings for broken CLI specs. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
parent
663982cda7
commit
8bb647a830
@ -24,6 +24,11 @@
|
|||||||
|
|
||||||
%{
|
%{
|
||||||
#include "command_parse.h"
|
#include "command_parse.h"
|
||||||
|
|
||||||
|
#define YY_USER_ACTION yylloc->last_column += yyleng;
|
||||||
|
#define LOC_STEP \
|
||||||
|
yylloc->first_column = yylloc->last_column; \
|
||||||
|
yylloc->first_line = yylloc->last_line;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
WORD (\-|\+)?[a-z0-9\*][-+_a-zA-Z0-9\*]*
|
WORD (\-|\+)?[a-z0-9\*][-+_a-zA-Z0-9\*]*
|
||||||
@ -45,9 +50,14 @@ RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
|
|||||||
%option prefix="cmd_yy"
|
%option prefix="cmd_yy"
|
||||||
%option reentrant
|
%option reentrant
|
||||||
%option bison-bridge
|
%option bison-bridge
|
||||||
|
%option bison-locations
|
||||||
|
|
||||||
%%
|
%%
|
||||||
[ \t] /* ignore whitespace */;
|
%{
|
||||||
|
LOC_STEP;
|
||||||
|
%}
|
||||||
|
|
||||||
|
[ \t]+ LOC_STEP /* ignore whitespace */;
|
||||||
{WORD} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return WORD;}
|
{WORD} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return WORD;}
|
||||||
{IPV4} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4;}
|
{IPV4} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4;}
|
||||||
{IPV4_PREFIX} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4_PREFIX;}
|
{IPV4_PREFIX} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4_PREFIX;}
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#define YYDEBUG 1
|
#define YYDEBUG 1
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
%locations
|
||||||
|
%define parse.error verbose
|
||||||
%define api.pure full
|
%define api.pure full
|
||||||
/* define api.prefix {cmd_yy} */
|
/* define api.prefix {cmd_yy} */
|
||||||
|
|
||||||
@ -49,6 +51,7 @@
|
|||||||
#include "graph.h"
|
#include "graph.h"
|
||||||
|
|
||||||
#define YYSTYPE CMD_YYSTYPE
|
#define YYSTYPE CMD_YYSTYPE
|
||||||
|
#define YYLTYPE CMD_YYLTYPE
|
||||||
struct parser_ctx;
|
struct parser_ctx;
|
||||||
|
|
||||||
/* subgraph semantic value */
|
/* subgraph semantic value */
|
||||||
@ -108,7 +111,7 @@
|
|||||||
|
|
||||||
/* bison declarations */
|
/* bison declarations */
|
||||||
void
|
void
|
||||||
cmd_yyerror (struct parser_ctx *ctx, char const *msg);
|
cmd_yyerror (CMD_YYLTYPE *locp, struct parser_ctx *ctx, char const *msg);
|
||||||
|
|
||||||
/* helper functions for parser */
|
/* helper functions for parser */
|
||||||
static char *
|
static char *
|
||||||
@ -130,7 +133,7 @@
|
|||||||
char *doc);
|
char *doc);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
terminate_graph (struct parser_ctx *ctx,
|
terminate_graph (CMD_YYLTYPE *locp, struct parser_ctx *ctx,
|
||||||
struct graph_node *);
|
struct graph_node *);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -169,7 +172,7 @@ start:
|
|||||||
cmd_token_seq
|
cmd_token_seq
|
||||||
{
|
{
|
||||||
// tack on the command element
|
// tack on the command element
|
||||||
terminate_graph (ctx, ctx->currnode);
|
terminate_graph (&@1, ctx, ctx->currnode);
|
||||||
}
|
}
|
||||||
| cmd_token_seq placeholder_token '.' '.' '.'
|
| cmd_token_seq placeholder_token '.' '.' '.'
|
||||||
{
|
{
|
||||||
@ -183,7 +186,7 @@ start:
|
|||||||
add_edge_dedup (ctx->currnode, ctx->currnode);
|
add_edge_dedup (ctx->currnode, ctx->currnode);
|
||||||
|
|
||||||
// tack on the command element
|
// tack on the command element
|
||||||
terminate_graph (ctx, ctx->currnode);
|
terminate_graph (&@1, ctx, ctx->currnode);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -255,7 +258,7 @@ placeholder_token:
|
|||||||
token->max = strtoll (yylval.string, &yylval.string, 10);
|
token->max = strtoll (yylval.string, &yylval.string, 10);
|
||||||
|
|
||||||
// validate range
|
// validate range
|
||||||
if (token->min > token->max) cmd_yyerror (ctx, "Invalid range.");
|
if (token->min > token->max) cmd_yyerror (&@1, ctx, "Invalid range.");
|
||||||
|
|
||||||
free ($1);
|
free ($1);
|
||||||
}
|
}
|
||||||
@ -352,11 +355,39 @@ command_parse_format (struct graph *graph, struct cmd_element *cmd)
|
|||||||
/* parser helper functions */
|
/* parser helper functions */
|
||||||
|
|
||||||
void
|
void
|
||||||
yyerror (struct parser_ctx *ctx, char const *msg)
|
yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
|
||||||
{
|
{
|
||||||
|
char *tmpstr = strdup(ctx->el->string);
|
||||||
|
char *line, *eol;
|
||||||
|
char spacing[256];
|
||||||
|
int lineno = 0;
|
||||||
|
|
||||||
zlog_err ("%s: FATAL parse error: %s", __func__, msg);
|
zlog_err ("%s: FATAL parse error: %s", __func__, msg);
|
||||||
zlog_err ("while parsing this command definition: \n\t%s\n", ctx->el->string);
|
zlog_err ("%s: %d:%d-%d of this command definition:", __func__, loc->first_line, loc->first_column, loc->last_column);
|
||||||
//exit(EXIT_FAILURE);
|
|
||||||
|
line = tmpstr;
|
||||||
|
do {
|
||||||
|
lineno++;
|
||||||
|
eol = strchr(line, '\n');
|
||||||
|
if (eol)
|
||||||
|
*eol++ = '\0';
|
||||||
|
|
||||||
|
zlog_err ("%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) {
|
||||||
|
|
||||||
|
int len = loc->last_column - loc->first_column;
|
||||||
|
if (len == 0)
|
||||||
|
len = 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);
|
||||||
|
}
|
||||||
|
} while ((line = eol));
|
||||||
|
free(tmpstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -371,7 +402,8 @@ cleanup (struct parser_ctx *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode)
|
terminate_graph (CMD_YYLTYPE *locp, struct parser_ctx *ctx,
|
||||||
|
struct graph_node *finalnode)
|
||||||
{
|
{
|
||||||
// end of graph should look like this
|
// end of graph should look like this
|
||||||
// * -> finalnode -> END_TKN -> cmd_element
|
// * -> finalnode -> END_TKN -> cmd_element
|
||||||
@ -385,7 +417,7 @@ terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode)
|
|||||||
graph_new_node (ctx->graph, element, NULL);
|
graph_new_node (ctx->graph, element, NULL);
|
||||||
|
|
||||||
if (node_adjacent (finalnode, end_token_node))
|
if (node_adjacent (finalnode, end_token_node))
|
||||||
cmd_yyerror (ctx, "Duplicate command.");
|
cmd_yyerror (locp, ctx, "Duplicate command.");
|
||||||
|
|
||||||
graph_add_edge (finalnode, end_token_node);
|
graph_add_edge (finalnode, end_token_node);
|
||||||
graph_add_edge (end_token_node, end_element_node);
|
graph_add_edge (end_token_node, end_element_node);
|
||||||
|
Loading…
Reference in New Issue
Block a user