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