Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
 
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
	return 0;
30
}
31
 
32
void
33
stuffdot(int a)
34
{
35
	if(a<0 || codep<=a)
36
		panic("Bad address %d in stuffdot", a);
37
	codebuf[a].i = codep;
38
}
39
 
40
int
41
compile(tree *t)
42
{
43
	ncode = 100;
44
	codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
45
	codep = 0;
46
	emiti(0);			/* reference count */
47
	outcode(t, flag['e']?1:0);
48
	if(nerror){
49
		efree((char *)codebuf);
50
		return 0;
51
	}
52
	readhere();
53
	emitf(Xreturn);
54
	emitf(0);
55
	return 1;
56
}
57
 
58
void
59
cleanhere(char *f)
60
{
61
	emitf(Xdelhere);
62
	emits(strdup(f));
63
}
64
 
65
char*
66
fnstr(tree *t)
67
{
68
	io *f = openstr();
69
	void *v;
70
	extern char nl;
71
	char svnl = nl;
72
 
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
}
81
 
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);
178
		}
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);
260
		}
261
		else{
262
			emitf(Xmark);
263
			emitf(Xword);
264
			emits(strdup("*"));
265
			emitf(Xdol);
266
		}
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);
288
		}
289
		else{
290
			emitf(Xclose);
291
			emiti(t->fd0);
292
		}
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));
306
		}
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;
326
		}
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){					/* var=value cmd */
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);		/* push var for cmd */
341
			}
342
			outcode(t, eflag);		/* gen. code for cmd */
343
			for(t = tt; t->type == '='; t = c2)
344
				emitf(Xunlocal);	/* pop var */
345
		}
346
		else{					/* var=value */
347
			for(t = tt;t;t = c2){
348
				emitf(Xmark);
349
				outcode(c1, eflag);
350
				emitf(Xmark);
351
				outcode(c0, eflag);
352
				emitf(Xassign);	/* set var permanently */
353
			}
354
		}
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);
370
		}
371
		outcode(c1, eflag);
372
		emitf(Xreturn);
373
		stuffdot(q);
374
		emitf(Xpipewait);
375
		break;
376
	}
377
	if(t->type!=NOT && t->type!=';')
378
		runq->iflast = t->type==IF;
379
	else if(c0) runq->iflast = c0->type==IF;
380
}
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
 */
401
 
402
void
403
codeswitch(tree *t, int eflag)
404
{
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;
414
	}
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;
435
			}
436
			else{
437
				if(!iscase(t)) outcode(t, eflag);
438
				break;
439
			}
440
		}
441
		emitf(Xjump);
442
		emiti(out);
443
		stuffdot(nextcase);
444
	}
445
	stuffdot(leave);
446
	emitf(Xpopm);
447
}
448
 
449
int
450
iscase(tree *t)
451
{
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;
456
}
457
 
458
code*
459
codecopy(code *cp)
460
{
461
	cp[0].i++;
462
	return cp;
463
}
464
 
465
void
466
codefree(code *cp)
467
{
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;
483
		}
484
	}
485
	efree((char *)cp);
486
}