Logo Search packages:      
Sourcecode: 9base version File versions  Download package

code.c

#include "rc.h"
#include "io.h"
#include "exec.h"
#include "fns.h"
#include "getflags.h"
#define     c0    t->child[0]
#define     c1    t->child[1]
#define     c2    t->child[2]
int codep, ncode;
#define     emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f=(x), codep++)
#define     emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i=(x), codep++)
#define     emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s=(x), codep++)
void stuffdot(int);
char *fnstr(tree*);
void outcode(tree*, int);
void codeswitch(tree*, int);
int iscase(tree*);
code *codecopy(code*);
void codefree(code*);
int morecode(void){
      ncode+=100;
      codebuf=(code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
      if(codebuf==0) panic("Can't realloc %d bytes in morecode!",
                        ncode*sizeof codebuf[0]);
      return 0;
}
void stuffdot(int a){
      if(a<0 || codep<=a) panic("Bad address %d in stuffdot", a);
      codebuf[a].i=codep;
}
int compile(tree *t)
{
      ncode=100;
      codebuf=(code *)emalloc(ncode*sizeof codebuf[0]);
      codep=0;
      emiti(0);               /* reference count */
      outcode(t, flag['e']?1:0);
      if(nerror){
            efree((char *)codebuf);
            return 0;
      }
      readhere();
      emitf(Xreturn);
      emitf(0);
      return 1;
}
void cleanhere(char *f)
{
      emitf(Xdelhere);
      emits(strdup(f));
}
char *fnstr(tree *t)
{
      io *f=openstr();
      char *v;
      extern char nl;
      char svnl=nl;
      nl=';';
      pfmt(f, "%t", t);
      nl=svnl;
      v=f->strp;
      f->strp=0;
      closeio(f);
      return v;
}
void outcode(tree *t, int eflag)
{
      int p, q;
      tree *tt;
      if(t==0) return;
      if(t->type!=NOT && t->type!=';') runq->iflast=0;
      switch(t->type){
      default:
            pfmt(err, "bad type %d in outcode\n", t->type);
            break;
      case '$':
            emitf(Xmark);
            outcode(c0, eflag);
            emitf(Xdol);
            break;
      case '"':
            emitf(Xmark);
            outcode(c0, eflag);
            emitf(Xqdol);
            break;
      case SUB:
            emitf(Xmark);
            outcode(c0, eflag);
            emitf(Xmark);
            outcode(c1, eflag);
            emitf(Xsub);
            break;
      case '&':
            emitf(Xasync);
            p=emiti(0);
            outcode(c0, eflag);
            emitf(Xexit);
            stuffdot(p);
            break;
      case ';':
            outcode(c0, eflag);
            outcode(c1, eflag);
            break;
      case '^':
            emitf(Xmark);
            outcode(c1, eflag);
            emitf(Xmark);
            outcode(c0, eflag);
            emitf(Xconc);
            break;
      case '`':
            emitf(Xbackq);
            p=emiti(0);
            outcode(c0, 0);
            emitf(Xexit);
            stuffdot(p);
            break;
      case ANDAND:
            outcode(c0, 0);
            emitf(Xtrue);
            p=emiti(0);
            outcode(c1, eflag);
            stuffdot(p);
            break;
      case ARGLIST:
            outcode(c1, eflag);
            outcode(c0, eflag);
            break;
      case BANG:
            outcode(c0, eflag);
            emitf(Xbang);
            break;
      case PCMD:
      case BRACE:
            outcode(c0, eflag);
            break;
      case COUNT:
            emitf(Xmark);
            outcode(c0, eflag);
            emitf(Xcount);
            break;
      case FN:
            emitf(Xmark);
            outcode(c0, eflag);
            if(c1){
                  emitf(Xfn);
                  p=emiti(0);
                  emits(fnstr(c1));
                  outcode(c1, eflag);
                  emitf(Xunlocal);  /* get rid of $* */
                  emitf(Xreturn);
                  stuffdot(p);
            }
            else
                  emitf(Xdelfn);
            break;
      case IF:
            outcode(c0, 0);
            emitf(Xif);
            p=emiti(0);
            outcode(c1, eflag);
            emitf(Xwastrue);
            stuffdot(p);
            break;
      case NOT:
            if(!runq->iflast) yyerror("`if not' does not follow `if(...)'");
            emitf(Xifnot);
            p=emiti(0);
            outcode(c0, eflag);
            stuffdot(p);
            break;
      case OROR:
            outcode(c0, 0);
            emitf(Xfalse);
            p=emiti(0);
            outcode(c1, eflag);
            stuffdot(p);
            break;
      case PAREN:
            outcode(c0, eflag);
            break;
      case SIMPLE:
            emitf(Xmark);
            outcode(c0, eflag);
            emitf(Xsimple);
            if(eflag) emitf(Xeflag);
            break;
      case SUBSHELL:
            emitf(Xsubshell);
            p=emiti(0);
            outcode(c0, eflag);
            emitf(Xexit);
            stuffdot(p);
            if(eflag) emitf(Xeflag);
            break;
      case SWITCH:
            codeswitch(t, eflag);
            break;
      case TWIDDLE:
            emitf(Xmark);
            outcode(c1, eflag);
            emitf(Xmark);
            outcode(c0, eflag);
            emitf(Xmatch);
            if(eflag) emitf(Xeflag);
            break;
      case WHILE:
            q=codep;
            outcode(c0, 0);
            if(q==codep) emitf(Xsettrue); /* empty condition == while(true) */
            emitf(Xtrue);
            p=emiti(0);
            outcode(c1, eflag);
            emitf(Xjump);
            emiti(q);
            stuffdot(p);
            break;
      case WORDS:
            outcode(c1, eflag);
            outcode(c0, eflag);
            break;
      case FOR:
            emitf(Xmark);
            if(c1){
                  outcode(c1, eflag);
                  emitf(Xglob);
            }
            else{
                  emitf(Xmark);
                  emitf(Xword);
                  emits(strdup("*"));
                  emitf(Xdol);
            }
            emitf(Xmark);           /* dummy value for Xlocal */
            emitf(Xmark);
            outcode(c0, eflag);
            emitf(Xlocal);
            p=emitf(Xfor);
            q=emiti(0);
            outcode(c2, eflag);
            emitf(Xjump);
            emiti(p);
            stuffdot(q);
            emitf(Xunlocal);
            break;
      case WORD:
            emitf(Xword);
            emits(strdup(t->str));
            break;
      case DUP:
            if(t->rtype==DUPFD){
                  emitf(Xdup);
                  emiti(t->fd0);
                  emiti(t->fd1);
            }
            else{
                  emitf(Xclose);
                  emiti(t->fd0);
            }
            outcode(c1, eflag);
            emitf(Xpopredir);
            break;
      case PIPEFD:
            emitf(Xpipefd);
            emiti(t->rtype);
            p=emiti(0);
            outcode(c0, eflag);
            emitf(Xexit);
            stuffdot(p);
            break;
      case REDIR:
            emitf(Xmark);
            outcode(c0, eflag);
            emitf(Xglob);
            switch(t->rtype){
            case APPEND:
                  emitf(Xappend);
                  break;
            case WRITE:
                  emitf(Xwrite);
                  break;
            case READ:
            case HERE:
                  emitf(Xread);
                  break;
            }
            emiti(t->fd0);
            outcode(c1, eflag);
            emitf(Xpopredir);
            break;
      case '=':
            tt=t;
            for(;t && t->type=='=';t=c2);
            if(t){
                  for(t=tt;t->type=='=';t=c2){
                        emitf(Xmark);
                        outcode(c1, eflag);
                        emitf(Xmark);
                        outcode(c0, eflag);
                        emitf(Xlocal);
                  }
                  t=tt;
                  outcode(c2, eflag);
                  for(;t->type=='=';t=c2) emitf(Xunlocal);
            }
            else{
                  for(t=tt;t;t=c2){
                        emitf(Xmark);
                        outcode(c1, eflag);
                        emitf(Xmark);
                        outcode(c0, eflag);
                        emitf(Xassign);
                  }
            }
            t=tt; /* so tests below will work */
            break;
      case PIPE:
            emitf(Xpipe);
            emiti(t->fd0);
            emiti(t->fd1);
            p=emiti(0);
            q=emiti(0);
            outcode(c0, eflag);
            emitf(Xexit);
            stuffdot(p);
            outcode(c1, eflag);
            emitf(Xreturn);
            stuffdot(q);
            emitf(Xpipewait);
            break;
      }
      if(t->type!=NOT && t->type!=';')
            runq->iflast=t->type==IF;
      else if(c0) runq->iflast=c0->type==IF;
}
/*
 * switch code looks like this:
 *    Xmark
 *    (get switch value)
 *    Xjump 1f
 * out:     Xjump leave
 * 1: Xmark
 *    (get case values)
 *    Xcase 1f
 *    (commands)
 *    Xjump out
 * 1: Xmark
 *    (get case values)
 *    Xcase 1f
 *    (commands)
 *    Xjump out
 * 1:
 * leave:
 *    Xpopm
 */
void codeswitch(tree *t, int eflag)
{
      int leave;        /* patch jump address to leave switch */
      int out;          /* jump here to leave switch */
      int nextcase;     /* patch jump address to next case */
      tree *tt;
      if(c1->child[0]==nil
      || c1->child[0]->type!=';'
      || !iscase(c1->child[0]->child[0])){
            yyerror("case missing in switch");
            return;
      }
      emitf(Xmark);
      outcode(c0, eflag);
      emitf(Xjump);
      nextcase=emiti(0);
      out=emitf(Xjump);
      leave=emiti(0);
      stuffdot(nextcase);
      t=c1->child[0];
      while(t->type==';'){
            tt=c1;
            emitf(Xmark);
            for(t=c0->child[0];t->type==ARGLIST;t=c0) outcode(c1, eflag);
            emitf(Xcase);
            nextcase=emiti(0);
            t=tt;
            for(;;){
                  if(t->type==';'){
                        if(iscase(c0)) break;
                        outcode(c0, eflag);
                        t=c1;
                  }
                  else{
                        if(!iscase(t)) outcode(t, eflag);
                        break;
                  }
            }
            emitf(Xjump);
            emiti(out);
            stuffdot(nextcase);
      }
      stuffdot(leave);
      emitf(Xpopm);
}
int iscase(tree *t)
{
      if(t->type!=SIMPLE) return 0;
      do t=c0; while(t->type==ARGLIST);
      return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
}
code *codecopy(code *cp)
{
      cp[0].i++;
      return cp;
}
void codefree(code *cp)
{
      code *p;
      if(--cp[0].i!=0) return;
      for(p=cp+1;p->f;p++){
            if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
            || p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
            || p->f==Xfor || p->f==Xjump
            || p->f==Xsubshell || p->f==Xtrue) p++;
            else if(p->f==Xdup || p->f==Xpipefd) p+=2;
            else if(p->f==Xpipe) p+=4;
            else if(p->f==Xword || p->f==Xdelhere) efree((++p)->s);
            else if(p->f==Xfn){
                  efree(p[2].s);
                  p+=2;
            }
      }
      efree((char *)cp);
}

Generated by  Doxygen 1.6.0   Back to index