Annotation of embedaddon/bird2/filter/config.Y, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *     BIRD - filters
                      3:  *
                      4:  *     Copyright 1998--2000 Pavel Machek
                      5:  *
                      6:  *     Can be freely distributed and used under the terms of the GNU GPL.
                      7:  *
                      8:        FIXME: priority of ! should be lower
                      9:  */
                     10: 
                     11: CF_HDR
                     12: 
                     13: #include "filter/f-inst.h"
                     14: #include "filter/data.h"
                     15: 
                     16: CF_DEFINES
                     17: 
                     18: static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
                     19: static inline u32 pair_a(u32 p) { return p >> 16; }
                     20: static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
                     21: 
                     22: #define f_generate_complex(fi_code, da, arg) \
                     23:   f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da)
                     24: 
                     25: /*
                     26:  * Sets and their items are during parsing handled as lists, linked
                     27:  * through left ptr. The first item in a list also contains a pointer
                     28:  * to the last item in a list (right ptr). For convenience, even items
                     29:  * are handled as one-item lists. Lists are merged by f_merge_items().
                     30:  */
                     31: static int
                     32: f_valid_set_type(int type)
                     33: {
                     34:   switch (type)
                     35:   {
                     36:   case T_INT:
                     37:   case T_PAIR:
                     38:   case T_QUAD:
                     39:   case T_ENUM:
                     40:   case T_IP:
                     41:   case T_EC:
                     42:   case T_LC:
                     43:   case T_RD:
                     44:     return 1;
                     45: 
                     46:   default:
                     47:     return 0;
                     48:   }
                     49: }
                     50: 
                     51: static inline struct f_tree *
                     52: f_new_item(struct f_val from, struct f_val to)
                     53: {
                     54:   struct f_tree *t = f_new_tree();
                     55:   t->right = t;
                     56:   t->from = from;
                     57:   t->to = to;
                     58:   return t;
                     59: }
                     60: 
                     61: static inline struct f_tree *
                     62: f_merge_items(struct f_tree *a, struct f_tree *b)
                     63: {
                     64:   if (!a) return b;
                     65:   a->right->left = b;
                     66:   a->right = b->right;
                     67:   b->right = NULL;
                     68:   return a;
                     69: }
                     70: 
                     71: static inline struct f_tree *
                     72: f_new_pair_item(int fa, int ta, int fb, int tb)
                     73: {
                     74:   check_u16(fa);
                     75:   check_u16(ta);
                     76:   check_u16(fb);
                     77:   check_u16(tb);
                     78: 
                     79:   if ((ta < fa) || (tb < fb))
                     80:     cf_error( "From value cannot be higher that To value in pair sets");
                     81: 
                     82:   struct f_tree *t = f_new_tree();
                     83:   t->right = t;
                     84:   t->from.type = t->to.type = T_PAIR;
                     85:   t->from.val.i = pair(fa, fb);
                     86:   t->to.val.i = pair(ta, tb);
                     87:   return t;
                     88: }
                     89: 
                     90: static inline struct f_tree *
                     91: f_new_pair_set(int fa, int ta, int fb, int tb)
                     92: {
                     93:   check_u16(fa);
                     94:   check_u16(ta);
                     95:   check_u16(fb);
                     96:   check_u16(tb);
                     97: 
                     98:   if ((ta < fa) || (tb < fb))
                     99:     cf_error( "From value cannot be higher that To value in pair sets");
                    100: 
                    101:   struct f_tree *lst = NULL;
                    102:   int i;
                    103: 
                    104:   for (i = fa; i <= ta; i++)
                    105:     lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
                    106: 
                    107:   return lst;
                    108: }
                    109: 
                    110: #define CC_ALL 0xFFFF
                    111: #define EC_ALL 0xFFFFFFFF
                    112: #define LC_ALL 0xFFFFFFFF
                    113: 
                    114: static struct f_tree *
                    115: f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
                    116: {
                    117:   u64 fm, to;
                    118: 
                    119:   if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
                    120:     check_u16(vf);
                    121:     if (vt == EC_ALL)
                    122:       vt = 0xFFFF;
                    123:     else
                    124:       check_u16(vt);
                    125:   }
                    126: 
                    127:   if (kind == EC_GENERIC) {
                    128:     fm = ec_generic(key, vf);
                    129:     to = ec_generic(key, vt);
                    130:   }
                    131:   else if (ipv4_used) {
                    132:     fm = ec_ip4(kind, key, vf);
                    133:     to = ec_ip4(kind, key, vt);
                    134:   }
                    135:   else if (key < 0x10000) {
                    136:     fm = ec_as2(kind, key, vf);
                    137:     to = ec_as2(kind, key, vt);
                    138:   }
                    139:   else {
                    140:     fm = ec_as4(kind, key, vf);
                    141:     to = ec_as4(kind, key, vt);
                    142:   }
                    143: 
                    144:   struct f_tree *t = f_new_tree();
                    145:   t->right = t;
                    146:   t->from.type = t->to.type = T_EC;
                    147:   t->from.val.ec = fm;
                    148:   t->to.val.ec = to;
                    149:   return t;
                    150: }
                    151: 
                    152: static struct f_tree *
                    153: f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
                    154: {
                    155:   struct f_tree *t = f_new_tree();
                    156:   t->right = t;
                    157:   t->from.type = t->to.type = T_LC;
                    158:   t->from.val.lc = (lcomm) {f1, f2, f3};
                    159:   t->to.val.lc = (lcomm) {t1, t2, t3};
                    160:   return t;
                    161: }
                    162: 
                    163: static inline struct f_inst *
                    164: f_generate_empty(struct f_dynamic_attr dyn)
                    165: {
                    166:   struct f_val empty;
                    167: 
                    168:   switch (dyn.type & EAF_TYPE_MASK) {
                    169:     case EAF_TYPE_AS_PATH:
                    170:       empty = f_const_empty_path;
                    171:       break;
                    172:     case EAF_TYPE_INT_SET:
                    173:       empty = f_const_empty_clist;
                    174:       break;
                    175:     case EAF_TYPE_EC_SET:
                    176:       empty = f_const_empty_eclist;
                    177:       break;
                    178:     case EAF_TYPE_LC_SET:
                    179:       empty = f_const_empty_lclist;
                    180:       break;
                    181:     default:
                    182:       cf_error("Can't empty that attribute");
                    183:   }
                    184: 
                    185:   return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn);
                    186: }
                    187: 
                    188: #if 0
                    189: 
                    190: static inline struct f_inst *
                    191: f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
                    192: {
                    193:   struct f_inst *rv;
                    194: 
                    195:   if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
                    196:     if ((t1->val.type != T_INT) || (t2->val.type != T_INT))
                    197:       cf_error( "Can't operate with value of non-integer type in pair constructor");
                    198: 
                    199:     check_u16(t1->a[1].i);
                    200:     check_u16(t2->a[1].i);
                    201: 
                    202:     rv = f_new_inst(FI_CONSTANT);
                    203:     rv->val = (struct f_val) {
                    204:       .type = T_PAIR,
                    205:       .val.i = pair(t1->a[1].i, t2->a[1].i),
                    206:     };
                    207:   }
                    208:   else {
                    209:     rv = f_new_inst(FI_PAIR_CONSTRUCT);
                    210:     rv->a[0].p = t1;
                    211:     rv->a[1].p = t2;
                    212:   }
                    213: 
                    214:   return rv;
                    215: }
                    216: 
                    217: static inline struct f_inst *
                    218: f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
                    219: {
                    220:   struct f_inst *rv;
                    221:   int c1 = 0, c2 = 0, ipv4_used = 0;
                    222:   u32 key = 0, val2 = 0;
                    223: 
                    224:   if (tk->fi_code == FI_CONSTANT) {
                    225:     c1 = 1;
                    226:     struct f_val *val = &(tk->val);
                    227: 
                    228:     if (val->type == T_INT) {
                    229:       ipv4_used = 0; key = val->val.i;
                    230:     }
                    231:     else if (tk->val.type == T_QUAD) {
                    232:       ipv4_used = 1; key = val->val.i;
                    233:     }
                    234:     else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) {
                    235:       ipv4_used = 1; key = ipa_to_u32(val->val.ip);
                    236:     }
                    237:     else
                    238:       cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
                    239:   }
                    240: 
                    241:   if (tv->fi_code == FI_CONSTANT) {
                    242:     if (tv->val.type != T_INT)
                    243:       cf_error("Can't operate with value of non-integer type in EC constructor");
                    244:     c2 = 1;
                    245:     val2 = tv->val.val.i;
                    246:   }
                    247: 
                    248:   if (c1 && c2) {
                    249:     u64 ec;
                    250: 
                    251:     if (kind == EC_GENERIC) {
                    252:       ec = ec_generic(key, val2);
                    253:     }
                    254:     else if (ipv4_used) {
                    255:       check_u16(val2);
                    256:       ec = ec_ip4(kind, key, val2);
                    257:     }
                    258:     else if (key < 0x10000) {
                    259:       ec = ec_as2(kind, key, val2);
                    260:     }
                    261:     else {
                    262:       check_u16(val2);
                    263:       ec = ec_as4(kind, key, val2);
                    264:     }
                    265: 
                    266:     rv = f_new_inst(FI_CONSTANT);
                    267:     rv->val = (struct f_val) {
                    268:       .type = T_EC,
                    269:       .val.ec = ec,
                    270:     };
                    271:   }
                    272:   else {
                    273:     rv = f_new_inst(FI_EC_CONSTRUCT);
                    274:     rv->aux = kind;
                    275:     rv->a[0].p = tk;
                    276:     rv->a[1].p = tv;
                    277:   }
                    278: 
                    279:   return rv;
                    280: }
                    281: 
                    282: static inline struct f_inst *
                    283: f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
                    284: {
                    285:   struct f_inst *rv;
                    286: 
                    287:   if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
                    288:     if ((t1->val.type != T_INT) || (t2->val.type != T_INT) || (t3->val.type != T_INT))
                    289:       cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
                    290: 
                    291:     rv = f_new_inst(FI_CONSTANT);
                    292:     rv->val = (struct f_val) {
                    293:       .type = T_LC,
                    294:       .val.lc = (lcomm) { t1->a[1].i, t2->a[1].i, t3->a[1].i },
                    295:     };
                    296:   }
                    297:   else
                    298:   {
                    299:     rv = f_new_inst(FI_LC_CONSTRUCT);
                    300:     rv->a[0].p = t1;
                    301:     rv->a[1].p = t2;
                    302:     rv->a[2].p = t3;
                    303:   }
                    304: 
                    305:   return rv;
                    306: }
                    307: 
                    308: static inline struct f_inst *
                    309: f_generate_path_mask(struct f_inst *t)
                    310: {
                    311:   uint len = 0;
                    312:   uint dyn = 0;
                    313:   for (const struct f_inst *tt = t; tt; tt = tt->next) {
                    314:     if (tt->fi_code != FI_CONSTANT)
                    315:       dyn++;
                    316:     len++;
                    317:   }
                    318: 
                    319:   if (dyn) {
                    320:     struct f_inst *pmc = f_new_inst(FI_PATHMASK_CONSTRUCT);
                    321:     pmc->a[0].p = t;
                    322:     pmc->a[1].i = len;
                    323:     return pmc;
                    324:   }
                    325: 
                    326:   struct f_path_mask *pm = cfg_allocz(sizeof(struct f_path_mask) + len * sizeof(struct f_path_mask_item));
                    327: 
                    328:   uint i = 0;
                    329:   for (const struct f_inst *tt = t; tt; tt = tt->next)
                    330:     pm->item[i++] = tt->val.val.pmi;
                    331: 
                    332:   pm->len = i;
                    333:   struct f_inst *pmc = f_new_inst(FI_CONSTANT);
                    334:   pmc->val = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = pm, };
                    335: 
                    336:   return pmc;
                    337: }
                    338: 
                    339: #endif
                    340: 
                    341: /*
                    342:  * Remove all new lines and doubled whitespaces
                    343:  * and convert all tabulators to spaces
                    344:  * and return a copy of string
                    345:  */
                    346: char *
                    347: assert_copy_expr(const char *start, size_t len)
                    348: {
                    349:   /* XXX: Allocates maybe a little more memory than we really finally need */
                    350:   char *str = cfg_alloc(len + 1);
                    351: 
                    352:   char *dst = str;
                    353:   const char *src = start - 1;
                    354:   const char *end = start + len;
                    355:   while (++src < end)
                    356:   {
                    357:     if (*src == '\n')
                    358:       continue;
                    359: 
                    360:     /* Skip doubled whitespaces */
                    361:     if (src != start)
                    362:     {
                    363:       const char *prev = src - 1;
                    364:       if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
                    365:        continue;
                    366:     }
                    367: 
                    368:     if (*src == '\t')
                    369:       *dst = ' ';
                    370:     else
                    371:       *dst = *src;
                    372: 
                    373:     dst++;
                    374:   }
                    375:   *dst = '\0';
                    376: 
                    377:   return str;
                    378: }
                    379: 
                    380: /*
                    381:  * assert_done - create f_instruction of bt_assert
                    382:  * @expr: expression in bt_assert()
                    383:  * @start: pointer to first char of test expression
                    384:  * @end: pointer to the last char of test expression
                    385:  */
                    386: static struct f_inst *
                    387: assert_done(struct f_inst *expr, const char *start, const char *end)
                    388: {
                    389:   return f_new_inst(FI_ASSERT, expr,
                    390:     (end >= start) ?
                    391:       assert_copy_expr(start, end - start + 1)
                    392:     : "???");
                    393: }
                    394: 
                    395: static struct f_inst *
                    396: assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end)
                    397: {
                    398:   struct f_inst *setter, *getter, *checker;
                    399:   switch (lval->type) {
                    400:     case F_LVAL_VARIABLE:
                    401:       setter = f_new_inst(FI_VAR_SET, expr, lval->sym);
                    402:       getter = f_new_inst(FI_VAR_GET, lval->sym);
                    403:       break;
                    404:     case F_LVAL_PREFERENCE:
                    405:       setter = f_new_inst(FI_PREF_SET, expr);
                    406:       getter = f_new_inst(FI_PREF_GET);
                    407:       break;
                    408:     case F_LVAL_SA:
                    409:       setter = f_new_inst(FI_RTA_SET, expr, lval->sa);
                    410:       getter = f_new_inst(FI_RTA_GET, lval->sa);
                    411:       break;
                    412:     case F_LVAL_EA:
                    413:       setter = f_new_inst(FI_EA_SET, expr, lval->da);
                    414:       getter = f_new_inst(FI_EA_GET, lval->da);
                    415:       break;
                    416:     default:
                    417:       bug("Unknown lval type");
                    418:   }
                    419: 
                    420:   checker = f_new_inst(FI_EQ, expr, getter);
                    421:   setter->next = checker;
                    422:   
                    423:   return assert_done(setter, start, end);
                    424: }
                    425: 
                    426: CF_DECLS
                    427: 
                    428: CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
                    429:        ACCEPT, REJECT, ERROR, QUITBIRD,
                    430:        INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC,
                    431:        SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
                    432:        IF, THEN, ELSE, CASE,
                    433:        TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
                    434:        FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
                    435:        PREFERENCE,
                    436:        ROA_CHECK, ASN, SRC,
                    437:        IS_V4, IS_V6,
                    438:        LEN, MAXLEN,
                    439:        DEFINED,
                    440:        ADD, DELETE, CONTAINS, RESET,
                    441:        PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
                    442:        EMPTY,
                    443:        FILTER, WHERE, EVAL, ATTRIBUTE,
                    444:        BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
                    445: 
                    446: %nonassoc THEN
                    447: %nonassoc ELSE
                    448: 
                    449: %type <xp> cmds_int cmd_prep
                    450: %type <x> term block cmd cmds constant constructor print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
                    451: %type <fda> dynamic_attr
                    452: %type <fsa> static_attr
                    453: %type <f> filter where_filter
                    454: %type <fl> filter_body function_body
                    455: %type <flv> lvalue
                    456: %type <i> type function_args function_vars
                    457: %type <ecs> ec_kind
                    458: %type <fret> break_command 
                    459: %type <i32> cnum
                    460: %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
                    461: %type <trie> fprefix_set
                    462: %type <v> set_atom switch_atom fipa
                    463: %type <px> fprefix
                    464: %type <t> get_cf_position
                    465: 
                    466: CF_GRAMMAR
                    467: 
                    468: conf: filter_def ;
                    469: filter_def:
                    470:    FILTER symbol { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
                    471:      filter_body {
                    472:      struct filter *f = cfg_alloc(sizeof(struct filter));
                    473:      *f = (struct filter) { .sym = $2, .root = $4 };
                    474:      $2->filter = f;
                    475: 
                    476:      cf_pop_scope();
                    477:    }
                    478:  ;
                    479: 
                    480: conf: filter_eval ;
                    481: filter_eval:
                    482:    EVAL term { f_eval_int(f_linearize($2)); }
                    483:  ;
                    484: 
                    485: conf: custom_attr ;
                    486: custom_attr: ATTRIBUTE type symbol ';' {
                    487:   cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda);
                    488: };
                    489: 
                    490: conf: bt_test_suite ;
                    491: bt_test_suite:
                    492:  BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' {
                    493:   cf_assert_symbol($3, SYM_FUNCTION);
                    494:   struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
                    495:   t->fn = $3->function;
                    496:   t->fn_name = $3->name;
                    497:   t->dsc = $5;
                    498: 
                    499:   add_tail(&new_config->tests, &t->n);
                    500:  }
                    501:  ;
                    502: 
                    503: conf: bt_test_same ;
                    504: bt_test_same:
                    505:  BT_TEST_SAME '(' CF_SYM_KNOWN ',' CF_SYM_KNOWN ',' NUM ')' {
                    506:   cf_assert_symbol($3, SYM_FUNCTION);
                    507:   cf_assert_symbol($5, SYM_FUNCTION);
                    508:   struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
                    509:   t->fn = $3->function;
                    510:   t->cmp = $5->function;
                    511:   t->result = $7;
                    512:   t->fn_name = $3->name;
                    513:   t->dsc = $5->name;
                    514:   add_tail(&new_config->tests, &t->n);
                    515:  }
                    516:  ;
                    517: 
                    518: type:
                    519:    INT { $$ = T_INT; }
                    520:  | BOOL { $$ = T_BOOL; }
                    521:  | IP { $$ = T_IP; }
                    522:  | RD { $$ = T_RD; }
                    523:  | PREFIX { $$ = T_NET; }
                    524:  | PAIR { $$ = T_PAIR; }
                    525:  | QUAD { $$ = T_QUAD; }
                    526:  | EC { $$ = T_EC; }
                    527:  | LC { $$ = T_LC; }
                    528:  | STRING { $$ = T_STRING; }
                    529:  | BGPMASK { $$ = T_PATH_MASK; }
                    530:  | BGPPATH { $$ = T_PATH; }
                    531:  | CLIST { $$ = T_CLIST; }
                    532:  | ECLIST { $$ = T_ECLIST; }
                    533:  | LCLIST { $$ = T_LCLIST; }
                    534:  | type SET {
                    535:        switch ($1) {
                    536:          case T_INT:
                    537:          case T_PAIR:
                    538:          case T_QUAD:
                    539:          case T_EC:
                    540:          case T_LC:
                    541:          case T_RD:
                    542:          case T_IP:
                    543:               $$ = T_SET;
                    544:               break;
                    545: 
                    546:          case T_NET:
                    547:               $$ = T_PREFIX_SET;
                    548:            break;
                    549: 
                    550:          default:
                    551:                cf_error( "You can't create sets of this type." );
                    552:        }
                    553:    }
                    554:  ;
                    555: 
                    556: function_argsn:
                    557:    /* EMPTY */
                    558:  | function_argsn type symbol ';' {
                    559:      if ($3->scope->slots >= 0xfe) cf_error("Too many declarations, at most 255 allowed");
                    560:      cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++);
                    561:    }
                    562:  ;
                    563: 
                    564: function_args:
                    565:    '(' ')' { $$ = 0; }
                    566:  | '(' function_argsn type symbol ')' {
                    567:      cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++);
                    568:      $$ = $4->scope->slots;
                    569:    }
                    570:  ;
                    571: 
                    572: function_vars:
                    573:    /* EMPTY */ { $$ = 0; }
                    574:  | function_vars type symbol ';' {
                    575:      cf_define_symbol($3, SYM_VARIABLE | $2, offset, $3->scope->slots++);
                    576:      $$ = $1 + 1;
                    577:    }
                    578:  ;
                    579: 
                    580: filter_body: function_body ;
                    581: 
                    582: filter:
                    583:    CF_SYM_KNOWN {
                    584:      cf_assert_symbol($1, SYM_FILTER);
                    585:      $$ = $1->filter;
                    586:    }
                    587:  | filter_body {
                    588:      struct filter *f = cfg_alloc(sizeof(struct filter));
                    589:      *f = (struct filter) { .root = $1 };
                    590:      $$ = f;
                    591:    }
                    592:  ;
                    593: 
                    594: where_filter:
                    595:    WHERE term {
                    596:      /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
                    597:      $$ = f_new_where($2);
                    598:    }
                    599:  ;
                    600: 
                    601: function_body:
                    602:    function_vars '{' cmds '}' {
                    603:      $$ = f_linearize($3);
                    604:      $$->vars = $1;
                    605:    }
                    606:  ;
                    607: 
                    608: conf: function_def ;
                    609: function_def:
                    610:    FUNCTION symbol { DBG( "Beginning of function %s\n", $2->name );
                    611:      $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL);
                    612:      cf_push_scope($2);
                    613:    } function_args function_body {
                    614:      DBG("Definition of function %s with %u args and %u local vars.\n", $2->name, $4, $5->vars);
                    615:      $5->args = $4;
                    616:      $2->function = $5;
                    617:      cf_pop_scope();
                    618:    }
                    619:  ;
                    620: 
                    621: /* Programs */
                    622: 
                    623: cmds: /* EMPTY */ { $$ = NULL; }
                    624:  | cmds_int { $$ = $1.begin; }
                    625:  ;
                    626: 
                    627: cmd_prep: cmd {
                    628:   $$.begin = $$.end = $1;
                    629:   if ($1)
                    630:     while ($$.end->next)
                    631:       $$.end = $$.end->next;
                    632: }
                    633:  ;
                    634: 
                    635: cmds_int: cmd_prep
                    636:  | cmds_int cmd_prep {
                    637:   if (!$1.begin)
                    638:     $$ = $2;
                    639:   else if (!$2.begin)
                    640:     $$ = $1;
                    641:   else {
                    642:     $$.begin = $1.begin;
                    643:     $$.end = $2.end;
                    644:     $1.end->next = $2.begin;
                    645:   }
                    646:  }
                    647:  ;
                    648: 
                    649: block:
                    650:    cmd {
                    651:      $$=$1;
                    652:    }
                    653:  | '{' cmds '}' {
                    654:      $$=$2;
                    655:    }
                    656:  ;
                    657: 
                    658: /*
                    659:  * Complex types, their bison value is struct f_val
                    660:  */
                    661: fipa:
                    662:    IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
                    663:  | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
                    664:  ;
                    665: 
                    666: 
                    667: 
                    668: /*
                    669:  * Set constants. They are also used in switch cases. We use separate
                    670:  * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
                    671:  * to elude a collision between symbol (in expr) in set_atom and symbol
                    672:  * as a function call in switch case cmds.
                    673:  */
                    674: 
                    675: set_atom:
                    676:    NUM    { $$.type = T_INT; $$.val.i = $1; }
                    677:  | fipa   { $$ = $1; }
                    678:  | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
                    679:  | ENUM   { $$.type = pair_a($1); $$.val.i = pair_b($1); }
                    680:  | '(' term ')' {
                    681:      if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
                    682:      if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
                    683:    }
                    684:  | CF_SYM_KNOWN {
                    685:      cf_assert_symbol($1, SYM_CONSTANT);
                    686:      if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
                    687:      $$ = *$1->val;
                    688:    }
                    689:  ;
                    690: 
                    691: switch_atom:
                    692:    NUM   { $$.type = T_INT; $$.val.i = $1; }
                    693:  | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); }
                    694:  | fipa  { $$ = $1; }
                    695:  | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
                    696:  ;
                    697: 
                    698: cnum:
                    699:    term { $$ = f_eval_int(f_linearize($1)); }
                    700: 
                    701: pair_item:
                    702:    '(' cnum ',' cnum ')'               { $$ = f_new_pair_item($2, $2, $4, $4); }
                    703:  | '(' cnum ',' cnum DDOT cnum ')'     { $$ = f_new_pair_item($2, $2, $4, $6); }
                    704:  | '(' cnum ',' '*' ')'                        { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
                    705:  | '(' cnum DDOT cnum ',' cnum ')'     { $$ = f_new_pair_set($2, $4, $6, $6); }
                    706:  | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
                    707:  | '(' cnum DDOT cnum ',' '*' ')'      { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
                    708:  | '(' '*' ',' cnum ')'                        { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
                    709:  | '(' '*' ',' cnum DDOT cnum ')'      { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
                    710:  | '(' '*' ',' '*' ')'                 { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
                    711:  | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
                    712:    { $$ = f_new_pair_item($2, $8, $4, $10); }
                    713:  ;
                    714: 
                    715: ec_kind:
                    716:    RT { $$ = EC_RT; }
                    717:  | RO { $$ = EC_RO; }
                    718:  | UNKNOWN NUM { $$ = $2; }
                    719:  | GENERIC { $$ = EC_GENERIC; }
                    720:  ;
                    721: 
                    722: ec_item:
                    723:    '(' ec_kind ',' cnum ',' cnum ')'           { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
                    724:  | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
                    725:  | '(' ec_kind ',' cnum ',' '*' ')'            { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
                    726:  ;
                    727: 
                    728: lc_item:
                    729:    '(' cnum ',' cnum ',' cnum ')'          { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
                    730:  | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
                    731:  | '(' cnum ',' cnum ',' '*' ')'           { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
                    732:  | '(' cnum ',' cnum DDOT cnum ',' '*' ')'  { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
                    733:  | '(' cnum ',' '*' ',' '*' ')'                    { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
                    734:  | '(' cnum DDOT cnum ',' '*' ',' '*' ')'   { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
                    735:  | '(' '*' ',' '*' ',' '*' ')'             { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
                    736:  | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
                    737:    { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
                    738: ;
                    739: 
                    740: set_item:
                    741:    pair_item
                    742:  | ec_item
                    743:  | lc_item
                    744:  | set_atom { $$ = f_new_item($1, $1); }
                    745:  | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
                    746:  ;
                    747: 
                    748: switch_item:
                    749:    pair_item
                    750:  | ec_item
                    751:  | lc_item
                    752:  | switch_atom { $$ = f_new_item($1, $1); }
                    753:  | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
                    754:  ;
                    755: 
                    756: set_items:
                    757:    set_item
                    758:  | set_items ',' set_item { $$ = f_merge_items($1, $3); }
                    759:  ;
                    760: 
                    761: switch_items:
                    762:    switch_item
                    763:  | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
                    764:  ;
                    765: 
                    766: fprefix:
                    767:    net_ip_     { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; }
                    768:  | net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; }
                    769:  | net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; }
                    770:  | net_ip_ '{' NUM ',' NUM '}' {
                    771:      $$.net = $1; $$.lo = $3; $$.hi = $5;
                    772:      if (($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
                    773:        cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5);
                    774:    }
                    775:  ;
                    776: 
                    777: fprefix_set:
                    778:    fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
                    779:  | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); }
                    780:  ;
                    781: 
                    782: switch_body: /* EMPTY */ { $$ = NULL; }
                    783:  | switch_body switch_items ':' cmds  {
                    784:      /* Fill data fields */
                    785:      struct f_tree *t;
                    786:      struct f_line *line = f_linearize($4);
                    787:      for (t = $2; t; t = t->left)
                    788:        t->data = line;
                    789:      $$ = f_merge_items($1, $2);
                    790:    }
                    791:  | switch_body ELSECOL cmds {
                    792:      struct f_tree *t = f_new_tree();
                    793:      t->from.type = t->to.type = T_VOID;
                    794:      t->right = t;
                    795:      t->data = f_linearize($3);
                    796:      $$ = f_merge_items($1, t);
                    797:  }
                    798:  ;
                    799: 
                    800: bgp_path_expr:
                    801:    symbol_value { $$ = $1; }
                    802:  | '(' term ')' { $$ = $2; }
                    803:  ;
                    804: 
                    805: bgp_path:
                    806:    PO  bgp_path_tail PC  { $$ = $2; }
                    807:  ;
                    808: 
                    809: bgp_path_tail:
                    810:    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;  }
                    811:  | 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; }
                    812:  | '[' set_items ']' bgp_path_tail {
                    813:    if ($2->from.type != T_INT) cf_error("Only integer sets allowed in path mask");
                    814:    $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .set = build_tree($2), .kind = PM_ASN_SET }, }); $$->next = $4;
                    815:  }
                    816:  | '*' bgp_path_tail           { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; }
                    817:  | '?' bgp_path_tail           { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; }
                    818:  | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
                    819:  |                             { $$ = NULL; }
                    820:  ;
                    821: 
                    822: constant:
                    823:    NUM    { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); }
                    824:  | TRUE   { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); }
                    825:  | FALSE  { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); }
                    826:  | TEXT   { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); }
                    827:  | fipa          { $$ = f_new_inst(FI_CONSTANT, $1); }
                    828:  | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); }
                    829:  | net_   { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); }
                    830:  | '[' set_items ']' {
                    831:      DBG( "We've got a set here..." );
                    832:      $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = build_tree($2), });
                    833:      DBG( "ook\n" );
                    834:  }
                    835:  | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); }
                    836:  | ENUM          { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); }
                    837:  ;
                    838: 
                    839: constructor:
                    840:    '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); }
                    841:  | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); }
                    842:  | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); }
                    843:  | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1); }
                    844:  ;
                    845: 
                    846: 
                    847: /* This generates the function_call variable list backwards. */
                    848: var_list: /* EMPTY */ { $$ = NULL; }
                    849:  | term { $$ = $1; }
                    850:  | var_list ',' term { $$ = $3; $$->next = $1; }
                    851: 
                    852: function_call:
                    853:    CF_SYM_KNOWN '(' var_list ')' {
                    854:      if ($1->class != SYM_FUNCTION)
                    855:        cf_error("You can't call something which is not a function. Really.");
                    856: 
                    857:      struct f_inst *fc = f_new_inst(FI_CALL, $1);
                    858:      uint args = 0;
                    859:      while ($3) {
                    860:        args++;
                    861:        struct f_inst *tmp = $3->next;
                    862:        $3->next = fc;
                    863: 
                    864:        fc = $3;
                    865:        $3 = tmp;
                    866:      }
                    867: 
                    868:      if (args != $1->function->args)
                    869:        cf_error("Function call '%s' got %u arguments, need %u arguments.",
                    870:           $1->name, args, $1->function->args);
                    871: 
                    872:      $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID });
                    873:      $$->next = fc;
                    874:    }
                    875:  ;
                    876: 
                    877: symbol_value: CF_SYM_KNOWN
                    878:   {
                    879:     switch ($1->class) {
                    880:       case SYM_CONSTANT_RANGE:
                    881:        $$ = f_new_inst(FI_CONSTANT, *($1->val));
                    882:        break;
                    883:       case SYM_VARIABLE_RANGE:
                    884:        $$ = f_new_inst(FI_VAR_GET, $1);
                    885:        break;
                    886:       case SYM_ATTRIBUTE:
                    887:        $$ = f_new_inst(FI_EA_GET, *$1->attribute);
                    888:        break;
                    889:       default:
                    890:        cf_error("Can't get value of symbol %s", $1->name);
                    891:     }
                    892:   }
                    893:  ;
                    894: 
                    895: static_attr:
                    896:    FROM    { $$ = f_new_static_attr(T_IP,         SA_FROM,     0); }
                    897:  | GW      { $$ = f_new_static_attr(T_IP,         SA_GW,       0); }
                    898:  | NET     { $$ = f_new_static_attr(T_NET,       SA_NET,       1); }
                    899:  | PROTO   { $$ = f_new_static_attr(T_STRING,     SA_PROTO,    1); }
                    900:  | SOURCE  { $$ = f_new_static_attr(T_ENUM_RTS,   SA_SOURCE,   1); }
                    901:  | SCOPE   { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE,    0); }
                    902:  | DEST    { $$ = f_new_static_attr(T_ENUM_RTD,   SA_DEST,     0); }
                    903:  | IFNAME  { $$ = f_new_static_attr(T_STRING,     SA_IFNAME,   0); }
                    904:  | IFINDEX { $$ = f_new_static_attr(T_INT,        SA_IFINDEX,  1); }
                    905:  ;
                    906: 
                    907: term:
                    908:    '(' term ')'                { $$ = $2; }
                    909:  | term '+' term       { $$ = f_new_inst(FI_ADD, $1, $3); }
                    910:  | term '-' term       { $$ = f_new_inst(FI_SUBTRACT, $1, $3); }
                    911:  | term '*' term       { $$ = f_new_inst(FI_MULTIPLY, $1, $3); }
                    912:  | term '/' term       { $$ = f_new_inst(FI_DIVIDE, $1, $3); }
                    913:  | term AND term       { $$ = f_new_inst(FI_AND, $1, $3); }
                    914:  | term OR  term       { $$ = f_new_inst(FI_OR, $1, $3); }
                    915:  | term '=' term       { $$ = f_new_inst(FI_EQ, $1, $3); }
                    916:  | term NEQ term       { $$ = f_new_inst(FI_NEQ, $1, $3); }
                    917:  | term '<' term       { $$ = f_new_inst(FI_LT, $1, $3); }
                    918:  | term LEQ term       { $$ = f_new_inst(FI_LTE, $1, $3); }
                    919:  | term '>' term       { $$ = f_new_inst(FI_LT, $3, $1); }
                    920:  | term GEQ term       { $$ = f_new_inst(FI_LTE, $3, $1); }
                    921:  | term '~' term       { $$ = f_new_inst(FI_MATCH, $1, $3); }
                    922:  | term NMA term       { $$ = f_new_inst(FI_NOT_MATCH, $1, $3); }
                    923:  | '!' term            { $$ = f_new_inst(FI_NOT, $2); }
                    924:  | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
                    925: 
                    926:  | symbol_value   { $$ = $1; }
                    927:  | constant { $$ = $1; }
                    928:  | constructor { $$ = $1; }
                    929: 
                    930:  | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
                    931: 
                    932:  | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
                    933: 
                    934:  | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
                    935: 
                    936:  | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
                    937:  | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
                    938:  | term '.' IP { $$ = f_new_inst(FI_IP, $1); }
                    939:  | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); }
                    940:  | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
                    941:  | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
                    942:  | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); }
                    943:  | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC, $1); }
                    944:  | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
                    945:  | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
                    946:  | term '.' LAST  { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
                    947:  | term '.' LAST_NONAGGREGATED  { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); }
                    948: 
                    949: /* Communities */
                    950: /* This causes one shift/reduce conflict
                    951:  | dynamic_attr '.' ADD '(' term ')' { }
                    952:  | dynamic_attr '.' DELETE '(' term ')' { }
                    953:  | dynamic_attr '.' CONTAINS '(' term ')' { }
                    954:  | dynamic_attr '.' RESET{ }
                    955: */
                    956: 
                    957:  | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); }
                    958:  | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_clist); }
                    959:  | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_eclist); }
                    960:  | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_lclist); }
                    961:  | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
                    962:  | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); }
                    963:  | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); }
                    964:  | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); }
                    965: 
                    966:  | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); }
                    967:  | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); }
                    968: 
                    969:  | FORMAT '(' term ')' {  $$ = f_new_inst(FI_FORMAT, $3); }
                    970: 
                    971: /* | term '.' LEN { $$->code = P('P','l'); } */
                    972: 
                    973:  | function_call
                    974:  ;
                    975: 
                    976: break_command:
                    977:    QUITBIRD { $$ = F_QUITBIRD; }
                    978:  | ACCEPT { $$ = F_ACCEPT; }
                    979:  | REJECT { $$ = F_REJECT; }
                    980:  | ERROR { $$ = F_ERROR; }
                    981:  ;
                    982: 
                    983: print_list: /* EMPTY */ { $$ = NULL; }
                    984:  | term { $$ = $1; }
                    985:  | term ',' print_list {
                    986:      ASSERT($1);
                    987:      ASSERT($1->next == NULL);
                    988:      $1->next = $3;
                    989:      $$ = $1;
                    990:    }
                    991:  ;
                    992: 
                    993: cmd:
                    994:    IF term THEN block {
                    995:      $$ = f_new_inst(FI_CONDITION, $2, $4, NULL);
                    996:    }
                    997:  | IF term THEN block ELSE block {
                    998:      $$ = f_new_inst(FI_CONDITION, $2, $4, $6);
                    999:    }
                   1000:  | CF_SYM_KNOWN '=' term ';' {
                   1001:      switch ($1->class) {
                   1002:        case SYM_VARIABLE_RANGE:
                   1003:         $$ = f_new_inst(FI_VAR_SET, $3, $1);
                   1004:         break;
                   1005:        case SYM_ATTRIBUTE:
                   1006:         $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
                   1007:         break;
                   1008:        default:
                   1009:         cf_error("Can't assign to symbol %s", $1->name);
                   1010:      }
                   1011:    }
                   1012:  | RETURN term ';' {
                   1013:      DBG( "Ook, we'll return the value\n" );
                   1014:      $$ = f_new_inst(FI_RETURN, $2);
                   1015:    }
                   1016:  | dynamic_attr '=' term ';' {
                   1017:      $$ = f_new_inst(FI_EA_SET, $3, $1);
                   1018:    }
                   1019:  | static_attr '=' term ';' {
                   1020:      if ($1.readonly)
                   1021:        cf_error( "This static attribute is read-only.");
                   1022:      $$ = f_new_inst(FI_RTA_SET, $3, $1);
                   1023:    }
                   1024:  | PREFERENCE '=' term ';' {
                   1025:      $$ = f_new_inst(FI_PREF_SET, $3);
                   1026:    }
                   1027:  | UNSET '(' dynamic_attr ')' ';' {
                   1028:      $$ = f_new_inst(FI_EA_UNSET, $3);
                   1029:    }
                   1030:  | break_command print_list ';' {
                   1031:     struct f_inst *breaker = f_new_inst(FI_DIE, $1);
                   1032:     if ($2) {
                   1033:       struct f_inst *printer = f_new_inst(FI_PRINT, $2);
                   1034:       struct f_inst *flusher = f_new_inst(FI_FLUSH);
                   1035:       printer->next = flusher;
                   1036:       flusher->next = breaker;
                   1037:       $$ = printer;
                   1038:     } else
                   1039:       $$ = breaker;
                   1040:    }
                   1041:  | PRINT print_list ';' {
                   1042:     $$ = f_new_inst(FI_PRINT, $2);
                   1043:     $$->next = f_new_inst(FI_FLUSH);
                   1044:    }
                   1045:  | PRINTN print_list ';' {
                   1046:     $$ = f_new_inst(FI_PRINT, $2);
                   1047:    }
                   1048:  | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); } 
                   1049:  | CASE term '{' switch_body '}' {
                   1050:       $$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
                   1051:    }
                   1052: 
                   1053:  | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); }
                   1054:  | dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); }
                   1055:  | dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); }
                   1056:  | dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); }
                   1057:  | dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); }
                   1058:  | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
                   1059:  | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); }
                   1060:  ;
                   1061: 
                   1062: get_cf_position:
                   1063: {
                   1064:   $$ = cf_text;
                   1065: };
                   1066: 
                   1067: lvalue:
                   1068:    CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; }
                   1069:  | PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; }
                   1070:  | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
                   1071:  | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };
                   1072: 
                   1073: CF_END

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>