diff --git a/conf/confbase.Y b/conf/confbase.Y index bcfd3f1a..775af22d 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -64,7 +64,9 @@ CF_DECLS struct rtable_config *r; struct channel_config *cc; struct f_inst *x; - struct f_inst *xp[2]; + struct { + struct f_inst *begin, *end; + } xp; enum filter_return fret; enum ec_subtype ecs; struct f_dynamic_attr fda; diff --git a/filter/config.Y b/filter/config.Y index ff2b966e..c40f28d4 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -447,7 +447,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %nonassoc ELSE %type cmds_int -%type term block cmd cmds constant constructor print_one print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail +%type term block cmd cmds constant constructor print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail %type dynamic_attr %type static_attr %type filter where_filter @@ -621,11 +621,21 @@ function_def: /* Programs */ cmds: /* EMPTY */ { $$ = NULL; } - | cmds_int { $$ = $1[0]; } + | cmds_int { $$ = $1.begin; } ; -cmds_int: cmd { $$[0] = $$[1] = $1; } - | cmds_int cmd { $$[1] = $2; $1[1]->next = $2; $$[0] = $1[0]; } +cmds_int: cmd { + $$.begin = $$.end = $1; + while ($$.end->next) + $$.end = $$.end->next; + } + | cmds_int cmd { + $$.begin = $1.begin; + $1.end->next = $2; + $$.end = $2; + while ($$.end->next) + $$.end = $$.end->next; + } ; block: @@ -960,17 +970,13 @@ break_command: | PRINTN { $$ = F_NONL; } ; -print_one: - term { $$ = f_new_inst(FI_PRINT, $1); } - ; - print_list: /* EMPTY */ { $$ = NULL; } - | print_one { $$ = $1; } - | print_one ',' print_list { - if ($1) { - $1->next = $3; - $$ = $1; - } else $$ = $3; + | term { $$ = $1; } + | term ',' print_list { + ASSERT($1); + ASSERT($1->next == NULL); + $1->next = $3; + $$ = $1; } ; @@ -1011,7 +1017,22 @@ cmd: | UNSET '(' dynamic_attr ')' ';' { $$ = f_new_inst(FI_EA_UNSET, $3); } - | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE, $2, $1); } + | break_command print_list ';' { + struct f_inst *breaker = NULL; + struct f_inst *printer = NULL; + if ($2) + printer = f_new_inst(FI_PRINT, $2); + if ($1 != F_NONL) + breaker = f_new_inst(FI_DIE, $1); + + if (printer && breaker) + printer->next = breaker; + + if (printer) + $$ = printer; + else + $$ = breaker; + } | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); } | CASE term '{' switch_body '}' { $$ = f_new_inst(FI_SWITCH, $2, build_tree($4)); diff --git a/filter/decl.m4 b/filter/decl.m4 index 42515c13..9bd9a140 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -93,6 +93,25 @@ FID_INTERPRET_EXEC()m4_dnl const $1 $2 = whati->$2 FID_INTERPRET_BODY') +m4_define(FID_MEMBER_IN, `m4_dnl +FID_LINE_IN()m4_dnl + $1 $2; +FID_STRUCT_IN()m4_dnl + $1 $2; +FID_LINEARIZE_BODY()m4_dnl +item->$2 = whati->$2; +m4_ifelse($3,,,[[ +FID_SAME_BODY()m4_dnl +if ($3) return 0; +]]) +m4_ifelse($4,,,[[ +FID_DUMP_BODY()m4_dnl +debug("%s$4\n", INDENT, $5); +]]) +FID_INTERPRET_EXEC()m4_dnl +const $1 $2 = whati->$2 +FID_INTERPRET_BODY') + # Instruction arguments are needed only until linearization is done. # This puts the arguments into the filter line to be executed before # the instruction itself. diff --git a/filter/f-inst.c b/filter/f-inst.c index 5f30ee38..8d5c6656 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -173,7 +173,7 @@ 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); -#define pv fstk->vstk[fstk->vcnt - count + i] +#define pv fstk->vstk[fstk->vcnt - whati->count + i] FID_INTERPRET_NEW #define pv items[i]->i_FI_CONSTANT.val @@ -320,11 +320,6 @@ RESULT_VAL(val); } - INST(FI_PRINT, 1, 0) { - NEVER_CONSTANT; - ARG_ANY(1); - val_format(&(v1), &fs->buf); - } INST(FI_CONDITION, 1, 0) { ARG(1, T_BOOL); if (v1.val.i) @@ -332,28 +327,37 @@ else LINE(3,1); } - INST(FI_PRINT_AND_DIE, 0, 0) { + + INST(FI_PRINT, 0, 0) { NEVER_CONSTANT; - FID_LINEARIZE_BODY - { - uint opos = pos; - FID_INTERPRET_BODY - ARG_ANY(1); + FID_MEMBER_IN(uint, count, f1->count != f2->count, number of items %u, item->count); + + FID_NEW_BODY + uint len = 0; + for (const struct f_inst *tt = f1; tt; tt = tt->next, len++) + ; + whati->count = len; - FID_LINEARIZE_BODY - if (opos < pos) - dest->items[pos].flags |= FIF_PRINTED; - } FID_INTERPRET_BODY +#define pv fstk->vstk[fstk->vcnt - whati->count + i] + if (whati->count) + for (uint i=0; icount; i++) + val_format(&(pv), &fs->buf); +#undef pv + + fstk->vcnt -= whati->count; + } + + INST(FI_DIE, 0, 0) { + NEVER_CONSTANT; FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret)); - if ((fret == F_NOP || (fret != F_NONL && (what->flags & FIF_PRINTED))) && - !(fs->flags & FF_SILENT)) + if (fs->buf.start < fs->buf.pos) log_commit(*L_INFO, &fs->buf); - switch (fret) { + switch (whati->fret) { case F_QUITBIRD: die( "Filter asked me to die" ); case F_ACCEPT: @@ -361,7 +365,6 @@ case F_ERROR: case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */ return fret; /* We have to return now, no more processing. */ - case F_NONL: case F_NOP: break; default: diff --git a/filter/f-util.c b/filter/f-util.c index b4105aad..e61949f2 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -33,17 +33,17 @@ filter_name(const struct filter *filter) struct filter *f_new_where(struct f_inst *where) { struct f_inst acc = { - .fi_code = FI_PRINT_AND_DIE, + .fi_code = FI_DIE, .lineno = ifs->lino, .size = 1, - .i_FI_PRINT_AND_DIE = { .fret = F_ACCEPT, }, + .i_FI_DIE = { .fret = F_ACCEPT, }, }; struct f_inst rej = { - .fi_code = FI_PRINT_AND_DIE, + .fi_code = FI_DIE, .lineno = ifs->lino, .size = 1, - .i_FI_PRINT_AND_DIE = { .fret = F_REJECT, }, + .i_FI_DIE = { .fret = F_REJECT, }, }; struct f_inst i = {