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