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