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