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