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*);21 int22 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 }33 void34 stuffdot(int a)35 {36 if(a<0 || codep<=a)37 panic("Bad address %d in stuffdot", a);38 codebuf[a].i = codep;39 }41 int42 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 }59 void60 cleanhere(char *f)61 {62 emitf(Xdelhere);63 emits(strdup(f));64 }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 }82 void83 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 } else120 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 } else141 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 else180 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 } else223 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 t = tt;343 outcode(c2, eflag);344 for(;t->type=='=';t = c2) 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 * Xmark384 * (get switch value)385 * Xjump 1f386 * out: Xjump leave387 * 1: Xmark388 * (get case values)389 * Xcase 1f390 * (commands)391 * Xjump out392 * 1: Xmark393 * (get case values)394 * Xcase 1f395 * (commands)396 * Xjump out397 * 1:398 * leave:399 * Xpopm400 */402 void403 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]==nil410 || 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 }449 int450 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 }458 code*459 codecopy(code *cp)460 {461 cp[0].i++;462 return cp;463 }465 void466 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==Xwrite473 || p->f==Xrdwr474 || p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse475 || p->f==Xfor || p->f==Xjump476 || 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 }