From: David Lamparter Date: Wed, 16 Nov 2016 06:03:51 +0000 (+0900) Subject: lib: parser: use reentrant mode on flex & bison X-Git-Tag: frr-3.0-branchpoint~133^2~3 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=e9484f70b21ed49d0ca6dbf2899b3a6306ffd2e9;p=matthieu%2Ffrr.git 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 --- diff --git a/lib/command_lex.l b/lib/command_lex.l index 5c709dce22..e978803b22 100644 --- a/lib/command_lex.l +++ b/lib/command_lex.l @@ -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); } diff --git a/lib/command_parse.y b/lib/command_parse.y index aac4a74666..d084ddd73f 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -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 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);