4223
|
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 }
|