code.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       code.c (8287B)
       ---
            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         ncode = 100;
           45         codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
           46         codep = 0;
           47         emiti(0);                        /* reference count */
           48         outcode(t, flag['e']?1:0);
           49         if(nerror){
           50                 efree((char *)codebuf);
           51                 return 0;
           52         }
           53         readhere();
           54         emitf(Xreturn);
           55         emitf(0);
           56         return 1;
           57 }
           58 
           59 void
           60 cleanhere(char *f)
           61 {
           62         emitf(Xdelhere);
           63         emits(strdup(f));
           64 }
           65 
           66 char*
           67 fnstr(tree *t)
           68 {
           69         io *f = openstr();
           70         char *v;
           71         extern char nl;
           72         char svnl = nl;
           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){
          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);
          341                         }
          342                         outcode(t, eflag);
          343                         for(t = tt; t->type=='='; t = c2)
          344                                 emitf(Xunlocal);
          345                 }
          346                 else{
          347                         for(t = tt;t;t = c2){
          348                                 emitf(Xmark);
          349                                 outcode(c1, eflag);
          350                                 emitf(Xmark);
          351                                 outcode(c0, eflag);
          352                                 emitf(Xassign);
          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 }