]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib: parser: wrap state in struct parser_ctx
authorDavid Lamparter <equinox@opensourcerouting.org>
Wed, 23 Nov 2016 08:02:08 +0000 (09:02 +0100)
committerDavid Lamparter <equinox@opensourcerouting.org>
Thu, 1 Dec 2016 17:45:27 +0000 (18:45 +0100)
This encapsulates all parser state into a new "struct parser_ctx", which
is allocated on stack and passed around as pointer.  The parser no
longer has any global variables with this.

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
lib/command_parse.y

index ac8e0601132509b6fee11f7418d0e8bc8b6b3dcf..aac4a746668b24d611105dbbb513896ed5f6e1ea 100644 (file)
 
   extern void
   cleanup_lexer (void);
+  struct parser_ctx {
+    struct cmd_element *el;
+
+    struct graph *graph;
+    struct graph_node *currnode, *startnode;
+
+    /* pointers to copy of command docstring */
+    char *docstr_start, *docstr;
+  };
 }
 
 /* functionality this unit exports */
 %code {
   /* bison declarations */
   void
-  yyerror (struct graph *, struct cmd_element *el, char const *msg);
+  yyerror (struct parser_ctx *ctx, char const *msg);
 
   /* subgraph semantic value */
   struct subgraph {
     struct graph_node *start, *end;
   };
 
-  struct graph_node *currnode, *startnode;
-
-  /* pointers to copy of command docstring */
-  char *docstr_start, *docstr;
-
   /* helper functions for parser */
   static char *
-  doc_next (struct cmd_element *);
+  doc_next (struct parser_ctx *ctx);
 
   static struct graph_node *
   node_adjacent (struct graph_node *, struct graph_node *);
   cmp_token (struct cmd_token *, struct cmd_token *);
 
   static struct graph_node *
-  new_token_node (struct graph *,
+  new_token_node (struct parser_ctx *,
                   enum cmd_token_type type,
-                  u_char attr, char *text,
+                  char *text,
                   char *doc);
 
   static void
-  terminate_graph (struct graph *,
-                   struct graph_node *,
-                   struct cmd_element *);
+  terminate_graph (struct parser_ctx *ctx,
+                   struct graph_node *);
 
   static void
-  cleanup (void);
+  cleanup (struct parser_ctx *ctx);
 }
 
 /* yyparse parameters */
-%parse-param { struct graph *graph }
-%parse-param { struct cmd_element *el }
+%parse-param { struct parser_ctx *ctx }
 
 /* called automatically before yyparse */
 %initial-action {
   /* clear state pointers */
-  currnode = startnode = NULL;
+  ctx->currnode = ctx->startnode = NULL;
 
-  startnode = vector_slot (graph->nodes, 0);
+  ctx->startnode = vector_slot (ctx->graph->nodes, 0);
 
   /* set string to parse */
-  set_lexer_string (el->string);
+  set_lexer_string (ctx->el->string);
 
   /* copy docstring and keep a pointer to the copy */
-  if (el->doc)
+  if (ctx->el->doc)
   {
     // allocate a new buffer, making room for a flag
-    size_t length = (size_t) strlen (el->doc) + 2;
-    docstr = malloc (length);
-    memcpy (docstr, el->doc, strlen (el->doc));
+    size_t length = (size_t) strlen (ctx->el->doc) + 2;
+    ctx->docstr = malloc (length);
+    memcpy (ctx->docstr, ctx->el->doc, strlen (ctx->el->doc));
     // set the flag so doc_next knows when to print a warning
-    docstr[length - 2] = 0x03;
+    ctx->docstr[length - 2] = 0x03;
     // null terminate
-    docstr[length - 1] = 0x00;
+    ctx->docstr[length - 1] = 0x00;
   }
-  docstr_start = docstr;
+  ctx->docstr_start = ctx->docstr;
 }
 
 %%
@@ -166,32 +169,32 @@ start:
   sentence_root cmd_token_seq
 {
   // tack on the command element
-  terminate_graph (graph, currnode, el);
+  terminate_graph (ctx, ctx->currnode);
 }
 | sentence_root cmd_token_seq placeholder_token '.' '.' '.'
 {
-  if ((currnode = add_edge_dedup (currnode, $3)) != $3)
-    graph_delete_node (graph, $3);
+  if ((ctx->currnode = add_edge_dedup (ctx->currnode, $3)) != $3)
+    graph_delete_node (ctx->graph, $3);
 
   // adding a node as a child of itself accepts any number
   // of the same token, which is what we want for variadics
-  add_edge_dedup (currnode, currnode);
+  add_edge_dedup (ctx->currnode, ctx->currnode);
 
   // tack on the command element
-  terminate_graph (graph, currnode, el);
+  terminate_graph (ctx, ctx->currnode);
 }
 ;
 
 sentence_root: WORD
 {
   struct graph_node *root =
-    new_token_node (graph, WORD_TKN, el->attr, strdup ($1), doc_next(el));
+    new_token_node (ctx, WORD_TKN, strdup ($1), doc_next(ctx));
 
-  if ((currnode = add_edge_dedup (startnode, root)) != root)
-    graph_delete_node (graph, root);
+  if ((ctx->currnode = add_edge_dedup (ctx->startnode, root)) != root)
+    graph_delete_node (ctx->graph, root);
 
   free ($1);
-  $$ = currnode;
+  $$ = ctx->currnode;
 }
 ;
 
@@ -203,13 +206,13 @@ cmd_token_seq:
 cmd_token:
   simple_token
 {
-  if ((currnode = add_edge_dedup (currnode, $1)) != $1)
-    graph_delete_node (graph, $1);
+  if ((ctx->currnode = add_edge_dedup (ctx->currnode, $1)) != $1)
+    graph_delete_node (ctx->graph, $1);
 }
 | compound_token
 {
-  graph_add_edge (currnode, $1->start);
-  currnode = $1->end;
+  graph_add_edge (ctx->currnode, $1->start);
+  ctx->currnode = $1->end;
   free ($1);
 }
 ;
@@ -226,7 +229,7 @@ compound_token:
 
 literal_token: WORD
 {
-  $$ = new_token_node (graph, WORD_TKN, el->attr, strdup($1), doc_next(el));
+  $$ = new_token_node (ctx, WORD_TKN, strdup($1), doc_next(ctx));
   free ($1);
 }
 ;
@@ -234,32 +237,32 @@ literal_token: WORD
 placeholder_token:
   IPV4
 {
-  $$ = new_token_node (graph, IPV4_TKN, el->attr, strdup($1), doc_next(el));
+  $$ = new_token_node (ctx, IPV4_TKN, strdup($1), doc_next(ctx));
   free ($1);
 }
 | IPV4_PREFIX
 {
-  $$ = new_token_node (graph, IPV4_PREFIX_TKN, el->attr, strdup($1), doc_next(el));
+  $$ = new_token_node (ctx, IPV4_PREFIX_TKN, strdup($1), doc_next(ctx));
   free ($1);
 }
 | IPV6
 {
-  $$ = new_token_node (graph, IPV6_TKN, el->attr, strdup($1), doc_next(el));
+  $$ = new_token_node (ctx, IPV6_TKN, strdup($1), doc_next(ctx));
   free ($1);
 }
 | IPV6_PREFIX
 {
-  $$ = new_token_node (graph, IPV6_PREFIX_TKN, el->attr, strdup($1), doc_next(el));
+  $$ = new_token_node (ctx, IPV6_PREFIX_TKN, strdup($1), doc_next(ctx));
   free ($1);
 }
 | VARIABLE
 {
-  $$ = new_token_node (graph, VARIABLE_TKN, el->attr, strdup($1), doc_next(el));
+  $$ = new_token_node (ctx, VARIABLE_TKN, strdup($1), doc_next(ctx));
   free ($1);
 }
 | RANGE
 {
-  $$ = new_token_node (graph, RANGE_TKN, el->attr, strdup($1), doc_next(el));
+  $$ = new_token_node (ctx, RANGE_TKN, strdup($1), doc_next(ctx));
   struct cmd_token *token = $$->data;
 
   // get the numbers out
@@ -269,7 +272,7 @@ placeholder_token:
   token->max = strtoll (yylval.string, &yylval.string, 10);
 
   // validate range
-  if (token->min > token->max) yyerror (graph, el, "Invalid range.");
+  if (token->min > token->max) yyerror (ctx, "Invalid range.");
 
   free ($1);
 }
@@ -278,8 +281,8 @@ placeholder_token:
 selector: '<' selector_seq_seq '>'
 {
   $$ = malloc (sizeof (struct subgraph));
-  $$->start = new_token_node (graph, SELECTOR_TKN, el->attr, NULL, NULL);
-  $$->end   = new_token_node (graph, NUL_TKN, el->attr, NULL, NULL);
+  $$->start = new_token_node (ctx, SELECTOR_TKN, NULL, NULL);
+  $$->end   = new_token_node (ctx, NUL_TKN, NULL, NULL);
   for (unsigned int i = 0; i < vector_active ($2->start->to); i++)
   {
     struct graph_node *sn = vector_slot ($2->start->to, i),
@@ -287,8 +290,8 @@ selector: '<' selector_seq_seq '>'
     graph_add_edge ($$->start, sn);
     graph_add_edge (en, $$->end);
   }
-  graph_delete_node (graph, $2->start);
-  graph_delete_node (graph, $2->end);
+  graph_delete_node (ctx->graph, $2->start);
+  graph_delete_node (ctx->graph, $2->end);
   free ($2);
 };
 
@@ -296,8 +299,8 @@ selector_seq_seq:
   selector_seq_seq '|' selector_token_seq
 {
   $$ = malloc (sizeof (struct subgraph));
-  $$->start = graph_new_node (graph, NULL, NULL);
-  $$->end   = graph_new_node (graph, NULL, NULL);
+  $$->start = graph_new_node (ctx->graph, NULL, NULL);
+  $$->end   = graph_new_node (ctx->graph, NULL, NULL);
 
   // link in last sequence
   graph_add_edge ($$->start, $3->start);
@@ -310,16 +313,16 @@ selector_seq_seq:
     graph_add_edge ($$->start, sn);
     graph_add_edge (en, $$->end);
   }
-  graph_delete_node (graph, $1->start);
-  graph_delete_node (graph, $1->end);
+  graph_delete_node (ctx->graph, $1->start);
+  graph_delete_node (ctx->graph, $1->end);
   free ($1);
   free ($3);
 }
 | selector_token_seq '|' selector_token_seq
 {
   $$ = malloc (sizeof (struct subgraph));
-  $$->start = graph_new_node (graph, NULL, NULL);
-  $$->end   = graph_new_node (graph, NULL, NULL);
+  $$->start = graph_new_node (ctx->graph, NULL, NULL);
+  $$->end   = graph_new_node (ctx->graph, NULL, NULL);
   graph_add_edge ($$->start, $1->start);
   graph_add_edge ($1->end, $$->end);
   graph_add_edge ($$->start, $3->start);
@@ -361,8 +364,8 @@ option: '[' option_token_seq ']'
 {
   // make a new option
   $$ = malloc (sizeof (struct subgraph));
-  $$->start = new_token_node (graph, OPTION_TKN, el->attr, NULL, NULL);
-  $$->end   = new_token_node (graph, NUL_TKN, el->attr, NULL, NULL);
+  $$->start = new_token_node (ctx, OPTION_TKN, NULL, NULL);
+  $$->end   = new_token_node (ctx, NUL_TKN, NULL, NULL);
   // add a path through the sequence to the end
   graph_add_edge ($$->start, $2->start);
   graph_add_edge ($2->end, $$->end);
@@ -399,69 +402,70 @@ option_token:
 void
 command_parse_format (struct graph *graph, struct cmd_element *cmd)
 {
+  struct parser_ctx ctx = { .graph = graph, .el = cmd };
+
   // set to 1 to enable parser traces
   yydebug = 0;
 
   // parse command into DFA
-  yyparse (graph, cmd);
+  yyparse (&ctx);
 
   // cleanup
-  cleanup ();
+  cleanup (&ctx);
 }
 
 /* parser helper functions */
 
 void
-yyerror (struct graph *graph, struct cmd_element *el, char const *msg)
+yyerror (struct parser_ctx *ctx, char const *msg)
 {
   zlog_err ("%s: FATAL parse error: %s", __func__, msg);
-  zlog_err ("while parsing this command definition: \n\t%s\n", el->string);
+  zlog_err ("while parsing this command definition: \n\t%s\n", ctx->el->string);
   //exit(EXIT_FAILURE);
 }
 
 static void
-cleanup()
+cleanup (struct parser_ctx *ctx)
 {
   /* free resources */
-  free (docstr_start);
+  free (ctx->docstr_start);
 
   /* cleanup lexer */
   cleanup_lexer ();
 
   /* clear state pointers */
-  currnode = NULL;
-  docstr_start = docstr = NULL;
+  ctx->currnode = NULL;
+  ctx->docstr_start = ctx->docstr = NULL;
 }
 
 static void
-terminate_graph (struct graph *graph, struct graph_node *finalnode,
-                 struct cmd_element *element)
+terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode)
 {
   // end of graph should look like this
   // * -> finalnode -> END_TKN -> cmd_element
+  struct cmd_element *element = ctx->el;
   struct graph_node *end_token_node =
-    new_token_node (graph,
+    new_token_node (ctx,
                     END_TKN,
-                    element->attr,
                     strdup (CMD_CR_TEXT),
                     strdup (""));
   struct graph_node *end_element_node =
-    graph_new_node (graph, element, (void (*)(void *)) &del_cmd_element);
+    graph_new_node (ctx->graph, element, (void (*)(void *)) &del_cmd_element);
 
   if (node_adjacent (finalnode, end_token_node))
-    yyerror (graph, element, "Duplicate command.");
+    yyerror (ctx, "Duplicate command.");
 
   graph_add_edge (finalnode, end_token_node);
   graph_add_edge (end_token_node, end_element_node);
 }
 
 static char *
-doc_next (struct cmd_element *el)
+doc_next (struct parser_ctx *ctx)
 {
-  const char *piece = docstr ? strsep (&docstr, "\n") : "";
+  const char *piece = ctx->docstr ? strsep (&ctx->docstr, "\n") : "";
   if (*piece == 0x03)
   {
-    zlog_debug ("Ran out of docstring while parsing '%s'", el->string);
+    zlog_debug ("Ran out of docstring while parsing '%s'", ctx->el->string);
     piece = "";
   }
 
@@ -469,11 +473,11 @@ doc_next (struct cmd_element *el)
 }
 
 static struct graph_node *
-new_token_node (struct graph *graph, enum cmd_token_type type,
-                u_char attr, char *text, char *doc)
+new_token_node (struct parser_ctx *ctx, enum cmd_token_type type,
+                char *text, char *doc)
 {
-  struct cmd_token *token = new_cmd_token (type, attr, text, doc);
-  return graph_new_node (graph, token, (void (*)(void *)) &del_cmd_token);
+  struct cmd_token *token = new_cmd_token (type, ctx->el->attr, text, doc);
+  return graph_new_node (ctx->graph, token, (void (*)(void *)) &del_cmd_token);
 }
 
 /**