Annotation of embedaddon/bird2/filter/decl.m4, revision 1.1.1.1

1.1       misho       1: m4_divert(-1)m4_dnl
                      2: #
                      3: #      BIRD -- Construction of per-instruction structures
                      4: #
                      5: #      (c) 2018 Maria Matejka <mq@jmq.cz>
                      6: #
                      7: #      Can be freely distributed and used under the terms of the GNU GPL.
                      8: #
                      9: #      THIS IS A M4 MACRO FILE GENERATING 3 FILES ALTOGETHER.
                     10: #      KEEP YOUR HANDS OFF UNLESS YOU KNOW WHAT YOU'RE DOING.
                     11: #      EDITING AND DEBUGGING THIS FILE MAY DAMAGE YOUR BRAIN SERIOUSLY.
                     12: #
                     13: #      But you're welcome to read and edit and debug if you aren't scared.
                     14: #
                     15: #      Uncomment the following line to get exhaustive debug output.
                     16: #      m4_debugmode(aceflqtx)
                     17: #
                     18: #      How it works:
                     19: #      1) Instruction to code conversion (uses diversions 100..199)
                     20: #      2) Code wrapping (uses diversions 1..99)
                     21: #      3) Final preparation (uses diversions 200..299)
                     22: #      4) Shipout
                     23: #
                     24: #      See below for detailed description.
                     25: #
                     26: #
                     27: #      1) Instruction to code conversion
                     28: #      The code provided in f-inst.c between consecutive INST() calls
                     29: #      is interleaved for many different places. It is here processed
                     30: #      and split into separate instances where split-by-instruction
                     31: #      happens. These parts are stored in temporary diversions listed:
                     32: #
                     33: #      101     content of per-inst struct
                     34: #      102     constructor arguments
                     35: #      103     constructor body
                     36: #      104     dump line item content
                     37: #              (there may be nothing in dump-line content and
                     38: #               it must be handled specially in phase 2)
                     39: #      105     linearize body
                     40: #      106     comparator body
                     41: #      107     struct f_line_item content
                     42: #      108     interpreter body
                     43: #
                     44: #      Here are macros to allow you to _divert to the right directions.
                     45: m4_define(FID_STRUCT_IN, `m4_divert(101)')
                     46: m4_define(FID_NEW_ARGS, `m4_divert(102)')
                     47: m4_define(FID_NEW_BODY, `m4_divert(103)')
                     48: m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define([[FID_DUMP_BODY_EXISTS]])')
                     49: m4_define(FID_LINEARIZE_BODY, `m4_divert(105)')
                     50: m4_define(FID_SAME_BODY, `m4_divert(106)')
                     51: m4_define(FID_LINE_IN, `m4_divert(107)')
                     52: m4_define(FID_INTERPRET_BODY, `m4_divert(108)')
                     53: 
                     54: #      Sometimes you want slightly different code versions in different
                     55: #      outputs.
                     56: #      Use FID_HIC(code for inst-gen.h, code for inst-gen.c, code for inst-interpret.c)
                     57: #      and put it into [[ ]] quotes if it shall contain commas.
                     58: m4_define(FID_HIC, `m4_ifelse(TARGET, [[H]], [[$1]], TARGET, [[I]], [[$2]], TARGET, [[C]], [[$3]])')
                     59: 
                     60: #      In interpreter code, this is quite common.
                     61: m4_define(FID_INTERPRET_EXEC, `FID_HIC(,[[FID_INTERPRET_BODY()]],[[m4_divert(-1)]])')
                     62: m4_define(FID_INTERPRET_NEW,  `FID_HIC(,[[m4_divert(-1)]],[[FID_INTERPRET_BODY()]])')
                     63: 
                     64: #      If the instruction is never converted to constant, the interpret
                     65: #      code is not produced at all for constructor
                     66: m4_define(NEVER_CONSTANT, `m4_define([[INST_NEVER_CONSTANT]])')
                     67: m4_define(FID_IFCONST, `m4_ifdef([[INST_NEVER_CONSTANT]],[[$2]],[[$1]])')
                     68: 
                     69: #      If the instruction has some attributes (here called members),
                     70: #      these are typically carried with the instruction from constructor
                     71: #      to interpreter. This yields a line of code everywhere on the path.
                     72: #      FID_MEMBER is a macro to help with this task.
                     73: m4_define(FID_MEMBER, `m4_dnl
                     74: FID_LINE_IN()m4_dnl
                     75:       $1 $2;
                     76: FID_STRUCT_IN()m4_dnl
                     77:       $1 $2;
                     78: FID_NEW_ARGS()m4_dnl
                     79:   , $1 $2
                     80: FID_NEW_BODY()m4_dnl
                     81: whati->$2 = $2;
                     82: FID_LINEARIZE_BODY()m4_dnl
                     83: item->$2 = whati->$2;
                     84: m4_ifelse($3,,,[[
                     85: FID_SAME_BODY()m4_dnl
                     86: if ($3) return 0;
                     87: ]])
                     88: m4_ifelse($4,,,[[
                     89: FID_DUMP_BODY()m4_dnl
                     90: debug("%s" $4 "\n", INDENT, $5);
                     91: ]])
                     92: FID_INTERPRET_EXEC()m4_dnl
                     93: const $1 $2 = whati->$2
                     94: FID_INTERPRET_BODY')
                     95: 
                     96: #      Instruction arguments are needed only until linearization is done.
                     97: #      This puts the arguments into the filter line to be executed before
                     98: #      the instruction itself.
                     99: #
                    100: #      To achieve this, ARG_ANY must be called before anything writes into
                    101: #      the instruction line as it moves the instruction pointer forward.
                    102: m4_define(ARG_ANY, `
                    103: FID_STRUCT_IN()m4_dnl
                    104:       struct f_inst * f$1;
                    105: FID_NEW_ARGS()m4_dnl
                    106:   , struct f_inst * f$1
                    107: FID_NEW_BODY
                    108: whati->f$1 = f$1;
                    109: for (const struct f_inst *child = f$1; child; child = child->next) {
                    110:   what->size += child->size;
                    111: FID_IFCONST([[
                    112:   if (child->fi_code != FI_CONSTANT)
                    113:     constargs = 0;
                    114: ]])
                    115: }
                    116: FID_LINEARIZE_BODY
                    117: pos = linearize(dest, whati->f$1, pos);
                    118: FID_INTERPRET_BODY()')
                    119: 
                    120: #      Some instructions accept variable number of arguments.
                    121: m4_define(VARARG, `
                    122: FID_NEW_ARGS()m4_dnl
                    123:   , struct f_inst * fvar
                    124: FID_STRUCT_IN()m4_dnl
                    125:       struct f_inst * fvar;
                    126:       uint varcount;
                    127: FID_LINE_IN()m4_dnl
                    128:       uint varcount;
                    129: FID_NEW_BODY()m4_dnl
                    130: whati->varcount = 0;
                    131: whati->fvar = fvar;
                    132: for (const struct f_inst *child = fvar; child; child = child->next, whati->varcount++) {
                    133:   what->size += child->size;
                    134: FID_IFCONST([[
                    135:   if (child->fi_code != FI_CONSTANT)
                    136:     constargs = 0;
                    137: ]])
                    138: }
                    139: FID_IFCONST([[
                    140:   const struct f_inst **items = NULL;
                    141:   if (constargs) {
                    142:     items = alloca(whati->varcount * sizeof(struct f_inst *));
                    143:     const struct f_inst *child = fvar;
                    144:     for (uint i=0; child; i++)
                    145:       child = (items[i] = child)->next;
                    146:   }
                    147: ]])
                    148: FID_LINEARIZE_BODY()m4_dnl
                    149:   pos = linearize(dest, whati->fvar, pos);
                    150:   item->varcount = whati->varcount;
                    151: FID_DUMP_BODY()m4_dnl
                    152:   debug("%snumber of varargs %u\n", INDENT, item->varcount);
                    153: FID_SAME_BODY()m4_dnl
                    154:   if (f1->varcount != f2->varcount) return 0;
                    155: FID_INTERPRET_BODY()
                    156: FID_HIC(,[[
                    157:   if (fstk->vcnt < whati->varcount) runtime("Stack underflow");
                    158:   fstk->vcnt -= whati->varcount;
                    159: ]],)
                    160: ')
                    161: 
                    162: #      Some arguments need to check their type. After that, ARG_ANY is called.
                    163: m4_define(ARG, `ARG_ANY($1)
                    164: FID_INTERPRET_EXEC()m4_dnl
                    165: if (v$1.type != $2) runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)m4_dnl
                    166: FID_INTERPRET_BODY()')
                    167: 
                    168: #      Executing another filter line. This replaces the recursion
                    169: #      that was needed in the former implementation.
                    170: m4_define(LINEX, `FID_INTERPRET_EXEC()LINEX_($1)FID_INTERPRET_NEW()return $1 FID_INTERPRET_BODY()')
                    171: m4_define(LINEX_, `do {
                    172:   fstk->estk[fstk->ecnt].pos = 0;
                    173:   fstk->estk[fstk->ecnt].line = $1;
                    174:   fstk->estk[fstk->ecnt].ventry = fstk->vcnt;
                    175:   fstk->estk[fstk->ecnt].vbase = fstk->estk[fstk->ecnt-1].vbase;
                    176:   fstk->estk[fstk->ecnt].emask = 0;
                    177:   fstk->ecnt++;
                    178: } while (0)')
                    179: 
                    180: m4_define(LINE, `
                    181: FID_LINE_IN()m4_dnl
                    182:       const struct f_line * fl$1;
                    183: FID_STRUCT_IN()m4_dnl
                    184:       struct f_inst * f$1;
                    185: FID_NEW_ARGS()m4_dnl
                    186:   , struct f_inst * f$1
                    187: FID_NEW_BODY()m4_dnl
                    188: whati->f$1 = f$1;
                    189: FID_DUMP_BODY()m4_dnl
                    190: f_dump_line(item->fl$1, indent + 1);
                    191: FID_LINEARIZE_BODY()m4_dnl
                    192: item->fl$1 = f_linearize(whati->f$1);
                    193: FID_SAME_BODY()m4_dnl
                    194: if (!f_same(f1->fl$1, f2->fl$1)) return 0;
                    195: FID_INTERPRET_EXEC()m4_dnl
                    196: do { if (whati->fl$1) {
                    197:   LINEX_(whati->fl$1);
                    198: } } while(0)
                    199: FID_INTERPRET_NEW()m4_dnl
                    200: return whati->f$1
                    201: FID_INTERPRET_BODY()')
                    202: 
                    203: #      Some of the instructions have a result. These constructions
                    204: #      state the result and put it to the right place.
                    205: m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])')
                    206: m4_define(RESULT_VAL, `FID_HIC(, [[do { res = $1; fstk->vcnt++; } while (0)]],
                    207: [[return fi_constant(what, $1)]])')
                    208: m4_define(RESULT_VOID, `RESULT_VAL([[ (struct f_val) { .type = T_VOID } ]])')
                    209: 
                    210: #      Some common filter instruction members
                    211: m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], "symbol %s", item->sym->name)')
                    212: m4_define(RTC, `FID_MEMBER(struct rtable_config *, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], "route table %s", item->rtc->name)')
                    213: m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, f1->sa.sa_code != f2->sa.sa_code,,)')
                    214: m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, f1->da.ea_code != f2->da.ea_code,,)')
                    215: m4_define(ACCESS_RTE, `FID_HIC(,[[do { if (!fs->rte) runtime("No route to access"); } while (0)]],NEVER_CONSTANT())')
                    216: 
                    217: #      2) Code wrapping
                    218: #      The code produced in 1xx temporary diversions is a raw code without
                    219: #      any auxiliary commands and syntactical structures around. When the
                    220: #      instruction is done, INST_FLUSH is called. More precisely, it is called
                    221: #      at the beginning of INST() call and at the end of file.
                    222: #
                    223: #      INST_FLUSH picks all the temporary diversions, wraps their content
                    224: #      into appropriate headers and structures and saves them into global
                    225: #      diversions listed:
                    226: #
                    227: #      4       enum fi_code
                    228: #      5       enum fi_code to string
                    229: #      6       dump line item
                    230: #      7       dump line item callers
                    231: #      8       linearize
                    232: #      9       same (filter comparator)
                    233: #      1       union in struct f_inst
                    234: #      3       constructors + interpreter
                    235: #
                    236: #      These global diversions contain blocks of code that can be directly
                    237: #      put into the final file, yet it still can't be written out now as
                    238: #      every instruction writes to all of these diversions.
                    239: 
                    240: #      Code wrapping diversion names. Here we want an explicit newline
                    241: #      after the C comment.
                    242: m4_define(FID_ZONE, `m4_divert($1) /* $2 for INST_NAME() */
                    243: ')
                    244: m4_define(FID_INST, `FID_ZONE(1, Instruction structure for config)')
                    245: m4_define(FID_LINE, `FID_ZONE(2, Instruction structure for interpreter)')
                    246: m4_define(FID_NEW, `FID_ZONE(3, Constructor)')
                    247: m4_define(FID_ENUM, `FID_ZONE(4, Code enum)')
                    248: m4_define(FID_ENUM_STR, `FID_ZONE(5, Code enum to string)')
                    249: m4_define(FID_DUMP, `FID_ZONE(6, Dump line)')
                    250: m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)')
                    251: m4_define(FID_LINEARIZE, `FID_ZONE(8, Linearize)')
                    252: m4_define(FID_SAME, `FID_ZONE(9, Comparison)')
                    253: 
                    254: #      This macro does all the code wrapping. See inline comments.
                    255: m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[
                    256: FID_ENUM()m4_dnl                        Contents of enum fi_code { ... }
                    257:   INST_NAME(),
                    258: FID_ENUM_STR()m4_dnl                    Contents of const char * indexed by enum fi_code
                    259:   [INST_NAME()] = "INST_NAME()",
                    260: FID_INST()m4_dnl                        Anonymous structure inside struct f_inst
                    261:     struct {
                    262: m4_undivert(101)m4_dnl
                    263:     } i_[[]]INST_NAME();
                    264: FID_LINE()m4_dnl                        Anonymous structure inside struct f_line_item
                    265:     struct {
                    266: m4_undivert(107)m4_dnl
                    267:     } i_[[]]INST_NAME();
                    268: FID_NEW()m4_dnl                                 Constructor and interpreter code together
                    269: FID_HIC(
                    270: [[m4_dnl                                Public declaration of constructor in H file
                    271: struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code
                    272: m4_undivert(102)m4_dnl
                    273: );]],
                    274: [[m4_dnl                                The one case in The Big Switch inside interpreter
                    275:   case INST_NAME():
                    276:   #define whati (&(what->i_]]INST_NAME()[[))
                    277:   m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]])
                    278:   m4_undivert(108)m4_dnl
                    279:   #undef whati
                    280:   break;
                    281: ]],
                    282: [[m4_dnl                                Constructor itself
                    283: struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code
                    284: m4_undivert(102)m4_dnl
                    285: )
                    286:   {
                    287:     /* Allocate the structure */
                    288:     struct f_inst *what = fi_new(fi_code);
                    289:     FID_IFCONST([[uint constargs = 1;]])
                    290: 
                    291:     /* Initialize all the members */
                    292:   #define whati (&(what->i_]]INST_NAME()[[))
                    293:   m4_undivert(103)m4_dnl
                    294: 
                    295:     /* If not constant, return the instruction itself */
                    296:     FID_IFCONST([[if (!constargs)]])
                    297:       return what;
                    298: 
                    299:     /* Try to pre-calculate the result */
                    300:     FID_IFCONST([[m4_undivert(108)]])m4_dnl
                    301:   #undef whati
                    302:   }
                    303: ]])
                    304: 
                    305: FID_DUMP_CALLER()m4_dnl                         Case in another big switch used in instruction dumping (debug)
                    306: case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break;
                    307: 
                    308: FID_DUMP()m4_dnl                        The dumper itself
                    309: m4_ifdef([[FID_DUMP_BODY_EXISTS]],
                    310: [[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item_, const int indent)]],
                    311: [[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item UNUSED, const int indent UNUSED)]])
                    312: m4_undefine([[FID_DUMP_BODY_EXISTS]])
                    313: {
                    314: #define item (&(item_->i_]]INST_NAME()[[))
                    315: m4_undivert(104)m4_dnl
                    316: #undef item
                    317: }
                    318: 
                    319: FID_LINEARIZE()m4_dnl                   The linearizer
                    320: case INST_NAME(): {
                    321: #define whati (&(what->i_]]INST_NAME()[[))
                    322: #define item (&(dest->items[pos].i_]]INST_NAME()[[))
                    323:   m4_undivert(105)m4_dnl
                    324: #undef whati
                    325: #undef item
                    326:   dest->items[pos].fi_code = what->fi_code;
                    327:   dest->items[pos].lineno = what->lineno;
                    328:   break;
                    329: }
                    330: 
                    331: FID_SAME()m4_dnl                        This code compares two f_line"s while reconfiguring
                    332: case INST_NAME():
                    333: #define f1 (&(f1_->i_]]INST_NAME()[[))
                    334: #define f2 (&(f2_->i_]]INST_NAME()[[))
                    335: m4_undivert(106)m4_dnl
                    336: #undef f1
                    337: #undef f2
                    338: break;
                    339: 
                    340: m4_divert(-1)FID_FLUSH(101,200)m4_dnl  And finally this flushes all the unused diversions
                    341: ]])')
                    342: 
                    343: m4_define(INST, `m4_dnl                                This macro is called on beginning of each instruction.
                    344: INST_FLUSH()m4_dnl                             First, old data is flushed
                    345: m4_define([[INST_NAME]], [[$1]])m4_dnl         Then we store instruction name,
                    346: m4_define([[INST_INVAL]], [[$2]])m4_dnl                instruction input value count
                    347: m4_undefine([[INST_NEVER_CONSTANT]])m4_dnl     and reset NEVER_CONSTANT trigger.
                    348: FID_INTERPRET_BODY()m4_dnl                     By default, every code is interpreter code.
                    349: ')
                    350: 
                    351: #      3) Final preparation
                    352: #
                    353: #      Now we prepare all the code around the global diversions.
                    354: #      It must be here, not in m4wrap, as we want M4 to mark the code
                    355: #      by #line directives correctly, not to claim that every single line
                    356: #      is at the beginning of the m4wrap directive.
                    357: #
                    358: #      This part is split by the final file.
                    359: #      H for inst-gen.h
                    360: #      I for inst-interpret.c
                    361: #      C for inst-gen.c
                    362: #
                    363: #      So we in cycle:
                    364: #        A. open a diversion
                    365: #        B. send there some code
                    366: #        C. close that diversion
                    367: #        D. flush a global diversion
                    368: #        E. open another diversion and goto B.
                    369: #
                    370: #      Final diversions
                    371: #      200+    completed text before it is flushed to output
                    372: 
                    373: #      This is a list of output diversions
                    374: m4_define(FID_WR_PUT_LIST)
                    375: 
                    376: #      This macro does the steps C to E, see before.
                    377: m4_define(FID_WR_PUT_ALSO, `m4_define([[FID_WR_PUT_LIST]],FID_WR_PUT_LIST()[[FID_WR_DPUT(]]FID_WR_DIDX[[)FID_WR_DPUT(]]$1[[)]])m4_define([[FID_WR_DIDX]],m4_eval(FID_WR_DIDX+1))m4_divert(FID_WR_DIDX)')
                    378: 
                    379: #      These macros do the splitting between H/I/C
                    380: m4_define(FID_WR_DIRECT, `m4_ifelse(TARGET,[[$1]],[[FID_WR_INIT()]],[[FID_WR_STOP()]])')
                    381: m4_define(FID_WR_INIT, `m4_define([[FID_WR_DIDX]],200)m4_define([[FID_WR_PUT]],[[FID_WR_PUT_ALSO($]][[@)]])m4_divert(200)')
                    382: m4_define(FID_WR_STOP, `m4_define([[FID_WR_PUT]])m4_divert(-1)')
                    383: 
                    384: #      Here is the direct code to be put into the output files
                    385: #      together with the undiversions, being hidden under FID_WR_PUT()
                    386: 
                    387: m4_changequote([[,]])
                    388: FID_WR_DIRECT(I)
                    389: FID_WR_PUT(3)
                    390: FID_WR_DIRECT(C)
                    391: 
                    392: #if defined(__GNUC__) && __GNUC__ >= 6
                    393: #pragma GCC diagnostic push
                    394: #pragma GCC diagnostic ignored "-Wmisleading-indentation"
                    395: #endif
                    396: 
                    397: #include "nest/bird.h"
                    398: #include "filter/filter.h"
                    399: #include "filter/f-inst.h"
                    400: 
                    401: /* Instruction codes to string */
                    402: static const char * const f_instruction_name_str[] = {
                    403: FID_WR_PUT(5)
                    404: };
                    405: 
                    406: const char *
                    407: f_instruction_name(enum f_instruction_code fi)
                    408: {
                    409:   if (fi < (sizeof(f_instruction_name_str) / sizeof(f_instruction_name_str[0])))
                    410:     return f_instruction_name_str[fi];
                    411:   else
                    412:     bug("Got unknown instruction code: %d", fi);
                    413: }
                    414: 
                    415: static inline struct f_inst *
                    416: fi_new(enum f_instruction_code fi_code)
                    417: {
                    418:   struct f_inst *what = cfg_allocz(sizeof(struct f_inst));
                    419:   what->lineno = ifs->lino;
                    420:   what->size = 1;
                    421:   what->fi_code = fi_code;
                    422:   return what;
                    423: }
                    424: 
                    425: static inline struct f_inst *
                    426: fi_constant(struct f_inst *what, struct f_val val)
                    427: {
                    428:   what->fi_code = FI_CONSTANT;
                    429:   what->i_FI_CONSTANT.val = val;
                    430:   return what;
                    431: }
                    432: 
                    433: #define v1 whati->f1->i_FI_CONSTANT.val
                    434: #define v2 whati->f2->i_FI_CONSTANT.val
                    435: #define v3 whati->f3->i_FI_CONSTANT.val
                    436: #define vv(i) items[i]->i_FI_CONSTANT.val
                    437: #define runtime(fmt, ...) cf_error("filter preevaluation, line %d: " fmt, ifs->lino, ##__VA_ARGS__)
                    438: #define fpool cfg_mem
                    439: #define falloc(size) cfg_alloc(size)
                    440: /* Instruction constructors */
                    441: FID_WR_PUT(3)
                    442: #undef v1
                    443: #undef v2
                    444: #undef v3
                    445: #undef vv
                    446: 
                    447: /* Line dumpers */
                    448: #define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1)
                    449: static const char f_dump_line_indent_str[] = "                                ";
                    450: 
                    451: FID_WR_PUT(6)
                    452: 
                    453: void f_dump_line(const struct f_line *dest, uint indent)
                    454: {
                    455:   if (!dest) {
                    456:     debug("%sNo filter line (NULL)\n", INDENT);
                    457:     return;
                    458:   }
                    459:   debug("%sFilter line %p (len=%u)\n", INDENT, dest, dest->len);
                    460:   for (uint i=0; i<dest->len; i++) {
                    461:     const struct f_line_item *item = &dest->items[i];
                    462:     debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno);
                    463:     switch (item->fi_code) {
                    464: FID_WR_PUT(7)
                    465:       default: bug("Unknown instruction %x in f_dump_line", item->fi_code);
                    466:     }
                    467:   }
                    468:   debug("%sFilter line %p dump done\n", INDENT, dest);
                    469: }
                    470: 
                    471: /* Linearize */
                    472: static uint
                    473: linearize(struct f_line *dest, const struct f_inst *what, uint pos)
                    474: {
                    475:   for ( ; what; what = what->next) {
                    476:     switch (what->fi_code) {
                    477: FID_WR_PUT(8)
                    478:     }
                    479:     pos++;
                    480:   }
                    481:   return pos;
                    482: }
                    483: 
                    484: struct f_line *
                    485: f_linearize_concat(const struct f_inst * const inst[], uint count)
                    486: {
                    487:   uint len = 0;
                    488:   for (uint i=0; i<count; i++)
                    489:     for (const struct f_inst *what = inst[i]; what; what = what->next)
                    490:       len += what->size;
                    491: 
                    492:   struct f_line *out = cfg_allocz(sizeof(struct f_line) + sizeof(struct f_line_item)*len);
                    493: 
                    494:   for (uint i=0; i<count; i++)
                    495:     out->len = linearize(out, inst[i], out->len);
                    496: 
                    497: #if DEBUGGING
                    498:   f_dump_line(out, 0);
                    499: #endif
                    500:   return out;
                    501: }
                    502: 
                    503: /* Filter line comparison */
                    504: int
                    505: f_same(const struct f_line *fl1, const struct f_line *fl2)
                    506: {
                    507:   if ((!fl1) && (!fl2))
                    508:     return 1;
                    509:   if ((!fl1) || (!fl2))
                    510:     return 0;
                    511:   if (fl1->len != fl2->len)
                    512:     return 0;
                    513:   for (uint i=0; i<fl1->len; i++) {
                    514: #define f1_ (&(fl1->items[i]))
                    515: #define f2_ (&(fl2->items[i]))
                    516:     if (f1_->fi_code != f2_->fi_code)
                    517:       return 0;
                    518:     if (f1_->flags != f2_->flags)
                    519:       return 0;
                    520: 
                    521:     switch(f1_->fi_code) {
                    522: FID_WR_PUT(9)
                    523:     }
                    524:   }
                    525: #undef f1_
                    526: #undef f2_
                    527:   return 1;
                    528: }
                    529: 
                    530: #if defined(__GNUC__) && __GNUC__ >= 6
                    531: #pragma GCC diagnostic pop
                    532: #endif
                    533: 
                    534: FID_WR_DIRECT(H)
                    535: /* Filter instruction codes */
                    536: enum f_instruction_code {
                    537: FID_WR_PUT(4)m4_dnl
                    538: } PACKED;
                    539: 
                    540: /* Filter instruction structure for config */
                    541: struct f_inst {
                    542:   struct f_inst *next;                 /* Next instruction */
                    543:   enum f_instruction_code fi_code;     /* Instruction code */
                    544:   int size;                            /* How many instructions are underneath */
                    545:   int lineno;                          /* Line number */
                    546:   union {
                    547: FID_WR_PUT(1)m4_dnl
                    548:   };
                    549: };
                    550: 
                    551: /* Filter line item */
                    552: struct f_line_item {
                    553:   enum f_instruction_code fi_code;     /* What to do */
                    554:   enum f_instruction_flags flags;      /* Flags, instruction-specific */
                    555:   uint lineno;                         /* Where */
                    556:   union {
                    557: FID_WR_PUT(2)m4_dnl
                    558:   };
                    559: };
                    560: 
                    561: /* Instruction constructors */
                    562: FID_WR_PUT(3)
                    563: m4_divert(-1)
                    564: 
                    565: #      4) Shipout
                    566: #
                    567: #      Everything is prepared in FID_WR_PUT_LIST now. Let's go!
                    568: 
                    569: m4_changequote(`,')
                    570: 
                    571: #      Flusher auxiliary macro
                    572: m4_define(FID_FLUSH, `m4_ifelse($1,$2,,[[m4_undivert($1)FID_FLUSH(m4_eval($1+1),$2)]])')
                    573: 
                    574: #      Defining the macro used in FID_WR_PUT_LIST
                    575: m4_define(FID_WR_DPUT, `m4_undivert($1)')
                    576: 
                    577: #      After the code is read and parsed, we:
                    578: m4_m4wrap(`INST_FLUSH()m4_divert(0)FID_WR_PUT_LIST()m4_divert(-1)FID_FLUSH(1,200)')
                    579: 
                    580: m4_changequote([[,]])
                    581: #      And now M4 is going to parse f-inst.c, fill the diversions
                    582: #      and after the file is done, the content of m4_m4wrap (see before)
                    583: #      is executed.

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