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