]>
Commit | Line | Data |
---|---|---|
4f082dfa MM |
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 | # | |
10 | # Global Diversions: | |
11 | # 4 enum fi_code | |
b256f241 | 12 | # 5 enum fi_code to string |
de12cd18 MM |
13 | # 6 dump line item |
14 | # 7 dump line item callers | |
23e3b1e6 | 15 | # 8 linearize |
132529ce | 16 | # 9 same (filter comparator) |
ea4f55e3 | 17 | # 1 union in struct f_inst |
236828d0 | 18 | # 3 constructors + interpreter |
4f082dfa MM |
19 | # |
20 | # Per-inst Diversions: | |
ea4f55e3 | 21 | # 101 content of per-inst struct |
04160812 MM |
22 | # 102 constructor arguments |
23 | # 103 constructor body | |
de12cd18 | 24 | # 104 dump line item content |
23e3b1e6 | 25 | # 105 linearize body |
132529ce | 26 | # 106 comparator body |
d1039926 MM |
27 | # 107 struct f_line_item content |
28 | # 108 interpreter body | |
04160812 | 29 | # |
64bb1346 MM |
30 | # Final diversions |
31 | # 200+ completed text before it is flushed to output | |
4f082dfa | 32 | |
87bd7cd7 MM |
33 | m4_dnl m4_debugmode(aceflqtx) |
34 | ||
4f082dfa | 35 | m4_define(FID_ZONE, `m4_divert($1) /* $2 for INST_NAME() */') |
ea4f55e3 MM |
36 | m4_define(FID_INST, `FID_ZONE(1, Instruction structure for config)') |
37 | m4_define(FID_LINE, `FID_ZONE(2, Instruction structure for interpreter)') | |
4f082dfa MM |
38 | m4_define(FID_NEW, `FID_ZONE(3, Constructor)') |
39 | m4_define(FID_ENUM, `FID_ZONE(4, Code enum)') | |
b256f241 | 40 | m4_define(FID_ENUM_STR, `FID_ZONE(5, Code enum to string)') |
de12cd18 MM |
41 | m4_define(FID_DUMP, `FID_ZONE(6, Dump line)') |
42 | m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)') | |
23e3b1e6 | 43 | m4_define(FID_LINEARIZE, `FID_ZONE(8, Linearize)') |
132529ce | 44 | m4_define(FID_SAME, `FID_ZONE(9, Comparison)') |
4f082dfa MM |
45 | |
46 | m4_define(FID_STRUCT_IN, `m4_divert(101)') | |
47 | m4_define(FID_NEW_ARGS, `m4_divert(102)') | |
48 | m4_define(FID_NEW_BODY, `m4_divert(103)') | |
dd4d4095 | 49 | m4_define(FID_DUMP_BODY, `m4_divert(104)m4_define([[FID_DUMP_BODY_EXISTS]])') |
23e3b1e6 | 50 | m4_define(FID_LINEARIZE_BODY, `m4_divert(105)m4_define([[FID_LINEARIZE_BODY_EXISTS]])') |
132529ce | 51 | m4_define(FID_SAME_BODY, `m4_divert(106)') |
ea4f55e3 | 52 | m4_define(FID_LINE_IN, `m4_divert(107)') |
d1039926 | 53 | m4_define(FID_INTERPRET_BODY, `m4_divert(108)') |
4f082dfa | 54 | |
d1039926 | 55 | m4_define(FID_ALL, `FID_INTERPRET_BODY'); |
64bb1346 | 56 | m4_define(FID_HIC, `m4_ifelse(TARGET, [[H]], $1, TARGET, [[I]], $2, TARGET, [[C]], $3)') |
87bd7cd7 | 57 | |
4f082dfa MM |
58 | m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[ |
59 | FID_ENUM | |
60 | INST_NAME(), | |
b256f241 MM |
61 | FID_ENUM_STR |
62 | [INST_NAME()] = "INST_NAME()", | |
ea4f55e3 MM |
63 | FID_INST |
64 | struct { | |
4f082dfa | 65 | m4_undivert(101) |
ea4f55e3 MM |
66 | } i_[[]]INST_NAME(); |
67 | FID_LINE | |
68 | struct { | |
69 | m4_undivert(107) | |
70 | } i_[[]]INST_NAME(); | |
4f082dfa | 71 | FID_NEW |
64bb1346 | 72 | FID_HIC( |
64bb1346 | 73 | [[ |
236828d0 MM |
74 | struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code |
75 | [[m4_undivert(102)]] | |
76 | );]], | |
77 | [[ | |
78 | case INST_NAME(): | |
79 | #define whati (&(what->i_]]INST_NAME()[[)) | |
80 | m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]]) | |
81 | [[m4_undivert(108)]] | |
82 | #undef whati | |
83 | break; | |
84 | ]], | |
85 | [[ | |
86 | struct f_inst *f_new_inst_]]INST_NAME()[[(enum f_instruction_code fi_code | |
87 | [[m4_undivert(102)]] | |
88 | ) | |
64bb1346 | 89 | { |
4212c0e7 | 90 | struct f_inst *what = fi_new(fi_code); |
63f49457 | 91 | #define whati (&(what->i_]]INST_NAME()[[)) |
64bb1346 | 92 | [[m4_undivert(103)]] |
63f49457 MM |
93 | #undef whati |
94 | return what; | |
64bb1346 MM |
95 | } |
96 | ]]) | |
de12cd18 MM |
97 | |
98 | FID_DUMP_CALLER | |
99 | case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break; | |
100 | ||
101 | FID_DUMP | |
102 | m4_ifdef([[FID_DUMP_BODY_EXISTS]], | |
ea4f55e3 | 103 | [[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item_, const int indent)]], |
de12cd18 MM |
104 | [[static inline void f_dump_line_item_]]INST_NAME()[[(const struct f_line_item *item UNUSED, const int indent UNUSED)]]) |
105 | m4_undefine([[FID_DUMP_BODY_EXISTS]]) | |
106 | { | |
ea4f55e3 | 107 | #define item (&(item_->i_]]INST_NAME()[[)) |
de12cd18 | 108 | m4_undivert(104) |
ea4f55e3 | 109 | #undef item |
de12cd18 | 110 | } |
dd4d4095 | 111 | |
23e3b1e6 | 112 | FID_LINEARIZE |
dd4d4095 | 113 | case INST_NAME(): { |
63f49457 | 114 | #define whati (&(what->i_]]INST_NAME()[[)) |
ea4f55e3 | 115 | #define item (&(dest->items[pos].i_]]INST_NAME()[[)) |
dd4d4095 | 116 | m4_undivert(105) |
63f49457 | 117 | #undef whati |
ea4f55e3 | 118 | #undef item |
63f49457 MM |
119 | dest->items[pos].fi_code = what->fi_code; |
120 | dest->items[pos].lineno = what->lineno; | |
dd4d4095 MM |
121 | break; |
122 | } | |
23e3b1e6 | 123 | m4_undefine([[FID_LINEARIZE_BODY_EXISTS]]) |
dd4d4095 | 124 | |
132529ce MM |
125 | FID_SAME |
126 | case INST_NAME(): | |
ea4f55e3 MM |
127 | #define f1 (&(f1_->i_]]INST_NAME()[[)) |
128 | #define f2 (&(f2_->i_]]INST_NAME()[[)) | |
132529ce | 129 | m4_undivert(106) |
ea4f55e3 MM |
130 | #undef f1 |
131 | #undef f2 | |
132529ce MM |
132 | break; |
133 | ||
4f082dfa MM |
134 | ]])') |
135 | ||
d1039926 MM |
136 | m4_define(INST, `m4_dnl |
137 | INST_FLUSH()m4_dnl | |
138 | m4_define([[INST_NAME]], [[$1]])m4_dnl | |
139 | m4_define([[INST_INVAL]], [[$2]])m4_dnl | |
140 | FID_ALL() m4_dnl | |
141 | ') | |
4f082dfa | 142 | |
dd4d4095 MM |
143 | m4_dnl FID_MEMBER call: |
144 | m4_dnl type | |
145 | m4_dnl name in f_inst | |
146 | m4_dnl name in f_line_item | |
132529ce | 147 | m4_dnl comparator for same |
dd4d4095 MM |
148 | m4_dnl dump format string |
149 | m4_dnl dump format args | |
d1039926 | 150 | m4_dnl interpreter body |
4f082dfa | 151 | m4_define(FID_MEMBER, `m4_dnl |
ea4f55e3 MM |
152 | FID_LINE_IN |
153 | $1 $2; | |
4f082dfa MM |
154 | FID_STRUCT_IN |
155 | $1 $2; | |
156 | FID_NEW_ARGS | |
157 | , $1 $2 | |
158 | FID_NEW_BODY | |
63f49457 | 159 | whati->$2 = $2; |
de12cd18 | 160 | m4_ifelse($3,,,[[ |
23e3b1e6 | 161 | FID_LINEARIZE_BODY |
63f49457 | 162 | item->$3 = whati->$2; |
dd4d4095 MM |
163 | ]]) |
164 | m4_ifelse($4,,,[[ | |
132529ce MM |
165 | FID_SAME_BODY |
166 | if ($4) return 0; | |
167 | ]]) | |
168 | m4_ifelse($5,,,[[ | |
de12cd18 | 169 | FID_DUMP_BODY |
132529ce | 170 | debug("%s$5\n", INDENT, $6); |
de12cd18 | 171 | ]]) |
d1039926 MM |
172 | m4_ifelse($7,,,[[ |
173 | FID_INTERPRET_BODY | |
174 | $7 | |
175 | ]]) | |
176 | FID_ALL') | |
4f082dfa | 177 | |
d1039926 | 178 | m4_define(ARG_ANY, ` |
ea4f55e3 | 179 | FID_STRUCT_IN |
63f49457 | 180 | struct f_inst * f$1; |
ea4f55e3 | 181 | FID_NEW_ARGS |
63f49457 | 182 | , struct f_inst * f$1 |
4f082dfa | 183 | FID_NEW_BODY |
63f49457 MM |
184 | whati->f$1 = f$1; |
185 | for (const struct f_inst *child = f$1; child; child = child->next) what->size += child->size; | |
23e3b1e6 | 186 | FID_LINEARIZE_BODY |
63f49457 | 187 | pos = linearize(dest, whati->f$1, pos);m4_dnl |
d1039926 MM |
188 | FID_ALL()') |
189 | ||
190 | m4_define(ARG, `ARG_ANY($1) | |
191 | FID_INTERPRET_BODY | |
192 | 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 | |
193 | FID_ALL()') | |
194 | ||
195 | m4_define(LINEX, `FID_INTERPRET_BODY | |
196 | do { | |
1757a6fc MM |
197 | fstk->estk[fstk->ecnt].pos = 0; |
198 | fstk->estk[fstk->ecnt].line = $1; | |
199 | fstk->estk[fstk->ecnt].ventry = fstk->vcnt; | |
200 | fstk->estk[fstk->ecnt].vbase = fstk->estk[fstk->ecnt-1].vbase; | |
201 | fstk->estk[fstk->ecnt].emask = 0; | |
202 | fstk->ecnt++; | |
d1039926 MM |
203 | } while (0)m4_dnl |
204 | FID_ALL()') | |
205 | ||
ea4f55e3 MM |
206 | m4_define(LINE, ` |
207 | FID_LINE_IN | |
208 | const struct f_line * fl$1; | |
209 | FID_STRUCT_IN | |
210 | const struct f_inst * f$1; | |
211 | FID_NEW_ARGS | |
212 | , const struct f_inst * f$1 | |
4f082dfa | 213 | FID_NEW_BODY |
63f49457 | 214 | whati->f$1 = f$1; |
de12cd18 | 215 | FID_DUMP_BODY |
ea4f55e3 | 216 | f_dump_line(item->fl$1, indent + 1); |
23e3b1e6 | 217 | FID_LINEARIZE_BODY |
63f49457 | 218 | item->fl$1 = f_linearize(whati->f$1); |
132529ce | 219 | FID_SAME_BODY |
ea4f55e3 | 220 | if (!f_same(f1->fl$1, f2->fl$1)) return 0; |
d1039926 MM |
221 | FID_INTERPRET_BODY |
222 | do { if (whati->fl$1) { | |
223 | LINEX(whati->fl$1); | |
224 | } } while(0)m4_dnl | |
225 | FID_ALL()') | |
226 | ||
a84b8b6e | 227 | m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])') |
f74d1976 MM |
228 | m4_define(RESULT_VAL, `FID_INTERPRET_BODY()do { res = $1; fstk->vcnt++; } while (0)FID_ALL()') |
229 | m4_define(RESULT_VOID, `RESULT_VAL([[ (struct f_val) { .type = T_VOID } ]])') | |
d1039926 | 230 | |
132529ce | 231 | m4_define(SYMBOL, `FID_MEMBER(const struct symbol *, sym, sym, |
d1039926 MM |
232 | [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], symbol %s, item->sym->name, const struct symbol *sym = whati->sym)') |
233 | m4_define(VAL, `FID_MEMBER(struct f_val $1, val, val m4_ifelse($1,,,[0]), [[!val_same(&f1->val, &f2->val)]], value %s, val_dump(&item->val),)') | |
234 | m4_define(FRET, `FID_MEMBER(enum filter_return, fret, fret, f1->fret != f2->fret, %s, filter_return_str(item->fret), enum filter_return fret = whati->fret)') | |
235 | m4_define(ECS, `FID_MEMBER(enum ec_subtype, ecs, ecs, f1->ecs != f2->ecs, ec subtype %s, ec_subtype_str(item->ecs), enum ec_subtype ecs = whati->ecs)') | |
236 | m4_define(RTC, `FID_MEMBER(const struct rtable_config *, rtc, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], route table %s, item->rtc->name, struct rtable *table = whati->rtc->table)') | |
237 | m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, sa, f1->sa.sa_code != f2->sa.sa_code,,, struct f_static_attr sa = whati->sa)') | |
238 | m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, da, f1->da.ea_code != f2->da.ea_code,,, struct f_dynamic_attr da = whati->da)') | |
132529ce | 239 | m4_define(COUNT, `FID_MEMBER(uint, count, count, f1->count != f2->count, number %u, item->count)') |
d1039926 | 240 | m4_define(TREE, `FID_MEMBER(const struct f_tree *, tree, tree, [[!same_tree(f1->tree, f2->tree)]], tree %p, item->tree, const struct f_tree *tree = whati->tree)') |
132529ce | 241 | m4_define(STRING, `FID_MEMBER(const char *, s, s, [[strcmp(f1->s, f2->s)]], string \"%s\", item->s)') |
de12cd18 MM |
242 | |
243 | m4_define(FID_WR_PUT_LIST) | |
64bb1346 | 244 | 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)') |
de12cd18 | 245 | |
64bb1346 MM |
246 | m4_define(FID_WR_DIRECT, `m4_ifelse(TARGET,[[$1]],[[FID_WR_INIT()]],[[FID_WR_STOP()]])') |
247 | m4_define(FID_WR_INIT, `m4_define([[FID_WR_DIDX]],200)m4_define([[FID_WR_PUT]],[[FID_WR_PUT_ALSO($]][[@)]])m4_divert(200)') | |
248 | m4_define(FID_WR_STOP, `m4_define([[FID_WR_PUT]])m4_divert(-1)') | |
4f082dfa | 249 | |
04160812 | 250 | m4_changequote([[,]]) |
64bb1346 | 251 | FID_WR_DIRECT(I) |
236828d0 | 252 | FID_WR_PUT(3) |
64bb1346 | 253 | FID_WR_DIRECT(C) |
87bd7cd7 MM |
254 | #include "nest/bird.h" |
255 | #include "filter/filter.h" | |
256 | #include "filter/f-inst.h" | |
b256f241 | 257 | |
b256f241 MM |
258 | /* Instruction codes to string */ |
259 | static const char * const f_instruction_name_str[] = { | |
260 | FID_WR_PUT(5) | |
261 | }; | |
262 | ||
263 | const char * | |
264 | f_instruction_name(enum f_instruction_code fi) | |
265 | { | |
266 | if (fi < (sizeof(f_instruction_name_str) / sizeof(f_instruction_name_str[0]))) | |
267 | return f_instruction_name_str[fi]; | |
268 | else | |
269 | bug("Got unknown instruction code: %d", fi); | |
270 | } | |
271 | ||
4212c0e7 MM |
272 | static inline struct f_inst * |
273 | fi_new(enum f_instruction_code fi_code) | |
274 | { | |
275 | struct f_inst *what = cfg_allocz(sizeof(struct f_inst)); | |
276 | what->lineno = ifs->lino; | |
277 | what->size = 1; | |
278 | what->fi_code = fi_code; | |
279 | return what; | |
280 | } | |
281 | ||
de12cd18 MM |
282 | /* Instruction constructors */ |
283 | FID_WR_PUT(3) | |
284 | ||
285 | /* Line dumpers */ | |
286 | #define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) | |
287 | static const char f_dump_line_indent_str[] = " "; | |
de12cd18 MM |
288 | |
289 | FID_WR_PUT(6) | |
290 | ||
ea4f55e3 | 291 | void f_dump_line(const struct f_line *dest, uint indent) |
de12cd18 MM |
292 | { |
293 | if (!dest) { | |
294 | debug("%sNo filter line (NULL)\n", INDENT); | |
295 | return; | |
296 | } | |
297 | debug("%sFilter line %p (len=%u)\n", INDENT, dest, dest->len); | |
298 | for (uint i=0; i<dest->len; i++) { | |
299 | const struct f_line_item *item = &dest->items[i]; | |
300 | debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno); | |
301 | switch (item->fi_code) { | |
302 | FID_WR_PUT(7) | |
303 | default: bug("Unknown instruction %x in f_dump_line", item->fi_code); | |
304 | } | |
305 | } | |
306 | debug("%sFilter line %p dump done\n", INDENT, dest); | |
307 | } | |
308 | ||
23e3b1e6 | 309 | /* Linearize */ |
dd4d4095 | 310 | static uint |
63f49457 | 311 | linearize(struct f_line *dest, const struct f_inst *what, uint pos) |
dd4d4095 | 312 | { |
63f49457 MM |
313 | for ( ; what; what = what->next) { |
314 | switch (what->fi_code) { | |
dd4d4095 MM |
315 | FID_WR_PUT(8) |
316 | } | |
317 | pos++; | |
318 | } | |
319 | return pos; | |
320 | } | |
321 | ||
322 | struct f_line * | |
23e3b1e6 | 323 | f_linearize_concat(const struct f_inst * const inst[], uint count) |
dd4d4095 MM |
324 | { |
325 | uint len = 0; | |
326 | for (uint i=0; i<count; i++) | |
327 | for (const struct f_inst *what = inst[i]; what; what = what->next) | |
328 | len += what->size; | |
329 | ||
330 | struct f_line *out = cfg_allocz(sizeof(struct f_line) + sizeof(struct f_line_item)*len); | |
331 | ||
332 | for (uint i=0; i<count; i++) | |
23e3b1e6 | 333 | out->len = linearize(out, inst[i], out->len); |
dd4d4095 MM |
334 | |
335 | #if DEBUGGING | |
336 | f_dump_line(out, 0); | |
337 | #endif | |
338 | return out; | |
339 | } | |
340 | ||
132529ce MM |
341 | /* Filter line comparison */ |
342 | int | |
343 | f_same(const struct f_line *fl1, const struct f_line *fl2) | |
344 | { | |
345 | if ((!fl1) && (!fl2)) | |
346 | return 1; | |
347 | if ((!fl1) || (!fl2)) | |
348 | return 0; | |
349 | if (fl1->len != fl2->len) | |
350 | return 0; | |
351 | for (uint i=0; i<fl1->len; i++) { | |
ea4f55e3 MM |
352 | #define f1_ (&(fl1->items[i])) |
353 | #define f2_ (&(fl2->items[i])) | |
354 | if (f1_->fi_code != f2_->fi_code) | |
132529ce | 355 | return 0; |
ea4f55e3 | 356 | if (f1_->flags != f2_->flags) |
132529ce MM |
357 | return 0; |
358 | ||
ea4f55e3 | 359 | switch(f1_->fi_code) { |
132529ce MM |
360 | FID_WR_PUT(9) |
361 | } | |
362 | } | |
ea4f55e3 MM |
363 | #undef f1_ |
364 | #undef f2_ | |
132529ce MM |
365 | return 1; |
366 | } | |
367 | ||
368 | ||
64bb1346 | 369 | FID_WR_DIRECT(H) |
de12cd18 MM |
370 | /* Filter instruction codes */ |
371 | enum f_instruction_code { | |
372 | FID_WR_PUT(4) | |
ea4f55e3 | 373 | } PACKED; |
4f082dfa | 374 | |
ea4f55e3 | 375 | /* Filter instruction structure for config */ |
4f082dfa | 376 | struct f_inst { |
96d757c1 | 377 | struct f_inst *next; /* Next instruction */ |
4f082dfa MM |
378 | enum f_instruction_code fi_code; /* Instruction code */ |
379 | int size; /* How many instructions are underneath */ | |
380 | int lineno; /* Line number */ | |
ea4f55e3 MM |
381 | union { |
382 | FID_WR_PUT(1) | |
383 | }; | |
384 | }; | |
385 | ||
386 | /* Filter line item */ | |
387 | struct f_line_item { | |
388 | enum f_instruction_code fi_code; /* What to do */ | |
389 | enum f_instruction_flags flags; /* Flags, instruction-specific */ | |
390 | uint lineno; /* Where */ | |
4f082dfa | 391 | union { |
04160812 | 392 | FID_WR_PUT(2) |
4f082dfa MM |
393 | }; |
394 | }; | |
395 | ||
396 | /* Instruction constructors */ | |
04160812 | 397 | FID_WR_PUT(3) |
de12cd18 | 398 | |
04160812 MM |
399 | m4_divert(-1) |
400 | m4_changequote(`,') | |
401 | ||
64bb1346 MM |
402 | m4_define(FID_CLEANUP, `m4_ifelse($1,$2,,[[m4_undivert($1)FID_CLEANUP(m4_eval($1+1),$2)]])') |
403 | m4_define(FID_WR_DPUT, `m4_undivert($1)') | |
404 | ||
405 | m4_m4wrap(`INST_FLUSH()m4_divert(0)FID_WR_PUT_LIST()m4_divert(-1)FID_CLEANUP(1,200)') | |
4f082dfa MM |
406 | |
407 | m4_changequote([[,]]) |