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