Commit | Line | Data |
ff8e2863 |
1 | /* $Header: cons.c,v 3.0.1.7 90/08/09 02:35:52 lwall Locked $ |
a687059c |
2 | * |
3 | * Copyright (c) 1989, Larry Wall |
4 | * |
5 | * You may distribute under the terms of the GNU General Public License |
6 | * as specified in the README file that comes with the perl 3.0 kit. |
7 | * |
8 | * $Log: cons.c,v $ |
ff8e2863 |
9 | * Revision 3.0.1.7 90/08/09 02:35:52 lwall |
10 | * patch19: did preliminary work toward debugging packages and evals |
11 | * patch19: Added support for linked-in C subroutines |
12 | * patch19: Numeric literals are now stored only in floating point |
13 | * patch19: Added -c switch to do compilation only |
14 | * |
0f85fab0 |
15 | * Revision 3.0.1.6 90/03/27 15:35:21 lwall |
16 | * patch16: formats didn't work inside eval |
17 | * patch16: $foo++ now optimized to ++$foo where value not required |
18 | * |
ff2452de |
19 | * Revision 3.0.1.5 90/03/12 16:23:10 lwall |
20 | * patch13: perl -d coredumped on scripts with subs that did explicit return |
21 | * |
afd9f252 |
22 | * Revision 3.0.1.4 90/02/28 16:44:00 lwall |
23 | * patch9: subs which return by both mechanisms can clobber local return data |
24 | * patch9: changed internal SUB label to _SUB_ |
25 | * patch9: line numbers were bogus during certain portions of foreach evaluation |
26 | * |
663a0e37 |
27 | * Revision 3.0.1.3 89/12/21 19:20:25 lwall |
28 | * patch7: made nested or recursive foreach work right |
29 | * |
0d3e774c |
30 | * Revision 3.0.1.2 89/11/17 15:08:53 lwall |
31 | * patch5: nested foreach on same array didn't work |
32 | * |
03a14243 |
33 | * Revision 3.0.1.1 89/10/26 23:09:01 lwall |
34 | * patch1: numeric switch optimization was broken |
35 | * patch1: unless was broken when run under the debugger |
36 | * |
a687059c |
37 | * Revision 3.0 89/10/18 15:10:23 lwall |
38 | * 3.0 baseline |
39 | * |
40 | */ |
41 | |
42 | #include "EXTERN.h" |
43 | #include "perl.h" |
44 | #include "perly.h" |
45 | |
46 | extern char *tokename[]; |
47 | extern int yychar; |
48 | |
49 | static int cmd_tosave(); |
50 | static int arg_tosave(); |
51 | static int spat_tosave(); |
52 | |
53 | static bool saw_return; |
54 | |
55 | SUBR * |
56 | make_sub(name,cmd) |
57 | char *name; |
58 | CMD *cmd; |
59 | { |
60 | register SUBR *sub; |
61 | STAB *stab = stabent(name,TRUE); |
62 | |
63 | Newz(101,sub,1,SUBR); |
64 | if (stab_sub(stab)) { |
65 | if (dowarn) { |
ff8e2863 |
66 | CMD *oldcurcmd = curcmd; |
a687059c |
67 | |
68 | if (cmd) |
ff8e2863 |
69 | curcmd = cmd; |
a687059c |
70 | warn("Subroutine %s redefined",name); |
ff8e2863 |
71 | curcmd = oldcurcmd; |
72 | } |
73 | if (stab_sub(stab)->cmd) { |
74 | cmd_free(stab_sub(stab)->cmd); |
75 | afree(stab_sub(stab)->tosave); |
a687059c |
76 | } |
a687059c |
77 | Safefree(stab_sub(stab)); |
78 | } |
79 | sub->filename = filename; |
80 | saw_return = FALSE; |
81 | tosave = anew(Nullstab); |
82 | tosave->ary_fill = 0; /* make 1 based */ |
83 | (void)cmd_tosave(cmd,FALSE); /* this builds the tosave array */ |
84 | sub->tosave = tosave; |
85 | if (saw_return) { |
86 | struct compcmd mycompblock; |
87 | |
88 | mycompblock.comp_true = cmd; |
89 | mycompblock.comp_alt = Nullcmd; |
afd9f252 |
90 | cmd = add_label(savestr("_SUB_"),make_ccmd(C_BLOCK,Nullarg,mycompblock)); |
a687059c |
91 | saw_return = FALSE; |
ff2452de |
92 | cmd->c_flags |= CF_TERM; |
a687059c |
93 | } |
94 | sub->cmd = cmd; |
95 | stab_sub(stab) = sub; |
96 | if (perldb) { |
97 | STR *str = str_nmake((double)subline); |
98 | |
99 | str_cat(str,"-"); |
ff8e2863 |
100 | sprintf(buf,"%ld",(long)curcmd->c_line); |
a687059c |
101 | str_cat(str,buf); |
102 | name = str_get(subname); |
103 | hstore(stab_xhash(DBsub),name,strlen(name),str,0); |
104 | str_set(subname,"main"); |
105 | } |
106 | subline = 0; |
107 | return sub; |
108 | } |
109 | |
ff8e2863 |
110 | SUBR * |
111 | make_usub(name, ix, subaddr, filename) |
112 | char *name; |
113 | int ix; |
114 | int (*subaddr)(); |
115 | char *filename; |
116 | { |
117 | register SUBR *sub; |
118 | STAB *stab = stabent(name,allstabs); |
119 | |
120 | if (!stab) /* unused function */ |
121 | return; |
122 | Newz(101,sub,1,SUBR); |
123 | if (stab_sub(stab)) { |
124 | if (dowarn) |
125 | warn("Subroutine %s redefined",name); |
126 | if (stab_sub(stab)->cmd) { |
127 | cmd_free(stab_sub(stab)->cmd); |
128 | afree(stab_sub(stab)->tosave); |
129 | } |
130 | Safefree(stab_sub(stab)); |
131 | } |
132 | sub->filename = filename; |
133 | sub->usersub = subaddr; |
134 | sub->userindex = ix; |
135 | stab_sub(stab) = sub; |
136 | return sub; |
137 | } |
138 | |
0f85fab0 |
139 | make_form(stab,fcmd) |
140 | STAB *stab; |
141 | FCMD *fcmd; |
142 | { |
143 | if (stab_form(stab)) { |
144 | FCMD *tmpfcmd; |
145 | FCMD *nextfcmd; |
146 | |
147 | for (tmpfcmd = stab_form(stab); tmpfcmd; tmpfcmd = nextfcmd) { |
148 | nextfcmd = tmpfcmd->f_next; |
149 | if (tmpfcmd->f_expr) |
150 | arg_free(tmpfcmd->f_expr); |
151 | if (tmpfcmd->f_unparsed) |
152 | str_free(tmpfcmd->f_unparsed); |
153 | if (tmpfcmd->f_pre) |
154 | Safefree(tmpfcmd->f_pre); |
155 | Safefree(tmpfcmd); |
156 | } |
157 | } |
158 | stab_form(stab) = fcmd; |
159 | } |
160 | |
a687059c |
161 | CMD * |
162 | block_head(tail) |
163 | register CMD *tail; |
164 | { |
165 | CMD *head; |
166 | register int opt; |
167 | register int last_opt = 0; |
168 | register STAB *last_stab = Nullstab; |
169 | register int count = 0; |
170 | register CMD *switchbeg = Nullcmd; |
171 | |
172 | if (tail == Nullcmd) { |
173 | return tail; |
174 | } |
175 | head = tail->c_head; |
176 | |
177 | for (tail = head; tail; tail = tail->c_next) { |
178 | |
179 | /* save one measly dereference at runtime */ |
180 | if (tail->c_type == C_IF) { |
181 | if (!(tail->ucmd.ccmd.cc_alt = tail->ucmd.ccmd.cc_alt->c_next)) |
182 | tail->c_flags |= CF_TERM; |
183 | } |
184 | else if (tail->c_type == C_EXPR) { |
185 | ARG *arg; |
186 | |
187 | if (tail->ucmd.acmd.ac_expr) |
188 | arg = tail->ucmd.acmd.ac_expr; |
189 | else |
190 | arg = tail->c_expr; |
191 | if (arg) { |
192 | if (arg->arg_type == O_RETURN) |
193 | tail->c_flags |= CF_TERM; |
194 | else if (arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD) |
195 | tail->c_flags |= CF_TERM; |
196 | } |
197 | } |
198 | if (!tail->c_next) |
199 | tail->c_flags |= CF_TERM; |
200 | |
201 | if (tail->c_expr && (tail->c_flags & CF_OPTIMIZE) == CFT_FALSE) |
202 | opt_arg(tail,1, tail->c_type == C_EXPR); |
203 | |
204 | /* now do a little optimization on case-ish structures */ |
205 | switch(tail->c_flags & (CF_OPTIMIZE|CF_FIRSTNEG|CF_INVERT)) { |
206 | case CFT_ANCHOR: |
207 | if (stabent("*",FALSE)) { /* bad assumption here!!! */ |
208 | opt = 0; |
209 | break; |
210 | } |
211 | /* FALL THROUGH */ |
212 | case CFT_STROP: |
213 | opt = (tail->c_flags & CF_NESURE) ? CFT_STROP : 0; |
214 | break; |
215 | case CFT_CCLASS: |
216 | opt = CFT_STROP; |
217 | break; |
218 | case CFT_NUMOP: |
219 | opt = (tail->c_slen == O_NE ? 0 : CFT_NUMOP); |
220 | if ((tail->c_flags&(CF_NESURE|CF_EQSURE)) != (CF_NESURE|CF_EQSURE)) |
221 | opt = 0; |
222 | break; |
223 | default: |
224 | opt = 0; |
225 | } |
226 | if (opt && opt == last_opt && tail->c_stab == last_stab) |
227 | count++; |
228 | else { |
229 | if (count >= 3) { /* is this the breakeven point? */ |
230 | if (last_opt == CFT_NUMOP) |
231 | make_nswitch(switchbeg,count); |
232 | else |
233 | make_cswitch(switchbeg,count); |
234 | } |
235 | if (opt) { |
236 | count = 1; |
237 | switchbeg = tail; |
238 | } |
239 | else |
240 | count = 0; |
241 | } |
242 | last_opt = opt; |
243 | last_stab = tail->c_stab; |
244 | } |
245 | if (count >= 3) { /* is this the breakeven point? */ |
246 | if (last_opt == CFT_NUMOP) |
247 | make_nswitch(switchbeg,count); |
248 | else |
249 | make_cswitch(switchbeg,count); |
250 | } |
251 | return head; |
252 | } |
253 | |
254 | /* We've spotted a sequence of CMDs that all test the value of the same |
255 | * spat. Thus we can insert a SWITCH in front and jump directly |
256 | * to the correct one. |
257 | */ |
258 | make_cswitch(head,count) |
259 | register CMD *head; |
260 | int count; |
261 | { |
262 | register CMD *cur; |
263 | register CMD **loc; |
264 | register int i; |
265 | register int min = 255; |
266 | register int max = 0; |
267 | |
268 | /* make a new head in the exact same spot */ |
269 | New(102,cur, 1, CMD); |
270 | #ifdef STRUCTCOPY |
271 | *cur = *head; |
272 | #else |
273 | Copy(head,cur,1,CMD); |
274 | #endif |
275 | Zero(head,1,CMD); |
276 | head->c_type = C_CSWITCH; |
277 | head->c_next = cur; /* insert new cmd at front of list */ |
278 | head->c_stab = cur->c_stab; |
279 | |
280 | Newz(103,loc,258,CMD*); |
281 | loc++; /* lie a little */ |
282 | while (count--) { |
283 | if ((cur->c_flags & CF_OPTIMIZE) == CFT_CCLASS) { |
284 | for (i = 0; i <= 255; i++) { |
285 | if (!loc[i] && cur->c_short->str_ptr[i>>3] & (1 << (i&7))) { |
286 | loc[i] = cur; |
287 | if (i < min) |
288 | min = i; |
289 | if (i > max) |
290 | max = i; |
291 | } |
292 | } |
293 | } |
294 | else { |
295 | i = *cur->c_short->str_ptr & 255; |
296 | if (!loc[i]) { |
297 | loc[i] = cur; |
298 | if (i < min) |
299 | min = i; |
300 | if (i > max) |
301 | max = i; |
302 | } |
303 | } |
304 | cur = cur->c_next; |
305 | } |
306 | max++; |
307 | if (min > 0) |
308 | Copy(&loc[min],&loc[0], max - min, CMD*); |
309 | loc--; |
310 | min--; |
311 | max -= min; |
312 | for (i = 0; i <= max; i++) |
313 | if (!loc[i]) |
314 | loc[i] = cur; |
315 | Renew(loc,max+1,CMD*); /* chop it down to size */ |
316 | head->ucmd.scmd.sc_offset = min; |
317 | head->ucmd.scmd.sc_max = max; |
318 | head->ucmd.scmd.sc_next = loc; |
319 | } |
320 | |
321 | make_nswitch(head,count) |
322 | register CMD *head; |
323 | int count; |
324 | { |
325 | register CMD *cur = head; |
326 | register CMD **loc; |
327 | register int i; |
328 | register int min = 32767; |
329 | register int max = -32768; |
330 | int origcount = count; |
331 | double value; /* or your money back! */ |
332 | short changed; /* so triple your money back! */ |
333 | |
334 | while (count--) { |
335 | i = (int)str_gnum(cur->c_short); |
336 | value = (double)i; |
337 | if (value != cur->c_short->str_u.str_nval) |
338 | return; /* fractional values--just forget it */ |
339 | changed = i; |
340 | if (changed != i) |
341 | return; /* too big for a short */ |
342 | if (cur->c_slen == O_LE) |
343 | i++; |
344 | else if (cur->c_slen == O_GE) /* we only do < or > here */ |
345 | i--; |
346 | if (i < min) |
347 | min = i; |
348 | if (i > max) |
349 | max = i; |
350 | cur = cur->c_next; |
351 | } |
352 | count = origcount; |
353 | if (max - min > count * 2 + 10) /* too sparse? */ |
354 | return; |
355 | |
356 | /* now make a new head in the exact same spot */ |
357 | New(104,cur, 1, CMD); |
358 | #ifdef STRUCTCOPY |
359 | *cur = *head; |
360 | #else |
361 | Copy(head,cur,1,CMD); |
362 | #endif |
363 | Zero(head,1,CMD); |
364 | head->c_type = C_NSWITCH; |
365 | head->c_next = cur; /* insert new cmd at front of list */ |
366 | head->c_stab = cur->c_stab; |
367 | |
368 | Newz(105,loc, max - min + 3, CMD*); |
369 | loc++; |
03a14243 |
370 | max -= min; |
371 | max++; |
a687059c |
372 | while (count--) { |
373 | i = (int)str_gnum(cur->c_short); |
374 | i -= min; |
a687059c |
375 | switch(cur->c_slen) { |
376 | case O_LE: |
377 | i++; |
378 | case O_LT: |
379 | for (i--; i >= -1; i--) |
380 | if (!loc[i]) |
381 | loc[i] = cur; |
382 | break; |
383 | case O_GE: |
384 | i--; |
385 | case O_GT: |
386 | for (i++; i <= max; i++) |
387 | if (!loc[i]) |
388 | loc[i] = cur; |
389 | break; |
390 | case O_EQ: |
391 | if (!loc[i]) |
392 | loc[i] = cur; |
393 | break; |
394 | } |
395 | cur = cur->c_next; |
396 | } |
397 | loc--; |
398 | min--; |
03a14243 |
399 | max++; |
a687059c |
400 | for (i = 0; i <= max; i++) |
401 | if (!loc[i]) |
402 | loc[i] = cur; |
403 | head->ucmd.scmd.sc_offset = min; |
404 | head->ucmd.scmd.sc_max = max; |
405 | head->ucmd.scmd.sc_next = loc; |
406 | } |
407 | |
408 | CMD * |
409 | append_line(head,tail) |
410 | register CMD *head; |
411 | register CMD *tail; |
412 | { |
413 | if (tail == Nullcmd) |
414 | return head; |
415 | if (!tail->c_head) /* make sure tail is well formed */ |
416 | tail->c_head = tail; |
417 | if (head != Nullcmd) { |
418 | tail = tail->c_head; /* get to start of tail list */ |
419 | if (!head->c_head) |
420 | head->c_head = head; /* start a new head list */ |
421 | while (head->c_next) { |
422 | head->c_next->c_head = head->c_head; |
423 | head = head->c_next; /* get to end of head list */ |
424 | } |
425 | head->c_next = tail; /* link to end of old list */ |
426 | tail->c_head = head->c_head; /* propagate head pointer */ |
427 | } |
428 | while (tail->c_next) { |
429 | tail->c_next->c_head = tail->c_head; |
430 | tail = tail->c_next; |
431 | } |
432 | return tail; |
433 | } |
434 | |
435 | CMD * |
436 | dodb(cur) |
437 | CMD *cur; |
438 | { |
439 | register CMD *cmd; |
440 | register CMD *head = cur->c_head; |
441 | register ARG *arg; |
442 | STR *str; |
443 | |
444 | if (!head) |
445 | head = cur; |
446 | if (!head->c_line) |
447 | return cur; |
448 | str = afetch(lineary,(int)head->c_line,FALSE); |
449 | if (!str || str->str_nok) |
450 | return cur; |
451 | str->str_u.str_nval = (double)head->c_line; |
452 | str->str_nok = 1; |
453 | Newz(106,cmd,1,CMD); |
454 | cmd->c_type = C_EXPR; |
455 | cmd->ucmd.acmd.ac_stab = Nullstab; |
456 | cmd->ucmd.acmd.ac_expr = Nullarg; |
457 | arg = make_op(O_ITEM,1,Nullarg,Nullarg,Nullarg); |
458 | arg[1].arg_type = A_SINGLE; |
459 | arg[1].arg_ptr.arg_str = str_nmake((double)head->c_line); |
460 | cmd->c_expr = make_op(O_SUBR, 2, |
461 | stab2arg(A_WORD,DBstab), |
462 | make_list(arg), |
463 | Nullarg); |
03a14243 |
464 | cmd->c_flags |= CF_COND|CF_DBSUB; |
a687059c |
465 | cmd->c_line = head->c_line; |
466 | cmd->c_label = head->c_label; |
467 | cmd->c_file = filename; |
ff8e2863 |
468 | cmd->c_pack = curpack; |
a687059c |
469 | return append_line(cmd, cur); |
470 | } |
471 | |
472 | CMD * |
473 | make_acmd(type,stab,cond,arg) |
474 | int type; |
475 | STAB *stab; |
476 | ARG *cond; |
477 | ARG *arg; |
478 | { |
479 | register CMD *cmd; |
480 | |
481 | Newz(107,cmd,1,CMD); |
482 | cmd->c_type = type; |
483 | cmd->ucmd.acmd.ac_stab = stab; |
484 | cmd->ucmd.acmd.ac_expr = arg; |
485 | cmd->c_expr = cond; |
486 | if (cond) |
487 | cmd->c_flags |= CF_COND; |
afd9f252 |
488 | if (cmdline == NOLINE) |
ff8e2863 |
489 | cmd->c_line = curcmd->c_line; |
afd9f252 |
490 | else { |
a687059c |
491 | cmd->c_line = cmdline; |
492 | cmdline = NOLINE; |
493 | } |
494 | cmd->c_file = filename; |
ff8e2863 |
495 | cmd->c_pack = curpack; |
a687059c |
496 | if (perldb) |
497 | cmd = dodb(cmd); |
498 | return cmd; |
499 | } |
500 | |
501 | CMD * |
502 | make_ccmd(type,arg,cblock) |
503 | int type; |
504 | ARG *arg; |
505 | struct compcmd cblock; |
506 | { |
507 | register CMD *cmd; |
508 | |
509 | Newz(108,cmd, 1, CMD); |
510 | cmd->c_type = type; |
511 | cmd->c_expr = arg; |
512 | cmd->ucmd.ccmd.cc_true = cblock.comp_true; |
513 | cmd->ucmd.ccmd.cc_alt = cblock.comp_alt; |
514 | if (arg) |
515 | cmd->c_flags |= CF_COND; |
afd9f252 |
516 | if (cmdline == NOLINE) |
ff8e2863 |
517 | cmd->c_line = curcmd->c_line; |
afd9f252 |
518 | else { |
a687059c |
519 | cmd->c_line = cmdline; |
520 | cmdline = NOLINE; |
521 | } |
522 | if (perldb) |
523 | cmd = dodb(cmd); |
524 | return cmd; |
525 | } |
526 | |
527 | CMD * |
528 | make_icmd(type,arg,cblock) |
529 | int type; |
530 | ARG *arg; |
531 | struct compcmd cblock; |
532 | { |
533 | register CMD *cmd; |
534 | register CMD *alt; |
535 | register CMD *cur; |
536 | register CMD *head; |
537 | struct compcmd ncblock; |
538 | |
539 | Newz(109,cmd, 1, CMD); |
540 | head = cmd; |
541 | cmd->c_type = type; |
542 | cmd->c_expr = arg; |
543 | cmd->ucmd.ccmd.cc_true = cblock.comp_true; |
544 | cmd->ucmd.ccmd.cc_alt = cblock.comp_alt; |
545 | if (arg) |
546 | cmd->c_flags |= CF_COND; |
afd9f252 |
547 | if (cmdline == NOLINE) |
ff8e2863 |
548 | cmd->c_line = curcmd->c_line; |
afd9f252 |
549 | else { |
a687059c |
550 | cmd->c_line = cmdline; |
551 | cmdline = NOLINE; |
552 | } |
553 | cur = cmd; |
554 | alt = cblock.comp_alt; |
555 | while (alt && alt->c_type == C_ELSIF) { |
556 | cur = alt; |
557 | alt = alt->ucmd.ccmd.cc_alt; |
558 | } |
559 | if (alt) { /* a real life ELSE at the end? */ |
560 | ncblock.comp_true = alt; |
561 | ncblock.comp_alt = Nullcmd; |
562 | alt = append_line(cur,make_ccmd(C_ELSE,Nullarg,ncblock)); |
563 | cur->ucmd.ccmd.cc_alt = alt; |
564 | } |
565 | else |
566 | alt = cur; /* no ELSE, so cur is proxy ELSE */ |
567 | |
568 | cur = cmd; |
569 | while (cmd) { /* now point everyone at the ELSE */ |
570 | cur = cmd; |
571 | cmd = cur->ucmd.ccmd.cc_alt; |
572 | cur->c_head = head; |
573 | if (cur->c_type == C_ELSIF) |
574 | cur->c_type = C_IF; |
575 | if (cur->c_type == C_IF) |
576 | cur->ucmd.ccmd.cc_alt = alt; |
577 | if (cur == alt) |
578 | break; |
579 | cur->c_next = cmd; |
580 | } |
581 | if (perldb) |
582 | cur = dodb(cur); |
583 | return cur; |
584 | } |
585 | |
586 | void |
587 | opt_arg(cmd,fliporflop,acmd) |
588 | register CMD *cmd; |
589 | int fliporflop; |
590 | int acmd; |
591 | { |
592 | register ARG *arg; |
593 | int opt = CFT_EVAL; |
594 | int sure = 0; |
595 | ARG *arg2; |
596 | int context = 0; /* 0 = normal, 1 = before &&, 2 = before || */ |
597 | int flp = fliporflop; |
598 | |
599 | if (!cmd) |
600 | return; |
601 | if (!(arg = cmd->c_expr)) { |
602 | cmd->c_flags &= ~CF_COND; |
603 | return; |
604 | } |
605 | |
606 | /* Can we turn && and || into if and unless? */ |
607 | |
608 | if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM) && |
609 | (arg->arg_type == O_AND || arg->arg_type == O_OR) ) { |
610 | dehoist(arg,1); |
611 | arg[2].arg_type &= A_MASK; /* don't suppress eval */ |
612 | dehoist(arg,2); |
613 | cmd->ucmd.acmd.ac_expr = arg[2].arg_ptr.arg_arg; |
614 | cmd->c_expr = arg[1].arg_ptr.arg_arg; |
615 | if (arg->arg_type == O_OR) |
616 | cmd->c_flags ^= CF_INVERT; /* || is like unless */ |
617 | arg->arg_len = 0; |
618 | free_arg(arg); |
619 | arg = cmd->c_expr; |
620 | } |
621 | |
622 | /* Turn "if (!expr)" into "unless (expr)" */ |
623 | |
624 | if (!(cmd->c_flags & CF_TERM)) { /* unless return value wanted */ |
625 | while (arg->arg_type == O_NOT) { |
626 | dehoist(arg,1); |
627 | cmd->c_flags ^= CF_INVERT; /* flip sense of cmd */ |
628 | cmd->c_expr = arg[1].arg_ptr.arg_arg; /* hoist the rest of expr */ |
629 | free_arg(arg); |
630 | arg = cmd->c_expr; /* here we go again */ |
631 | } |
632 | } |
633 | |
634 | if (!arg->arg_len) { /* sanity check */ |
635 | cmd->c_flags |= opt; |
636 | return; |
637 | } |
638 | |
639 | /* for "cond .. cond" we set up for the initial check */ |
640 | |
641 | if (arg->arg_type == O_FLIP) |
642 | context |= 4; |
643 | |
644 | /* for "cond && expr" and "cond || expr" we can ignore expr, sort of */ |
645 | |
646 | morecontext: |
647 | if (arg->arg_type == O_AND) |
648 | context |= 1; |
649 | else if (arg->arg_type == O_OR) |
650 | context |= 2; |
651 | if (context && (arg[flp].arg_type & A_MASK) == A_EXPR) { |
652 | arg = arg[flp].arg_ptr.arg_arg; |
653 | flp = 1; |
654 | if (arg->arg_type == O_AND || arg->arg_type == O_OR) |
655 | goto morecontext; |
656 | } |
657 | if ((context & 3) == 3) |
658 | return; |
659 | |
660 | if (arg[flp].arg_flags & (AF_PRE|AF_POST)) { |
661 | cmd->c_flags |= opt; |
0f85fab0 |
662 | if (acmd && !cmd->ucmd.acmd.ac_expr && !(cmd->c_flags & CF_TERM)) { |
663 | arg[flp].arg_flags &= ~AF_POST; /* prefer ++$foo to $foo++ */ |
664 | arg[flp].arg_flags |= AF_PRE; /* if value not wanted */ |
665 | } |
a687059c |
666 | return; /* side effect, can't optimize */ |
667 | } |
668 | |
669 | if (arg->arg_type == O_ITEM || arg->arg_type == O_FLIP || |
670 | arg->arg_type == O_AND || arg->arg_type == O_OR) { |
671 | if ((arg[flp].arg_type & A_MASK) == A_SINGLE) { |
672 | opt = (str_true(arg[flp].arg_ptr.arg_str) ? CFT_TRUE : CFT_FALSE); |
673 | cmd->c_short = str_smake(arg[flp].arg_ptr.arg_str); |
674 | goto literal; |
675 | } |
676 | else if ((arg[flp].arg_type & A_MASK) == A_STAB || |
677 | (arg[flp].arg_type & A_MASK) == A_LVAL) { |
678 | cmd->c_stab = arg[flp].arg_ptr.arg_stab; |
679 | opt = CFT_REG; |
680 | literal: |
681 | if (!context) { /* no && or ||? */ |
682 | free_arg(arg); |
683 | cmd->c_expr = Nullarg; |
684 | } |
685 | if (!(context & 1)) |
686 | cmd->c_flags |= CF_EQSURE; |
687 | if (!(context & 2)) |
688 | cmd->c_flags |= CF_NESURE; |
689 | } |
690 | } |
691 | else if (arg->arg_type == O_MATCH || arg->arg_type == O_SUBST || |
692 | arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) { |
693 | if ((arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) && |
694 | (arg[2].arg_type & A_MASK) == A_SPAT && |
695 | arg[2].arg_ptr.arg_spat->spat_short ) { |
696 | cmd->c_stab = arg[1].arg_ptr.arg_stab; |
697 | cmd->c_short = str_smake(arg[2].arg_ptr.arg_spat->spat_short); |
698 | cmd->c_slen = arg[2].arg_ptr.arg_spat->spat_slen; |
699 | if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ALL && |
700 | !(arg[2].arg_ptr.arg_spat->spat_flags & SPAT_ONCE) && |
701 | (arg->arg_type == O_MATCH || arg->arg_type == O_NMATCH) ) |
702 | sure |= CF_EQSURE; /* (SUBST must be forced even */ |
703 | /* if we know it will work.) */ |
704 | if (arg->arg_type != O_SUBST) { |
705 | arg[2].arg_ptr.arg_spat->spat_short = Nullstr; |
706 | arg[2].arg_ptr.arg_spat->spat_slen = 0; /* only one chk */ |
707 | } |
708 | sure |= CF_NESURE; /* normally only sure if it fails */ |
709 | if (arg->arg_type == O_NMATCH || arg->arg_type == O_NSUBST) |
710 | cmd->c_flags |= CF_FIRSTNEG; |
711 | if (context & 1) { /* only sure if thing is false */ |
712 | if (cmd->c_flags & CF_FIRSTNEG) |
713 | sure &= ~CF_NESURE; |
714 | else |
715 | sure &= ~CF_EQSURE; |
716 | } |
717 | else if (context & 2) { /* only sure if thing is true */ |
718 | if (cmd->c_flags & CF_FIRSTNEG) |
719 | sure &= ~CF_EQSURE; |
720 | else |
721 | sure &= ~CF_NESURE; |
722 | } |
723 | if (sure & (CF_EQSURE|CF_NESURE)) { /* if we know anything*/ |
724 | if (arg[2].arg_ptr.arg_spat->spat_flags & SPAT_SCANFIRST) |
725 | opt = CFT_SCAN; |
726 | else |
727 | opt = CFT_ANCHOR; |
728 | if (sure == (CF_EQSURE|CF_NESURE) /* really sure? */ |
729 | && arg->arg_type == O_MATCH |
730 | && context & 4 |
731 | && fliporflop == 1) { |
732 | spat_free(arg[2].arg_ptr.arg_spat); |
733 | arg[2].arg_ptr.arg_spat = Nullspat; /* don't do twice */ |
734 | } |
735 | cmd->c_flags |= sure; |
736 | } |
737 | } |
738 | } |
739 | else if (arg->arg_type == O_SEQ || arg->arg_type == O_SNE || |
740 | arg->arg_type == O_SLT || arg->arg_type == O_SGT) { |
741 | if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) { |
742 | if (arg[2].arg_type == A_SINGLE) { |
ff8e2863 |
743 | char *junk = str_get(arg[2].arg_ptr.arg_str); |
744 | |
a687059c |
745 | cmd->c_stab = arg[1].arg_ptr.arg_stab; |
746 | cmd->c_short = str_smake(arg[2].arg_ptr.arg_str); |
747 | cmd->c_slen = cmd->c_short->str_cur+1; |
748 | switch (arg->arg_type) { |
749 | case O_SLT: case O_SGT: |
750 | sure |= CF_EQSURE; |
751 | cmd->c_flags |= CF_FIRSTNEG; |
752 | break; |
753 | case O_SNE: |
754 | cmd->c_flags |= CF_FIRSTNEG; |
755 | /* FALL THROUGH */ |
756 | case O_SEQ: |
757 | sure |= CF_NESURE|CF_EQSURE; |
758 | break; |
759 | } |
760 | if (context & 1) { /* only sure if thing is false */ |
761 | if (cmd->c_flags & CF_FIRSTNEG) |
762 | sure &= ~CF_NESURE; |
763 | else |
764 | sure &= ~CF_EQSURE; |
765 | } |
766 | else if (context & 2) { /* only sure if thing is true */ |
767 | if (cmd->c_flags & CF_FIRSTNEG) |
768 | sure &= ~CF_EQSURE; |
769 | else |
770 | sure &= ~CF_NESURE; |
771 | } |
772 | if (sure & (CF_EQSURE|CF_NESURE)) { |
773 | opt = CFT_STROP; |
774 | cmd->c_flags |= sure; |
775 | } |
776 | } |
777 | } |
778 | } |
779 | else if (arg->arg_type == O_EQ || arg->arg_type == O_NE || |
780 | arg->arg_type == O_LE || arg->arg_type == O_GE || |
781 | arg->arg_type == O_LT || arg->arg_type == O_GT) { |
782 | if (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) { |
783 | if (arg[2].arg_type == A_SINGLE) { |
784 | cmd->c_stab = arg[1].arg_ptr.arg_stab; |
785 | if (dowarn) { |
786 | STR *str = arg[2].arg_ptr.arg_str; |
787 | |
788 | if ((!str->str_nok && !looks_like_number(str))) |
789 | warn("Possible use of == on string value"); |
790 | } |
791 | cmd->c_short = str_nmake(str_gnum(arg[2].arg_ptr.arg_str)); |
792 | cmd->c_slen = arg->arg_type; |
793 | sure |= CF_NESURE|CF_EQSURE; |
794 | if (context & 1) { /* only sure if thing is false */ |
795 | sure &= ~CF_EQSURE; |
796 | } |
797 | else if (context & 2) { /* only sure if thing is true */ |
798 | sure &= ~CF_NESURE; |
799 | } |
800 | if (sure & (CF_EQSURE|CF_NESURE)) { |
801 | opt = CFT_NUMOP; |
802 | cmd->c_flags |= sure; |
803 | } |
804 | } |
805 | } |
806 | } |
807 | else if (arg->arg_type == O_ASSIGN && |
808 | (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) && |
809 | arg[1].arg_ptr.arg_stab == defstab && |
810 | arg[2].arg_type == A_EXPR ) { |
811 | arg2 = arg[2].arg_ptr.arg_arg; |
812 | if (arg2->arg_type == O_ITEM && arg2[1].arg_type == A_READ) { |
813 | opt = CFT_GETS; |
814 | cmd->c_stab = arg2[1].arg_ptr.arg_stab; |
815 | if (!(stab_io(arg2[1].arg_ptr.arg_stab)->flags & IOF_ARGV)) { |
816 | free_arg(arg2); |
817 | free_arg(arg); |
818 | cmd->c_expr = Nullarg; |
819 | } |
820 | } |
821 | } |
822 | else if (arg->arg_type == O_CHOP && |
823 | (arg[1].arg_type == A_STAB || arg[1].arg_type == A_LVAL) ) { |
824 | opt = CFT_CHOP; |
825 | cmd->c_stab = arg[1].arg_ptr.arg_stab; |
826 | free_arg(arg); |
827 | cmd->c_expr = Nullarg; |
828 | } |
829 | if (context & 4) |
830 | opt |= CF_FLIP; |
831 | cmd->c_flags |= opt; |
832 | |
833 | if (cmd->c_flags & CF_FLIP) { |
834 | if (fliporflop == 1) { |
835 | arg = cmd->c_expr; /* get back to O_FLIP arg */ |
836 | New(110,arg[3].arg_ptr.arg_cmd, 1, CMD); |
837 | Copy(cmd, arg[3].arg_ptr.arg_cmd, 1, CMD); |
838 | New(111,arg[4].arg_ptr.arg_cmd,1,CMD); |
839 | Copy(cmd, arg[4].arg_ptr.arg_cmd, 1, CMD); |
840 | opt_arg(arg[4].arg_ptr.arg_cmd,2,acmd); |
841 | arg->arg_len = 2; /* this is a lie */ |
842 | } |
843 | else { |
844 | if ((opt & CF_OPTIMIZE) == CFT_EVAL) |
845 | cmd->c_flags = (cmd->c_flags & ~CF_OPTIMIZE) | CFT_UNFLIP; |
846 | } |
847 | } |
848 | } |
849 | |
850 | CMD * |
851 | add_label(lbl,cmd) |
852 | char *lbl; |
853 | register CMD *cmd; |
854 | { |
855 | if (cmd) |
856 | cmd->c_label = lbl; |
857 | return cmd; |
858 | } |
859 | |
860 | CMD * |
861 | addcond(cmd, arg) |
862 | register CMD *cmd; |
863 | register ARG *arg; |
864 | { |
865 | cmd->c_expr = arg; |
866 | cmd->c_flags |= CF_COND; |
867 | return cmd; |
868 | } |
869 | |
870 | CMD * |
871 | addloop(cmd, arg) |
872 | register CMD *cmd; |
873 | register ARG *arg; |
874 | { |
875 | void while_io(); |
876 | |
877 | cmd->c_expr = arg; |
878 | cmd->c_flags |= CF_COND|CF_LOOP; |
879 | |
880 | if (!(cmd->c_flags & CF_INVERT)) |
881 | while_io(cmd); /* add $_ =, if necessary */ |
882 | |
883 | if (cmd->c_type == C_BLOCK) |
884 | cmd->c_flags &= ~CF_COND; |
885 | else { |
886 | arg = cmd->ucmd.acmd.ac_expr; |
887 | if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_CMD) |
888 | cmd->c_flags &= ~CF_COND; /* "do {} while" happens at least once */ |
889 | if (arg && arg->arg_type == O_SUBR) |
890 | cmd->c_flags &= ~CF_COND; /* likewise for "do subr() while" */ |
891 | } |
892 | return cmd; |
893 | } |
894 | |
895 | CMD * |
896 | invert(cmd) |
03a14243 |
897 | CMD *cmd; |
a687059c |
898 | { |
03a14243 |
899 | register CMD *targ = cmd; |
900 | if (targ->c_head) |
901 | targ = targ->c_head; |
902 | if (targ->c_flags & CF_DBSUB) |
903 | targ = targ->c_next; |
904 | targ->c_flags ^= CF_INVERT; |
a687059c |
905 | return cmd; |
906 | } |
907 | |
908 | yyerror(s) |
909 | char *s; |
910 | { |
911 | char tmpbuf[258]; |
912 | char tmp2buf[258]; |
913 | char *tname = tmpbuf; |
914 | |
915 | if (bufptr > oldoldbufptr && bufptr - oldoldbufptr < 200 && |
916 | oldoldbufptr != oldbufptr && oldbufptr != bufptr) { |
917 | while (isspace(*oldoldbufptr)) |
918 | oldoldbufptr++; |
919 | strncpy(tmp2buf, oldoldbufptr, bufptr - oldoldbufptr); |
920 | tmp2buf[bufptr - oldoldbufptr] = '\0'; |
921 | sprintf(tname,"next 2 tokens \"%s\"",tmp2buf); |
922 | } |
923 | else if (bufptr > oldbufptr && bufptr - oldbufptr < 200 && |
924 | oldbufptr != bufptr) { |
925 | while (isspace(*oldbufptr)) |
926 | oldbufptr++; |
927 | strncpy(tmp2buf, oldbufptr, bufptr - oldbufptr); |
928 | tmp2buf[bufptr - oldbufptr] = '\0'; |
929 | sprintf(tname,"next token \"%s\"",tmp2buf); |
930 | } |
931 | else if (yychar > 256) |
932 | tname = "next token ???"; |
933 | else if (!yychar) |
934 | (void)strcpy(tname,"at EOF"); |
935 | else if (yychar < 32) |
936 | (void)sprintf(tname,"next char ^%c",yychar+64); |
937 | else if (yychar == 127) |
938 | (void)strcpy(tname,"at EOF"); |
939 | else |
940 | (void)sprintf(tname,"next char %c",yychar); |
941 | (void)sprintf(buf, "%s in file %s at line %d, %s\n", |
ff8e2863 |
942 | s,filename,curcmd->c_line,tname); |
943 | if (curcmd->c_line == multi_end && multi_start < multi_end) |
a687059c |
944 | sprintf(buf+strlen(buf), |
945 | " (Might be a runaway multi-line %c%c string starting on line %d)\n", |
946 | multi_open,multi_close,multi_start); |
947 | if (in_eval) |
948 | str_cat(stab_val(stabent("@",TRUE)),buf); |
949 | else |
950 | fputs(buf,stderr); |
951 | if (++error_count >= 10) |
ff8e2863 |
952 | fatal("%s has too many errors.\n", filename); |
a687059c |
953 | } |
954 | |
955 | void |
956 | while_io(cmd) |
957 | register CMD *cmd; |
958 | { |
959 | register ARG *arg = cmd->c_expr; |
960 | STAB *asgnstab; |
961 | |
962 | /* hoist "while (<channel>)" up into command block */ |
963 | |
964 | if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_READ) { |
965 | cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ |
966 | cmd->c_flags |= CFT_GETS; /* and set it to do the input */ |
967 | cmd->c_stab = arg[1].arg_ptr.arg_stab; |
968 | if (stab_io(arg[1].arg_ptr.arg_stab)->flags & IOF_ARGV) { |
969 | cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$_ =" */ |
970 | stab2arg(A_LVAL,defstab), arg, Nullarg)); |
971 | } |
972 | else { |
973 | free_arg(arg); |
974 | cmd->c_expr = Nullarg; |
975 | } |
976 | } |
977 | else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_INDREAD) { |
978 | cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ |
979 | cmd->c_flags |= CFT_INDGETS; /* and set it to do the input */ |
980 | cmd->c_stab = arg[1].arg_ptr.arg_stab; |
981 | free_arg(arg); |
982 | cmd->c_expr = Nullarg; |
983 | } |
984 | else if (arg && arg->arg_type == O_ITEM && arg[1].arg_type == A_GLOB) { |
985 | if ((cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) |
986 | asgnstab = cmd->c_stab; |
987 | else |
988 | asgnstab = defstab; |
989 | cmd->c_expr = l(make_op(O_ASSIGN, 2, /* fake up "$foo =" */ |
990 | stab2arg(A_LVAL,asgnstab), arg, Nullarg)); |
991 | cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ |
992 | } |
993 | } |
994 | |
995 | CMD * |
996 | wopt(cmd) |
997 | register CMD *cmd; |
998 | { |
999 | register CMD *tail; |
1000 | CMD *newtail; |
1001 | register int i; |
1002 | |
1003 | if (cmd->c_expr && (cmd->c_flags & CF_OPTIMIZE) == CFT_FALSE) |
1004 | opt_arg(cmd,1, cmd->c_type == C_EXPR); |
1005 | |
1006 | while_io(cmd); /* add $_ =, if necessary */ |
1007 | |
1008 | /* First find the end of the true list */ |
1009 | |
1010 | tail = cmd->ucmd.ccmd.cc_true; |
1011 | if (tail == Nullcmd) |
1012 | return cmd; |
1013 | New(112,newtail, 1, CMD); /* guaranteed continue */ |
1014 | for (;;) { |
1015 | /* optimize "next" to point directly to continue block */ |
1016 | if (tail->c_type == C_EXPR && |
1017 | tail->ucmd.acmd.ac_expr && |
1018 | tail->ucmd.acmd.ac_expr->arg_type == O_NEXT && |
1019 | (tail->ucmd.acmd.ac_expr->arg_len == 0 || |
1020 | (cmd->c_label && |
1021 | strEQ(cmd->c_label, |
1022 | tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) ))) |
1023 | { |
1024 | arg_free(tail->ucmd.acmd.ac_expr); |
1025 | tail->c_type = C_NEXT; |
1026 | if (cmd->ucmd.ccmd.cc_alt != Nullcmd) |
1027 | tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt; |
1028 | else |
1029 | tail->ucmd.ccmd.cc_alt = newtail; |
1030 | tail->ucmd.ccmd.cc_true = Nullcmd; |
1031 | } |
1032 | else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) { |
1033 | if (cmd->ucmd.ccmd.cc_alt != Nullcmd) |
1034 | tail->ucmd.ccmd.cc_alt = cmd->ucmd.ccmd.cc_alt; |
1035 | else |
1036 | tail->ucmd.ccmd.cc_alt = newtail; |
1037 | } |
1038 | else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) { |
1039 | if (cmd->ucmd.ccmd.cc_alt != Nullcmd) { |
1040 | for (i = tail->ucmd.scmd.sc_max; i >= 0; i--) |
1041 | if (!tail->ucmd.scmd.sc_next[i]) |
1042 | tail->ucmd.scmd.sc_next[i] = cmd->ucmd.ccmd.cc_alt; |
1043 | } |
1044 | else { |
1045 | for (i = tail->ucmd.scmd.sc_max; i >= 0; i--) |
1046 | if (!tail->ucmd.scmd.sc_next[i]) |
1047 | tail->ucmd.scmd.sc_next[i] = newtail; |
1048 | } |
1049 | } |
1050 | |
1051 | if (!tail->c_next) |
1052 | break; |
1053 | tail = tail->c_next; |
1054 | } |
1055 | |
1056 | /* if there's a continue block, link it to true block and find end */ |
1057 | |
1058 | if (cmd->ucmd.ccmd.cc_alt != Nullcmd) { |
1059 | tail->c_next = cmd->ucmd.ccmd.cc_alt; |
1060 | tail = tail->c_next; |
1061 | for (;;) { |
1062 | /* optimize "next" to point directly to continue block */ |
1063 | if (tail->c_type == C_EXPR && |
1064 | tail->ucmd.acmd.ac_expr && |
1065 | tail->ucmd.acmd.ac_expr->arg_type == O_NEXT && |
1066 | (tail->ucmd.acmd.ac_expr->arg_len == 0 || |
1067 | (cmd->c_label && |
1068 | strEQ(cmd->c_label, |
1069 | tail->ucmd.acmd.ac_expr[1].arg_ptr.arg_str->str_ptr) ))) |
1070 | { |
1071 | arg_free(tail->ucmd.acmd.ac_expr); |
1072 | tail->c_type = C_NEXT; |
1073 | tail->ucmd.ccmd.cc_alt = newtail; |
1074 | tail->ucmd.ccmd.cc_true = Nullcmd; |
1075 | } |
1076 | else if (tail->c_type == C_IF && !tail->ucmd.ccmd.cc_alt) { |
1077 | tail->ucmd.ccmd.cc_alt = newtail; |
1078 | } |
1079 | else if (tail->c_type == C_CSWITCH || tail->c_type == C_NSWITCH) { |
1080 | for (i = tail->ucmd.scmd.sc_max; i >= 0; i--) |
1081 | if (!tail->ucmd.scmd.sc_next[i]) |
1082 | tail->ucmd.scmd.sc_next[i] = newtail; |
1083 | } |
1084 | |
1085 | if (!tail->c_next) |
1086 | break; |
1087 | tail = tail->c_next; |
1088 | } |
1089 | for ( ; tail->c_next; tail = tail->c_next) ; |
1090 | } |
1091 | |
1092 | /* Here's the real trick: link the end of the list back to the beginning, |
1093 | * inserting a "last" block to break out of the loop. This saves one or |
1094 | * two procedure calls every time through the loop, because of how cmd_exec |
1095 | * does tail recursion. |
1096 | */ |
1097 | |
1098 | tail->c_next = newtail; |
1099 | tail = newtail; |
1100 | if (!cmd->ucmd.ccmd.cc_alt) |
1101 | cmd->ucmd.ccmd.cc_alt = tail; /* every loop has a continue now */ |
1102 | |
1103 | #ifndef lint |
1104 | (void)bcopy((char *)cmd, (char *)tail, sizeof(CMD)); |
1105 | #endif |
1106 | tail->c_type = C_EXPR; |
1107 | tail->c_flags ^= CF_INVERT; /* turn into "last unless" */ |
1108 | tail->c_next = tail->ucmd.ccmd.cc_true; /* loop directly back to top */ |
1109 | tail->ucmd.acmd.ac_expr = make_op(O_LAST,0,Nullarg,Nullarg,Nullarg); |
1110 | tail->ucmd.acmd.ac_stab = Nullstab; |
1111 | return cmd; |
1112 | } |
1113 | |
1114 | CMD * |
1115 | over(eachstab,cmd) |
1116 | STAB *eachstab; |
1117 | register CMD *cmd; |
1118 | { |
1119 | /* hoist "for $foo (@bar)" up into command block */ |
1120 | |
1121 | cmd->c_flags &= ~CF_OPTIMIZE; /* clear optimization type */ |
1122 | cmd->c_flags |= CFT_ARRAY; /* and set it to do the iteration */ |
1123 | cmd->c_stab = eachstab; |
0d3e774c |
1124 | cmd->c_short = str_new(0); /* just to save a field in struct cmd */ |
1125 | cmd->c_short->str_u.str_useful = -1; |
a687059c |
1126 | |
1127 | return cmd; |
1128 | } |
1129 | |
1130 | cmd_free(cmd) |
1131 | register CMD *cmd; |
1132 | { |
1133 | register CMD *tofree; |
1134 | register CMD *head = cmd; |
1135 | |
1136 | while (cmd) { |
1137 | if (cmd->c_type != C_WHILE) { /* WHILE block is duplicated */ |
1138 | if (cmd->c_label) |
1139 | Safefree(cmd->c_label); |
1140 | if (cmd->c_short) |
1141 | str_free(cmd->c_short); |
1142 | if (cmd->c_spat) |
1143 | spat_free(cmd->c_spat); |
1144 | if (cmd->c_expr) |
1145 | arg_free(cmd->c_expr); |
1146 | } |
1147 | switch (cmd->c_type) { |
1148 | case C_WHILE: |
1149 | case C_BLOCK: |
1150 | case C_ELSE: |
1151 | case C_IF: |
1152 | if (cmd->ucmd.ccmd.cc_true) |
1153 | cmd_free(cmd->ucmd.ccmd.cc_true); |
1154 | break; |
1155 | case C_EXPR: |
1156 | if (cmd->ucmd.acmd.ac_expr) |
1157 | arg_free(cmd->ucmd.acmd.ac_expr); |
1158 | break; |
1159 | } |
1160 | tofree = cmd; |
1161 | cmd = cmd->c_next; |
ff8e2863 |
1162 | if (tofree != head) /* to get Saber to shut up */ |
1163 | Safefree(tofree); |
a687059c |
1164 | if (cmd && cmd == head) /* reached end of while loop */ |
1165 | break; |
1166 | } |
ff8e2863 |
1167 | Safefree(head); |
a687059c |
1168 | } |
1169 | |
1170 | arg_free(arg) |
1171 | register ARG *arg; |
1172 | { |
1173 | register int i; |
1174 | |
1175 | for (i = 1; i <= arg->arg_len; i++) { |
1176 | switch (arg[i].arg_type & A_MASK) { |
1177 | case A_NULL: |
1178 | break; |
1179 | case A_LEXPR: |
1180 | if (arg->arg_type == O_AASSIGN && |
1181 | arg[i].arg_ptr.arg_arg->arg_type == O_LARRAY) { |
1182 | char *name = |
1183 | stab_name(arg[i].arg_ptr.arg_arg[1].arg_ptr.arg_stab); |
1184 | |
1185 | if (strnEQ("_GEN_",name, 5)) /* array for foreach */ |
1186 | hdelete(defstash,name,strlen(name)); |
1187 | } |
1188 | /* FALL THROUGH */ |
1189 | case A_EXPR: |
1190 | arg_free(arg[i].arg_ptr.arg_arg); |
1191 | break; |
1192 | case A_CMD: |
1193 | cmd_free(arg[i].arg_ptr.arg_cmd); |
1194 | break; |
1195 | case A_WORD: |
1196 | case A_STAB: |
1197 | case A_LVAL: |
1198 | case A_READ: |
1199 | case A_GLOB: |
1200 | case A_ARYLEN: |
1201 | case A_LARYLEN: |
1202 | case A_ARYSTAB: |
1203 | case A_LARYSTAB: |
1204 | break; |
1205 | case A_SINGLE: |
1206 | case A_DOUBLE: |
1207 | case A_BACKTICK: |
1208 | str_free(arg[i].arg_ptr.arg_str); |
1209 | break; |
1210 | case A_SPAT: |
1211 | spat_free(arg[i].arg_ptr.arg_spat); |
1212 | break; |
1213 | } |
1214 | } |
1215 | free_arg(arg); |
1216 | } |
1217 | |
1218 | spat_free(spat) |
1219 | register SPAT *spat; |
1220 | { |
1221 | register SPAT *sp; |
1222 | HENT *entry; |
1223 | |
1224 | if (spat->spat_runtime) |
1225 | arg_free(spat->spat_runtime); |
1226 | if (spat->spat_repl) { |
1227 | arg_free(spat->spat_repl); |
1228 | } |
1229 | if (spat->spat_short) { |
1230 | str_free(spat->spat_short); |
1231 | } |
1232 | if (spat->spat_regexp) { |
1233 | regfree(spat->spat_regexp); |
1234 | } |
1235 | |
1236 | /* now unlink from spat list */ |
1237 | |
1238 | for (entry = defstash->tbl_array['_']; entry; entry = entry->hent_next) { |
1239 | register HASH *stash; |
1240 | STAB *stab = (STAB*)entry->hent_val; |
1241 | |
1242 | if (!stab) |
1243 | continue; |
1244 | stash = stab_hash(stab); |
1245 | if (!stash || stash->tbl_spatroot == Null(SPAT*)) |
1246 | continue; |
1247 | if (stash->tbl_spatroot == spat) |
1248 | stash->tbl_spatroot = spat->spat_next; |
1249 | else { |
1250 | for (sp = stash->tbl_spatroot; |
1251 | sp && sp->spat_next != spat; |
1252 | sp = sp->spat_next) |
1253 | ; |
1254 | if (sp) |
1255 | sp->spat_next = spat->spat_next; |
1256 | } |
1257 | } |
1258 | Safefree(spat); |
1259 | } |
1260 | |
1261 | /* Recursively descend a command sequence and push the address of any string |
1262 | * that needs saving on recursion onto the tosave array. |
1263 | */ |
1264 | |
1265 | static int |
1266 | cmd_tosave(cmd,willsave) |
1267 | register CMD *cmd; |
1268 | int willsave; /* willsave passes down the tree */ |
1269 | { |
1270 | register CMD *head = cmd; |
1271 | int shouldsave = FALSE; /* shouldsave passes up the tree */ |
1272 | int tmpsave; |
1273 | register CMD *lastcmd = Nullcmd; |
1274 | |
1275 | while (cmd) { |
1276 | if (cmd->c_spat) |
1277 | shouldsave |= spat_tosave(cmd->c_spat); |
1278 | if (cmd->c_expr) |
1279 | shouldsave |= arg_tosave(cmd->c_expr,willsave); |
1280 | switch (cmd->c_type) { |
1281 | case C_WHILE: |
1282 | if (cmd->ucmd.ccmd.cc_true) { |
1283 | tmpsave = cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave); |
1284 | |
1285 | /* Here we check to see if the temporary array generated for |
1286 | * a foreach needs to be localized because of recursion. |
1287 | */ |
663a0e37 |
1288 | if (tmpsave && (cmd->c_flags & CF_OPTIMIZE) == CFT_ARRAY) { |
1289 | if (lastcmd && |
1290 | lastcmd->c_type == C_EXPR && |
1291 | lastcmd->ucmd.acmd.ac_expr) { |
1292 | ARG *arg = lastcmd->ucmd.acmd.ac_expr; |
1293 | |
1294 | if (arg->arg_type == O_ASSIGN && |
1295 | arg[1].arg_type == A_LEXPR && |
1296 | arg[1].arg_ptr.arg_arg->arg_type == O_LARRAY && |
1297 | strnEQ("_GEN_", |
1298 | stab_name( |
1299 | arg[1].arg_ptr.arg_arg[1].arg_ptr.arg_stab), |
1300 | 5)) { /* array generated for foreach */ |
1301 | (void)localize(arg[1].arg_ptr.arg_arg); |
1302 | } |
a687059c |
1303 | } |
663a0e37 |
1304 | |
1305 | /* in any event, save the iterator */ |
1306 | |
1307 | (void)apush(tosave,cmd->c_short); |
a687059c |
1308 | } |
1309 | shouldsave |= tmpsave; |
1310 | } |
1311 | break; |
1312 | case C_BLOCK: |
1313 | case C_ELSE: |
1314 | case C_IF: |
1315 | if (cmd->ucmd.ccmd.cc_true) |
1316 | shouldsave |= cmd_tosave(cmd->ucmd.ccmd.cc_true,willsave); |
1317 | break; |
1318 | case C_EXPR: |
1319 | if (cmd->ucmd.acmd.ac_expr) |
1320 | shouldsave |= arg_tosave(cmd->ucmd.acmd.ac_expr,willsave); |
1321 | break; |
1322 | } |
1323 | lastcmd = cmd; |
1324 | cmd = cmd->c_next; |
1325 | if (cmd && cmd == head) /* reached end of while loop */ |
1326 | break; |
1327 | } |
1328 | return shouldsave; |
1329 | } |
1330 | |
1331 | static int |
1332 | arg_tosave(arg,willsave) |
1333 | register ARG *arg; |
1334 | int willsave; |
1335 | { |
1336 | register int i; |
1337 | int shouldsave = FALSE; |
1338 | |
1339 | for (i = arg->arg_len; i >= 1; i--) { |
1340 | switch (arg[i].arg_type & A_MASK) { |
1341 | case A_NULL: |
1342 | break; |
1343 | case A_LEXPR: |
1344 | case A_EXPR: |
1345 | shouldsave |= arg_tosave(arg[i].arg_ptr.arg_arg,shouldsave); |
1346 | break; |
1347 | case A_CMD: |
1348 | shouldsave |= cmd_tosave(arg[i].arg_ptr.arg_cmd,shouldsave); |
1349 | break; |
1350 | case A_WORD: |
1351 | case A_STAB: |
1352 | case A_LVAL: |
1353 | case A_READ: |
1354 | case A_GLOB: |
1355 | case A_ARYLEN: |
1356 | case A_SINGLE: |
1357 | case A_DOUBLE: |
1358 | case A_BACKTICK: |
1359 | break; |
1360 | case A_SPAT: |
1361 | shouldsave |= spat_tosave(arg[i].arg_ptr.arg_spat); |
1362 | break; |
1363 | } |
1364 | } |
1365 | switch (arg->arg_type) { |
1366 | case O_RETURN: |
1367 | saw_return = TRUE; |
1368 | break; |
1369 | case O_EVAL: |
1370 | case O_SUBR: |
1371 | shouldsave = TRUE; |
1372 | break; |
1373 | } |
1374 | if (willsave) |
1375 | (void)apush(tosave,arg->arg_ptr.arg_str); |
1376 | return shouldsave; |
1377 | } |
1378 | |
1379 | static int |
1380 | spat_tosave(spat) |
1381 | register SPAT *spat; |
1382 | { |
1383 | int shouldsave = FALSE; |
1384 | |
1385 | if (spat->spat_runtime) |
1386 | shouldsave |= arg_tosave(spat->spat_runtime,FALSE); |
1387 | if (spat->spat_repl) { |
1388 | shouldsave |= arg_tosave(spat->spat_repl,FALSE); |
1389 | } |
1390 | |
1391 | return shouldsave; |
1392 | } |
1393 | |