CF_HDR
-CF_DEFINES
+#include "filter/f-inst.h"
+#include "filter/data.h"
-#define P(a,b) ((a << 8) | b)
+CF_DEFINES
static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
static inline u32 pair_a(u32 p) { return p >> 16; }
static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
+#define f_generate_complex(fi_code, da, arg) \
+ f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da)
/*
* Sets and their items are during parsing handled as lists, linked
case T_IP:
case T_EC:
case T_LC:
+ case T_RD:
return 1;
default:
static inline struct f_tree *
f_new_pair_item(int fa, int ta, int fb, int tb)
{
+ check_u16(fa);
+ check_u16(ta);
+ check_u16(fb);
+ check_u16(tb);
+
+ if ((ta < fa) || (tb < fb))
+ cf_error( "From value cannot be higher that To value in pair sets");
+
struct f_tree *t = f_new_tree();
t->right = t;
t->from.type = t->to.type = T_PAIR;
static inline struct f_tree *
f_new_pair_set(int fa, int ta, int fb, int tb)
{
- struct f_tree *lst = NULL;
- int i;
+ check_u16(fa);
+ check_u16(ta);
+ check_u16(fb);
+ check_u16(tb);
- if ((fa == ta) || ((fb == 0) && (tb == 0xFFFF)))
- return f_new_pair_item(fa, ta, fb, tb);
-
if ((ta < fa) || (tb < fb))
cf_error( "From value cannot be higher that To value in pair sets");
+ struct f_tree *lst = NULL;
+ int i;
+
for (i = fa; i <= ta; i++)
lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
return lst;
}
+#define CC_ALL 0xFFFF
#define EC_ALL 0xFFFFFFFF
+#define LC_ALL 0xFFFFFFFF
static struct f_tree *
f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
{
u64 fm, to;
- if (ipv4_used || (key >= 0x10000)) {
+ if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
check_u16(vf);
if (vt == EC_ALL)
vt = 0xFFFF;
return t;
}
+static struct f_tree *
+f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
+{
+ struct f_tree *t = f_new_tree();
+ t->right = t;
+ t->from.type = t->to.type = T_LC;
+ t->from.val.lc = (lcomm) {f1, f2, f3};
+ t->to.val.lc = (lcomm) {t1, t2, t3};
+ return t;
+}
+
static inline struct f_inst *
-f_generate_empty(struct f_inst *dyn)
-{
- struct f_inst *e = f_new_inst();
- e->code = 'E';
+f_generate_empty(struct f_dynamic_attr dyn)
+{
+ struct f_val empty;
- switch (dyn->aux & EAF_TYPE_MASK) {
+ switch (dyn.type & EAF_TYPE_MASK) {
case EAF_TYPE_AS_PATH:
- e->aux = T_PATH;
+ empty = f_const_empty_path;
break;
case EAF_TYPE_INT_SET:
- e->aux = T_CLIST;
+ empty = f_const_empty_clist;
break;
case EAF_TYPE_EC_SET:
- e->aux = T_ECLIST;
+ empty = f_const_empty_eclist;
break;
case EAF_TYPE_LC_SET:
- e->aux = T_LCLIST;
+ empty = f_const_empty_lclist;
break;
default:
cf_error("Can't empty that attribute");
}
- dyn->code = P('e','S');
- dyn->a1.p = e;
- return dyn;
+ return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn);
}
+#if 0
static inline struct f_inst *
f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
{
struct f_inst *rv;
- if ((t1->code == 'c') && (t2->code == 'c')) {
- if ((t1->aux != T_INT) || (t2->aux != T_INT))
+ if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
+ if ((t1->val.type != T_INT) || (t2->val.type != T_INT))
cf_error( "Can't operate with value of non-integer type in pair constructor");
- check_u16(t1->a2.i);
- check_u16(t2->a2.i);
+ check_u16(t1->a[1].i);
+ check_u16(t2->a[1].i);
- rv = f_new_inst();
- rv->code = 'c';
- rv->aux = T_PAIR;
- rv->a2.i = pair(t1->a2.i, t2->a2.i);
+ rv = f_new_inst(FI_CONSTANT);
+ rv->val = (struct f_val) {
+ .type = T_PAIR,
+ .val.i = pair(t1->a[1].i, t2->a[1].i),
+ };
}
else {
- rv = f_new_inst();
- rv->code = P('m', 'p');
- rv->a1.p = t1;
- rv->a2.p = t2;
+ rv = f_new_inst(FI_PAIR_CONSTRUCT);
+ rv->a[0].p = t1;
+ rv->a[1].p = t2;
}
return rv;
int c1 = 0, c2 = 0, ipv4_used = 0;
u32 key = 0, val2 = 0;
- if (tk->code == 'c') {
+ if (tk->fi_code == FI_CONSTANT) {
c1 = 1;
-
- if (tk->aux == T_INT) {
- ipv4_used = 0; key = tk->a2.i;
- }
- else if (tk->aux == T_QUAD) {
- ipv4_used = 1; key = tk->a2.i;
- }
- else
- cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
- }
-
-#ifndef IPV6
- /* IP->Quad implicit conversion */
- else if (tk->code == 'C') {
- c1 = 1;
- struct f_val *val = tk->a1.p;
+ struct f_val *val = &(tk->val);
if (val->type == T_INT) {
ipv4_used = 0; key = val->val.i;
}
- else if (val->type == T_QUAD) {
+ else if (tk->val.type == T_QUAD) {
ipv4_used = 1; key = val->val.i;
}
- else if (val->type == T_IP) {
- ipv4_used = 1; key = ipa_to_u32(val->val.px.ip);
+ else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) {
+ ipv4_used = 1; key = ipa_to_u32(val->val.ip);
}
else
cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
}
-#endif
- if (tv->code == 'c') {
- if (tv->aux != T_INT)
+ if (tv->fi_code == FI_CONSTANT) {
+ if (tv->val.type != T_INT)
cf_error("Can't operate with value of non-integer type in EC constructor");
c2 = 1;
- val2 = tv->a2.i;
+ val2 = tv->val.val.i;
}
if (c1 && c2) {
u64 ec;
-
+
if (kind == EC_GENERIC) {
ec = ec_generic(key, val2);
}
ec = ec_as4(kind, key, val2);
}
- NEW_F_VAL;
- rv = f_new_inst();
- rv->code = 'C';
- rv->a1.p = val;
- val->type = T_EC;
- val->val.ec = ec;
+ rv = f_new_inst(FI_CONSTANT);
+ rv->val = (struct f_val) {
+ .type = T_EC,
+ .val.ec = ec,
+ };
}
else {
- rv = f_new_inst();
- rv->code = P('m','c');
+ rv = f_new_inst(FI_EC_CONSTRUCT);
rv->aux = kind;
- rv->a1.p = tk;
- rv->a2.p = tv;
+ rv->a[0].p = tk;
+ rv->a[1].p = tv;
}
return rv;
{
struct f_inst *rv;
- if ((t1->code == 'c') && (t2->code == 'c') && (t3->code == 'c')) {
- if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
+ if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
+ if ((t1->val.type != T_INT) || (t2->val.type != T_INT) || (t3->val.type != T_INT))
cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
- rv = f_new_inst();
- rv->code = 'C';
-
- NEW_F_VAL;
- rv->a1.p = val;
- val->type = T_LC;
- val->val.lc = (lcomm) { t1->a2.i, t2->a2.i, t3->a2.i };
+ rv = f_new_inst(FI_CONSTANT);
+ rv->val = (struct f_val) {
+ .type = T_LC,
+ .val.lc = (lcomm) { t1->a[1].i, t2->a[1].i, t3->a[1].i },
+ };
}
else
{
- rv = cfg_allocz(sizeof(struct f_inst3));
- rv->lineno = ifs->lino;
- rv->code = P('m','l');
- rv->a1.p = t1;
- rv->a2.p = t2;
- INST3(rv).p = t3;
+ rv = f_new_inst(FI_LC_CONSTRUCT);
+ rv->a[0].p = t1;
+ rv->a[1].p = t2;
+ rv->a[2].p = t3;
}
return rv;
}
+static inline struct f_inst *
+f_generate_path_mask(struct f_inst *t)
+{
+ uint len = 0;
+ uint dyn = 0;
+ for (const struct f_inst *tt = t; tt; tt = tt->next) {
+ if (tt->fi_code != FI_CONSTANT)
+ dyn++;
+ len++;
+ }
+
+ if (dyn) {
+ struct f_inst *pmc = f_new_inst(FI_PATHMASK_CONSTRUCT);
+ pmc->a[0].p = t;
+ pmc->a[1].i = len;
+ return pmc;
+ }
+
+ struct f_path_mask *pm = cfg_allocz(sizeof(struct f_path_mask) + len * sizeof(struct f_path_mask_item));
+
+ uint i = 0;
+ for (const struct f_inst *tt = t; tt; tt = tt->next)
+ pm->item[i++] = tt->val.val.pmi;
+
+ pm->len = i;
+ struct f_inst *pmc = f_new_inst(FI_CONSTANT);
+ pmc->val = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = pm, };
+
+ return pmc;
+}
+
+#endif
+
+/*
+ * Remove all new lines and doubled whitespaces
+ * and convert all tabulators to spaces
+ * and return a copy of string
+ */
+char *
+assert_copy_expr(const char *start, size_t len)
+{
+ /* XXX: Allocates maybe a little more memory than we really finally need */
+ char *str = cfg_alloc(len + 1);
+
+ char *dst = str;
+ const char *src = start - 1;
+ const char *end = start + len;
+ while (++src < end)
+ {
+ if (*src == '\n')
+ continue;
+
+ /* Skip doubled whitespaces */
+ if (src != start)
+ {
+ const char *prev = src - 1;
+ if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
+ continue;
+ }
+
+ if (*src == '\t')
+ *dst = ' ';
+ else
+ *dst = *src;
+
+ dst++;
+ }
+ *dst = '\0';
+ return str;
+}
+
+/*
+ * assert_done - create f_instruction of bt_assert
+ * @expr: expression in bt_assert()
+ * @start: pointer to first char of test expression
+ * @end: pointer to the last char of test expression
+ */
+static struct f_inst *
+assert_done(struct f_inst *expr, const char *start, const char *end)
+{
+ return f_new_inst(FI_ASSERT, expr,
+ (end >= start) ?
+ assert_copy_expr(start, end - start + 1)
+ : "???");
+}
+
+static struct f_inst *
+assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end)
+{
+ struct f_inst *setter, *getter, *checker;
+ switch (lval->type) {
+ case F_LVAL_VARIABLE:
+ setter = f_new_inst(FI_VAR_SET, expr, lval->sym);
+ getter = f_new_inst(FI_VAR_GET, lval->sym);
+ break;
+ case F_LVAL_PREFERENCE:
+ setter = f_new_inst(FI_PREF_SET, expr);
+ getter = f_new_inst(FI_PREF_GET);
+ break;
+ case F_LVAL_SA:
+ setter = f_new_inst(FI_RTA_SET, expr, lval->sa);
+ getter = f_new_inst(FI_RTA_GET, lval->sa);
+ break;
+ case F_LVAL_EA:
+ setter = f_new_inst(FI_EA_SET, expr, lval->da);
+ getter = f_new_inst(FI_EA_GET, lval->da);
+ break;
+ default:
+ bug("Unknown lval type");
+ }
+
+ checker = f_new_inst(FI_EQ, expr, getter);
+ setter->next = checker;
+
+ return assert_done(setter, start, end);
+}
CF_DECLS
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
ACCEPT, REJECT, ERROR, QUITBIRD,
- INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, LC,
+ INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC,
SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
IF, THEN, ELSE, CASE,
TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
- FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
+ FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
PREFERENCE,
- LEN,
+ ROA_CHECK, ASN, SRC,
+ IS_V4, IS_V6,
+ LEN, MAXLEN,
DEFINED,
ADD, DELETE, CONTAINS, RESET,
PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
- ROA_CHECK,
EMPTY,
- FILTER, WHERE, EVAL)
+ FILTER, WHERE, EVAL, ATTRIBUTE,
+ BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
%nonassoc THEN
%nonassoc ELSE
-%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr
-%type <f> filter filter_body where_filter
-%type <i> type break_command pair_expr ec_kind
-%type <i32> pair_atom ec_expr
-%type <e> pair_item ec_item set_item switch_item set_items switch_items switch_body
+%type <xp> cmds_int
+%type <x> term block cmd cmds constant constructor print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
+%type <fda> dynamic_attr
+%type <fsa> static_attr
+%type <f> filter where_filter
+%type <fl> filter_body function_body
+%type <flv> lvalue
+%type <i> type function_params declsn decls
+%type <ecs> ec_kind
+%type <fret> break_command
+%type <i32> cnum
+%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
%type <trie> fprefix_set
-%type <v> set_atom switch_atom fprefix fprefix_s fipa
-%type <s> decls declsn one_decl function_params
-%type <h> bgp_path bgp_path_tail1 bgp_path_tail2
+%type <v> set_atom switch_atom fipa
+%type <px> fprefix
+%type <t> get_cf_position
CF_GRAMMAR
-CF_ADDTO(conf, filter_def)
+conf: filter_def ;
filter_def:
- FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
+ FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
filter_body {
- $2->def = $4;
- $4->name = $2->name;
- DBG( "We have new filter defined (%s)\n", $2->name );
+ struct filter *f = cfg_alloc(sizeof(struct filter));
+ *f = (struct filter) { .sym = $2, .root = $4 };
+ $2->filter = f;
+
cf_pop_scope();
}
;
-CF_ADDTO(conf, filter_eval)
+conf: filter_eval ;
filter_eval:
- EVAL term { f_eval_int($2); }
+ EVAL term { f_eval_int(f_linearize($2)); }
+ ;
+
+conf: custom_attr ;
+custom_attr: ATTRIBUTE type CF_SYM_VOID ';' {
+ cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda);
+};
+
+conf: bt_test_suite ;
+bt_test_suite:
+ BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' {
+ cf_assert_symbol($3, SYM_FUNCTION);
+ struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
+ t->fn = $3->function;
+ t->fn_name = $3->name;
+ t->dsc = $5;
+
+ add_tail(&new_config->tests, &t->n);
+ }
+ ;
+
+conf: bt_test_same ;
+bt_test_same:
+ BT_TEST_SAME '(' CF_SYM_KNOWN ',' CF_SYM_KNOWN ',' NUM ')' {
+ cf_assert_symbol($3, SYM_FUNCTION);
+ cf_assert_symbol($5, SYM_FUNCTION);
+ struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
+ t->fn = $3->function;
+ t->cmp = $5->function;
+ t->result = $7;
+ t->fn_name = $3->name;
+ t->dsc = $5->name;
+ add_tail(&new_config->tests, &t->n);
+ }
;
type:
INT { $$ = T_INT; }
| BOOL { $$ = T_BOOL; }
| IP { $$ = T_IP; }
- | PREFIX { $$ = T_PREFIX; }
+ | RD { $$ = T_RD; }
+ | PREFIX { $$ = T_NET; }
| PAIR { $$ = T_PAIR; }
| QUAD { $$ = T_QUAD; }
| EC { $$ = T_EC; }
| CLIST { $$ = T_CLIST; }
| ECLIST { $$ = T_ECLIST; }
| LCLIST { $$ = T_LCLIST; }
- | type SET {
+ | type SET {
switch ($1) {
case T_INT:
case T_PAIR:
case T_QUAD:
case T_EC:
case T_LC:
+ case T_RD:
case T_IP:
$$ = T_SET;
break;
- case T_PREFIX:
+ case T_NET:
$$ = T_PREFIX_SET;
break;
}
;
-one_decl:
- type SYM {
- struct f_val * val = cfg_alloc(sizeof(struct f_val));
- val->type = T_VOID;
- $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
- DBG( "New variable %s type %x\n", $2->name, $1 );
- $2->aux2 = NULL;
- $$=$2;
- }
- ;
-
-/* Decls with ';' at the end */
-decls: /* EMPTY */ { $$ = NULL; }
- | one_decl ';' decls {
- $$ = $1;
- $$->aux2 = $3;
- }
+/* Declarations with ';' at the end */
+decls:
+ /* EMPTY */ { $$ = 0; }
+ | declsn ';' { $$ = $1; }
;
/* Declarations that have no ';' at the end. */
-declsn: one_decl { $$ = $1; }
- | one_decl ';' declsn {
- $$ = $1;
- $$->aux2 = $3;
+declsn:
+ type CF_SYM_VOID {
+ cf_define_symbol($2, SYM_VARIABLE | $1, offset, $2->scope->slots++);
+ $$ = $2->scope->slots;
}
- ;
-
-filter_body:
- function_body {
- struct filter *f = cfg_alloc(sizeof(struct filter));
- f->name = NULL;
- f->root = $1;
- $$ = f;
+ | declsn ';' type CF_SYM_VOID {
+ if ($4->scope->slots >= 0xff) cf_error("Too many declarations, at most 255 allowed");
+ cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++);
+ $$ = $4->scope->slots;
}
;
+filter_body: function_body ;
+
filter:
- SYM {
- if ($1->class != SYM_FILTER) cf_error("No such filter.");
- $$ = $1->def;
+ CF_SYM_KNOWN {
+ cf_assert_symbol($1, SYM_FILTER);
+ $$ = $1->filter;
+ }
+ | filter_body {
+ struct filter *f = cfg_alloc(sizeof(struct filter));
+ *f = (struct filter) { .root = $1 };
+ $$ = f;
}
- | filter_body
;
where_filter:
WHERE term {
- /* Construct 'IF term THEN ACCEPT; REJECT;' */
- struct filter *f = cfg_alloc(sizeof(struct filter));
- struct f_inst *i, *acc, *rej;
- acc = f_new_inst(); /* ACCEPT */
- acc->code = P('p',',');
- acc->a1.p = NULL;
- acc->a2.i = F_ACCEPT;
- rej = f_new_inst(); /* REJECT */
- rej->code = P('p',',');
- rej->a1.p = NULL;
- rej->a2.i = F_REJECT;
- i = f_new_inst(); /* IF */
- i->code = '?';
- i->a1.p = $2;
- i->a2.p = acc;
- i->next = rej;
- f->name = NULL;
- f->root = i;
- $$ = f;
- }
+ /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
+ $$ = f_new_where($2);
+ }
;
function_params:
- '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
- | '(' ')' { $$=NULL; }
+ '(' declsn ')' { $$ = $2; }
+ | '(' ')' { $$ = 0; }
;
function_body:
decls '{' cmds '}' {
- if ($1) {
- /* Prepend instruction to clear local variables */
- $$ = f_new_inst();
- $$->code = P('c','v');
- $$->a1.p = $1;
- $$->next = $3;
- } else
- $$ = $3;
+ $$ = f_linearize($3);
+ $$->vars = $1;
}
;
-CF_ADDTO(conf, function_def)
+conf: function_def ;
function_def:
- FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
- $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
+ FUNCTION CF_SYM_VOID { DBG( "Beginning of function %s\n", $2->name );
+ $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL);
cf_push_scope($2);
} function_params function_body {
- $2->def = $5;
- $2->aux2 = $4;
- DBG("Hmm, we've got one function here - %s\n", $2->name);
+ $5->vars -= $4;
+ $5->args = $4;
+ $2->function = $5;
cf_pop_scope();
}
;
/* Programs */
-/* Hack: $$ of cmds_int is the last node.
- $$->next of cmds_int is temporary used for the first node */
-
cmds: /* EMPTY */ { $$ = NULL; }
- | cmds_int { $$ = $1->next; $1->next = NULL; }
+ | cmds_int { $$ = $1.begin; }
;
-cmds_int: cmd { $$ = $1; $1->next = $1; }
- | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
+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:
* Complex types, their bison value is struct f_val
*/
fipa:
- IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; }
+ IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
+ | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
;
*/
set_atom:
- NUM { $$.type = T_INT; $$.val.i = $1; }
- | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
- | fipa { $$ = $1; }
- | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
+ NUM { $$.type = T_INT; $$.val.i = $1; }
+ | fipa { $$ = $1; }
+ | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
+ | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
| '(' term ')' {
- $$ = f_eval($2, cfg_mem);
+ if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
}
- | SYM {
- if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
+ | CF_SYM_KNOWN {
+ cf_assert_symbol($1, SYM_CONSTANT);
if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
- $$ = *(struct f_val *)($1->def);
+ $$ = *$1->val;
}
;
switch_atom:
NUM { $$.type = T_INT; $$.val.i = $1; }
- | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
- | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
+ | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); }
| fipa { $$ = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
;
-pair_expr:
- term { $$ = f_eval_int($1); check_u16($$); }
-
-pair_atom:
- pair_expr { $$ = pair($1, $1); }
- | pair_expr DDOT pair_expr { $$ = pair($1, $3); }
- | '*' { $$ = 0xFFFF; }
- ;
+cnum:
+ term { $$ = f_eval_int(f_linearize($1)); }
pair_item:
- '(' pair_atom ',' pair_atom ')' {
- $$ = f_new_pair_set(pair_a($2), pair_b($2), pair_a($4), pair_b($4));
- }
- | '(' pair_atom ',' pair_atom ')' DDOT '(' pair_expr ',' pair_expr ')' {
- /* Hack: $2 and $4 should be pair_expr, but that would cause shift/reduce conflict */
- if ((pair_a($2) != pair_b($2)) || (pair_a($4) != pair_b($4)))
- cf_error("syntax error");
- $$ = f_new_pair_item(pair_b($2), $8, pair_b($4), $10);
- }
+ '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
+ | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
+ | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
+ | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
+ | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
+ | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
+ | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
+ | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
+ | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
+ | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
+ { $$ = f_new_pair_item($2, $8, $4, $10); }
;
-ec_expr:
- term { $$ = f_eval_int($1); }
-
ec_kind:
RT { $$ = EC_RT; }
| RO { $$ = EC_RO; }
;
ec_item:
- '(' ec_kind ',' ec_expr ',' ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
- | '(' ec_kind ',' ec_expr ',' ec_expr DDOT ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
- | '(' ec_kind ',' ec_expr ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
+ '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
+ | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
+ | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
;
+lc_item:
+ '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
+ | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
+ | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
+ | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
+ | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
+ | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
+ | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
+ | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
+ { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
+;
+
set_item:
pair_item
| ec_item
+ | lc_item
| set_atom { $$ = f_new_item($1, $1); }
| set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
;
switch_item:
pair_item
| ec_item
+ | lc_item
| switch_atom { $$ = f_new_item($1, $1); }
| switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
;
| switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
;
-fprefix_s:
- IPA '/' NUM %prec '/' {
- if (($3 < 0) || ($3 > MAX_PREFIX_LENGTH) || !ip_is_prefix($1, $3)) cf_error("Invalid network prefix: %I/%d.", $1, $3);
- $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3;
- }
- ;
-
fprefix:
- fprefix_s { $$ = $1; }
- | fprefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; }
- | fprefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; }
- | fprefix_s '{' NUM ',' NUM '}' {
- if (! ((0 <= $3) && ($3 <= $5) && ($5 <= MAX_PREFIX_LENGTH))) cf_error("Invalid prefix pattern range: {%d, %d}.", $3, $5);
- $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8);
+ net_ip_ { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; }
+ | net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; }
+ | net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; }
+ | net_ip_ '{' NUM ',' NUM '}' {
+ $$.net = $1; $$.lo = $3; $$.hi = $5;
+ if (($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
+ cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5);
}
;
fprefix_set:
- fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_fprefix($$, &($1.val.px)); }
- | fprefix_set ',' fprefix { $$ = $1; trie_add_fprefix($$, &($3.val.px)); }
+ fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
+ | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); }
;
switch_body: /* EMPTY */ { $$ = NULL; }
| switch_body switch_items ':' cmds {
/* Fill data fields */
struct f_tree *t;
+ struct f_line *line = f_linearize($4);
for (t = $2; t; t = t->left)
- t->data = $4;
+ t->data = line;
$$ = f_merge_items($1, $2);
}
- | switch_body ELSECOL cmds {
+ | switch_body ELSECOL cmds {
struct f_tree *t = f_new_tree();
t->from.type = t->to.type = T_VOID;
t->right = t;
- t->data = $3;
+ t->data = f_linearize($3);
$$ = f_merge_items($1, t);
}
;
-/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */
-
bgp_path_expr:
- symbol { $$ = $1; }
+ symbol_value { $$ = $1; }
| '(' term ')' { $$ = $2; }
;
bgp_path:
- PO bgp_path_tail1 PC { $$ = $2; }
- | '/' bgp_path_tail2 '/' { $$ = $2; }
+ PO bgp_path_tail PC { $$ = $2; }
;
-bgp_path_tail1:
- NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
- | NUM DDOT NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
- | '*' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
- | '?' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
- | bgp_path_expr bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
+bgp_path_tail:
+ NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }); $$->next = $2; }
+ | NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }); $$->next = $4; }
+ | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; }
+ | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; }
+ | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
| { $$ = NULL; }
;
-bgp_path_tail2:
- NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
- | '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
- | { $$ = NULL; }
- ;
-
constant:
- NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
- | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }
- | FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; }
- | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
- | fipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
- | fprefix_s {NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
- | RTRID { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_QUAD; $$->a2.i = $1; }
- | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
- | '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
- | ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
- | bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
+ NUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); }
+ | TRUE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); }
+ | FALSE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); }
+ | TEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); }
+ | fipa { $$ = f_new_inst(FI_CONSTANT, $1); }
+ | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); }
+ | net_ { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); }
+ | '[' set_items ']' {
+ DBG( "We've got a set here..." );
+ $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = build_tree($2), });
+ DBG( "ook\n" );
+ }
+ | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); }
+ | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); }
;
constructor:
- '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
- | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
- | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
+ '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); }
+ | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); }
+ | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); }
+ | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1, 0); }
;
-/*
- * Maybe there are no dynamic attributes defined by protocols.
- * For such cases, we force the dynamic_attr list to contain
- * at least an invalid token, so it is syntantically correct.
- */
-CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
-
-rtadot: /* EMPTY, we are not permitted RTA. prefix */
- ;
+/* This generates the function_call variable list backwards. */
+var_list: /* EMPTY */ { $$ = NULL; }
+ | term { $$ = $1; }
+ | var_list ',' term { $$ = $3; $$->next = $1; }
function_call:
- SYM '(' var_list ')' {
- struct symbol *sym;
- struct f_inst *inst = $3;
+ CF_SYM_KNOWN '(' var_list ')' {
if ($1->class != SYM_FUNCTION)
cf_error("You can't call something which is not a function. Really.");
- DBG("You are calling function %s\n", $1->name);
- $$ = f_new_inst();
- $$->code = P('c','a');
- $$->a1.p = inst;
- $$->a2.p = $1->def;
- sym = $1->aux2;
- while (sym || inst) {
- if (!sym || !inst)
- cf_error("Wrong number of arguments for function %s.", $1->name);
- DBG( "You should pass parameter called %s\n", sym->name);
- inst->a1.p = sym;
- sym = sym->aux2;
- inst = inst->next;
- }
- }
- ;
-symbol:
- SYM {
- $$ = f_new_inst();
+ struct f_inst *fc = f_new_inst(FI_CALL, $1);
+ uint args = 0;
+ while ($3) {
+ args++;
+ struct f_inst *tmp = $3->next;
+ $3->next = fc;
- switch ($1->class & 0xff00) {
- case SYM_CONSTANT: $$->code = 'C'; break;
- case SYM_VARIABLE: $$->code = 'V'; break;
- default: cf_error("%s: variable expected.", $1->name);
+ fc = $3;
+ $3 = tmp;
}
- $$->a1.p = $1->def;
- $$->a2.p = $1->name;
+ if (args != $1->function->args)
+ cf_error("Function call '%s' got %u arguments, need %u arguments.",
+ $1->name, args, $1->function->args);
+
+ $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID });
+ $$->next = fc;
}
+ ;
+
+symbol_value: CF_SYM_KNOWN
+ {
+ switch ($1->class) {
+ case SYM_CONSTANT_RANGE:
+ $$ = f_new_inst(FI_CONSTANT, *($1->val));
+ break;
+ case SYM_VARIABLE_RANGE:
+ $$ = f_new_inst(FI_VAR_GET, $1);
+ break;
+ case SYM_ATTRIBUTE:
+ $$ = f_new_inst(FI_EA_GET, *$1->attribute);
+ break;
+ default:
+ cf_error("Can't get value of symbol %s", $1->name);
+ }
+ }
+ ;
static_attr:
- FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_FROM; $$->a1.i = 1; }
- | GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_GW; $$->a1.i = 1; }
- | NET { $$ = f_new_inst(); $$->aux = T_PREFIX; $$->a2.i = SA_NET; }
- | PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_PROTO; }
- | SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = SA_SOURCE; }
- | SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE; $$->a1.i = 1; }
- | CAST { $$ = f_new_inst(); $$->aux = T_ENUM_RTC; $$->a2.i = SA_CAST; }
- | DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = SA_DEST; $$->a1.i = 1; }
- | IFNAME { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_IFNAME; }
- | IFINDEX { $$ = f_new_inst(); $$->aux = T_INT; $$->a2.i = SA_IFINDEX; }
+ FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
+ | GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); }
+ | NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); }
+ | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); }
+ | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); }
+ | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 0); }
+ | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); }
+ | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
+ | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
;
term:
- '(' term ')' { $$ = $2; }
- | term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; }
- | term '-' term { $$ = f_new_inst(); $$->code = '-'; $$->a1.p = $1; $$->a2.p = $3; }
- | term '*' term { $$ = f_new_inst(); $$->code = '*'; $$->a1.p = $1; $$->a2.p = $3; }
- | term '/' term { $$ = f_new_inst(); $$->code = '/'; $$->a1.p = $1; $$->a2.p = $3; }
- | term AND term { $$ = f_new_inst(); $$->code = '&'; $$->a1.p = $1; $$->a2.p = $3; }
- | term OR term { $$ = f_new_inst(); $$->code = '|'; $$->a1.p = $1; $$->a2.p = $3; }
- | term '=' term { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; }
- | term NEQ term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $3; }
- | term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; }
- | term LEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $1; $$->a2.p = $3; }
- | term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; }
- | term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; }
- | term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; }
- | term NMA term { $$ = f_new_inst(); $$->code = P('!','~'); $$->a1.p = $1; $$->a2.p = $3; }
- | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; }
- | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; }
-
- | symbol { $$ = $1; }
+ '(' term ')' { $$ = $2; }
+ | term '+' term { $$ = f_new_inst(FI_ADD, $1, $3); }
+ | term '-' term { $$ = f_new_inst(FI_SUBTRACT, $1, $3); }
+ | term '*' term { $$ = f_new_inst(FI_MULTIPLY, $1, $3); }
+ | term '/' term { $$ = f_new_inst(FI_DIVIDE, $1, $3); }
+ | term AND term { $$ = f_new_inst(FI_AND, $1, $3); }
+ | term OR term { $$ = f_new_inst(FI_OR, $1, $3); }
+ | term '=' term { $$ = f_new_inst(FI_EQ, $1, $3); }
+ | term NEQ term { $$ = f_new_inst(FI_NEQ, $1, $3); }
+ | term '<' term { $$ = f_new_inst(FI_LT, $1, $3); }
+ | term LEQ term { $$ = f_new_inst(FI_LTE, $1, $3); }
+ | term '>' term { $$ = f_new_inst(FI_LT, $3, $1); }
+ | term GEQ term { $$ = f_new_inst(FI_LTE, $3, $1); }
+ | term '~' term { $$ = f_new_inst(FI_MATCH, $1, $3); }
+ | term NMA term { $$ = f_new_inst(FI_NOT_MATCH, $1, $3); }
+ | '!' term { $$ = f_new_inst(FI_NOT, $2); }
+ | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
+
+ | symbol_value { $$ = $1; }
| constant { $$ = $1; }
| constructor { $$ = $1; }
- | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
+ | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
- | rtadot static_attr { $$ = $2; $$->code = 'a'; }
+ | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
- | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); }
+ | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
- | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
- | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
- | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
- | term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; }
- | term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; }
- | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; }
+ | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
+ | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
+ | term '.' IP { $$ = f_new_inst(FI_IP, $1); }
+ | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); }
+ | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
+ | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
+ | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); }
+ | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC, $1); }
+ | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
+ | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
+ | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
+ | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); }
/* Communities */
/* This causes one shift/reduce conflict
- | rtadot dynamic_attr '.' ADD '(' term ')' { }
- | rtadot dynamic_attr '.' DELETE '(' term ')' { }
- | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
- | rtadot dynamic_attr '.' RESET{ }
+ | dynamic_attr '.' ADD '(' term ')' { }
+ | dynamic_attr '.' DELETE '(' term ')' { }
+ | dynamic_attr '.' CONTAINS '(' term ')' { }
+ | dynamic_attr '.' RESET{ }
*/
- | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
- | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
- | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; }
- | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_LCLIST; }
- | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; }
- | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
- | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
- | FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
+ | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); }
+ | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_clist); }
+ | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_eclist); }
+ | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_lclist); }
+ | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
+ | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); }
+ | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); }
+ | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); }
+
+ | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); }
+ | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); }
- | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
- | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
+ | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
/* | term '.' LEN { $$->code = P('P','l'); } */
-/* function_call is inlined here */
- | SYM '(' var_list ')' {
- struct symbol *sym;
- struct f_inst *inst = $3;
- if ($1->class != SYM_FUNCTION)
- cf_error("You can't call something which is not a function. Really.");
- DBG("You are calling function %s\n", $1->name);
- $$ = f_new_inst();
- $$->code = P('c','a');
- $$->a1.p = inst;
- $$->a2.p = $1->def;
- sym = $1->aux2;
- while (sym || inst) {
- if (!sym || !inst)
- cf_error("Wrong number of arguments for function %s.", $1->name);
- DBG( "You should pass parameter called %s\n", sym->name);
- inst->a1.p = sym;
- sym = sym->aux2;
- inst = inst->next;
- }
- }
+ | function_call
;
break_command:
| PRINTN { $$ = F_NONL; }
;
-print_one:
- term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
- ;
-
print_list: /* EMPTY */ { $$ = NULL; }
- | print_one { $$ = $1; }
- | print_one ',' print_list {
- if ($1) {
- $1->next = $3;
- $$ = $1;
- } else $$ = $3;
- }
- ;
-
-var_listn: term {
- $$ = f_new_inst();
- $$->code = 's';
- $$->a1.p = NULL;
- $$->a2.p = $1;
- $$->next = NULL;
- }
- | term ',' var_listn {
- $$ = f_new_inst();
- $$->code = 's';
- $$->a1.p = NULL;
- $$->a2.p = $1;
- $$->next = $3;
+ | term { $$ = $1; }
+ | term ',' print_list {
+ ASSERT($1);
+ ASSERT($1->next == NULL);
+ $1->next = $3;
+ $$ = $1;
}
;
-var_list: /* EMPTY */ { $$ = NULL; }
- | var_listn { $$ = $1; }
- ;
-
cmd:
IF term THEN block {
- $$ = f_new_inst();
- $$->code = '?';
- $$->a1.p = $2;
- $$->a2.p = $4;
+ $$ = f_new_inst(FI_CONDITION, $2, $4, NULL);
}
| IF term THEN block ELSE block {
- struct f_inst *i = f_new_inst();
- i->code = '?';
- i->a1.p = $2;
- i->a2.p = $4;
- $$ = f_new_inst();
- $$->code = '?';
- $$->a1.p = i;
- $$->a2.p = $6;
+ $$ = f_new_inst(FI_CONDITION, $2, $4, $6);
}
- | SYM '=' term ';' {
- $$ = f_new_inst();
- DBG( "Ook, we'll set value\n" );
- if (($1->class & ~T_MASK) != SYM_VARIABLE)
- cf_error( "You may set only variables." );
- $$->code = 's';
- $$->a1.p = $1;
- $$->a2.p = $3;
+ | CF_SYM_KNOWN '=' term ';' {
+ switch ($1->class) {
+ case SYM_VARIABLE_RANGE:
+ $$ = f_new_inst(FI_VAR_SET, $3, $1);
+ break;
+ case SYM_ATTRIBUTE:
+ $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
+ break;
+ default:
+ cf_error("Can't assign to symbol %s", $1->name);
+ }
}
| RETURN term ';' {
- $$ = f_new_inst();
DBG( "Ook, we'll return the value\n" );
- $$->code = 'r';
- $$->a1.p = $2;
+ $$ = f_new_inst(FI_RETURN, $2);
}
- | rtadot dynamic_attr '=' term ';' {
- $$ = $2;
- $$->code = P('e','S');
- $$->a1.p = $4;
+ | dynamic_attr '=' term ';' {
+ $$ = f_new_inst(FI_EA_SET, $3, $1);
}
- | rtadot static_attr '=' term ';' {
- $$ = $2;
- if (!$$->a1.i)
+ | static_attr '=' term ';' {
+ if ($1.readonly)
cf_error( "This static attribute is read-only.");
- $$->code = P('a','S');
- $$->a1.p = $4;
+ $$ = f_new_inst(FI_RTA_SET, $3, $1);
}
| PREFERENCE '=' term ';' {
- $$ = f_new_inst();
- $$->code = P('P','S');
- $$->a1.p = $3;
- }
- | UNSET '(' rtadot dynamic_attr ')' ';' {
- $$ = $4;
- $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
- $$->code = P('e','S');
- $$->a1.p = NULL;
+ $$ = f_new_inst(FI_PREF_SET, $3);
}
- | break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; }
- | function_call ';' { $$ = $1; }
+ | UNSET '(' dynamic_attr ')' ';' {
+ $$ = f_new_inst(FI_EA_UNSET, $3);
+ }
+ | 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();
- $$->code = P('S','W');
- $$->a1.p = $2;
- $$->a2.p = build_tree( $4 );
+ $$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
}
-
- | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
- | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
- | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
- | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
- | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
+ | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); }
+ | dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); }
+ | dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); }
+ | dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); }
+ | dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); }
+ | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
+ | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); }
;
+get_cf_position:
+{
+ $$ = cf_text;
+};
+
+lvalue:
+ CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; }
+ | PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; }
+ | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
+ | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };
+
CF_END