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

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