xref: /plan9/sys/src/cmd/rc/code.c (revision d9306527b4a7229dcf0cf3c58aed36bb9da82854)
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 	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);
153 		}
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);
227 		}
228 		else{
229 			emitf(Xmark);
230 			emitf(Xword);
231 			emits(strdup("*"));
232 			emitf(Xdol);
233 		}
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);
255 		}
256 		else{
257 			emitf(Xclose);
258 			emiti(t->fd0);
259 		}
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;
286 		}
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);
301 			}
302 			t=tt;
303 			outcode(c2, eflag);
304 			for(;t->type=='=';t=c2) emitf(Xunlocal);
305 		}
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);
313 			}
314 		}
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;
331 	}
332 	if(t->type!=NOT && t->type!=';')
333 		runq->iflast=t->type==IF;
334 	else if(c0) runq->iflast=c0->type==IF;
335 }
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)
357 {
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;
367 	}
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;
388 			}
389 			else{
390 				if(!iscase(t)) outcode(t, eflag);
391 				break;
392 			}
393 		}
394 		emitf(Xjump);
395 		emiti(out);
396 		stuffdot(nextcase);
397 	}
398 	stuffdot(leave);
399 	emitf(Xpopm);
400 }
401 int iscase(tree *t)
402 {
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;
406 }
407 code *codecopy(code *cp)
408 {
409 	cp[0].i++;
410 	return cp;
411 }
412 void codefree(code *cp)
413 {
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;
427 		}
428 	}
429 	efree((char *)cp);
430 }
431