]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: parser: use reentrant mode on flex & bison
authorDavid Lamparter <equinox@opensourcerouting.org>
Wed, 16 Nov 2016 06:03:51 +0000 (15:03 +0900)
committerDavid Lamparter <equinox@opensourcerouting.org>
Thu, 1 Dec 2016 17:45:27 +0000 (18:45 +0100)
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>
lib/command_lex.l
lib/command_parse.y

index 5c709dce222120299e5c846f37a862fe5bbf8c07..e978803b2213e8cf27ad277366cfc8a9993dfd26 100644 (file)
 
 %{
 #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);
 }
index aac4a746668b24d611105dbbb513896ed5f6e1ea..d084ddd73f41e64d9e4aaa4a43424c6e3eb5649f 100644 (file)
  */
 
 %{
+
+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"
   #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
 }
 %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 {
 
   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 {
 
   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);