mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-04 02:06:12 +00:00
lib: parser: use reentrant mode on flex & bison
This removes remaining global variables from the lexer, pushing the lexer state into struct parser_ctx too. At the same time, "cmd_yy" is used as prefix for all parser & lexer routines. The result is that (a) there is no collision anymore if a program uses flex/bison and links libzebra, and (b) the parser is fully encapsulated and could be called in parallel from multiple threads. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
parent
b07a15f82d
commit
e9484f70b2
@ -24,10 +24,7 @@
|
||||
|
||||
%{
|
||||
#include "command_parse.h"
|
||||
|
||||
extern void set_lexer_string (const char *);
|
||||
extern void cleanup_lexer (void);
|
||||
YY_BUFFER_STATE buffer;
|
||||
#define YYSTYPE CMD_YYSTYPE
|
||||
%}
|
||||
|
||||
WORD (\-|\+)?[a-z\*][-+_a-zA-Z0-9\*]*
|
||||
@ -45,27 +42,34 @@ RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
|
||||
%option nounput
|
||||
%option noinput
|
||||
%option outfile="command_lex.c"
|
||||
%option header-file="command_lex.h"
|
||||
%option prefix="cmd_yy"
|
||||
%option reentrant
|
||||
%option bison-bridge
|
||||
|
||||
%%
|
||||
[ /t] /* ignore whitespace */;
|
||||
{WORD} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return WORD;}
|
||||
{IPV4} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return IPV4;}
|
||||
{IPV4_PREFIX} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return IPV4_PREFIX;}
|
||||
{IPV6} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return IPV6;}
|
||||
{IPV6_PREFIX} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return IPV6_PREFIX;}
|
||||
{VARIABLE} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return VARIABLE;}
|
||||
{RANGE} {yylval.string = XSTRDUP(MTYPE_TMP, yytext); return RANGE;}
|
||||
{WORD} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return WORD;}
|
||||
{IPV4} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4;}
|
||||
{IPV4_PREFIX} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4_PREFIX;}
|
||||
{IPV6} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV6;}
|
||||
{IPV6_PREFIX} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV6_PREFIX;}
|
||||
{VARIABLE} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return VARIABLE;}
|
||||
{RANGE} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return RANGE;}
|
||||
. {return yytext[0];}
|
||||
%%
|
||||
|
||||
void
|
||||
set_lexer_string (const char *string)
|
||||
YY_BUFFER_STATE buffer;
|
||||
|
||||
void set_lexer_string (yyscan_t *scn, const char *string)
|
||||
{
|
||||
buffer = yy_scan_string (string);
|
||||
*scn = NULL;
|
||||
yylex_init(scn);
|
||||
buffer = yy_scan_string (string, *scn);
|
||||
}
|
||||
|
||||
void
|
||||
cleanup_lexer ()
|
||||
void cleanup_lexer (yyscan_t *scn)
|
||||
{
|
||||
yy_delete_buffer (buffer);
|
||||
// yy_delete_buffer (buffer, *scn);
|
||||
yylex_destroy(*scn);
|
||||
}
|
||||
|
@ -23,10 +23,18 @@
|
||||
*/
|
||||
|
||||
%{
|
||||
|
||||
typedef union CMD_YYSTYPE CMD_YYSTYPE;
|
||||
#define YYSTYPE CMD_YYSTYPE
|
||||
#include "command_lex.h"
|
||||
|
||||
// compile with debugging facilities
|
||||
#define YYDEBUG 1
|
||||
%}
|
||||
|
||||
%define api.pure full
|
||||
%define api.prefix {cmd_yy}
|
||||
|
||||
/* names for generated header and parser files */
|
||||
%defines "command_parse.h"
|
||||
%output "command_parse.c"
|
||||
@ -39,16 +47,9 @@
|
||||
#include "log.h"
|
||||
#include "graph.h"
|
||||
|
||||
extern int
|
||||
yylex (void);
|
||||
|
||||
extern void
|
||||
set_lexer_string (const char *);
|
||||
|
||||
extern void
|
||||
cleanup_lexer (void);
|
||||
|
||||
struct parser_ctx {
|
||||
yyscan_t scanner;
|
||||
|
||||
struct cmd_element *el;
|
||||
|
||||
struct graph *graph;
|
||||
@ -61,7 +62,6 @@
|
||||
|
||||
/* functionality this unit exports */
|
||||
%code provides {
|
||||
|
||||
/* maximum length of a number, lexer will not match anything longer */
|
||||
#define DECIMAL_STRLEN_MAX 20
|
||||
}
|
||||
@ -99,9 +99,13 @@
|
||||
%type <subgraph> compound_token
|
||||
|
||||
%code {
|
||||
|
||||
extern void set_lexer_string (yyscan_t *scn, const char *string);
|
||||
extern void cleanup_lexer (yyscan_t *scn);
|
||||
|
||||
/* bison declarations */
|
||||
void
|
||||
yyerror (struct parser_ctx *ctx, char const *msg);
|
||||
cmd_yyerror (struct parser_ctx *ctx, char const *msg);
|
||||
|
||||
/* subgraph semantic value */
|
||||
struct subgraph {
|
||||
@ -133,10 +137,13 @@
|
||||
|
||||
static void
|
||||
cleanup (struct parser_ctx *ctx);
|
||||
|
||||
#define scanner ctx->scanner
|
||||
}
|
||||
|
||||
/* yyparse parameters */
|
||||
%parse-param { struct parser_ctx *ctx }
|
||||
%lex-param {yyscan_t scanner}
|
||||
%parse-param {struct parser_ctx *ctx}
|
||||
|
||||
/* called automatically before yyparse */
|
||||
%initial-action {
|
||||
@ -145,9 +152,6 @@
|
||||
|
||||
ctx->startnode = vector_slot (ctx->graph->nodes, 0);
|
||||
|
||||
/* set string to parse */
|
||||
set_lexer_string (ctx->el->string);
|
||||
|
||||
/* copy docstring and keep a pointer to the copy */
|
||||
if (ctx->el->doc)
|
||||
{
|
||||
@ -272,7 +276,7 @@ placeholder_token:
|
||||
token->max = strtoll (yylval.string, &yylval.string, 10);
|
||||
|
||||
// validate range
|
||||
if (token->min > token->max) yyerror (ctx, "Invalid range.");
|
||||
if (token->min > token->max) cmd_yyerror (ctx, "Invalid range.");
|
||||
|
||||
free ($1);
|
||||
}
|
||||
@ -399,6 +403,8 @@ option_token:
|
||||
|
||||
%%
|
||||
|
||||
#undef scanner
|
||||
|
||||
void
|
||||
command_parse_format (struct graph *graph, struct cmd_element *cmd)
|
||||
{
|
||||
@ -407,8 +413,13 @@ command_parse_format (struct graph *graph, struct cmd_element *cmd)
|
||||
// set to 1 to enable parser traces
|
||||
yydebug = 0;
|
||||
|
||||
set_lexer_string (&ctx.scanner, cmd->string);
|
||||
|
||||
// parse command into DFA
|
||||
yyparse (&ctx);
|
||||
cmd_yyparse (&ctx);
|
||||
|
||||
/* cleanup lexer */
|
||||
cleanup_lexer (&ctx.scanner);
|
||||
|
||||
// cleanup
|
||||
cleanup (&ctx);
|
||||
@ -430,9 +441,6 @@ cleanup (struct parser_ctx *ctx)
|
||||
/* free resources */
|
||||
free (ctx->docstr_start);
|
||||
|
||||
/* cleanup lexer */
|
||||
cleanup_lexer ();
|
||||
|
||||
/* clear state pointers */
|
||||
ctx->currnode = NULL;
|
||||
ctx->docstr_start = ctx->docstr = NULL;
|
||||
@ -453,7 +461,7 @@ terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode)
|
||||
graph_new_node (ctx->graph, element, (void (*)(void *)) &del_cmd_element);
|
||||
|
||||
if (node_adjacent (finalnode, end_token_node))
|
||||
yyerror (ctx, "Duplicate command.");
|
||||
cmd_yyerror (ctx, "Duplicate command.");
|
||||
|
||||
graph_add_edge (finalnode, end_token_node);
|
||||
graph_add_edge (end_token_node, end_element_node);
|
||||
|
Loading…
Reference in New Issue
Block a user