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