]> git.ipfire.org Git - thirdparty/bird.git/blobdiff - filter/f-inst.c
Filter: Getting rid of RESULT_OK. Adding RESULT_VOID.
[thirdparty/bird.git] / filter / f-inst.c
index 4ab46529fee7b2753d8b98dabf3497240b9dd985..d48a60866f526ef6148813bc092538106fe85d02 100644 (file)
@@ -7,47 +7,81 @@
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
  *
+ *     Filter instructions. You shall define your instruction only here
+ *     and nowhere else.
+ *
+ *     Beware. This file is interpreted by M4 macros. These macros
+ *     may be more stupid than you could imagine. If something strange
+ *     happens after changing this file, compare the results before and
+ *     after your change (see the Makefile to find out where the results are)
+ *     and see what really happened.
+ *
+ *     This file is not directly a C source code -> it is a generator input
+ *     for several C sources; every instruction block gets expanded into many
+ *     different places.
+ *
+ *     What is the syntax here?
+ *     m4_dnl  INST(FI_NOP, in, out) {                 enum value, input args, output args
+ *     m4_dnl    ARG(num, type);                       argument, its id (in data fields) and type
+ *     m4_dnl    ARG_ANY(num);                         argument with no type check
+ *     m4_dnl    LINE(num, unused);                    this argument has to be converted to its own f_line
+ *     m4_dnl    ECS;                                  extended community subtype
+ *     m4_dnl    COUNT(unused);                        simply a uint
+ *     m4_dnl    SYMBOL;                               symbol handed from config
+ *     m4_dnl    FRET;                                 filter return value
+ *     m4_dnl    STATIC_ATTR;                          static attribute definition
+ *     m4_dnl    DYNAMIC_ATTR;                         dynamic attribute definition
+ *     m4_dnl    RTC;                                  route table config
+ *     m4_dnl    TREE;                                 a tree
+ *     m4_dnl    ACCESS_RTE;                           this instruction needs route
+ *     m4_dnl    ACCESS_EATTRS;                        this instruction needs extended attributes
+ *     m4_dnl    RESULT(type, union-field, value);     putting this on value stack
+ *     m4_dnl    RESULT_VAL(value-struct);             pass the struct f_val directly
+ *     m4_dnl    RESULT_VOID;                          return undef
+ *     m4_dnl  }
+ *
+ *     Other code is just copied into the interpreter part.
+ *
+ *     If you want to write something really special, see FI_CALL
+ *     or FI_CONSTANT or whatever else to see how to use the FID_*
+ *     macros.
  */
 
 /* Binary operators */
   INST(FI_ADD, 2, 1) {
     ARG(1,T_INT);
     ARG(2,T_INT);
-    res.val.i += v2.val.i;
-    RESULT_OK;
+    RESULT(T_INT, i, v1.val.i + v2.val.i);
   }
   INST(FI_SUBTRACT, 2, 1) {
     ARG(1,T_INT);
     ARG(2,T_INT);
-    res.val.i -= v2.val.i;
-    RESULT_OK;
+    RESULT(T_INT, i, v1.val.i - v2.val.i);
   }
   INST(FI_MULTIPLY, 2, 1) {
     ARG(1,T_INT);
     ARG(2,T_INT);
-    res.val.i *= v2.val.i;
-    RESULT_OK;
+    RESULT(T_INT, i, v1.val.i * v2.val.i);
   }
   INST(FI_DIVIDE, 2, 1) {
     ARG(1,T_INT);
     ARG(2,T_INT);
     if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
-    res.val.i /= v2.val.i;
-    RESULT_OK;
+    RESULT(T_INT, i, v1.val.i / v2.val.i);
   }
   INST(FI_AND, 1, 1) {
     ARG(1,T_BOOL);
-    if (res.val.i)
+    if (v1.val.i)
       LINE(2,0);
     else
-      RESULT_OK;
+      RESULT_VAL(v1);
   }
   INST(FI_OR, 1, 1) {
     ARG(1,T_BOOL);
-    if (!res.val.i)
+    if (!v1.val.i)
       LINE(2,0);
     else
-      RESULT_OK;
+      RESULT_VAL(v1);
   }
   INST(FI_PAIR_CONSTRUCT, 2, 1) {
     ARG(1,T_INT);
        if (tt->fi_code != FI_CONSTANT)
          dyn++;
 
-      what->count = len;
-    FID_END
+      whati->count = len;
+    FID_ALL
 
-    if (vstk.cnt < what->count) /* TODO: make this check systematic */
-      runtime("Construction of BGP path mask from %u elements must have at least that number of elements", what->count);
+    if (fstk->vcnt < whati->count) /* TODO: make this check systematic */
+      runtime("Construction of BGP path mask from %u elements must have at least that number of elements", whati->count);
 
-    struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + what->count * sizeof(struct f_path_mask_item));
-    for (uint i=0; i<what->count; i++) {
-//#define pv vstk.val[vstk.cnt-i-1]
-#define pv vstk.val[vstk.cnt - what->count + i]
+    struct f_path_mask *pm = lp_alloc(fs->pool, sizeof(struct f_path_mask) + whati->count * sizeof(struct f_path_mask_item));
+    for (uint i=0; i<whati->count; i++) {
+#define pv fstk->vstk[fstk->vcnt - whati->count + i]
       switch (pv.type) {
        case T_PATH_MASK_ITEM:
          pm->item[i] = pv.val.pmi;
       }
     }
 
-    vstk.cnt -= what->count;
-    pm->len = what->count;
+    fstk->vcnt -= whati->count;
+    pm->len = whati->count;
 
     RESULT(T_PATH_MASK, path_mask, pm);
   }
     ARG_ANY(1);
     ARG_ANY(2);
     int i = val_in_range(&v1, &v2);
-    if (res.val.i == F_CMP_ERROR)
+    if (i == F_CMP_ERROR)
       runtime( "!~ applied on unknown type pair" );
     RESULT(T_BOOL, i, !i);
   }
   }
 
   /* Set to indirect value prepared in v1 */
-  INST(FI_SET, 1, 0) {
-    ARG_ANY(2);
-    SYMBOL(1);
+  INST(FI_VAR_SET, 1, 0) {
+    ARG_ANY(1);
+    SYMBOL;
     if ((sym->class != (SYM_VARIABLE | v1.type)) && (v1.type != T_VOID))
     {
       /* IP->Quad implicit conversion */
       if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(&v1))
-      {
-       *((struct f_val *) sym->def) = (struct f_val) {
+       v1 = (struct f_val) {
          .type = T_QUAD,
          .val.i = ipa_to_u32(v1.val.ip),
-       }; 
-       break;
-      }
-      runtime( "Assigning to variable of incompatible type" );
+       };
+      else 
+       runtime( "Assigning to variable of incompatible type" );
     }
-    *((struct f_val *) sym->def) = v1;
+
+    fstk->vstk[curline.vbase + sym->offset] = v1;
+  }
+
+  INST(FI_VAR_GET, 0, 1) {
+    SYMBOL(1);
+    RESULT_VAL(fstk->vstk[curline.vbase + sym->offset]);
   }
 
     /* some constants have value in a[1], some in *a[0].p, strange. */
   INST(FI_CONSTANT, 0, 1) {    /* integer (or simple type) constant, string, set, or prefix_set */
-    VALI; // res = what->val;
-    RESULT_OK;
-  }
-  INST(FI_VARIABLE, 0, 1) {
-    VAR;
-    RESULT_OK;
+    FID_LINE_IN
+      struct f_val val;
+    FID_STRUCT_IN
+      struct f_val val;
+    FID_NEW_ARGS
+    , const struct f_val val
+    FID_NEW_BODY
+      whati->val = val;
+    FID_LINEARIZE_BODY
+      item->val = whati->val;
+    FID_SAME_BODY
+      if (!val_same(&(f1->val), &(f2->val))) return 0;
+    FID_DUMP_BODY
+      debug("%svalue %s\n", INDENT, val_dump(&item->val));
+    FID_ALL
+
+    RESULT_VAL(whati->val);
   }
-  INST(FI_CONSTANT_INDIRECT, 0, 1) {
-    VALP;
-    RESULT_OK;
+  INST(FI_CONSTANT_DEFINED, 0, 1) {
+    FID_STRUCT_IN
+      const struct symbol *sym;
+    FID_LINE_IN
+      const struct symbol *sym;
+      const struct f_val *valp;
+    FID_NEW_ARGS
+      , const struct symbol *sym
+    FID_NEW_BODY
+      whati->sym = sym;
+    FID_LINEARIZE_BODY
+      item->valp = (item->sym = whati->sym)->val;
+    FID_SAME_BODY
+      if (strcmp(f1->sym->name, f2->sym->name) || !val_same(f1->sym->val, f2->sym->val)) return 0;
+    FID_DUMP_BODY
+      debug("%sconstant %s with value %s\n", INDENT, item->sym->name, val_dump(item->valp));
+    FID_ALL
+
+    RESULT_VAL(*whati->valp);
   }
   INST(FI_PRINT, 1, 0) {
     ARG_ANY(1);
       LINE(3,1);
   }
   INST(FI_PRINT_AND_DIE, 0, 0) {
-    FID_POSTFIXIFY_BODY
+    FID_LINEARIZE_BODY
     {
       uint opos = pos;
-      FID_END
+      FID_ALL
 
     ARG_ANY(1);
 
-      FID_POSTFIXIFY_BODY
+      FID_LINEARIZE_BODY
       if (opos < pos)
        dest->items[pos].flags |= FIF_PRINTED;
     }
-    FID_END
+    FID_ALL
 
     FRET(2);
 
        }
 
        /* Undefined value */
-       res.type = T_VOID;
-       RESULT_OK;
+       RESULT_VOID;
        break;
       }
 
        RESULT(T_LCLIST, ad, e->u.ptr);
        break;
       case EAF_TYPE_UNDEF:
-       res.type = T_VOID;
-       RESULT_OK;
+       RESULT_VOID;
        break;
       default:
        bug("Unknown dynamic attribute type");
       l->count = 1;
       l->attrs[0].id = da.ea_code;
       l->attrs[0].flags = 0;
-      l->attrs[0].type = EAF_TYPE_UNDEF | EAF_TEMP | EAF_ORIGINATED | EAF_FRESH;
+      l->attrs[0].type = EAF_TYPE_UNDEF | EAF_ORIGINATED | EAF_FRESH;
       l->attrs[0].u.data = 0;
 
       f_rta_cow(fs);
   INST(FI_RETURN, 1, 1) {
     /* Acquire the return value */
     ARG_ANY(1);
-    uint retpos = vstk.cnt;
+    uint retpos = fstk->vcnt;
 
     /* Drop every sub-block including ourselves */
-    while ((estk.cnt-- > 0) && !(estk.item[estk.cnt].emask & FE_RETURN))
+    while ((fstk->ecnt-- > 0) && !(fstk->estk[fstk->ecnt].emask & FE_RETURN))
       ;
 
     /* Now we are at the caller frame; if no such, try to convert to accept/reject. */
-    if (!estk.cnt)
-      if (vstk.val[retpos].type == T_BOOL)
-       if (vstk.val[retpos].val.i)
+    if (!fstk->ecnt)
+      if (fstk->vstk[retpos].type == T_BOOL)
+       if (fstk->vstk[retpos].val.i)
 
          return F_ACCEPT;
        else
       else
        runtime("Can't return non-bool from non-function");
 
-    /* Set the value stack position */
-    vstk.cnt = estk.item[estk.cnt].ventry;
+    /* Set the value stack position, overwriting the former implicit void */
+    fstk->vcnt = fstk->estk[fstk->ecnt].ventry - 1;
 
     /* Copy the return value */
-    RESULT_VAL(vstk.val[retpos]);
+    RESULT_VAL(fstk->vstk[retpos]);
   }
 
   INST(FI_CALL, 0, 1) {
-    /* Do not use the symbol on execution */
-    if (0) {
-      UNUSED SYMBOL;
-    }
-
-    /* Postfixify extracts the function body from the symbol */
-    FID_POSTFIXIFY_BODY
-    dest->items[pos].lines[0] = what->sym->def;
-    FID_END
+    SYMBOL;
 
-    /* First push the body on stack */
-    LINEX(what->lines[0]);
+    /* Push the body on stack */
+    LINEX(sym->function);
     curline.emask |= FE_RETURN;
-
-    /* Then push the arguments */
-    LINE(1,1);
-
-    FID_NEW_BODY
-      if (sym->class != SYM_FUNCTION)
-       cf_error("You can't call something which is not a function. Really.");
-
-      uint count = 0;
-      for (const struct f_inst *inst = f1; inst; inst = inst->next)
-       count++;
-
-      if (count != sym->aux2)
-       cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->aux2, count);
-    FID_END
-
-    /* FIXME: Optimization of function comparison. */
+  
+    /* Before this instruction was called, there was the T_VOID
+     * automatic return value pushed on value stack and also
+     * sym->function->args function arguments. Setting the
+     * vbase to point to first argument. */
+    ASSERT(curline.ventry >= sym->function->args);
+    curline.ventry -= sym->function->args;
+    curline.vbase = curline.ventry;
+
+    /* Storage for local variables */
+    memset(&(fstk->vstk[fstk->vcnt]), 0, sizeof(struct f_val) * sym->function->vars);
+    fstk->vcnt += sym->function->vars;
   }
 
   INST(FI_DROP_RESULT, 1, 0) {
   INST(FI_SWITCH, 1, 0) {
     ARG_ANY(1);
     TREE;
-    const struct f_tree *t = find_tree(what->tree, &v1);
+    const struct f_tree *t = find_tree(tree, &v1);
     if (!t) {
       v1.type = T_VOID;
-      t = find_tree(what->tree, &v1);
+      t = find_tree(tree, &v1);
       if (!t) {
        debug( "No else statement?\n");
        break;