Annotation of embedaddon/bird/filter/config.Y, revision 1.1.1.2

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: CF_DEFINES
                     14: 
                     15: static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
                     16: static inline u32 pair_a(u32 p) { return p >> 16; }
                     17: static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
                     18: 
                     19: 
                     20: /*
                     21:  * Sets and their items are during parsing handled as lists, linked
                     22:  * through left ptr. The first item in a list also contains a pointer
                     23:  * to the last item in a list (right ptr). For convenience, even items
                     24:  * are handled as one-item lists. Lists are merged by f_merge_items().
                     25:  */
                     26: static int
                     27: f_valid_set_type(int type)
                     28: {
                     29:   switch (type)
                     30:   {
                     31:   case T_INT:
                     32:   case T_PAIR:
                     33:   case T_QUAD:
                     34:   case T_ENUM:
                     35:   case T_IP:
                     36:   case T_EC:
                     37:   case T_LC:
                     38:     return 1;
                     39: 
                     40:   default:
                     41:     return 0;
                     42:   }
                     43: }
                     44: 
                     45: static inline struct f_tree *
                     46: f_new_item(struct f_val from, struct f_val to)
                     47: {
                     48:   struct f_tree *t = f_new_tree();
                     49:   t->right = t;
                     50:   t->from = from;
                     51:   t->to = to;
                     52:   return t;
                     53: }
                     54: 
                     55: static inline struct f_tree *
                     56: f_merge_items(struct f_tree *a, struct f_tree *b)
                     57: {
                     58:   if (!a) return b;
                     59:   a->right->left = b;
                     60:   a->right = b->right;
                     61:   b->right = NULL;
                     62:   return a;
                     63: }
                     64: 
                     65: static inline struct f_tree *
                     66: f_new_pair_item(int fa, int ta, int fb, int tb)
                     67: {
                     68:   check_u16(fa);
                     69:   check_u16(ta);
                     70:   check_u16(fb);
                     71:   check_u16(tb);
                     72: 
                     73:   if ((ta < fa) || (tb < fb))
                     74:     cf_error( "From value cannot be higher that To value in pair sets");
                     75: 
                     76:   struct f_tree *t = f_new_tree();
                     77:   t->right = t;
                     78:   t->from.type = t->to.type = T_PAIR;
                     79:   t->from.val.i = pair(fa, fb);
                     80:   t->to.val.i = pair(ta, tb);
                     81:   return t;
                     82: }
                     83: 
                     84: static inline struct f_tree *
                     85: f_new_pair_set(int fa, int ta, int fb, int tb)
                     86: {
                     87:   check_u16(fa);
                     88:   check_u16(ta);
                     89:   check_u16(fb);
                     90:   check_u16(tb);
                     91: 
                     92:   if ((ta < fa) || (tb < fb))
                     93:     cf_error( "From value cannot be higher that To value in pair sets");
                     94: 
                     95:   struct f_tree *lst = NULL;
                     96:   int i;
                     97: 
                     98:   for (i = fa; i <= ta; i++)
                     99:     lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
                    100: 
                    101:   return lst;
                    102: }
                    103: 
                    104: #define CC_ALL 0xFFFF
                    105: #define EC_ALL 0xFFFFFFFF
                    106: #define LC_ALL 0xFFFFFFFF
                    107: 
                    108: static struct f_tree *
                    109: f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
                    110: {
                    111:   u64 fm, to;
                    112: 
1.1.1.2 ! misho     113:   if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
1.1       misho     114:     check_u16(vf);
                    115:     if (vt == EC_ALL)
                    116:       vt = 0xFFFF;
                    117:     else
                    118:       check_u16(vt);
                    119:   }
                    120: 
                    121:   if (kind == EC_GENERIC) {
                    122:     fm = ec_generic(key, vf);
                    123:     to = ec_generic(key, vt);
                    124:   }
                    125:   else if (ipv4_used) {
                    126:     fm = ec_ip4(kind, key, vf);
                    127:     to = ec_ip4(kind, key, vt);
                    128:   }
                    129:   else if (key < 0x10000) {
                    130:     fm = ec_as2(kind, key, vf);
                    131:     to = ec_as2(kind, key, vt);
                    132:   }
                    133:   else {
                    134:     fm = ec_as4(kind, key, vf);
                    135:     to = ec_as4(kind, key, vt);
                    136:   }
                    137: 
                    138:   struct f_tree *t = f_new_tree();
                    139:   t->right = t;
                    140:   t->from.type = t->to.type = T_EC;
                    141:   t->from.val.ec = fm;
                    142:   t->to.val.ec = to;
                    143:   return t;
                    144: }
                    145: 
                    146: static struct f_tree *
                    147: f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
                    148: {
                    149:   struct f_tree *t = f_new_tree();
                    150:   t->right = t;
                    151:   t->from.type = t->to.type = T_LC;
                    152:   t->from.val.lc = (lcomm) {f1, f2, f3};
                    153:   t->to.val.lc = (lcomm) {t1, t2, t3};
                    154:   return t;
                    155: }
                    156: 
                    157: static inline struct f_inst *
1.1.1.2 ! misho     158: f_generate_empty(struct f_dynamic_attr dyn)
1.1       misho     159: {
1.1.1.2 ! misho     160:   struct f_inst *e = f_new_inst(FI_EMPTY);
1.1       misho     161: 
1.1.1.2 ! misho     162:   switch (dyn.type & EAF_TYPE_MASK) {
1.1       misho     163:     case EAF_TYPE_AS_PATH:
                    164:       e->aux = T_PATH;
                    165:       break;
                    166:     case EAF_TYPE_INT_SET:
                    167:       e->aux = T_CLIST;
                    168:       break;
                    169:     case EAF_TYPE_EC_SET:
                    170:       e->aux = T_ECLIST;
                    171:       break;
                    172:     case EAF_TYPE_LC_SET:
                    173:       e->aux = T_LCLIST;
                    174:       break;
                    175:     default:
                    176:       cf_error("Can't empty that attribute");
                    177:   }
                    178: 
1.1.1.2 ! misho     179:   struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn);
        !           180:   s->a1.p = e;
        !           181:   return s;
1.1       misho     182: }
                    183: 
                    184: 
                    185: static inline struct f_inst *
                    186: f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
                    187: {
                    188:   struct f_inst *rv;
                    189: 
1.1.1.2 ! misho     190:   if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
1.1       misho     191:     if ((t1->aux != T_INT) || (t2->aux != T_INT))
                    192:       cf_error( "Can't operate with value of non-integer type in pair constructor");
                    193: 
                    194:     check_u16(t1->a2.i);
                    195:     check_u16(t2->a2.i);
                    196: 
1.1.1.2 ! misho     197:     rv = f_new_inst(FI_CONSTANT);
1.1       misho     198:     rv->aux = T_PAIR;
                    199:     rv->a2.i = pair(t1->a2.i, t2->a2.i);
                    200:   }
                    201:   else {
1.1.1.2 ! misho     202:     rv = f_new_inst(FI_PAIR_CONSTRUCT);
1.1       misho     203:     rv->a1.p = t1;
                    204:     rv->a2.p = t2;
                    205:   }
                    206: 
                    207:   return rv;
                    208: }
                    209: 
                    210: static inline struct f_inst *
                    211: f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
                    212: {
                    213:   struct f_inst *rv;
                    214:   int c1 = 0, c2 = 0, ipv4_used = 0;
                    215:   u32 key = 0, val2 = 0;
                    216: 
1.1.1.2 ! misho     217:   if (tk->fi_code == FI_CONSTANT) {
1.1       misho     218:     c1 = 1;
                    219: 
                    220:     if (tk->aux == T_INT) {
                    221:       ipv4_used = 0; key = tk->a2.i;
                    222:     }
                    223:     else if (tk->aux == T_QUAD) {
                    224:       ipv4_used = 1; key = tk->a2.i;
                    225:     }
                    226:     else
                    227:       cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
                    228:   }
                    229: 
                    230: #ifndef IPV6
                    231:   /* IP->Quad implicit conversion */
1.1.1.2 ! misho     232:   else if (tk->fi_code == FI_CONSTANT_INDIRECT) {
1.1       misho     233:     c1 = 1;
                    234:     struct f_val *val = tk->a1.p;
                    235: 
                    236:     if (val->type == T_INT) {
                    237:       ipv4_used = 0; key = val->val.i;
                    238:     }
                    239:     else if (val->type == T_QUAD) {
                    240:       ipv4_used = 1; key = val->val.i;
                    241:     }
                    242:     else if (val->type == T_IP) {
                    243:       ipv4_used = 1; key = ipa_to_u32(val->val.px.ip);
                    244:     }
                    245:     else
                    246:       cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
                    247:   }
                    248: #endif
                    249: 
1.1.1.2 ! misho     250:   if (tv->fi_code == FI_CONSTANT) {
1.1       misho     251:     if (tv->aux != T_INT)
                    252:       cf_error("Can't operate with value of non-integer type in EC constructor");
                    253:     c2 = 1;
                    254:     val2 = tv->a2.i;
                    255:   }
                    256: 
                    257:   if (c1 && c2) {
                    258:     u64 ec;
                    259: 
                    260:     if (kind == EC_GENERIC) {
                    261:       ec = ec_generic(key, val2);
                    262:     }
                    263:     else if (ipv4_used) {
                    264:       check_u16(val2);
                    265:       ec = ec_ip4(kind, key, val2);
                    266:     }
                    267:     else if (key < 0x10000) {
                    268:       ec = ec_as2(kind, key, val2);
                    269:     }
                    270:     else {
                    271:       check_u16(val2);
                    272:       ec = ec_as4(kind, key, val2);
                    273:     }
                    274: 
                    275:     NEW_F_VAL;
1.1.1.2 ! misho     276:     rv = f_new_inst(FI_CONSTANT_INDIRECT);
1.1       misho     277:     rv->a1.p = val;
                    278:     val->type = T_EC;
                    279:     val->val.ec = ec;
                    280:   }
                    281:   else {
1.1.1.2 ! misho     282:     rv = f_new_inst(FI_EC_CONSTRUCT);
1.1       misho     283:     rv->aux = kind;
                    284:     rv->a1.p = tk;
                    285:     rv->a2.p = tv;
                    286:   }
                    287: 
                    288:   return rv;
                    289: }
                    290: 
                    291: static inline struct f_inst *
                    292: f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
                    293: {
                    294:   struct f_inst *rv;
                    295: 
1.1.1.2 ! misho     296:   if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
1.1       misho     297:     if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
                    298:       cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
                    299: 
1.1.1.2 ! misho     300:     rv = f_new_inst(FI_CONSTANT_INDIRECT);
1.1       misho     301: 
                    302:     NEW_F_VAL;
                    303:     rv->a1.p = val;
                    304:     val->type = T_LC;
                    305:     val->val.lc = (lcomm) { t1->a2.i, t2->a2.i, t3->a2.i };
                    306:   }
                    307:   else
                    308:   {
                    309:     rv = cfg_allocz(sizeof(struct f_inst3));
                    310:     rv->lineno = ifs->lino;
1.1.1.2 ! misho     311:     rv->fi_code = FI_LC_CONSTRUCT;
1.1       misho     312:     rv->a1.p = t1;
                    313:     rv->a2.p = t2;
                    314:     INST3(rv).p = t3;
                    315:   }
                    316: 
                    317:   return rv;
                    318: }
                    319: 
1.1.1.2 ! misho     320: static inline struct f_inst *
        !           321: f_generate_path_mask(struct f_path_mask *t)
        !           322: {
        !           323:   struct f_path_mask *tt;
        !           324:   for (tt = t; tt; tt = tt->next) {
        !           325:     if (tt->kind == PM_ASN_EXPR) {
        !           326:       struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT);
        !           327:       mrv->a1.p = t;
        !           328:       return mrv;
        !           329:     }
        !           330:   }
        !           331: 
        !           332:   NEW_F_VAL;
        !           333:   val->type = T_PATH_MASK;
        !           334:   val->val.path_mask = t;
        !           335: 
        !           336:   struct f_inst *rv = f_new_inst(FI_CONSTANT_INDIRECT);
        !           337:   rv->a1.p = val;
        !           338: 
        !           339:   return rv;
        !           340: }
1.1       misho     341: 
                    342: 
                    343: CF_DECLS
                    344: 
                    345: CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
                    346:        ACCEPT, REJECT, ERROR, QUITBIRD,
                    347:        INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, LC,
                    348:        SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
                    349:        IF, THEN, ELSE, CASE,
                    350:        TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
                    351:        FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
                    352:        PREFERENCE,
                    353:        LEN,
                    354:        DEFINED,
                    355:        ADD, DELETE, CONTAINS, RESET,
                    356:        PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
                    357:        ROA_CHECK,
                    358:        EMPTY,
                    359:        FILTER, WHERE, EVAL)
                    360: 
                    361: %nonassoc THEN
                    362: %nonassoc ELSE
                    363: 
1.1.1.2 ! misho     364: %type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr
        !           365: %type <fda> dynamic_attr
        !           366: %type <fsa> static_attr
1.1       misho     367: %type <f> filter filter_body where_filter
                    368: %type <i> type break_command ec_kind
                    369: %type <i32> cnum
                    370: %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
                    371: %type <trie> fprefix_set
                    372: %type <v> set_atom switch_atom fprefix fprefix_s fipa
                    373: %type <s> decls declsn one_decl function_params
                    374: %type <h> bgp_path bgp_path_tail1 bgp_path_tail2
                    375: 
                    376: CF_GRAMMAR
                    377: 
                    378: CF_ADDTO(conf, filter_def)
                    379: filter_def:
                    380:    FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
                    381:      filter_body {
                    382:      $2->def = $4;
                    383:      $4->name = $2->name;
                    384:      DBG( "We have new filter defined (%s)\n", $2->name );
                    385:      cf_pop_scope();
                    386:    }
                    387:  ;
                    388: 
                    389: CF_ADDTO(conf, filter_eval)
                    390: filter_eval:
                    391:    EVAL term { f_eval_int($2); }
                    392:  ;
                    393: 
                    394: type:
                    395:    INT { $$ = T_INT; }
                    396:  | BOOL { $$ = T_BOOL; }
                    397:  | IP { $$ = T_IP; }
                    398:  | PREFIX { $$ = T_PREFIX; }
                    399:  | PAIR { $$ = T_PAIR; }
                    400:  | QUAD { $$ = T_QUAD; }
                    401:  | EC { $$ = T_EC; }
                    402:  | LC { $$ = T_LC; }
                    403:  | STRING { $$ = T_STRING; }
                    404:  | BGPMASK { $$ = T_PATH_MASK; }
                    405:  | BGPPATH { $$ = T_PATH; }
                    406:  | CLIST { $$ = T_CLIST; }
                    407:  | ECLIST { $$ = T_ECLIST; }
                    408:  | LCLIST { $$ = T_LCLIST; }
                    409:  | type SET {
                    410:        switch ($1) {
                    411:          case T_INT:
                    412:          case T_PAIR:
                    413:          case T_QUAD:
                    414:          case T_EC:
                    415:          case T_LC:
                    416:          case T_IP:
                    417:               $$ = T_SET;
                    418:               break;
                    419: 
                    420:          case T_PREFIX:
                    421:               $$ = T_PREFIX_SET;
                    422:            break;
                    423: 
                    424:          default:
                    425:                cf_error( "You can't create sets of this type." );
                    426:        }
                    427:    }
                    428:  ;
                    429: 
                    430: one_decl:
                    431:    type SYM {
                    432:      struct f_val * val = cfg_alloc(sizeof(struct f_val));
                    433:      val->type = T_VOID;
                    434:      $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
                    435:      DBG( "New variable %s type %x\n", $2->name, $1 );
                    436:      $2->aux2 = NULL;
                    437:      $$=$2;
                    438:    }
                    439:  ;
                    440: 
                    441: /* Decls with ';' at the end */
                    442: decls: /* EMPTY */ { $$ = NULL; }
                    443:  | one_decl ';' decls {
                    444:      $$ = $1;
                    445:      $$->aux2 = $3;
                    446:    }
                    447:  ;
                    448: 
                    449: /* Declarations that have no ';' at the end. */
                    450: declsn: one_decl { $$ = $1; }
                    451:  | one_decl ';' declsn {
                    452:      $$ = $1;
                    453:      $$->aux2 = $3;
                    454:    }
                    455:  ;
                    456: 
                    457: filter_body:
                    458:    function_body {
                    459:      struct filter *f = cfg_alloc(sizeof(struct filter));
                    460:      f->name = NULL;
                    461:      f->root = $1;
                    462:      $$ = f;
                    463:    }
                    464:  ;
                    465: 
                    466: filter:
                    467:    SYM {
                    468:      if ($1->class != SYM_FILTER) cf_error("No such filter.");
                    469:      $$ = $1->def;
                    470:    }
                    471:  | filter_body
                    472:  ;
                    473: 
                    474: where_filter:
                    475:    WHERE term {
                    476:      /* Construct 'IF term THEN ACCEPT; REJECT;' */
                    477:      struct filter *f = cfg_alloc(sizeof(struct filter));
                    478:      struct f_inst *i, *acc, *rej;
1.1.1.2 ! misho     479:      acc = f_new_inst(FI_PRINT_AND_DIE);       /* ACCEPT */
1.1       misho     480:      acc->a1.p = NULL;
                    481:      acc->a2.i = F_ACCEPT;
1.1.1.2 ! misho     482:      rej = f_new_inst(FI_PRINT_AND_DIE);       /* REJECT */
1.1       misho     483:      rej->a1.p = NULL;
                    484:      rej->a2.i = F_REJECT;
1.1.1.2 ! misho     485:      i = f_new_inst(FI_CONDITION);                     /* IF */
1.1       misho     486:      i->a1.p = $2;
                    487:      i->a2.p = acc;
                    488:      i->next = rej;
                    489:      f->name = NULL;
                    490:      f->root = i;
                    491:      $$ = f;
                    492:   }
                    493:  ;
                    494: 
                    495: function_params:
                    496:    '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
                    497:  | '(' ')' { $$=NULL; }
                    498:  ;
                    499: 
                    500: function_body:
                    501:    decls '{' cmds '}' {
                    502:      if ($1) {
                    503:        /* Prepend instruction to clear local variables */
1.1.1.2 ! misho     504:        $$ = f_new_inst(FI_CLEAR_LOCAL_VARS);
1.1       misho     505:        $$->a1.p = $1;
                    506:        $$->next = $3;
                    507:      } else
                    508:        $$ = $3;
                    509:    }
                    510:  ;
                    511: 
                    512: CF_ADDTO(conf, function_def)
                    513: function_def:
                    514:    FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
                    515:      $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
                    516:      cf_push_scope($2);
                    517:    } function_params function_body {
                    518:      $2->def = $5;
                    519:      $2->aux2 = $4;
                    520:      DBG("Hmm, we've got one function here - %s\n", $2->name);
                    521:      cf_pop_scope();
                    522:    }
                    523:  ;
                    524: 
                    525: /* Programs */
                    526: 
                    527: /* Hack: $$ of cmds_int is the last node.
                    528:    $$->next of cmds_int is temporary used for the first node */
                    529: 
                    530: cmds: /* EMPTY */ { $$ = NULL; }
                    531:  | cmds_int { $$ = $1->next; $1->next = NULL; }
                    532:  ;
                    533: 
                    534: cmds_int: cmd { $$ = $1; $1->next = $1; }
                    535:  | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
                    536:  ;
                    537: 
                    538: block:
                    539:    cmd {
                    540:      $$=$1;
                    541:    }
                    542:  | '{' cmds '}' {
                    543:      $$=$2;
                    544:    }
                    545:  ;
                    546: 
                    547: /*
                    548:  * Complex types, their bison value is struct f_val
                    549:  */
                    550: fipa:
                    551:    IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; }
                    552:  ;
                    553: 
                    554: 
                    555: 
                    556: /*
                    557:  * Set constants. They are also used in switch cases. We use separate
                    558:  * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
                    559:  * to elude a collision between symbol (in expr) in set_atom and symbol
                    560:  * as a function call in switch case cmds.
                    561:  */
                    562: 
                    563: set_atom:
                    564:    NUM   { $$.type = T_INT; $$.val.i = $1; }
                    565:  | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
                    566:  | fipa  { $$ = $1; }
                    567:  | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
                    568:  | '(' term ')' {
                    569:      $$ = f_eval($2, cfg_mem);
                    570:      if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
                    571:    }
                    572:  | SYM {
                    573:      if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
                    574:      if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
                    575:      $$ = *(struct f_val *)($1->def);
                    576:    }
                    577:  ;
                    578: 
                    579: switch_atom:
                    580:    NUM   { $$.type = T_INT; $$.val.i = $1; }
                    581:  | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
                    582:  | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
                    583:  | fipa  { $$ = $1; }
                    584:  | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
                    585:  ;
                    586: 
                    587: cnum:
                    588:    term { $$ = f_eval_int($1); }
                    589: 
                    590: pair_item:
                    591:    '(' cnum ',' cnum ')'               { $$ = f_new_pair_item($2, $2, $4, $4); }
                    592:  | '(' cnum ',' cnum DDOT cnum ')'     { $$ = f_new_pair_item($2, $2, $4, $6); }
                    593:  | '(' cnum ',' '*' ')'                        { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
                    594:  | '(' cnum DDOT cnum ',' cnum ')'     { $$ = f_new_pair_set($2, $4, $6, $6); }
                    595:  | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
                    596:  | '(' cnum DDOT cnum ',' '*' ')'      { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
                    597:  | '(' '*' ',' cnum ')'                        { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
                    598:  | '(' '*' ',' cnum DDOT cnum ')'      { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
                    599:  | '(' '*' ',' '*' ')'                 { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
                    600:  | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
                    601:    { $$ = f_new_pair_item($2, $8, $4, $10); }
                    602:  ;
                    603: 
                    604: ec_kind:
                    605:    RT { $$ = EC_RT; }
                    606:  | RO { $$ = EC_RO; }
                    607:  | UNKNOWN NUM { $$ = $2; }
                    608:  | GENERIC { $$ = EC_GENERIC; }
                    609:  ;
                    610: 
                    611: ec_item:
                    612:    '(' ec_kind ',' cnum ',' cnum ')'           { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
                    613:  | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
                    614:  | '(' ec_kind ',' cnum ',' '*' ')'            { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
                    615:  ;
                    616: 
                    617: lc_item:
                    618:    '(' cnum ',' cnum ',' cnum ')'          { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
                    619:  | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
                    620:  | '(' cnum ',' cnum ',' '*' ')'           { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
                    621:  | '(' cnum ',' cnum DDOT cnum ',' '*' ')'  { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
                    622:  | '(' cnum ',' '*' ',' '*' ')'                    { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
                    623:  | '(' cnum DDOT cnum ',' '*' ',' '*' ')'   { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
                    624:  | '(' '*' ',' '*' ',' '*' ')'             { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
                    625:  | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
                    626:    { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
                    627: ;
                    628: 
                    629: set_item:
                    630:    pair_item
                    631:  | ec_item
                    632:  | lc_item
                    633:  | set_atom { $$ = f_new_item($1, $1); }
                    634:  | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
                    635:  ;
                    636: 
                    637: switch_item:
                    638:    pair_item
                    639:  | ec_item
                    640:  | lc_item
                    641:  | switch_atom { $$ = f_new_item($1, $1); }
                    642:  | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
                    643:  ;
                    644: 
                    645: set_items:
                    646:    set_item
                    647:  | set_items ',' set_item { $$ = f_merge_items($1, $3); }
                    648:  ;
                    649: 
                    650: switch_items:
                    651:    switch_item
                    652:  | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
                    653:  ;
                    654: 
                    655: fprefix_s:
                    656:    IPA '/' NUM %prec '/' {
                    657:      if (($3 < 0) || ($3 > MAX_PREFIX_LENGTH) || !ip_is_prefix($1, $3)) cf_error("Invalid network prefix: %I/%d.", $1, $3);
                    658:      $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3;
                    659:    }
                    660:  ;
                    661: 
                    662: fprefix:
                    663:    fprefix_s { $$ = $1; }
                    664:  | fprefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; }
                    665:  | fprefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; }
                    666:  | fprefix_s '{' NUM ',' NUM '}' {
                    667:      if (! ((0 <= $3) && ($3 <= $5) && ($5 <= MAX_PREFIX_LENGTH))) cf_error("Invalid prefix pattern range: {%d, %d}.", $3, $5);
                    668:      $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8);
                    669:    }
                    670:  ;
                    671: 
                    672: fprefix_set:
                    673:    fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_fprefix($$, &($1.val.px)); }
                    674:  | fprefix_set ',' fprefix { $$ = $1; trie_add_fprefix($$, &($3.val.px)); }
                    675:  ;
                    676: 
                    677: switch_body: /* EMPTY */ { $$ = NULL; }
                    678:  | switch_body switch_items ':' cmds  {
                    679:      /* Fill data fields */
                    680:      struct f_tree *t;
                    681:      for (t = $2; t; t = t->left)
                    682:        t->data = $4;
                    683:      $$ = f_merge_items($1, $2);
                    684:    }
                    685:  | switch_body ELSECOL cmds {
                    686:      struct f_tree *t = f_new_tree();
                    687:      t->from.type = t->to.type = T_VOID;
                    688:      t->right = t;
                    689:      t->data = $3;
                    690:      $$ = f_merge_items($1, t);
                    691:  }
                    692:  ;
                    693: 
1.1.1.2 ! misho     694: /* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $3; } */
1.1       misho     695: 
                    696: bgp_path_expr:
                    697:    symbol       { $$ = $1; }
                    698:  | '(' term ')' { $$ = $2; }
                    699:  ;
                    700: 
                    701: bgp_path:
                    702:    PO  bgp_path_tail1 PC  { $$ = $2; }
                    703:  | '/' bgp_path_tail2 '/' { $$ = $2; }
                    704:  ;
                    705: 
                    706: bgp_path_tail1:
                    707:    NUM bgp_path_tail1          { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
                    708:  | NUM DDOT NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
                    709:  | '*' bgp_path_tail1          { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
                    710:  | '?' bgp_path_tail1          { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
                    711:  | bgp_path_expr bgp_path_tail1        { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
                    712:  |                             { $$ = NULL; }
                    713:  ;
                    714: 
                    715: bgp_path_tail2:
                    716:    NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
                    717:  | '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
                    718:  |                   { $$ = NULL; }
                    719:  ;
                    720: 
                    721: constant:
1.1.1.2 ! misho     722:    NUM    { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT;  $$->a2.i = $1; }
        !           723:  | TRUE   { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1;  }
        !           724:  | FALSE  { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0;  }
        !           725:  | TEXT   { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; }
        !           726:  | fipa           { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
        !           727:  | fprefix_s {NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
        !           728:  | RTRID  { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_QUAD;  $$->a2.i = $1; }
        !           729:  | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
        !           730:  | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET;  $$->a2.p = $2; }
        !           731:  | ENUM          { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
1.1       misho     732:  ;
                    733: 
                    734: constructor:
                    735:    '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
                    736:  | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
                    737:  | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
1.1.1.2 ! misho     738:  | bgp_path { $$ = f_generate_path_mask($1); }
1.1       misho     739:  ;
                    740: 
                    741: 
                    742: /*
                    743:  *  Maybe there are no dynamic attributes defined by protocols.
                    744:  *  For such cases, we force the dynamic_attr list to contain
                    745:  *  at least an invalid token, so it is syntantically correct.
                    746:  */
1.1.1.2 ! misho     747: CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = (struct f_dynamic_attr) {}; })
1.1       misho     748: 
                    749: rtadot: /* EMPTY, we are not permitted RTA. prefix */
                    750:  ;
                    751: 
                    752: function_call:
                    753:    SYM '(' var_list ')' {
                    754:      struct symbol *sym;
                    755:      struct f_inst *inst = $3;
                    756:      if ($1->class != SYM_FUNCTION)
                    757:        cf_error("You can't call something which is not a function. Really.");
                    758:      DBG("You are calling function %s\n", $1->name);
1.1.1.2 ! misho     759:      $$ = f_new_inst(FI_CALL);
1.1       misho     760:      $$->a1.p = inst;
                    761:      $$->a2.p = $1->def;
                    762:      sym = $1->aux2;
                    763:      while (sym || inst) {
                    764:        if (!sym || !inst)
                    765:         cf_error("Wrong number of arguments for function %s.", $1->name);
                    766:        DBG( "You should pass parameter called %s\n", sym->name);
                    767:        inst->a1.p = sym;
                    768:        sym = sym->aux2;
                    769:        inst = inst->next;
                    770:      }
                    771:    }
                    772:  ;
                    773: 
                    774: symbol:
                    775:    SYM {
                    776:      switch ($1->class & 0xff00) {
1.1.1.2 ! misho     777:        case SYM_CONSTANT: $$ = f_new_inst(FI_CONSTANT_INDIRECT); break;
        !           778:        case SYM_VARIABLE: $$ = f_new_inst(FI_VARIABLE); break;
1.1       misho     779:        default: cf_error("%s: variable expected.", $1->name);
                    780:      }
                    781: 
                    782:      $$->a1.p = $1->def;
                    783:      $$->a2.p = $1->name;
                    784:    }
                    785: 
                    786: static_attr:
1.1.1.2 ! misho     787:    FROM    { $$ = f_new_static_attr(T_IP,         SA_FROM,     1); }
        !           788:  | GW      { $$ = f_new_static_attr(T_IP,         SA_GW,       1); }
        !           789:  | NET     { $$ = f_new_static_attr(T_PREFIX,     SA_NET,      0); }
        !           790:  | PROTO   { $$ = f_new_static_attr(T_STRING,     SA_PROTO,    0); }
        !           791:  | SOURCE  { $$ = f_new_static_attr(T_ENUM_RTS,   SA_SOURCE,   0); }
        !           792:  | SCOPE   { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE,    1); }
        !           793:  | CAST    { $$ = f_new_static_attr(T_ENUM_RTC,   SA_CAST,     0); }
        !           794:  | DEST    { $$ = f_new_static_attr(T_ENUM_RTD,   SA_DEST,     1); }
        !           795:  | IFNAME  { $$ = f_new_static_attr(T_STRING,     SA_IFNAME,   1); }
        !           796:  | IFINDEX { $$ = f_new_static_attr(T_INT,        SA_IFINDEX,  0); }
1.1       misho     797:  ;
                    798: 
                    799: term:
1.1.1.2 ! misho     800:    '(' term ')'                { $$ = $2; }
        !           801:  | term '+' term       { $$ = f_new_inst(FI_ADD);      $$->a1.p = $1; $$->a2.p = $3; }
        !           802:  | term '-' term       { $$ = f_new_inst(FI_SUBTRACT); $$->a1.p = $1; $$->a2.p = $3; }
        !           803:  | term '*' term       { $$ = f_new_inst(FI_MULTIPLY); $$->a1.p = $1; $$->a2.p = $3; }
        !           804:  | term '/' term       { $$ = f_new_inst(FI_DIVIDE);   $$->a1.p = $1; $$->a2.p = $3; }
        !           805:  | term AND term       { $$ = f_new_inst(FI_AND);      $$->a1.p = $1; $$->a2.p = $3; }
        !           806:  | term OR  term       { $$ = f_new_inst(FI_OR);       $$->a1.p = $1; $$->a2.p = $3; }
        !           807:  | term '=' term       { $$ = f_new_inst(FI_EQ);       $$->a1.p = $1; $$->a2.p = $3; }
        !           808:  | term NEQ term       { $$ = f_new_inst(FI_NEQ);      $$->a1.p = $1; $$->a2.p = $3; }
        !           809:  | term '<' term       { $$ = f_new_inst(FI_LT);       $$->a1.p = $1; $$->a2.p = $3; }
        !           810:  | term LEQ term       { $$ = f_new_inst(FI_LTE);      $$->a1.p = $1; $$->a2.p = $3; }
        !           811:  | term '>' term       { $$ = f_new_inst(FI_LT);       $$->a1.p = $3; $$->a2.p = $1; }
        !           812:  | term GEQ term       { $$ = f_new_inst(FI_LTE);      $$->a1.p = $3; $$->a2.p = $1; }
        !           813:  | term '~' term       { $$ = f_new_inst(FI_MATCH);    $$->a1.p = $1; $$->a2.p = $3; }
        !           814:  | term NMA term       { $$ = f_new_inst(FI_NOT_MATCH);$$->a1.p = $1; $$->a2.p = $3; }
        !           815:  | '!' term            { $$ = f_new_inst(FI_NOT);      $$->a1.p = $2; }
        !           816:  | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a1.p = $3; }
1.1       misho     817: 
                    818:  | symbol   { $$ = $1; }
                    819:  | constant { $$ = $1; }
                    820:  | constructor { $$ = $1; }
                    821: 
1.1.1.2 ! misho     822:  | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
1.1       misho     823: 
1.1.1.2 ! misho     824:  | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); }
1.1       misho     825: 
1.1.1.2 ! misho     826:  | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
1.1       misho     827: 
1.1.1.2 ! misho     828:  | term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; }
        !           829:  | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; }
        !           830:  | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; }
        !           831:  | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; }
        !           832:  | term '.' LAST  { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; }
        !           833:  | term '.' LAST_NONAGGREGATED  { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; }
1.1       misho     834: 
                    835: /* Communities */
                    836: /* This causes one shift/reduce conflict
                    837:  | rtadot dynamic_attr '.' ADD '(' term ')' { }
                    838:  | rtadot dynamic_attr '.' DELETE '(' term ')' { }
                    839:  | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
                    840:  | rtadot dynamic_attr '.' RESET{ }
                    841: */
                    842: 
1.1.1.2 ! misho     843:  | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
        !           844:  | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
        !           845:  | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
        !           846:  | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
        !           847:  | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; }
        !           848:  | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
        !           849:  | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
        !           850:  | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
1.1       misho     851: 
                    852:  | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
                    853:  | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
                    854: 
                    855: /* function_call is inlined here */
                    856:  | SYM '(' var_list ')' {
                    857:      struct symbol *sym;
                    858:      struct f_inst *inst = $3;
                    859:      if ($1->class != SYM_FUNCTION)
                    860:        cf_error("You can't call something which is not a function. Really.");
                    861:      DBG("You are calling function %s\n", $1->name);
1.1.1.2 ! misho     862:      $$ = f_new_inst(FI_CALL);
1.1       misho     863:      $$->a1.p = inst;
                    864:      $$->a2.p = $1->def;
                    865:      sym = $1->aux2;
                    866:      while (sym || inst) {
                    867:        if (!sym || !inst)
                    868:         cf_error("Wrong number of arguments for function %s.", $1->name);
                    869:        DBG( "You should pass parameter called %s\n", sym->name);
                    870:        inst->a1.p = sym;
                    871:        sym = sym->aux2;
                    872:        inst = inst->next;
                    873:      }
                    874:    }
                    875:  ;
                    876: 
                    877: break_command:
                    878:    QUITBIRD { $$ = F_QUITBIRD; }
                    879:  | ACCEPT { $$ = F_ACCEPT; }
                    880:  | REJECT { $$ = F_REJECT; }
                    881:  | ERROR { $$ = F_ERROR; }
                    882:  | PRINT { $$ = F_NOP; }
                    883:  | PRINTN { $$ = F_NONL; }
                    884:  ;
                    885: 
                    886: print_one:
1.1.1.2 ! misho     887:    term { $$ = f_new_inst(FI_PRINT); $$->a1.p = $1; $$->a2.p = NULL; }
1.1       misho     888:  ;
                    889: 
                    890: print_list: /* EMPTY */ { $$ = NULL; }
                    891:  | print_one { $$ = $1; }
                    892:  | print_one ',' print_list {
                    893:      if ($1) {
                    894:        $1->next = $3;
                    895:        $$ = $1;
                    896:      } else $$ = $3;
                    897:    }
                    898:  ;
                    899: 
                    900: var_listn: term {
1.1.1.2 ! misho     901:      $$ = f_new_inst(FI_SET);
1.1       misho     902:      $$->a1.p = NULL;
                    903:      $$->a2.p = $1;
                    904:      $$->next = NULL;
                    905:    }
                    906:  | term ',' var_listn {
1.1.1.2 ! misho     907:      $$ = f_new_inst(FI_SET);
1.1       misho     908:      $$->a1.p = NULL;
                    909:      $$->a2.p = $1;
                    910:      $$->next = $3;
                    911:    }
                    912:  ;
                    913: 
                    914: var_list: /* EMPTY */ { $$ = NULL; }
                    915:  | var_listn { $$ = $1; }
                    916:  ;
                    917: 
                    918: cmd:
                    919:    IF term THEN block {
1.1.1.2 ! misho     920:      $$ = f_new_inst(FI_CONDITION);
1.1       misho     921:      $$->a1.p = $2;
                    922:      $$->a2.p = $4;
                    923:    }
                    924:  | IF term THEN block ELSE block {
1.1.1.2 ! misho     925:      struct f_inst *i = f_new_inst(FI_CONDITION);
1.1       misho     926:      i->a1.p = $2;
                    927:      i->a2.p = $4;
1.1.1.2 ! misho     928:      $$ = f_new_inst(FI_CONDITION);
1.1       misho     929:      $$->a1.p = i;
                    930:      $$->a2.p = $6;
                    931:    }
                    932:  | SYM '=' term ';' {
                    933:      DBG( "Ook, we'll set value\n" );
                    934:      if (($1->class & ~T_MASK) != SYM_VARIABLE)
                    935:        cf_error( "You may set only variables." );
1.1.1.2 ! misho     936:      $$ = f_new_inst(FI_SET);
1.1       misho     937:      $$->a1.p = $1;
                    938:      $$->a2.p = $3;
                    939:    }
                    940:  | RETURN term ';' {
                    941:      DBG( "Ook, we'll return the value\n" );
1.1.1.2 ! misho     942:      $$ = f_new_inst(FI_RETURN);
1.1       misho     943:      $$->a1.p = $2;
                    944:    }
                    945:  | rtadot dynamic_attr '=' term ';' {
1.1.1.2 ! misho     946:      $$ = f_new_inst_da(FI_EA_SET, $2);
1.1       misho     947:      $$->a1.p = $4;
                    948:    }
                    949:  | rtadot static_attr '=' term ';' {
1.1.1.2 ! misho     950:      $$ = f_new_inst_sa(FI_RTA_SET, $2);
1.1       misho     951:      if (!$$->a1.i)
                    952:        cf_error( "This static attribute is read-only.");
                    953:      $$->a1.p = $4;
                    954:    }
                    955:  | PREFERENCE '=' term ';' {
1.1.1.2 ! misho     956:      $$ = f_new_inst(FI_PREF_SET);
1.1       misho     957:      $$->a1.p = $3;
                    958:    }
                    959:  | UNSET '(' rtadot dynamic_attr ')' ';' {
1.1.1.2 ! misho     960:      $$ = f_new_inst_da(FI_EA_SET, $4);
1.1       misho     961:      $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
                    962:      $$->a1.p = NULL;
                    963:    }
1.1.1.2 ! misho     964:  | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a1.p = $2; $$->a2.i = $1; }
1.1       misho     965:  | function_call ';' { $$ = $1; }
                    966:  | CASE term '{' switch_body '}' {
1.1.1.2 ! misho     967:       $$ = f_new_inst(FI_SWITCH);
1.1       misho     968:       $$->a1.p = $2;
                    969:       $$->a2.p = build_tree( $4 );
                    970:    }
                    971: 
                    972: 
                    973:  | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
1.1.1.2 ! misho     974:  | rtadot dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
        !           975:  | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
        !           976:  | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
        !           977:  | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
1.1       misho     978:  ;
                    979: 
                    980: CF_END

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