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