1 #include "rc.h"
2 #include "io.h"
3 #include "exec.h"
4 #include "fns.h"
5
6 #define c0 t->child[0]
7 #define c1 t->child[1]
8 #define c2 t->child[2]
9 int codep, ncode;
10 #define emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
11 #define emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
12 #define emits(x) ((codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
13 void stuffdot(int);
14 char *fnstr(tree*);
15 void outcode(tree*, int);
16 void codeswitch(tree*, int);
17 int iscase(tree*);
18 code *codecopy(code*);
19 void codefree(code*);
20
21 int
morecode(void)22 morecode(void)
23 {
24 ncode+=100;
25 codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
26 if(codebuf==0)
27 panic("Can't realloc %d bytes in morecode!",
28 ncode*sizeof codebuf[0]);
29 return 0;
30 }
31
32 void
stuffdot(int a)33 stuffdot(int a)
34 {
35 if(a<0 || codep<=a)
36 panic("Bad address %d in stuffdot", a);
37 codebuf[a].i = codep;
38 }
39
40 int
compile(tree * t)41 compile(tree *t)
42 {
43 ncode = 100;
44 codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
45 codep = 0;
46 emiti(0); /* reference count */
47 outcode(t, flag['e']?1:0);
48 if(nerror){
49 efree((char *)codebuf);
50 return 0;
51 }
52 readhere();
53 emitf(Xreturn);
54 emitf(0);
55 return 1;
56 }
57
58 void
cleanhere(char * f)59 cleanhere(char *f)
60 {
61 emitf(Xdelhere);
62 emits(strdup(f));
63 }
64
65 char*
fnstr(tree * t)66 fnstr(tree *t)
67 {
68 io *f = openstr();
69 void *v;
70 extern char nl;
71 char svnl = nl;
72
73 nl = ';';
74 pfmt(f, "%t", t);
75 nl = svnl;
76 v = f->strp;
77 f->strp = 0;
78 closeio(f);
79 return v;
80 }
81
82 void
outcode(tree * t,int eflag)83 outcode(tree *t, int eflag)
84 {
85 int p, q;
86 tree *tt;
87 char *ifs;
88
89 if(t==0)
90 return;
91 if(t->type!=NOT && t->type!=';')
92 runq->iflast = 0;
93 switch(t->type){
94 default:
95 pfmt(err, "bad type %d in outcode\n", t->type);
96 break;
97 case '$':
98 emitf(Xmark);
99 outcode(c0, eflag);
100 emitf(Xdol);
101 break;
102 case '"':
103 emitf(Xmark);
104 outcode(c0, eflag);
105 emitf(Xqdol);
106 break;
107 case SUB:
108 emitf(Xmark);
109 outcode(c0, eflag);
110 emitf(Xmark);
111 outcode(c1, eflag);
112 emitf(Xsub);
113 break;
114 case '&':
115 emitf(Xasync);
116 if(havefork){
117 p = emiti(0);
118 outcode(c0, eflag);
119 emitf(Xexit);
120 stuffdot(p);
121 } else
122 emits(fnstr(c0));
123 break;
124 case ';':
125 outcode(c0, eflag);
126 outcode(c1, eflag);
127 break;
128 case '^':
129 emitf(Xmark);
130 outcode(c1, eflag);
131 emitf(Xmark);
132 outcode(c0, eflag);
133 emitf(Xconc);
134 break;
135 case '`':
136 emitf(Xmark);
137 if(c0){
138 outcode(c0, 0);
139 emitf(Xglob);
140 } else {
141 if((ifs = strdup("ifs")) == nil)
142 sysfatal("strdup: %r");
143 emitf(Xmark);
144 emitf(Xword);
145 emits(ifs);
146 emitf(Xdol);
147 }
148 emitf(Xbackq);
149 if(havefork){
150 p = emiti(0);
151 outcode(c1, 0);
152 emitf(Xexit);
153 stuffdot(p);
154 } else
155 emits(fnstr(c0));
156 break;
157 case ANDAND:
158 outcode(c0, 0);
159 emitf(Xtrue);
160 p = emiti(0);
161 outcode(c1, eflag);
162 stuffdot(p);
163 break;
164 case ARGLIST:
165 outcode(c1, eflag);
166 outcode(c0, eflag);
167 break;
168 case BANG:
169 outcode(c0, eflag);
170 emitf(Xbang);
171 break;
172 case PCMD:
173 case BRACE:
174 outcode(c0, eflag);
175 break;
176 case COUNT:
177 emitf(Xmark);
178 outcode(c0, eflag);
179 emitf(Xcount);
180 break;
181 case FN:
182 emitf(Xmark);
183 outcode(c0, eflag);
184 if(c1){
185 emitf(Xfn);
186 p = emiti(0);
187 emits(fnstr(c1));
188 outcode(c1, eflag);
189 emitf(Xunlocal); /* get rid of $* */
190 emitf(Xreturn);
191 stuffdot(p);
192 }
193 else
194 emitf(Xdelfn);
195 break;
196 case IF:
197 outcode(c0, 0);
198 emitf(Xif);
199 p = emiti(0);
200 outcode(c1, eflag);
201 emitf(Xwastrue);
202 stuffdot(p);
203 break;
204 case NOT:
205 if(!runq->iflast)
206 yyerror("`if not' does not follow `if(...)'");
207 emitf(Xifnot);
208 p = emiti(0);
209 outcode(c0, eflag);
210 stuffdot(p);
211 break;
212 case OROR:
213 outcode(c0, 0);
214 emitf(Xfalse);
215 p = emiti(0);
216 outcode(c1, eflag);
217 stuffdot(p);
218 break;
219 case PAREN:
220 outcode(c0, eflag);
221 break;
222 case SIMPLE:
223 emitf(Xmark);
224 outcode(c0, eflag);
225 emitf(Xsimple);
226 if(eflag)
227 emitf(Xeflag);
228 break;
229 case SUBSHELL:
230 emitf(Xsubshell);
231 if(havefork){
232 p = emiti(0);
233 outcode(c0, eflag);
234 emitf(Xexit);
235 stuffdot(p);
236 } else
237 emits(fnstr(c0));
238 if(eflag)
239 emitf(Xeflag);
240 break;
241 case SWITCH:
242 codeswitch(t, eflag);
243 break;
244 case TWIDDLE:
245 emitf(Xmark);
246 outcode(c1, eflag);
247 emitf(Xmark);
248 outcode(c0, eflag);
249 emitf(Xmatch);
250 if(eflag)
251 emitf(Xeflag);
252 break;
253 case WHILE:
254 q = codep;
255 outcode(c0, 0);
256 if(q==codep)
257 emitf(Xsettrue); /* empty condition == while(true) */
258 emitf(Xtrue);
259 p = emiti(0);
260 outcode(c1, eflag);
261 emitf(Xjump);
262 emiti(q);
263 stuffdot(p);
264 break;
265 case WORDS:
266 outcode(c1, eflag);
267 outcode(c0, eflag);
268 break;
269 case FOR:
270 emitf(Xmark);
271 if(c1){
272 outcode(c1, eflag);
273 emitf(Xglob);
274 }
275 else{
276 emitf(Xmark);
277 emitf(Xword);
278 emits(strdup("*"));
279 emitf(Xdol);
280 }
281 emitf(Xmark); /* dummy value for Xlocal */
282 emitf(Xmark);
283 outcode(c0, eflag);
284 emitf(Xlocal);
285 p = emitf(Xfor);
286 q = emiti(0);
287 outcode(c2, eflag);
288 emitf(Xjump);
289 emiti(p);
290 stuffdot(q);
291 emitf(Xunlocal);
292 break;
293 case WORD:
294 emitf(Xword);
295 emits(strdup(t->str));
296 break;
297 case DUP:
298 if(t->rtype==DUPFD){
299 emitf(Xdup);
300 emiti(t->fd0);
301 emiti(t->fd1);
302 }
303 else{
304 emitf(Xclose);
305 emiti(t->fd0);
306 }
307 outcode(c1, eflag);
308 emitf(Xpopredir);
309 break;
310 case PIPEFD:
311 emitf(Xpipefd);
312 emiti(t->rtype);
313 if(havefork){
314 p = emiti(0);
315 outcode(c0, eflag);
316 emitf(Xexit);
317 stuffdot(p);
318 } else {
319 emits(fnstr(c0));
320 }
321 break;
322 case REDIR:
323 emitf(Xmark);
324 outcode(c0, eflag);
325 emitf(Xglob);
326 switch(t->rtype){
327 case APPEND:
328 emitf(Xappend);
329 break;
330 case WRITE:
331 emitf(Xwrite);
332 break;
333 case READ:
334 case HERE:
335 emitf(Xread);
336 break;
337 case RDWR:
338 emitf(Xrdwr);
339 break;
340 }
341 emiti(t->fd0);
342 outcode(c1, eflag);
343 emitf(Xpopredir);
344 break;
345 case '=':
346 tt = t;
347 for(;t && t->type=='=';t = c2);
348 if(t){ /* var=value cmd */
349 for(t = tt;t->type=='=';t = c2){
350 emitf(Xmark);
351 outcode(c1, eflag);
352 emitf(Xmark);
353 outcode(c0, eflag);
354 emitf(Xlocal); /* push var for cmd */
355 }
356 outcode(t, eflag); /* gen. code for cmd */
357 for(t = tt; t->type == '='; t = c2)
358 emitf(Xunlocal); /* pop var */
359 }
360 else{ /* var=value */
361 for(t = tt;t;t = c2){
362 emitf(Xmark);
363 outcode(c1, eflag);
364 emitf(Xmark);
365 outcode(c0, eflag);
366 emitf(Xassign); /* set var permanently */
367 }
368 }
369 t = tt; /* so tests below will work */
370 break;
371 case PIPE:
372 emitf(Xpipe);
373 emiti(t->fd0);
374 emiti(t->fd1);
375 if(havefork){
376 p = emiti(0);
377 q = emiti(0);
378 outcode(c0, eflag);
379 emitf(Xexit);
380 stuffdot(p);
381 } else {
382 emits(fnstr(c0));
383 q = emiti(0);
384 }
385 outcode(c1, eflag);
386 emitf(Xreturn);
387 stuffdot(q);
388 emitf(Xpipewait);
389 break;
390 }
391 if(t->type!=NOT && t->type!=';')
392 runq->iflast = t->type==IF;
393 else if(c0) runq->iflast = c0->type==IF;
394 }
395 /*
396 * switch code looks like this:
397 * Xmark
398 * (get switch value)
399 * Xjump 1f
400 * out: Xjump leave
401 * 1: Xmark
402 * (get case values)
403 * Xcase 1f
404 * (commands)
405 * Xjump out
406 * 1: Xmark
407 * (get case values)
408 * Xcase 1f
409 * (commands)
410 * Xjump out
411 * 1:
412 * leave:
413 * Xpopm
414 */
415
416 void
codeswitch(tree * t,int eflag)417 codeswitch(tree *t, int eflag)
418 {
419 int leave; /* patch jump address to leave switch */
420 int out; /* jump here to leave switch */
421 int nextcase; /* patch jump address to next case */
422 tree *tt;
423 if(c1->child[0]==nil
424 || c1->child[0]->type!=';'
425 || !iscase(c1->child[0]->child[0])){
426 yyerror("case missing in switch");
427 return;
428 }
429 emitf(Xmark);
430 outcode(c0, eflag);
431 emitf(Xjump);
432 nextcase = emiti(0);
433 out = emitf(Xjump);
434 leave = emiti(0);
435 stuffdot(nextcase);
436 t = c1->child[0];
437 while(t->type==';'){
438 tt = c1;
439 emitf(Xmark);
440 for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag);
441 emitf(Xcase);
442 nextcase = emiti(0);
443 t = tt;
444 for(;;){
445 if(t->type==';'){
446 if(iscase(c0)) break;
447 outcode(c0, eflag);
448 t = c1;
449 }
450 else{
451 if(!iscase(t)) outcode(t, eflag);
452 break;
453 }
454 }
455 emitf(Xjump);
456 emiti(out);
457 stuffdot(nextcase);
458 }
459 stuffdot(leave);
460 emitf(Xpopm);
461 }
462
463 int
iscase(tree * t)464 iscase(tree *t)
465 {
466 if(t->type!=SIMPLE)
467 return 0;
468 do t = c0; while(t->type==ARGLIST);
469 return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
470 }
471
472 code*
codecopy(code * cp)473 codecopy(code *cp)
474 {
475 cp[0].i++;
476 return cp;
477 }
478
479 void
codefree(code * cp)480 codefree(code *cp)
481 {
482 code *p;
483 if(--cp[0].i!=0)
484 return;
485 for(p = cp+1;p->f;p++){
486 if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
487 || p->f==Xrdwr
488 || p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
489 || p->f==Xfor || p->f==Xjump
490 || p->f==Xsubshell || p->f==Xtrue) p++;
491 else if(p->f==Xdup || p->f==Xpipefd) p+=2;
492 else if(p->f==Xpipe) p+=4;
493 else if(p->f==Xword || p->f==Xdelhere) efree((++p)->s);
494 else if(p->f==Xfn){
495 efree(p[2].s);
496 p+=2;
497 }
498 }
499 efree((char *)cp);
500 }
501