Blob


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