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