]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/command_parse.y
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[mirror_frr.git] / lib / command_parse.y
index 1c220b6b69843e574e380bf10acf574a944be423..1b304a98b2b151dcaa51084d98383b7c340a31cc 100644 (file)
@@ -33,8 +33,8 @@
 /* define api.prefix {cmd_yy} */
 
 /* names for generated header and parser files */
-%defines "command_parse.h"
-%output  "command_parse.c"
+%defines "lib/command_parse.h"
+%output  "lib/command_parse.c"
 
 /* note: code blocks are output in order, to both .c and .h:
  *  1. %code requires
  * struct parser_ctx is needed for the bison forward decls.
  */
 %code requires {
-  #include "stdlib.h"
-  #include "string.h"
-  #include "memory.h"
-  #include "command.h"
+  #include "config.h"
+
+  #include <stdlib.h>
+  #include <string.h>
+  #include <ctype.h>
+
+  #include "command_graph.h"
   #include "log.h"
-  #include "graph.h"
 
   DECLARE_MTYPE(LEX)
 
 %token <string> IPV6_PREFIX
 %token <string> VARIABLE
 %token <string> RANGE
+%token <string> MAC
+%token <string> MAC_PREFIX
 
 /* union types for parsed rules */
 %type <node> start
 %type <node> literal_token
 %type <node> placeholder_token
+%type <node> placeholder_token_real
 %type <node> simple_token
 %type <subgraph> selector
 %type <subgraph> selector_token
 %type <subgraph> selector_token_seq
 %type <subgraph> selector_seq_seq
 
+%type <string> varname_token
+
 %code {
 
   /* bison declarations */
   static const char *
   doc_next (struct parser_ctx *ctx);
 
-  static struct graph_node *
-  node_adjacent (struct graph_node *, struct graph_node *);
-
-  static struct graph_node *
-  add_edge_dedup (struct graph_node *, struct graph_node *);
-
-  static int
-  cmp_token (struct cmd_token *, struct cmd_token *);
-
   static struct graph_node *
   new_token_node (struct parser_ctx *,
                   enum cmd_token_type type,
@@ -179,20 +177,30 @@ start:
 }
 | cmd_token_seq placeholder_token '.' '.' '.'
 {
-  if ((ctx->currnode = add_edge_dedup (ctx->currnode, $2)) != $2)
+  if ((ctx->currnode = graph_add_edge (ctx->currnode, $2)) != $2)
     graph_delete_node (ctx->graph, $2);
 
   ((struct cmd_token *)ctx->currnode->data)->allowrepeat = 1;
 
   // 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 (ctx->currnode, ctx->currnode);
+  graph_add_edge (ctx->currnode, ctx->currnode);
 
   // tack on the command element
   terminate_graph (&@1, ctx, ctx->currnode);
 }
 ;
 
+varname_token: '$' WORD
+{
+  $$ = $2;
+}
+| /* empty */
+{
+  $$ = NULL;
+}
+;
+
 cmd_token_seq:
   /* empty */
 | cmd_token_seq cmd_token
@@ -201,7 +209,7 @@ cmd_token_seq:
 cmd_token:
   simple_token
 {
-  if ((ctx->currnode = add_edge_dedup (ctx->currnode, $1)) != $1)
+  if ((ctx->currnode = graph_add_edge (ctx->currnode, $1)) != $1)
     graph_delete_node (ctx->graph, $1);
 }
 | selector
@@ -216,14 +224,16 @@ simple_token:
 | placeholder_token
 ;
 
-literal_token: WORD
+literal_token: WORD varname_token
 {
   $$ = new_token_node (ctx, WORD_TKN, $1, doc_next(ctx));
+  cmd_token_varname_set ($$->data, $2);
+  XFREE (MTYPE_LEX, $2);
   XFREE (MTYPE_LEX, $1);
 }
 ;
 
-placeholder_token:
+placeholder_token_real:
   IPV4
 {
   $$ = new_token_node (ctx, IPV4_TKN, $1, doc_next(ctx));
@@ -265,11 +275,33 @@ placeholder_token:
 
   XFREE (MTYPE_LEX, $1);
 }
+| MAC
+{
+  $$ = new_token_node (ctx, MAC_TKN, $1, doc_next(ctx));
+  XFREE (MTYPE_LEX, $1);
+}
+| MAC_PREFIX
+{
+  $$ = new_token_node (ctx, MAC_PREFIX_TKN, $1, doc_next(ctx));
+  XFREE (MTYPE_LEX, $1);
+}
+
+placeholder_token:
+  placeholder_token_real varname_token
+{
+  struct cmd_token *token = $$->data;
+  $$ = $1;
+  cmd_token_varname_set (token, $2);
+  XFREE (MTYPE_LEX, $2);
+};
+
 
 /* <selector|set> productions */
-selector: '<' selector_seq_seq '>'
+selector: '<' selector_seq_seq '>' varname_token
 {
   $$ = $2;
+  cmd_token_varname_set ($2.end->data, $4);
+  XFREE (MTYPE_LEX, $4);
 };
 
 selector_seq_seq:
@@ -292,7 +324,7 @@ selector_seq_seq:
 ;
 
 /* {keyword} productions */
-selector: '{' selector_seq_seq '}'
+selector: '{' selector_seq_seq '}' varname_token
 {
   $$ = $2;
   graph_add_edge ($$.end, $$.start);
@@ -302,6 +334,9 @@ selector: '{' selector_seq_seq '}'
    *    loop-avoidal fails to handle
    * just use [{a|b}] if neccessary, that will work perfectly fine, and reason
    * #1 is good enough to keep it this way. */
+
+  cmd_token_varname_set ($2.end->data, $4);
+  XFREE (MTYPE_LEX, $4);
 };
 
 
@@ -324,10 +359,12 @@ selector_token_seq:
 ;
 
 /* [option] productions */
-selector: '[' selector_seq_seq ']'
+selector: '[' selector_seq_seq ']' varname_token
 {
   $$ = $2;
   graph_add_edge ($$.start, $$.end);
+  cmd_token_varname_set ($2.end->data, $4);
+  XFREE (MTYPE_LEX, $4);
 }
 ;
 
@@ -338,7 +375,7 @@ selector: '[' selector_seq_seq ']'
 DEFINE_MTYPE(LIB, LEX, "Lexer token (temporary)")
 
 void
-command_parse_format (struct graph *graph, struct cmd_element *cmd)
+cmd_graph_parse (struct graph *graph, struct cmd_element *cmd)
 {
   struct parser_ctx ctx = { .graph = graph, .el = cmd };
 
@@ -367,8 +404,8 @@ yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
   char spacing[256];
   int lineno = 0;
 
-  zlog_err ("%s: FATAL parse error: %s", __func__, msg);
-  zlog_err ("%s: %d:%d-%d of this command definition:", __func__, loc->first_line, loc->first_column, loc->last_column);
+  zlog_notice ("%s: FATAL parse error: %s", __func__, msg);
+  zlog_notice ("%s: %d:%d-%d of this command definition:", __func__, loc->first_line, loc->first_column, loc->last_column);
 
   line = tmpstr;
   do {
@@ -377,7 +414,7 @@ yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
     if (eol)
       *eol++ = '\0';
 
-    zlog_err ("%s: | %s", __func__, line);
+    zlog_notice ("%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) {
@@ -389,7 +426,7 @@ yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
       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);
+      zlog_notice ("%s: | %s", __func__, spacing);
     }
   } while ((line = eol));
   free(tmpstr);
@@ -418,8 +455,13 @@ terminate_graph (CMD_YYLTYPE *locp, struct parser_ctx *ctx,
   struct graph_node *end_element_node =
     graph_new_node (ctx->graph, element, NULL);
 
-  if (node_adjacent (finalnode, end_token_node))
-    cmd_yyerror (locp, ctx, "Duplicate command.");
+  if (ctx->docstr && strlen (ctx->docstr) > 1) {
+    zlog_debug ("Excessive docstring while parsing '%s'", ctx->el->string);
+    zlog_debug ("----------");
+    while (ctx->docstr && ctx->docstr[1] != '\0')
+      zlog_debug ("%s", strsep(&ctx->docstr, "\n"));
+    zlog_debug ("----------\n");
+  }
 
   graph_add_edge (finalnode, end_token_node);
   graph_add_edge (end_token_node, end_element_node);
@@ -442,99 +484,6 @@ static struct graph_node *
 new_token_node (struct parser_ctx *ctx, enum cmd_token_type type,
                 const char *text, const char *doc)
 {
-  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);
-}
-
-/**
- * Determines if there is an out edge from the first node to the second
- */
-static struct graph_node *
-node_adjacent (struct graph_node *first, struct graph_node *second)
-{
-  struct graph_node *adj;
-  for (unsigned int i = 0; i < vector_active (first->to); i++)
-    {
-      adj = vector_slot (first->to, i);
-      struct cmd_token *ftok = adj->data,
-                         *stok = second->data;
-      if (cmp_token (ftok, stok))
-        return adj;
-    }
-  return NULL;
-}
-
-/**
- * Creates an edge betwen two nodes, unless there is already an edge to an
- * equivalent node.
- *
- * The first node's out edges are searched to see if any of them point to a
- * node that is equivalent to the second node. If such a node exists, it is
- * returned. Otherwise an edge is created from the first node to the second.
- *
- * @param from start node for edge
- * @param to end node for edge
- * @return the node which the new edge points to
- */
-static struct graph_node *
-add_edge_dedup (struct graph_node *from, struct graph_node *to)
-{
-  struct graph_node *existing = node_adjacent (from, to);
-  if (existing)
-  {
-    struct cmd_token *ex_tok = existing->data;
-    struct cmd_token *to_tok = to->data;
-    // NORMAL takes precedence over DEPRECATED takes precedence over HIDDEN
-    ex_tok->attr = (ex_tok->attr < to_tok->attr) ? ex_tok->attr : to_tok->attr;
-    return existing;
-  }
-  else
-    return graph_add_edge (from, to);
-}
-
-/**
- * Compares two cmd_token's for equality,
- *
- * As such, this function is the working definition of token equality
- * for parsing purposes and determines overall graph structure.
- */
-static int
-cmp_token (struct cmd_token *first, struct cmd_token *second)
-{
-  // compare types
-  if (first->type != second->type) return 0;
-
-  switch (first->type) {
-    case WORD_TKN:
-    case VARIABLE_TKN:
-      if (first->text && second->text)
-        {
-          if (strcmp (first->text, second->text))
-            return 0;
-        }
-      else if (first->text != second->text) return 0;
-      break;
-    case RANGE_TKN:
-      if (first->min != second->min || first->max != second->max)
-        return 0;
-      break;
-    /* selectors and options should be equal if their subgraphs are equal,
-     * but the graph isomorphism problem is not known to be solvable in
-     * polynomial time so we consider selectors and options inequal in all
-     * cases; ultimately this forks the graph, but the matcher can handle
-     * this regardless
-     */
-    case FORK_TKN:
-      return 0;
-
-    /* end nodes are always considered equal, since each node may only
-     * have one END_TKN child at a time
-     */
-    case START_TKN:
-    case END_TKN:
-    case JOIN_TKN:
-    default:
-      break;
-  }
-  return 1;
+  struct cmd_token *token = cmd_token_new (type, ctx->el->attr, text, doc);
+  return graph_new_node (ctx->graph, token, (void (*)(void *)) &cmd_token_del);
 }