bc.y (13425B)
1 %{ 2 #include <u.h> 3 #include <libc.h> 4 #include <bio.h> 5 6 #define bsp_max 5000 7 8 Biobuf *in; 9 Biobuf bstdin; 10 Biobuf bstdout; 11 char cary[1000]; 12 char* cp = { cary }; 13 char string[1000]; 14 char* str = { string }; 15 int crs = 128; 16 int rcrs = 128; /* reset crs */ 17 int bindx = 0; 18 int lev = 0; 19 int ln; 20 char* ttp; 21 char* ss = ""; 22 int bstack[10] = { 0 }; 23 char* numb[15] = 24 { 25 " 0", " 1", " 2", " 3", " 4", " 5", 26 " 6", " 7", " 8", " 9", " 10", " 11", 27 " 12", " 13", " 14" 28 }; 29 char* pre; 30 char* post; 31 32 long peekc = -1; 33 int sargc; 34 int ifile; 35 char** sargv; 36 37 char *funtab[] = 38 { 39 "<1>","<2>","<3>","<4>","<5>", 40 "<6>","<7>","<8>","<9>","<10>", 41 "<11>","<12>","<13>","<14>","<15>", 42 "<16>","<17>","<18>","<19>","<20>", 43 "<21>","<22>","<23>","<24>","<25>", 44 "<26>" 45 }; 46 char *atab[] = 47 { 48 "<221>","<222>","<223>","<224>","<225>", 49 "<226>","<227>","<228>","<229>","<230>", 50 "<231>","<232>","<233>","<234>","<235>", 51 "<236>","<237>","<238>","<239>","<240>", 52 "<241>","<242>","<243>","<244>","<245>", 53 "<246>" 54 }; 55 char* letr[26] = 56 { 57 "a","b","c","d","e","f","g","h","i","j", 58 "k","l","m","n","o","p","q","r","s","t", 59 "u","v","w","x","y","z" 60 }; 61 char* dot = { "." }; 62 char* bspace[bsp_max]; 63 char** bsp_nxt = bspace; 64 int bdebug = 0; 65 int lflag; 66 int cflag; 67 int sflag; 68 69 char* bundle(int, ...); 70 void conout(char*, char*); 71 int cpeek(int, int, int); 72 int getch(void); 73 char* geta(char*); 74 char* getf(char*); 75 void getout(void); 76 void output(char*); 77 void pp(char*); 78 void routput(char*); 79 void tp(char*); 80 void yyerror(char*, ...); 81 int yyparse(void); 82 83 typedef void* pointer; 84 #pragma varargck type "lx" pointer 85 86 %} 87 %union 88 { 89 char* cptr; 90 int cc; 91 } 92 93 %type <cptr> pstat stat stat1 def slist dlets e ase nase 94 %type <cptr> slist re fprefix cargs eora cons constant lora 95 %type <cptr> crs 96 97 %token <cptr> LETTER EQOP _AUTO DOT 98 %token <cc> DIGIT SQRT LENGTH _IF FFF EQ 99 %token <cc> _PRINT _WHILE _FOR NE LE GE INCR DECR 100 %token <cc> _RETURN _BREAK _DEFINE BASE OBASE SCALE 101 %token <cc> QSTR ERROR 102 103 %right '=' EQOP 104 %left '+' '-' 105 %left '*' '/' '%' 106 %right '^' 107 %left UMINUS 108 109 %% 110 start: 111 start stuff 112 | stuff 113 114 stuff: 115 pstat tail 116 { 117 output($1); 118 } 119 | def dargs ')' '{' dlist slist '}' 120 { 121 ttp = bundle(6, pre, $6, post , "0", numb[lev], "Q"); 122 conout(ttp, (char*)$1); 123 rcrs = crs; 124 output(""); 125 lev = bindx = 0; 126 } 127 128 dlist: 129 tail 130 | dlist _AUTO dlets tail 131 132 stat: 133 stat1 134 | nase 135 { 136 if(sflag) 137 bundle(2, $1, "s."); 138 } 139 140 pstat: 141 stat1 142 { 143 if(sflag) 144 bundle(2, $1, "0"); 145 } 146 | nase 147 { 148 if(!sflag) 149 bundle(2, $1, "ps."); 150 } 151 152 stat1: 153 { 154 bundle(1, ""); 155 } 156 | ase 157 { 158 bundle(2, $1, "s."); 159 } 160 | SCALE '=' e 161 { 162 bundle(2, $3, "k"); 163 } 164 | SCALE EQOP e 165 { 166 bundle(4, "K", $3, $2, "k"); 167 } 168 | BASE '=' e 169 { 170 bundle(2, $3, "i"); 171 } 172 | BASE EQOP e 173 { 174 bundle(4, "I", $3, $2, "i"); 175 } 176 | OBASE '=' e 177 { 178 bundle(2, $3, "o"); 179 } 180 | OBASE EQOP e 181 { 182 bundle(4, "O", $3, $2, "o"); 183 } 184 | QSTR 185 { 186 bundle(3, "[", $1, "]P"); 187 } 188 | _BREAK 189 { 190 bundle(2, numb[lev-bstack[bindx-1]], "Q"); 191 } 192 | _PRINT e 193 { 194 bundle(2, $2, "ps."); 195 } 196 | _RETURN e 197 { 198 bundle(4, $2, post, numb[lev], "Q"); 199 } 200 | _RETURN 201 { 202 bundle(4, "0", post, numb[lev], "Q"); 203 } 204 | '{' slist '}' 205 { 206 $$ = $2; 207 } 208 | FFF 209 { 210 bundle(1, "fY"); 211 } 212 | _IF crs BLEV '(' re ')' stat 213 { 214 conout($7, $2); 215 bundle(3, $5, $2, " "); 216 } 217 | _WHILE crs '(' re ')' stat BLEV 218 { 219 bundle(3, $6, $4, $2); 220 conout($$, $2); 221 bundle(3, $4, $2, " "); 222 } 223 | fprefix crs re ';' e ')' stat BLEV 224 { 225 bundle(5, $7, $5, "s.", $3, $2); 226 conout($$, $2); 227 bundle(5, $1, "s.", $3, $2, " "); 228 } 229 | '~' LETTER '=' e 230 { 231 bundle(3, $4, "S", $2); 232 } 233 234 fprefix: 235 _FOR '(' e ';' 236 { 237 $$ = $3; 238 } 239 240 BLEV: 241 = 242 { 243 --bindx; 244 } 245 246 slist: 247 stat 248 | slist tail stat 249 { 250 bundle(2, $1, $3); 251 } 252 253 tail: 254 '\n' 255 { 256 ln++; 257 } 258 | ';' 259 260 re: 261 e EQ e 262 { 263 $$ = bundle(3, $1, $3, "="); 264 } 265 | e '<' e 266 { 267 bundle(3, $1, $3, ">"); 268 } 269 | e '>' e 270 { 271 bundle(3, $1, $3, "<"); 272 } 273 | e NE e 274 { 275 bundle(3, $1, $3, "!="); 276 } 277 | e GE e 278 { 279 bundle(3, $1, $3, "!>"); 280 } 281 | e LE e 282 { 283 bundle(3, $1, $3, "!<"); 284 } 285 | e 286 { 287 bundle(2, $1, " 0!="); 288 } 289 290 nase: 291 '(' e ')' 292 { 293 $$ = $2; 294 } 295 | cons 296 { 297 bundle(3, " ", $1, " "); 298 } 299 | DOT cons 300 { 301 bundle(3, " .", $2, " "); 302 } 303 | cons DOT cons 304 { 305 bundle(5, " ", $1, ".", $3, " "); 306 } 307 | cons DOT 308 { 309 bundle(4, " ", $1, ".", " "); 310 } 311 | DOT 312 { 313 $<cptr>$ = "l."; 314 } 315 | LETTER '[' e ']' 316 { 317 bundle(3, $3, ";", geta($1)); 318 } 319 | LETTER INCR 320 { 321 bundle(4, "l", $1, "d1+s", $1); 322 } 323 | INCR LETTER 324 { 325 bundle(4, "l", $2, "1+ds", $2); 326 } 327 | DECR LETTER 328 { 329 bundle(4, "l", $2, "1-ds", $2); 330 } 331 | LETTER DECR 332 { 333 bundle(4, "l", $1, "d1-s", $1); 334 } 335 | LETTER '[' e ']' INCR 336 { 337 bundle(7, $3, ";", geta($1), "d1+" ,$3, ":" ,geta($1)); 338 } 339 | INCR LETTER '[' e ']' 340 { 341 bundle(7, $4, ";", geta($2), "1+d", $4, ":", geta($2)); 342 } 343 | LETTER '[' e ']' DECR 344 { 345 bundle(7, $3, ";", geta($1), "d1-", $3, ":", geta($1)); 346 } 347 | DECR LETTER '[' e ']' 348 { 349 bundle(7, $4, ";", geta($2), "1-d", $4, ":" ,geta($2)); 350 } 351 | SCALE INCR 352 { 353 bundle(1, "Kd1+k"); 354 } 355 | INCR SCALE 356 { 357 bundle(1, "K1+dk"); 358 } 359 | SCALE DECR 360 { 361 bundle(1, "Kd1-k"); 362 } 363 | DECR SCALE 364 { 365 bundle(1, "K1-dk"); 366 } 367 | BASE INCR 368 { 369 bundle(1, "Id1+i"); 370 } 371 | INCR BASE 372 { 373 bundle(1, "I1+di"); 374 } 375 | BASE DECR 376 { 377 bundle(1, "Id1-i"); 378 } 379 | DECR BASE 380 { 381 bundle(1, "I1-di"); 382 } 383 | OBASE INCR 384 { 385 bundle(1, "Od1+o"); 386 } 387 | INCR OBASE 388 { 389 bundle(1, "O1+do"); 390 } 391 | OBASE DECR 392 { 393 bundle(1, "Od1-o"); 394 } 395 | DECR OBASE 396 { 397 bundle(1, "O1-do"); 398 } 399 | LETTER '(' cargs ')' 400 { 401 bundle(4, $3, "l", getf($1), "x"); 402 } 403 | LETTER '(' ')' 404 { 405 bundle(3, "l", getf($1), "x"); 406 } 407 | LETTER = { 408 bundle(2, "l", $1); 409 } 410 | LENGTH '(' e ')' 411 { 412 bundle(2, $3, "Z"); 413 } 414 | SCALE '(' e ')' 415 { 416 bundle(2, $3, "X"); 417 } 418 | '?' 419 { 420 bundle(1, "?"); 421 } 422 | SQRT '(' e ')' 423 { 424 bundle(2, $3, "v"); 425 } 426 | '~' LETTER 427 { 428 bundle(2, "L", $2); 429 } 430 | SCALE 431 { 432 bundle(1, "K"); 433 } 434 | BASE 435 { 436 bundle(1, "I"); 437 } 438 | OBASE 439 { 440 bundle(1, "O"); 441 } 442 | '-' e 443 { 444 bundle(3, " 0", $2, "-"); 445 } 446 | e '+' e 447 { 448 bundle(3, $1, $3, "+"); 449 } 450 | e '-' e 451 { 452 bundle(3, $1, $3, "-"); 453 } 454 | e '*' e 455 { 456 bundle(3, $1, $3, "*"); 457 } 458 | e '/' e 459 { 460 bundle(3, $1, $3, "/"); 461 } 462 | e '%' e 463 { 464 bundle(3, $1, $3, "%%"); 465 } 466 | e '^' e 467 { 468 bundle(3, $1, $3, "^"); 469 } 470 471 ase: 472 LETTER '=' e 473 { 474 bundle(3, $3, "ds", $1); 475 } 476 | LETTER '[' e ']' '=' e 477 { 478 bundle(5, $6, "d", $3, ":", geta($1)); 479 } 480 | LETTER EQOP e 481 { 482 bundle(6, "l", $1, $3, $2, "ds", $1); 483 } 484 | LETTER '[' e ']' EQOP e 485 { 486 bundle(9, $3, ";", geta($1), $6, $5, "d", $3, ":", geta($1)); 487 } 488 489 e: 490 ase 491 | nase 492 493 cargs: 494 eora 495 | cargs ',' eora 496 { 497 bundle(2, $1, $3); 498 } 499 500 eora: 501 e 502 | LETTER '[' ']' 503 { 504 bundle(2, "l", geta($1)); 505 } 506 507 cons: 508 constant 509 { 510 *cp++ = 0; 511 } 512 513 constant: 514 '_' 515 { 516 $<cptr>$ = cp; 517 *cp++ = '_'; 518 } 519 | DIGIT 520 { 521 $<cptr>$ = cp; 522 *cp++ = $1; 523 } 524 | constant DIGIT 525 { 526 *cp++ = $2; 527 } 528 529 crs: 530 = 531 { 532 $$ = cp; 533 *cp++ = '<'; 534 *cp++ = crs/100+'0'; 535 *cp++ = (crs%100)/10+'0'; 536 *cp++ = crs%10+'0'; 537 *cp++ = '>'; 538 *cp++ = '\0'; 539 if(crs++ >= 220) { 540 yyerror("program too big"); 541 getout(); 542 } 543 bstack[bindx++] = lev++; 544 } 545 546 def: 547 _DEFINE LETTER '(' 548 { 549 $$ = getf($2); 550 pre = (char*)""; 551 post = (char*)""; 552 lev = 1; 553 bindx = 0; 554 bstack[bindx] = 0; 555 } 556 557 dargs: 558 | lora 559 { 560 pp((char*)$1); 561 } 562 | dargs ',' lora 563 { 564 pp((char*)$3); 565 } 566 567 dlets: 568 lora 569 { 570 tp((char*)$1); 571 } 572 | dlets ',' lora 573 { 574 tp((char*)$3); 575 } 576 577 lora: 578 LETTER 579 { 580 $<cptr>$=$1; 581 } 582 | LETTER '[' ']' 583 { 584 $$ = geta($1); 585 } 586 587 %% 588 589 int 590 yylex(void) 591 { 592 int c, ch; 593 594 restart: 595 c = getch(); 596 peekc = -1; 597 while(c == ' ' || c == '\t') 598 c = getch(); 599 if(c == '\\') { 600 getch(); 601 goto restart; 602 } 603 if(c >= 'a' && c <= 'z') { 604 /* look ahead to look for reserved words */ 605 peekc = getch(); 606 if(peekc >= 'a' && peekc <= 'z') { /* must be reserved word */ 607 if(c=='p' && peekc=='r') { 608 c = _PRINT; 609 goto skip; 610 } 611 if(c=='i' && peekc=='f') { 612 c = _IF; 613 goto skip; 614 } 615 if(c=='w' && peekc=='h') { 616 c = _WHILE; 617 goto skip; 618 } 619 if(c=='f' && peekc=='o') { 620 c = _FOR; 621 goto skip; 622 } 623 if(c=='s' && peekc=='q') { 624 c = SQRT; 625 goto skip; 626 } 627 if(c=='r' && peekc=='e') { 628 c = _RETURN; 629 goto skip; 630 } 631 if(c=='b' && peekc=='r') { 632 c = _BREAK; 633 goto skip; 634 } 635 if(c=='d' && peekc=='e') { 636 c = _DEFINE; 637 goto skip; 638 } 639 if(c=='s' && peekc=='c') { 640 c = SCALE; 641 goto skip; 642 } 643 if(c=='b' && peekc=='a') { 644 c = BASE; 645 goto skip; 646 } 647 if(c=='i' && peekc=='b') { 648 c = BASE; 649 goto skip; 650 } 651 if(c=='o' && peekc=='b') { 652 c = OBASE; 653 goto skip; 654 } 655 if(c=='d' && peekc=='i') { 656 c = FFF; 657 goto skip; 658 } 659 if(c=='a' && peekc=='u') { 660 c = _AUTO; 661 goto skip; 662 } 663 if(c=='l' && peekc=='e') { 664 c = LENGTH; 665 goto skip; 666 } 667 if(c=='q' && peekc=='u') 668 getout(); 669 /* could not be found */ 670 return ERROR; 671 672 skip: /* skip over rest of word */ 673 peekc = -1; 674 for(;;) { 675 ch = getch(); 676 if(ch < 'a' || ch > 'z') 677 break; 678 } 679 peekc = ch; 680 return c; 681 } 682 683 /* usual case; just one single letter */ 684 yylval.cptr = letr[c-'a']; 685 return LETTER; 686 } 687 if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) { 688 yylval.cc = c; 689 return DIGIT; 690 } 691 switch(c) { 692 case '.': 693 return DOT; 694 case '*': 695 yylval.cptr = "*"; 696 return cpeek('=', EQOP, c); 697 case '%': 698 yylval.cptr = "%%"; 699 return cpeek('=', EQOP, c); 700 case '^': 701 yylval.cptr = "^"; 702 return cpeek('=', EQOP, c); 703 case '+': 704 ch = cpeek('=', EQOP, c); 705 if(ch == EQOP) { 706 yylval.cptr = "+"; 707 return ch; 708 } 709 return cpeek('+', INCR, c); 710 case '-': 711 ch = cpeek('=', EQOP, c); 712 if(ch == EQOP) { 713 yylval.cptr = "-"; 714 return ch; 715 } 716 return cpeek('-', DECR, c); 717 case '=': 718 return cpeek('=', EQ, '='); 719 case '<': 720 return cpeek('=', LE, '<'); 721 case '>': 722 return cpeek('=', GE, '>'); 723 case '!': 724 return cpeek('=', NE, '!'); 725 case '/': 726 ch = cpeek('=', EQOP, c); 727 if(ch == EQOP) { 728 yylval.cptr = "/"; 729 return ch; 730 } 731 if(peekc == '*') { 732 peekc = -1; 733 for(;;) { 734 ch = getch(); 735 if(ch == '*') { 736 peekc = getch(); 737 if(peekc == '/') { 738 peekc = -1; 739 goto restart; 740 } 741 } 742 } 743 } 744 return c; 745 case '"': 746 yylval.cptr = str; 747 while((c=getch()) != '"'){ 748 *str++ = c; 749 if(str >= &string[999]){ 750 yyerror("string space exceeded"); 751 getout(); 752 } 753 } 754 *str++ = 0; 755 return QSTR; 756 default: 757 return c; 758 } 759 } 760 761 int 762 cpeek(int c, int yes, int no) 763 { 764 765 peekc = getch(); 766 if(peekc == c) { 767 peekc = -1; 768 return yes; 769 } 770 return no; 771 } 772 773 int 774 getch(void) 775 { 776 long ch; 777 778 loop: 779 ch = peekc; 780 if(ch < 0){ 781 if(in == 0) 782 ch = -1; 783 else 784 ch = Bgetc(in); 785 } 786 peekc = -1; 787 if(ch >= 0) 788 return ch; 789 790 ifile++; 791 if(ifile >= sargc) { 792 if(ifile >= sargc+1) 793 getout(); 794 in = &bstdin; 795 Binit(in, 0, OREAD); 796 ln = 0; 797 goto loop; 798 } 799 if(in) 800 Bterm(in); 801 if((in = Bopen(sargv[ifile], OREAD)) != 0){ 802 ln = 0; 803 ss = sargv[ifile]; 804 goto loop; 805 } 806 fprint(2, "open %s: %r\n", sargv[ifile]); 807 yyerror("cannot open input file"); 808 return 0; /* shut up ken */ 809 } 810 811 char* 812 bundle(int a, ...) 813 { 814 int i; 815 char **q; 816 va_list arg; 817 818 i = a; 819 va_start(arg, a); 820 q = bsp_nxt; 821 if(bdebug) 822 fprint(2, "bundle %d elements at %lx\n", i, q); 823 while(i-- > 0) { 824 if(bsp_nxt >= &bspace[bsp_max]) 825 yyerror("bundling space exceeded"); 826 *bsp_nxt++ = va_arg(arg, char*); 827 } 828 *bsp_nxt++ = 0; 829 va_end(arg); 830 yyval.cptr = (char*)q; 831 return (char*)q; 832 } 833 834 void 835 routput(char *p) 836 { 837 char **pp; 838 839 if(bdebug) 840 fprint(2, "routput(%lx)\n", p); 841 if((char**)p >= &bspace[0] && (char**)p < &bspace[bsp_max]) { 842 /* part of a bundle */ 843 pp = (char**)p; 844 while(*pp != 0) 845 routput(*pp++); 846 } else 847 Bprint(&bstdout, p); /* character string */ 848 } 849 850 void 851 output(char *p) 852 { 853 routput(p); 854 bsp_nxt = &bspace[0]; 855 Bprint(&bstdout, "\n"); 856 Bflush(&bstdout); 857 cp = cary; 858 crs = rcrs; 859 } 860 861 void 862 conout(char *p, char *s) 863 { 864 Bprint(&bstdout, "["); 865 routput(p); 866 Bprint(&bstdout, "]s%s\n", s); 867 Bflush(&bstdout); 868 lev--; 869 } 870 871 void 872 yyerror(char *s, ...) 873 { 874 if(ifile > sargc) 875 ss = "teletype"; 876 Bprint(&bstdout, "c[%s:%d, %s]pc\n", s, ln+1, ss); 877 Bflush(&bstdout); 878 cp = cary; 879 crs = rcrs; 880 bindx = 0; 881 lev = 0; 882 bsp_nxt = &bspace[0]; 883 } 884 885 void 886 pp(char *s) 887 { 888 /* puts the relevant stuff on pre and post for the letter s */ 889 bundle(3, "S", s, pre); 890 pre = yyval.cptr; 891 bundle(4, post, "L", s, "s."); 892 post = yyval.cptr; 893 } 894 895 void 896 tp(char *s) 897 { 898 /* same as pp, but for temps */ 899 bundle(3, "0S", s, pre); 900 pre = yyval.cptr; 901 bundle(4, post, "L", s, "s."); 902 post = yyval.cptr; 903 } 904 905 void 906 yyinit(int argc, char **argv) 907 { 908 Binit(&bstdout, 1, OWRITE); 909 sargv = argv; 910 sargc = argc; 911 if(sargc == 0) { 912 in = &bstdin; 913 Binit(in, 0, OREAD); 914 } else if((in = Bopen(sargv[0], OREAD)) == 0) 915 yyerror("cannot open input file"); 916 ifile = 0; 917 ln = 0; 918 ss = sargv[0]; 919 } 920 921 void 922 getout(void) 923 { 924 Bprint(&bstdout, "q"); 925 Bflush(&bstdout); 926 exits(0); 927 } 928 929 char* 930 getf(char *p) 931 { 932 return funtab[*p - 'a']; 933 } 934 935 char* 936 geta(char *p) 937 { 938 return atab[*p - 'a']; 939 } 940 941 void 942 main(int argc, char **argv) 943 { 944 int p[2]; 945 946 ARGBEGIN{ 947 case 'd': 948 bdebug++; 949 break; 950 case 'c': 951 cflag++; 952 break; 953 case 'l': 954 lflag++; 955 break; 956 case 's': 957 sflag++; 958 break; 959 default: 960 fprint(2, "Usage: bc [-l] [-c] [file ...]\n"); 961 exits("usage"); 962 }ARGEND 963 964 if(lflag) { 965 argc++; 966 argv--; 967 *argv = unsharp("#9/lib/bclib"); 968 } 969 if(cflag) { 970 yyinit(argc, argv); 971 for(;;) 972 yyparse(); 973 exits(0); 974 } 975 pipe(p); 976 if(fork() == 0) { 977 dup(p[1], 1); 978 close(p[0]); 979 close(p[1]); 980 yyinit(argc, argv); 981 for(;;) 982 yyparse(); 983 } 984 dup(p[0], 0); 985 close(p[0]); 986 close(p[1]); 987 execl(unsharp("#9/bin/dc"), "dc", nil); 988 }