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) ((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 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 else 155 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 * Xmark 339 * (get switch value) 340 * Xjump 1f 341 * out: Xjump leave 342 * 1: Xmark 343 * (get case values) 344 * Xcase 1f 345 * (commands) 346 * Xjump out 347 * 1: Xmark 348 * (get case values) 349 * Xcase 1f 350 * (commands) 351 * Xjump out 352 * 1: 353 * leave: 354 * Xpopm 355 */ 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]==nil 363 || 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==Xwrite 418 || p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse 419 || p->f==Xfor || p->f==Xjump 420 || 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 } 431