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