Mercurial > repo
comparison src/ploki/deparse.c @ 4223:ac0403686959
<oerjan> rm -rf src/ploki; mv ploki src
author | HackBot |
---|---|
date | Fri, 20 Dec 2013 22:18:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4222:b0f3e267bb1e | 4223:ac0403686959 |
---|---|
1 #include "config.h" | |
2 #include "Str.h" | |
3 #include "deparse.h" | |
4 #include "expr.h" | |
5 #include "main_io.h" | |
6 #include "main_label.h" | |
7 #include "text.h" | |
8 #include "val.h" | |
9 #include "venus.h" | |
10 #include "xmalloc.h" | |
11 #include "zz.h" | |
12 | |
13 #include <ctype.h> | |
14 #include <stdio.h> | |
15 #include <assert.h> | |
16 | |
17 #if HAVE_VSNPRINTF_P | |
18 #define MAKE_LABEL(s, c) \ | |
19 do { \ | |
20 static unsigned long seq__; \ | |
21 St_init(s); \ | |
22 St_xprintf(s, "%c%lu", c, seq__++); \ | |
23 } while (0) | |
24 #else | |
25 #define MAKE_LABEL(s, c) \ | |
26 do { \ | |
27 static unsigned long seq__; \ | |
28 St_init(s); \ | |
29 St_num(s, seq__++); \ | |
30 St_tac_c(s, c); \ | |
31 } while (0) | |
32 #endif | |
33 | |
34 ATTR_CONST | |
35 static int display(enum t_binop b) { | |
36 switch (b) { | |
37 case B_SPARK_SPOT: return '!'; | |
38 case B_DOUBLE_OH_SEVEN: return '%'; | |
39 case B_AMPERSAND: return '&'; | |
40 case B_SPARK: return '\''; | |
41 case B_SPLAT: return '*'; | |
42 case B_INTERSECTION: return '+'; | |
43 case B_TAIL: return ','; | |
44 case B_WORM: return '-'; | |
45 case B_SPOT: return '.'; | |
46 case B_SLAT: return '/'; | |
47 case B_TWO_SPOT: return ':'; | |
48 case B_HYBRID: return ';'; | |
49 case B_ANGLE: return '<'; | |
50 case B_HALF_MESH: return '='; | |
51 case B_RIGHT_ANGLE: return '>'; | |
52 case B_U_TURN: return '['; | |
53 case B_U_TURN_BACK: return ']'; | |
54 case B_SHARK_FIN: return '^'; | |
55 case B_FLATWORM: return '_'; | |
56 case B_BACKSPARK: return '`'; | |
57 case B_EMBRACE: return '{'; | |
58 case B_SPIKE: return '|'; | |
59 case B_BRACELET: return '}'; | |
60 case B_SQIGGLE: return '~'; | |
61 default: break; | |
62 } | |
63 NOTREACHED; | |
64 } | |
65 | |
66 static void dump_str(const String *s) { | |
67 size_t i; | |
68 | |
69 io_write_m(Out, "\"", 1); | |
70 for (i = 0; i < St_len(s); ++i) { | |
71 const unsigned char c = ST_INDEX(s, i); | |
72 if (c != '\\' && c != '"' && isprint(c)) { | |
73 io_write_m(Out, &c, 1); | |
74 } else { | |
75 io_write_m(Out, "\\", 1); | |
76 switch (c) { | |
77 case '"': | |
78 case '\\': io_write_m(Out, &c , 1); break; | |
79 case '\a': io_write_m(Out, "a", 1); break; | |
80 case '\b': io_write_m(Out, "b", 1); break; | |
81 case '\f': io_write_m(Out, "f", 1); break; | |
82 case '\n': io_write_m(Out, "n", 1); break; | |
83 case '\r': io_write_m(Out, "r", 1); break; | |
84 case '\t': io_write_m(Out, "t", 1); break; | |
85 case '\v': io_write_m(Out, "v", 1); break; | |
86 default: fprintf(io_fp(Out), "%03o", c); break; | |
87 } | |
88 } | |
89 } | |
90 io_write_m(Out, "\"", 1); | |
91 } | |
92 | |
93 static void dump_ko(const struct kork *k) { | |
94 String tmp; | |
95 St_fake(&tmp, (char *)ko_ptr(k), ko_length(k)); | |
96 dump_str(&tmp); | |
97 } | |
98 | |
99 static void to_id(struct kork *k, size_t n) { | |
100 static char id[] = | |
101 "abcdefghijklmnopqrstuvwxyz" | |
102 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
103 "$" | |
104 ; | |
105 const size_t base = sizeof id - 1; | |
106 do { | |
107 ko_cat_c(k, id[n % base]); | |
108 n /= base; | |
109 } while (n); | |
110 } | |
111 | |
112 static void make_var(struct val *v) { | |
113 static size_t seq; | |
114 | |
115 ko_decouple(v->ko); | |
116 to_id(v->ko, seq++); | |
117 v->type = V_STR_K; | |
118 } | |
119 | |
120 static void dump_expr(const struct expr *e, int inlist) { | |
121 assert(e != NULL); | |
122 | |
123 switch (e->type) { | |
124 case literE: | |
125 if (V_EXT_P(e->v.val)) { | |
126 fprintf(io_fp(Out), "?%s?", io_name(e->v.val->magic.ext, NULL)); | |
127 } else if (V_SUB_P(e->v.val)) { | |
128 fprintf(io_fp(Out), "?CODE(%p)?", (void *)e->v.val->magic.sub); | |
129 } else if (V_STR_P(e->v.val)) { | |
130 dump_ko(e->v.val->ko); | |
131 } else if (V_NUM_P(e->v.val)) { | |
132 if (e->v.val->num < 0.0) { | |
133 fprintf(io_fp(Out), "@NEG %g", -e->v.val->num); | |
134 } else { | |
135 fprintf(io_fp(Out), "%g", e->v.val->num); | |
136 } | |
137 } else { | |
138 #if 0 | |
139 io_write_m(Out, "()", 2); | |
140 #endif | |
141 } | |
142 break; | |
143 | |
144 case varE: | |
145 if (!V_STR_P(e->v.val)) { | |
146 assert(e->v.val->type == V_UNDEF); | |
147 make_var(e->v.val); | |
148 } | |
149 io_write_m(Out, ko_ptr(e->v.val->ko), ko_length(e->v.val->ko)); | |
150 break; | |
151 | |
152 case varhashE: { | |
153 struct val *tmp; | |
154 if (!(tmp = sh_get(e->v.hash, "name", 4))) { | |
155 tmp = v_undef(); | |
156 make_var(tmp); | |
157 sh_put(e->v.hash, "name", 4, tmp); | |
158 } | |
159 io_write_m(Out, ko_ptr(tmp->ko), ko_length(tmp->ko)); | |
160 io_write_m(Out, "(", 1); | |
161 dump_expr(e->right, 0); | |
162 io_write_m(Out, ")", 1); | |
163 break; | |
164 } | |
165 | |
166 case symbolE: | |
167 io_write_m(Out, "\\", 1); | |
168 switch (e->op) { | |
169 case S_NUL: break; | |
170 case S_ARG: io_write_m(Out, "@", 1); break; | |
171 case S_ARGC: io_write_m(Out, "ARG", 3); break; | |
172 | |
173 case S_ARGV: | |
174 io_write_m(Out, "ARG:", 4); | |
175 if (e->right->type == binopE) { | |
176 io_write_m(Out, "(", 1); | |
177 dump_expr(e->right, 0); | |
178 io_write_m(Out, ")", 1); | |
179 } else { | |
180 dump_expr(e->right, 0); | |
181 } | |
182 break; | |
183 | |
184 case S_ERR: io_write_m(Out, "!", 1); break; | |
185 case S_EULER: io_write_m(Out, "E", 1); break; | |
186 case S_LUDOLF: io_write_m(Out, "PI", 2); break; | |
187 case S_MATCH: | |
188 fprintf(io_fp(Out), "%lu", (unsigned long)e->left.bonus); | |
189 break; | |
190 case S_RAND: io_write_m(Out, "?", 1); break; | |
191 case S_RESULT: io_write_m(Out, "_", 1); break; | |
192 case S_STDIN: io_write_m(Out, "EING", 4); break; | |
193 case S_STDOUT: io_write_m(Out, "AUSG", 4); break; | |
194 case S_STDERR: io_write_m(Out, "FEHL", 4); break; | |
195 | |
196 default: NOTREACHED; break; | |
197 } | |
198 break; | |
199 | |
200 case unopE: | |
201 switch (e->op) { | |
202 case F_EXP: io_write_m(Out, "\\E^", 3); break; | |
203 case F_LOWER: io_write_m(Out, "\\L" , 2); break; | |
204 case F_QUOTE: io_write_m(Out, "\\Q" , 2); break; | |
205 case F_RE_ESC: io_write_m(Out, "\\R" , 2); break; | |
206 case F_UPPER: io_write_m(Out, "\\U" , 2); break; | |
207 case F_MATCH: { | |
208 String tmp; | |
209 io_write_m(Out, "(", 1); | |
210 dump_expr(e->right, 0); | |
211 io_write_m(Out, " ~ ", 3); | |
212 St_init(&tmp); | |
213 re_decompile(e->left.rx, &tmp); | |
214 dump_str(&tmp); | |
215 St_clear(&tmp); | |
216 io_write_m(Out, ")", 1); | |
217 return; | |
218 } | |
219 | |
220 default: | |
221 io_write_m(Out, "@", 1); | |
222 switch (e->op) { | |
223 case F_CALL: io_write(Out, &e->left.op->txt); | |
224 case F_NUL: break; | |
225 case F_ABS: io_write_m(Out, "ABS", 3); break; | |
226 case F_ACOS: io_write_m(Out, "ACOS", 4); break; | |
227 case F_ASIN: io_write_m(Out, "ASIN", 4); break; | |
228 case F_ATAN: io_write_m(Out, "ATAN", 4); break; | |
229 case F_ATAN2: io_write_m(Out, "ATAN2", 5); break; | |
230 case F_CATCH: io_write_m(Out, "EVAL", 4); break; | |
231 case F_CHR: io_write_m(Out, "CHR", 3); break; | |
232 case F_COS: io_write_m(Out, "COS", 3); break; | |
233 case F_DEFINED: io_write_m(Out, "DEF-P", 5); break; | |
234 case F_EOF: io_write_m(Out, "EDD-P", 5); break; | |
235 case F_ERROR: io_write_m(Out, "ERR-P", 5); break; | |
236 case F_FREEZE: io_write_m(Out, "OMFG", 4); break; | |
237 case F_GETC: io_write_m(Out, "GET", 3); break; | |
238 case F_GETENV: io_write_m(Out, "ENV", 3); break; | |
239 case F_GETS: io_write_m(Out, "LEGS", 4); break; | |
240 case F_HANG: { | |
241 size_t i; | |
242 String tmp; | |
243 | |
244 St_init(&tmp); | |
245 for (St_num(&tmp, i = 1); | |
246 ve_findnext(&Venus, &tmp, 0); | |
247 St_num(&tmp, ++i)) | |
248 ; | |
249 fprintf(io_fp(Out), "(%s)", St_ptr(&tmp)); | |
250 St_clear(&tmp); | |
251 break; | |
252 } | |
253 case F_INT: io_write_m(Out, "INT", 3); break; | |
254 case F_IO: io_write_m(Out, "IO-P", 4); break; | |
255 case F_LENGTH: io_write_m(Out, "LENGTH", 6); break; | |
256 case F_LOG10: io_write_m(Out, "LG", 2); break; | |
257 case F_LOG: io_write_m(Out, "LN", 2); break; | |
258 case F_MOEND: io_write_m(Out, "+", 1); break; | |
259 case F_MOSTART: io_write_m(Out, "-", 1); break; | |
260 case F_NEG: io_write_m(Out, "NEG", 3); break; | |
261 case F_NOT: io_write_m(Out, "NOT", 3); break; | |
262 case F_NUM: io_write_m(Out, "NUM", 3); break; | |
263 case F_OPEN: io_write_m(Out, "APERS", 5); break; | |
264 case F_OPENR: io_write_m(Out, "LAPERS", 6); break; | |
265 case F_OPENW: io_write_m(Out, "SAPERS", 6); break; | |
266 case F_ORD: io_write_m(Out, "ORD", 3); break; | |
267 case F_REMOVE: io_write_m(Out, "REMOVE", 6); break; | |
268 case F_RENAME: io_write_m(Out, "RENAEM", 6); break; | |
269 case F_REVERSE: io_write_m(Out, "REVERSE", 7); break; | |
270 case F_SEEK: io_write_m(Out, "SUCH", 4); break; | |
271 case F_SIN: io_write_m(Out, "SIN", 3); break; | |
272 case F_SQRT: io_write_m(Out, "SPQR", 4); break; | |
273 case F_STR: io_write_m(Out, "STR", 3); break; | |
274 case F_TAN: io_write_m(Out, "TAN", 3); break; | |
275 case F_TELL: io_write_m(Out, "SAG", 3); break; | |
276 case F_TYPEOF: io_write_m(Out, "TYPE OF", 7); break; | |
277 default: | |
278 NOTREACHED; | |
279 break; | |
280 } | |
281 break; | |
282 } | |
283 if (e->right->type != unopE || e->op == F_NUL) { | |
284 io_write_m(Out, "(", 1); | |
285 dump_expr(e->right, 0); | |
286 io_write_m(Out, ")", 1); | |
287 } else { | |
288 io_write_m(Out, " ", 1); | |
289 dump_expr(e->right, 0); | |
290 } | |
291 break; | |
292 | |
293 case binopE: | |
294 dump_expr(e->left.expr, 0); | |
295 | |
296 if (e->op == B_XMATCH) { | |
297 io_write_m(Out, " ?o~ ", 5); | |
298 } else { | |
299 fprintf(io_fp(Out), "%s%c ", &" "[e->op == B_TAIL], display(e->op)); | |
300 } | |
301 | |
302 if (e->right->type == binopE) { | |
303 io_write_m(Out, "(", 1); | |
304 dump_expr(e->right, 0); | |
305 io_write_m(Out, ")", 1); | |
306 } else { | |
307 dump_expr(e->right, 0); | |
308 } | |
309 break; | |
310 | |
311 case listE: | |
312 if (!inlist) { | |
313 io_write_m(Out, "#<", 2); | |
314 } | |
315 if (e->right) { | |
316 io_write_m(Out, "(", 1); | |
317 dump_expr(e->right, 0); | |
318 io_write_m(Out, ")", 1); | |
319 if (e->left.expr) { | |
320 io_write_m(Out, " ", 1); | |
321 dump_expr(e->left.expr, 1); | |
322 } | |
323 } | |
324 if (!inlist) { | |
325 io_write_m(Out, "#>", 2); | |
326 } | |
327 break; | |
328 | |
329 } | |
330 } | |
331 | |
332 static void dump_op(struct op *op) { | |
333 switch (op->type) { | |
334 case OP_NOP: | |
335 io_write_m(Out, "REM", 3); | |
336 break; | |
337 | |
338 case OP_SET_VAL: | |
339 case OP_ASSIGN: | |
340 io_write_m(Out, "LET ", 4); | |
341 if (op->arh.expr) { | |
342 dump_expr(op->arh.expr, 0); | |
343 io_write_m(Out, " ", 1); | |
344 dump_expr(op->arg, 0); | |
345 } else { | |
346 io_write_m(Out, "(", 1); | |
347 dump_expr(op->arg, 0); | |
348 io_write_m(Out, ")", 1); | |
349 } | |
350 break; | |
351 | |
352 case OP_CALL: | |
353 if (op->arh.op) { | |
354 fprintf(io_fp(Out), "%s ", St_ptr(&op->arh.op->txt)); | |
355 dump_expr(op->arg, 0); | |
356 } else { | |
357 io_write_m(Out, "LET () ", 7); | |
358 dump_expr(op->arg, 0); | |
359 if (op->next) { | |
360 io_write_m(Out, "\nEND", 4); | |
361 } | |
362 } | |
363 break; | |
364 | |
365 case OP_CALL_BACK: | |
366 io_write_m(Out, "ABRUF (", 7); | |
367 dump_expr(op->arh.expr, 0); | |
368 io_write_m(Out, ") ", 2); | |
369 dump_expr(op->arg, 0); | |
370 break; | |
371 | |
372 case OP_CALL_DYN: | |
373 io_write_m(Out, "ANRUF ", 6); | |
374 dump_expr(op->arg, 0); | |
375 break; | |
376 | |
377 case OP_CLOSE: | |
378 io_write_m(Out, "CLAUDS ", 7); | |
379 dump_expr(op->arg, 0); | |
380 break; | |
381 | |
382 case OP_ELSE: | |
383 NOTREACHED; | |
384 break; | |
385 | |
386 case OP_EXIT: | |
387 if (op->arg->type == literE && !op->arg->v.val->type) { | |
388 io_write_m(Out, "END", 3); | |
389 } else { | |
390 io_write_m(Out, "END ", 4); | |
391 dump_expr(op->arg, 0); | |
392 } | |
393 break; | |
394 | |
395 case OP_FI: | |
396 NOTREACHED; | |
397 break; | |
398 | |
399 case OP_FLUSH: | |
400 io_write_m(Out, "FLUSH ", 6); | |
401 dump_expr(op->arg, 0); | |
402 break; | |
403 | |
404 case OP_GOBACK: | |
405 io_write_m(Out, "GOFOR ", 6); | |
406 dump_expr(op->arg, 0); | |
407 break; | |
408 | |
409 case OP_GOTO: | |
410 io_write_m(Out, "GOTO ", 5); | |
411 dump_expr(op->arg, 0); | |
412 break; | |
413 | |
414 case OP_HANG: | |
415 if (St_ptr(&op->txt)) { | |
416 fprintf(io_fp(Out), "NEXT %s", St_ptr(&op->txt)); | |
417 } else { | |
418 String tmp; | |
419 MAKE_LABEL(&tmp, '*'); | |
420 fprintf(io_fp(Out), "FOR %s NEXT %s", St_ptr(&tmp), St_ptr(&tmp)); | |
421 St_clear(&tmp); | |
422 } | |
423 break; | |
424 | |
425 case OP_IF: | |
426 if (op->arg->type == unopE && op->arg->op == F_NOT) { | |
427 io_write_m(Out, "IF ", 3); | |
428 dump_expr(op->arg->right, 0); | |
429 } else { | |
430 io_write_m(Out, "IF @NOT ", 8); | |
431 if (op->arg->type == binopE) { | |
432 io_write_m(Out, "(", 1); | |
433 dump_expr(op->arg, 0); | |
434 io_write_m(Out, ")", 1); | |
435 } else { | |
436 dump_expr(op->arg, 0); | |
437 } | |
438 } | |
439 | |
440 if (op->next) { | |
441 fprintf(io_fp(Out), "\n NEXT %s\nFI", St_ptr(&op->next->txt)); | |
442 } else { | |
443 io_write_m(Out, "\n END\nFI", 9); | |
444 } | |
445 break; | |
446 | |
447 case OP_MODIFY: | |
448 io_write_m(Out, "LET ", 4); | |
449 dump_expr(op->arh.expr, 0); | |
450 if (op->arh.expr->op == B_XMATCH) { | |
451 io_write_m(Out, " ?o~= ", 6); | |
452 } else { | |
453 fprintf(io_fp(Out), " %c= ", display(op->arh.expr->op)); | |
454 } | |
455 dump_expr(op->arg, 0); | |
456 break; | |
457 | |
458 case OP_PRINT: | |
459 io_write_m(Out, "WUNT ", 5); | |
460 if (op->arh.expr) { | |
461 dump_expr(op->arh.expr, 0); | |
462 io_write_m(Out, " ", 1); | |
463 dump_expr(op->arg, 0); | |
464 } else if (op->arg->type != binopE) { | |
465 dump_expr(op->arg, 0); | |
466 } else { | |
467 io_write_m(Out, "(", 1); | |
468 dump_expr(op->arg, 0); | |
469 io_write_m(Out, ")", 1); | |
470 } | |
471 break; | |
472 | |
473 case OP_PUTC: | |
474 io_write_m(Out, "SET ", 4); | |
475 dump_expr(op->arg, 0); | |
476 break; | |
477 | |
478 case OP_RESET: | |
479 io_write_m(Out, "RESET ", 6); | |
480 dump_expr(op->arg, 0); | |
481 break; | |
482 | |
483 case OP_RETURN: | |
484 io_write_m(Out, "KTHX ", 5); | |
485 dump_expr(op->arg, 0); | |
486 break; | |
487 | |
488 case OP_SYSTEM: | |
489 io_write_m(Out, "# ", 2); | |
490 dump_expr(op->arg, 0); | |
491 break; | |
492 | |
493 case OP_TEMP: | |
494 io_write_m(Out, "LEET ", 5); | |
495 dump_expr(op->arh.expr, 0); | |
496 io_write_m(Out, " ", 1); | |
497 dump_expr(op->arg, 0); | |
498 break; | |
499 | |
500 case OP_THROW: | |
501 io_write_m(Out, "IACS ", 5); | |
502 dump_expr(op->arg, 0); | |
503 break; | |
504 | |
505 default: | |
506 NOTREACHED; | |
507 break; | |
508 } | |
509 } | |
510 | |
511 static struct { | |
512 size_t length; | |
513 size_t size; | |
514 struct op **ops; | |
515 } seen; | |
516 | |
517 #define PUSH_SEEN(p) do { \ | |
518 if (seen.length >= seen.size) { \ | |
519 seen.ops = xrealloc(seen.ops, seen.size *= 2); \ | |
520 } \ | |
521 seen.ops[seen.length++] = (p); \ | |
522 } while (0) | |
523 | |
524 static int walk(const struct expr *e) { | |
525 for (;;) { | |
526 switch (e->type) { | |
527 case literE: | |
528 case symbolE: | |
529 return 0; | |
530 | |
531 case varE: | |
532 return 0; | |
533 | |
534 case varhashE: | |
535 e = e->right; | |
536 continue; | |
537 | |
538 case unopE: | |
539 if (e->op == F_NUL) { | |
540 return 1; | |
541 } else if (e->op == F_CALL && !St_ptr(&e->left.op->txt)) { | |
542 MAKE_LABEL(&e->left.op->txt, 'f'); | |
543 PUSH_SEEN(e->left.op); | |
544 } | |
545 e = e->right; | |
546 continue; | |
547 | |
548 case binopE: | |
549 return walk(e->left.expr) | walk(e->right); | |
550 | |
551 case listE: | |
552 return e->right && (walk(e->right) | (e->left.expr && walk(e->left.expr))); | |
553 } | |
554 } | |
555 } | |
556 | |
557 static void do_stuff(struct op *op) { | |
558 for (; op && !op->line; op = op->next) { | |
559 op->line = 1; | |
560 | |
561 if (St_ptr(&op->txt)) { | |
562 fprintf(io_fp(Out), "FOR %s ", St_ptr(&op->txt)); | |
563 if (op->type != OP_NOP) { | |
564 dump_op(op); | |
565 } else { | |
566 io_write_m(Out, "REM", 4); | |
567 } | |
568 io_write_m(Out, "\n", 1); | |
569 } else { | |
570 dump_op(op); | |
571 #if 0 | |
572 if (op->type != OP_NOP) | |
573 #endif | |
574 io_write_m(Out, "\n", 1); | |
575 } | |
576 | |
577 if (op->type == OP_IF) { | |
578 if (op->arh.op) { | |
579 if (op->arh.op->line) { | |
580 fprintf(io_fp(Out), "NEXT %s\n", St_ptr(&op->arh.op->txt)); | |
581 } else { | |
582 do_stuff(op->arh.op); | |
583 } | |
584 } | |
585 } else if (op->type == OP_CALL) { | |
586 if (op->arh.op && !op->arh.op->line) { | |
587 PUSH_SEEN(op->arh.op); | |
588 } | |
589 } else if (op->type == OP_HANG) { | |
590 return; | |
591 } | |
592 | |
593 if (op->next) { | |
594 if (op->next->line && op->type != OP_IF && op->type != OP_RETURN) { | |
595 fprintf(io_fp(Out), "NEXT %s\n", St_ptr(&op->next->txt)); | |
596 } | |
597 } else if ( | |
598 op->type != OP_EXIT && | |
599 op->type != OP_CALL && | |
600 op->type != OP_CALL_BACK && | |
601 op->type != OP_CALL_DYN && | |
602 op->type != OP_HANG && | |
603 op->type != OP_RETURN | |
604 ) { | |
605 io_write_m(Out, "END\n", 4); | |
606 } | |
607 } | |
608 } | |
609 | |
610 enum {MAGIC = 23}; | |
611 void deparse(const struct text *t) { | |
612 size_t i; | |
613 int computed_jumps; | |
614 | |
615 computed_jumps = 0; | |
616 seen.ops = xmalloc(seen.size = MAGIC, sizeof *seen.ops); | |
617 seen.length = 0; | |
618 | |
619 for (i = 0; i < t->length; ++i) { | |
620 struct op *op = t->start[i]; | |
621 | |
622 op->line = 0; | |
623 | |
624 if ( | |
625 op->type == OP_GOBACK || | |
626 op->type == OP_GOTO || | |
627 op->type == OP_CALL_DYN | |
628 ) { | |
629 walk(op->arg); | |
630 computed_jumps |= 1; | |
631 } else if (op->type == OP_CALL_BACK) { | |
632 walk(op->arh.expr); | |
633 walk(op->arg); | |
634 computed_jumps |= 1; | |
635 } else if (OP_1ARG_P(op->type)) { | |
636 computed_jumps |= walk(op->arg); | |
637 if (op->type == OP_CALL && op->arh.op) { | |
638 if (!St_ptr(&op->arh.op->txt)) { | |
639 MAKE_LABEL(&op->arh.op->txt, 'c'); | |
640 } | |
641 } | |
642 } else if (OP_2ARG_P(op->type)) { | |
643 if (op->arh.expr) { | |
644 computed_jumps |= walk(op->arh.expr); | |
645 } | |
646 computed_jumps |= walk(op->arg); | |
647 } | |
648 | |
649 if ( | |
650 op->next && | |
651 (op->next != t->start[i + 1] || op->type == OP_CALL) && | |
652 !St_ptr(&op->next->txt) | |
653 ) { | |
654 MAKE_LABEL(&op->next->txt, 'x'); | |
655 } | |
656 } | |
657 | |
658 if (!computed_jumps) { | |
659 do_stuff(t->start[0]); | |
660 for (i = 0; i < seen.length; ++i) { | |
661 do_stuff(seen.ops[i]); | |
662 } | |
663 } else { | |
664 for (i = 0; i < t->length; ++i) { | |
665 struct op *op = t->start[i]; | |
666 const String *tmp; | |
667 | |
668 if ((tmp = ve_label(&Venus, op))) { | |
669 if (St_ptr(&op->txt)) { | |
670 fprintf(io_fp(Out), " FOR %s\n", St_ptr(&op->txt)); | |
671 } | |
672 fprintf(io_fp(Out), "%s%s", St_ptr(tmp), &" "[!St_len(tmp)]); | |
673 } else { | |
674 if (St_ptr(&op->txt)) { | |
675 fprintf(io_fp(Out), "FOR %s ", St_ptr(&op->txt)); | |
676 } | |
677 } | |
678 | |
679 dump_op(op); | |
680 io_write_m(Out, "\n", 1); | |
681 | |
682 if (op->next && op->next != t->start[i + 1] && op->type != OP_IF) { | |
683 fprintf(io_fp(Out), "NEXT %s\n", St_ptr(&op->next->txt)); | |
684 } | |
685 } | |
686 } | |
687 xfree(seen.ops); | |
688 } |