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