4223
|
1 #include "config.h"
|
|
2 #include "Str.h"
|
|
3 #include "expr.h"
|
|
4 #include "kork.h"
|
|
5 #include "main_label.h"
|
|
6 #include "op.h"
|
|
7 #include "text.h"
|
|
8 #include "transmogrify.h"
|
|
9 #include "val.h"
|
|
10 #include "venus.h"
|
|
11 #include "xmalloc.h"
|
|
12 #include "zz.h"
|
|
13
|
|
14 #include <ctype.h>
|
|
15 #include <math.h>
|
|
16 #include <stddef.h>
|
|
17 #include <assert.h>
|
|
18
|
|
19 ATTR_PURE
|
|
20 static int liter_expr(const struct expr *const e) {
|
|
21 return
|
|
22 e->type == literE ||
|
|
23 (
|
|
24 e->type == symbolE &&
|
|
25 e->op != S_ARG && e->op != S_ARGC && e->op != S_ARGV &&
|
|
26 e->op != S_ERR && e->op != S_MATCH && e->op != S_RAND &&
|
|
27 e->op != S_RESULT
|
|
28 ) ||
|
|
29 (
|
|
30 e->type == listE &&
|
|
31 (e->right == NULL || liter_expr(e->right)) &&
|
|
32 e->left.expr == NULL
|
|
33 )
|
|
34 ;
|
|
35 }
|
|
36
|
|
37 #define const_unop(op) \
|
|
38 ( \
|
|
39 (op) == F_ABS || (op) == F_ACOS || (op) == F_ASIN || \
|
|
40 (op) == F_ATAN || (op) == F_ATAN2 || (op) == F_CHR || \
|
|
41 (op) == F_CHR || (op) == F_COS || (op) == F_DEFINED || \
|
|
42 (op) == F_EXP || (op) == F_GETENV || (op) == F_INT || \
|
|
43 (op) == F_IO || (op) == F_LENGTH || (op) == F_LOG || \
|
|
44 (op) == F_LOG10 || (op) == F_LOWER || (op) == F_NEG || \
|
|
45 (op) == F_NOT || (op) == F_NUM || (op) == F_ORD || \
|
|
46 (op) == F_QUOTE || (op) == F_RE_ESC || (op) == F_REVERSE || \
|
|
47 (op) == F_SIN || (op) == F_TAN || (op) == F_SQRT || \
|
|
48 (op) == F_STR || (op) == F_TYPEOF || (op) == F_UPPER \
|
|
49 )
|
|
50
|
|
51 #define const_binop(op) \
|
|
52 ( \
|
|
53 !((op) == B_SPOT || (op) == B_SQIGGLE || (op) == B_XMATCH) \
|
|
54 )
|
|
55
|
|
56 static int hp_expr(const struct expr *e) {
|
|
57 switch (e->type) {
|
|
58 case literE:
|
|
59 return 1;
|
|
60
|
|
61 case varE:
|
|
62 return 1;
|
|
63
|
|
64 case varhashE:
|
|
65 return hp_expr(e->right);
|
|
66
|
|
67 case symbolE:
|
|
68 if (e->op != S_RAND) {
|
|
69 return 1;
|
|
70 }
|
|
71 return 0;
|
|
72
|
|
73 case unopE:
|
|
74 if (!const_unop(e->op)) {
|
|
75 return 0;
|
|
76 }
|
|
77 return hp_expr(e->right);
|
|
78
|
|
79 case binopE:
|
|
80 if (!const_binop(e->op)) {
|
|
81 return 0;
|
|
82 }
|
|
83 if (!hp_expr(e->left.expr)) {
|
|
84 return 0;
|
|
85 }
|
|
86 return hp_expr(e->right);
|
|
87
|
|
88 case listE:
|
|
89 if (e->right) {
|
|
90 if (!hp_expr(e->right)) {
|
|
91 return 0;
|
|
92 }
|
|
93 if (!e->left.expr) {
|
|
94 return 1;
|
|
95 }
|
|
96 return hp_expr(e->left.expr);
|
|
97 }
|
|
98 return 1;
|
|
99 }
|
|
100
|
|
101 NOTREACHED;
|
|
102 }
|
|
103
|
|
104 void trans_fold(struct expr **e) {
|
|
105 struct val *v;
|
|
106
|
|
107 switch ((*e)->type) {
|
|
108 case literE:
|
|
109 break;
|
|
110
|
|
111 case varE:
|
|
112 break;
|
|
113
|
|
114 case varhashE:
|
|
115 trans_fold(&(*e)->right);
|
|
116 break;
|
|
117
|
|
118 case symbolE:
|
|
119 break;
|
|
120
|
|
121 case unopE:
|
|
122 trans_fold(&(*e)->right);
|
|
123 if (liter_expr((*e)->right)) {
|
|
124 if ((*e)->op == F_NUL) {
|
|
125 v = eval_expr((*e)->right);
|
|
126 free_expr((*e)->right);
|
|
127 (*e)->right = xmalloc(1, sizeof *(*e)->right);
|
|
128 (*e)->right->type = literE;
|
|
129 (*e)->right->left.expr = (*e)->right->right = NULL;
|
|
130 (*e)->right->v.val = v_undef();
|
|
131 TOLABEL(v);
|
|
132 if (((*e)->left.op = ve_findnext(&Venus, ko_str(v->ko), (*e)->left.bonus))) {
|
|
133 (*e)->op = F_CALL;
|
|
134 } else {
|
|
135 (*e)->op = F_HANG;
|
|
136 }
|
|
137 v_delete(v);
|
|
138 } else if (const_unop((*e)->op)) {
|
|
139 (*e)->v.val = eval_expr(*e);
|
|
140 free_expr((*e)->right);
|
|
141 (*e)->right = NULL;
|
|
142 (*e)->type = literE;
|
|
143 }
|
|
144 } else if (
|
|
145 (*e)->right->type == unopE &&
|
|
146 (*e)->op == (*e)->right->op &&
|
|
147 ((*e)->op == F_STR || (*e)->op == F_NUM)
|
|
148 ) {
|
|
149 struct expr *const tmp = (*e)->right;
|
|
150 (*e)->right = (*e)->right->right;
|
|
151 tmp->right = NULL;
|
|
152 free_expr(tmp);
|
|
153 }
|
|
154 break;
|
|
155
|
|
156 case binopE:
|
|
157 trans_fold(&(*e)->left.expr);
|
|
158 trans_fold(&(*e)->right);
|
|
159 if (liter_expr((*e)->left.expr) && liter_expr((*e)->right) && const_binop((*e)->op)) {
|
|
160 (*e)->v.val = eval_expr(*e);
|
|
161 free_expr((*e)->left.expr);
|
|
162 (*e)->left.expr = NULL;
|
|
163 free_expr((*e)->right);
|
|
164 (*e)->right = NULL;
|
|
165 (*e)->type = literE;
|
|
166 } else switch ((*e)->op) {
|
|
167 case B_INTERSECTION:
|
|
168 if ((*e)->left.expr->type == literE) {
|
|
169 V_NUM((*e)->left.expr->v.val);
|
|
170 if ((*e)->left.expr->v.val->num == 0.0) {
|
|
171 free_expr((*e)->left.expr);
|
|
172 (*e)->left.expr = NULL;
|
|
173 (*e)->op = F_NUM;
|
|
174 (*e)->type = unopE;
|
|
175 }
|
|
176 } else if ((*e)->right->type == literE) {
|
|
177 V_NUM((*e)->right->v.val);
|
|
178 if ((*e)->right->v.val->num == 0.0) {
|
|
179 free_expr((*e)->right);
|
|
180 (*e)->right = (*e)->left.expr;
|
|
181 (*e)->left.expr = NULL;
|
|
182 (*e)->op = F_NUM;
|
|
183 (*e)->type = unopE;
|
|
184 }
|
|
185 }
|
|
186 break;
|
|
187
|
|
188 case B_TAIL:
|
|
189 if (hp_expr((*e)->left.expr)) {
|
|
190 struct expr *tmp;
|
|
191
|
|
192 free_expr((*e)->left.expr);
|
|
193 tmp = *e;
|
|
194 *e = (*e)->right;
|
|
195 xfree(tmp);
|
|
196 }
|
|
197 break;
|
|
198
|
|
199 case B_WORM:
|
|
200 if ((*e)->left.expr->type == literE) {
|
|
201 V_NUM((*e)->left.expr->v.val);
|
|
202 if ((*e)->left.expr->v.val->num == 0.0) {
|
|
203 free_expr((*e)->left.expr);
|
|
204 (*e)->left.expr = NULL;
|
|
205 (*e)->op = F_NEG;
|
|
206 (*e)->type = unopE;
|
|
207 }
|
|
208 } else if ((*e)->right->type == literE) {
|
|
209 V_NUM((*e)->right->v.val);
|
|
210 if ((*e)->right->v.val->num == 0.0) {
|
|
211 free_expr((*e)->right);
|
|
212 (*e)->right = (*e)->left.expr;
|
|
213 (*e)->left.expr = NULL;
|
|
214 (*e)->op = F_NUM;
|
|
215 (*e)->type = unopE;
|
|
216 }
|
|
217 }
|
|
218 break;
|
|
219
|
|
220 case B_SHARK_FIN:
|
|
221 if ((*e)->left.expr->type == symbolE) {
|
|
222 if ((*e)->left.expr->op == S_EULER) {
|
|
223 free_expr((*e)->left.expr);
|
|
224 (*e)->left.expr = NULL;
|
|
225 (*e)->op = F_EXP;
|
|
226 (*e)->type = unopE;
|
|
227 }
|
|
228 } else if ((*e)->right->type == literE) {
|
|
229 V_NUM((*e)->right->v.val);
|
|
230 if ((*e)->right->v.val->num == 0.5) {
|
|
231 free_expr((*e)->right);
|
|
232 (*e)->right = (*e)->left.expr;
|
|
233 (*e)->left.expr = NULL;
|
|
234 (*e)->op = F_SQRT;
|
|
235 (*e)->type = unopE;
|
|
236 }
|
|
237 }
|
|
238 break;
|
|
239
|
|
240 case B_FLATWORM:
|
|
241 if ((*e)->left.expr->type == literE) {
|
|
242 V_STR((*e)->left.expr->v.val);
|
|
243 if (!ko_length((*e)->left.expr->v.val->ko)) {
|
|
244 free_expr((*e)->left.expr);
|
|
245 (*e)->left.expr = NULL;
|
|
246 (*e)->op = F_STR;
|
|
247 (*e)->type = unopE;
|
|
248 }
|
|
249 } else if ((*e)->right->type == literE) {
|
|
250 V_STR((*e)->right->v.val);
|
|
251 if (!ko_length((*e)->right->v.val->ko)) {
|
|
252 free_expr((*e)->right);
|
|
253 (*e)->right = (*e)->left.expr;
|
|
254 (*e)->left.expr = NULL;
|
|
255 (*e)->op = F_STR;
|
|
256 (*e)->type = unopE;
|
|
257 }
|
|
258 }
|
|
259 break;
|
|
260
|
|
261 case B_SQIGGLE:
|
|
262 case B_XMATCH:
|
|
263 if ((*e)->right->type == literE) {
|
|
264 t_regex *rx;
|
|
265 V_STR((*e)->right->v.val);
|
|
266 rx = re_compile(ko_str((*e)->right->v.val->ko));
|
|
267 free_expr((*e)->right);
|
|
268 (*e)->right = (*e)->left.expr;
|
|
269 (*e)->left.rx = rx;
|
|
270 (*e)->op = F_MATCH;
|
|
271 (*e)->type = unopE;
|
|
272 }
|
|
273 break;
|
|
274 }
|
|
275 break;
|
|
276
|
|
277 case listE:
|
|
278 if ((*e)->right) {
|
|
279 trans_fold(&(*e)->right);
|
|
280 if ((*e)->left.expr) {
|
|
281 trans_fold(&(*e)->left.expr);
|
|
282 }
|
|
283 }
|
|
284 break;
|
|
285 }
|
|
286 }
|
|
287
|
|
288 #define SNAP(p) \
|
|
289 do { \
|
|
290 while ( \
|
|
291 (p) && \
|
|
292 (p)->type == OP_NOP && \
|
|
293 (p) != (p)->next \
|
|
294 ) { \
|
|
295 (p) = (p)->next; \
|
|
296 } \
|
|
297 } while (0)
|
|
298
|
|
299 static void walk(struct expr *e) {
|
|
300 for (;;) {
|
|
301 switch (e->type) {
|
|
302 case literE:
|
|
303 case symbolE:
|
|
304 return;
|
|
305
|
|
306 case varE:
|
|
307 return;
|
|
308
|
|
309 case varhashE:
|
|
310 e = e->right;
|
|
311 continue;
|
|
312
|
|
313 case unopE:
|
|
314 if (e->op == F_CALL) {
|
|
315 SNAP(e->left.op);
|
|
316 if (
|
|
317 e->left.op &&
|
|
318 e->left.op->type == OP_RETURN &&
|
|
319 hp_expr(e->right) &&
|
|
320 liter_expr(e->left.op->arg)
|
|
321 ) {
|
|
322 free_expr(e->right);
|
|
323 e->right = NULL;
|
|
324 switch (e->left.op->arg->type) {
|
|
325 case literE:
|
|
326 e->v.val = v_undef();
|
|
327 v_set(e->v.val, e->left.op->arg->v.val);
|
|
328 e->type = literE;
|
|
329 break;
|
|
330
|
|
331 case symbolE:
|
|
332 e->op = e->left.op->arg->op;
|
|
333 e->type = symbolE;
|
|
334 break;
|
|
335
|
|
336 case listE:
|
|
337 assert(!e->left.op->arg->left.expr && !e->left.op->arg->right);
|
|
338 e->type = listE;
|
|
339 break;
|
|
340
|
|
341 default:
|
|
342 NOTREACHED;
|
|
343 }
|
|
344 e->left.expr = NULL;
|
|
345 return;
|
|
346 }
|
|
347 }
|
|
348 e = e->right;
|
|
349 continue;
|
|
350
|
|
351 case binopE:
|
|
352 walk(e->left.expr);
|
|
353 e = e->right;
|
|
354 continue;
|
|
355
|
|
356 case listE:
|
|
357 if (e->right) {
|
|
358 if (e->left.expr) {
|
|
359 walk(e->left.expr);
|
|
360 }
|
|
361 e = e->right;
|
|
362 continue;
|
|
363 }
|
|
364 return;
|
|
365 }
|
|
366 }
|
|
367 }
|
|
368
|
|
369 void transmogrify(struct text *code) {
|
|
370 size_t i;
|
|
371 struct op *hang = NULL;
|
|
372
|
|
373 for (i = 0; i < code->length; ++i) {
|
|
374 struct op *op = code->start[i];
|
|
375
|
|
376 switch (op->type) {
|
|
377 case OP_CALL:
|
|
378 case OP_CALL_DYN:
|
|
379 case OP_CLOSE:
|
|
380 case OP_EXIT:
|
|
381 case OP_FLUSH:
|
|
382 case OP_GOBACK:
|
|
383 case OP_GOTO:
|
|
384 case OP_IF:
|
|
385 case OP_RESET:
|
|
386 case OP_RETURN:
|
|
387 case OP_SYSTEM:
|
|
388 case OP_THROW:
|
|
389 trans_fold(&op->arg);
|
|
390 break;
|
|
391
|
|
392 case OP_ASSIGN:
|
|
393 trans_fold(&op->arg);
|
|
394 if (!op->arh.expr) {
|
|
395 if (hp_expr(op->arg)) {
|
|
396 free_expr(op->arg);
|
|
397 op->arg = NULL;
|
|
398 op->type = OP_NOP;
|
|
399 }
|
|
400 } else {
|
|
401 trans_fold(&op->arh.expr);
|
|
402 if (
|
|
403 op->arh.expr->type == varE &&
|
|
404 op->arg->type == binopE &&
|
|
405 op->arg->left.expr->type == varE &&
|
|
406 op->arh.expr->v.val == op->arg->left.expr->v.val
|
|
407 ) {
|
|
408 struct expr *const tmp = op->arg;
|
|
409 op->arh.expr->op = op->arg->op;
|
|
410 op->arg = op->arg->right;
|
|
411 xfree(tmp->left.expr);
|
|
412 xfree(tmp);
|
|
413 op->type = OP_MODIFY;
|
|
414 } else if (op->arg->type == literE) {
|
|
415 op->type = OP_SET_VAL;
|
|
416 }
|
|
417 }
|
|
418 break;
|
|
419
|
|
420 case OP_CALL_BACK:
|
|
421 case OP_MODIFY:
|
|
422 trans_fold(&op->arh.expr);
|
|
423 trans_fold(&op->arg);
|
|
424 break;
|
|
425
|
|
426 case OP_PRINT:
|
|
427 case OP_PUTC:
|
|
428 case OP_TEMP:
|
|
429 trans_fold(&op->arg);
|
|
430 if (op->arh.expr) {
|
|
431 trans_fold(&op->arh.expr);
|
|
432 }
|
|
433 break;
|
|
434
|
|
435 default:
|
|
436 break;
|
|
437 }
|
|
438 }
|
|
439
|
|
440 for (i = 0; i < code->length; ++i) {
|
|
441 struct op *op = code->start[i];
|
|
442
|
|
443 switch (op->type) {
|
|
444 case OP_CALL_BACK:
|
|
445 if (liter_expr(op->arh.expr)) {
|
|
446 struct val *v;
|
|
447
|
|
448 v = eval_expr(op->arh.expr);
|
|
449 TOLABEL(v);
|
|
450 free_expr(op->arh.expr);
|
|
451 if ((op->arh.op = ve_findprev(&Venus, ko_str(v->ko), op->line))) {
|
|
452 op->type = OP_CALL;
|
|
453 } else {
|
|
454 free_expr(op->arg);
|
|
455 op->arg = NULL;
|
|
456 op->type = OP_HANG;
|
|
457 hang = op;
|
|
458 }
|
|
459 v_end(v);
|
|
460 xfree(v);
|
|
461 }
|
|
462 break;
|
|
463
|
|
464 case OP_CALL_DYN:
|
|
465 case OP_GOBACK:
|
|
466 case OP_GOTO:
|
|
467 if (liter_expr(op->arg)) {
|
|
468 struct val *v;
|
|
469
|
|
470 v = eval_expr(op->arg);
|
|
471 TOLABEL(v);
|
|
472 free_expr(op->arg);
|
|
473 op->arg = NULL;
|
|
474 if ((op->arh.op = (op->type == OP_GOBACK ? ve_findprev : ve_findnext)(&Venus, ko_str(v->ko), op->line))) {
|
|
475 if (op->type == OP_CALL_DYN) {
|
|
476 op->type = OP_CALL;
|
|
477 op->arg = xmalloc(1, sizeof *op->arg);
|
|
478 op->arg->left.expr = op->arg->right = NULL;
|
|
479 op->arg->type = literE;
|
|
480 op->arg->v.val = v_undef();
|
|
481 } else {
|
|
482 op->next = op->arh.op;
|
|
483 op->arh.op = NULL;
|
|
484 op->type = OP_NOP;
|
|
485 }
|
|
486 } else {
|
|
487 op->type = OP_HANG;
|
|
488 hang = op;
|
|
489 }
|
|
490 v_end(v);
|
|
491 xfree(v);
|
|
492 }
|
|
493 break;
|
|
494
|
|
495 case OP_HANG:
|
|
496 hang = op;
|
|
497 break;
|
|
498
|
|
499 case OP_IF:
|
|
500 if (liter_expr(op->arg)) {
|
|
501 struct val *v;
|
|
502
|
|
503 v = eval_expr(op->arg);
|
|
504 if (v_true(v)) {
|
|
505 op->next = op->arh.op;
|
|
506 }
|
|
507 v_delete(v);
|
|
508 op->type = OP_NOP;
|
|
509 op->arh.expr = NULL;
|
|
510 free_expr(op->arg);
|
|
511 op->arg = NULL;
|
|
512 }
|
|
513 break;
|
|
514
|
|
515 case OP_PRINT:
|
|
516 if (
|
|
517 op->arg->type == literE &&
|
|
518 (
|
|
519 (
|
|
520 op->arg->v.val->type == V_STR_K &&
|
|
521 ko_length(op->arg->v.val->ko) == 0
|
|
522 ) ||
|
|
523 op->arg->v.val->type == V_UNDEF
|
|
524 )
|
|
525 ) {
|
|
526 op->type = OP_NOP;
|
|
527 free_expr(op->arg);
|
|
528 op->arg = NULL;
|
|
529 if (op->arh.expr) {
|
|
530 free_expr(op->arh.expr);
|
|
531 op->arh.expr = NULL;
|
|
532 }
|
|
533 break;
|
|
534 }
|
|
535 if (
|
|
536 op->arh.expr &&
|
|
537 op->arh.expr->type == symbolE &&
|
|
538 op->arh.expr->op == S_STDOUT
|
|
539 ) {
|
|
540 free_expr(op->arh.expr);
|
|
541 op->arh.expr = NULL;
|
|
542 }
|
|
543 break;
|
|
544
|
|
545 default:
|
|
546 break;
|
|
547 }
|
|
548 }
|
|
549
|
|
550 if (!hang) {
|
|
551 struct op tmp;
|
|
552
|
|
553 tmp.type = OP_HANG;
|
|
554 tmp.arg = tmp.arh.expr = NULL;
|
|
555 tmp.next = NULL;
|
|
556 St_init(&tmp.txt);
|
|
557 St_clear(&tmp.txt);
|
|
558 tmp.line = -1;
|
|
559
|
|
560 hang = text_push(code, &tmp);
|
|
561 }
|
|
562
|
|
563 for (i = 0; i < code->length; ++i) {
|
|
564 struct op *op = code->start[i];
|
|
565
|
|
566 SNAP(op->next);
|
|
567 if (op->type == OP_IF) {
|
|
568 SNAP(op->arh.op);
|
|
569 } else if (op->type == OP_CALL) {
|
|
570 SNAP(op->arh.op);
|
|
571 if (!op->arh.op) {
|
|
572 struct expr *tmp = xmalloc(1, sizeof *tmp);
|
|
573 tmp->type = binopE;
|
|
574 tmp->op = B_TAIL;
|
|
575 tmp->left.expr = op->arg;
|
|
576 tmp->right = xmalloc(1, sizeof *tmp->right);
|
|
577 tmp->right->type = literE;
|
|
578 tmp->right->v.val = v_undef();
|
|
579 tmp->right->left.expr = tmp->right->right = NULL;
|
|
580 op->arg = tmp;
|
|
581 op->type = OP_EXIT;
|
|
582 trans_fold(&op->arg);
|
|
583 }
|
|
584 }
|
|
585
|
|
586 if (op == op->next) {
|
|
587 op->next = hang;
|
|
588 }
|
|
589 if (OP_1ARG_P(op->type)) {
|
|
590 walk(op->arg);
|
|
591 } else if (OP_2ARG_P(op->type)) {
|
|
592 if (op->arh.expr) {
|
|
593 walk(op->arh.expr);
|
|
594 }
|
|
595 walk(op->arg);
|
|
596 }
|
|
597 }
|
|
598 }
|