|
|
1.1 ! root 1: /* Bc - an infix desk calculator */ ! 2: ! 3: %{ ! 4: #include <stdio.h> ! 5: #include "bc.h" ! 6: #define YYTNAMES ! 7: ! 8: /* This will generate yyerror() and error recovery */ ! 9: #define YYSYNTAX goto YYerract ! 10: /* This will enter error recovery */ ! 11: #define YYERROR ++yyerrflag; goto YYerract ! 12: ! 13: static code *breakloc = NULL; /* where to go on break statement */ ! 14: static code *contloc = NULL; /* where to go on continue statement */ ! 15: static dicent *retfrom = NULL; /* what function to return from */ ! 16: static dicent **dvec; /* list of locals */ ! 17: static dicent **pardvec; /* list of formal parameters */ ! 18: static dicent **autdvec; /* list of automatic variables */ ! 19: static int ldvec; /* length of dvec */ ! 20: static int lpardvec; /* length of pardvec */ ! 21: static int lautdvec; /* length of autdvec */ ! 22: %} ! 23: ! 24: ! 25: %union { ! 26: opcode opcode; ! 27: rvalue *lvalue; ! 28: char *svalue; ! 29: dicent *dvalue; ! 30: int ivalue; ! 31: code *location; ! 32: } ! 33: ! 34: ! 35: %token <lvalue> NUMBER ! 36: %token <svalue> STRING ! 37: %token <dvalue> IDENTIFIER ! 38: %token ADDAB AUTO BREAK CONTINUE DECR DEFINE ! 39: %token DIVAB DO DOT ELSE EQP ERROR ! 40: %token EXPAB FOR GEP GTP IBASE IF ! 41: %token INCR LENGTH_ LEP LTP MULAB NEP ! 42: %token OBASE QUIT REMAB RETURN_ SCALE_ SQRT_ ! 43: %token SUBAB WHILE ! 44: ! 45: %type <opcode> assignment_op special_load special_store ! 46: %type <opcode> function_like_primitive relational ! 47: %type <dvalue> local ! 48: %type <ivalue> argument_list non_empty_argument_list ! 49: %type <location> jump_true jump_false else_part ! 50: %type <location> goto save_loc save_break ! 51: %type <location> save_continue ! 52: ! 53: %right '=' ! 54: %left '+' '-' ! 55: %left '*' '/' '%' ! 56: %right '^' ! 57: %left INCR DECR UMINUS ! 58: ! 59: %% ! 60: /* Error recovery: allok is FALSE if any syntax or semantic error ! 61: * occurred, but the error production will be reduced in all cases ! 62: * except one, the case where cstream overflows. ! 63: */ ! 64: ! 65: session: ! 66: /* empty */ ! 67: | session statement { ! 68: emitop(STOP); ! 69: immfix: if (allok) ! 70: interp(); ! 71: litfree(cstream, loc); ! 72: loc = cstream; ! 73: allok = TRUE; ! 74: breakloc = contloc = retfrom = NULL; ! 75: } ! 76: | session definition { ! 77: if (loc[-1].opcode != RETURN) { ! 78: emitop(PGLSC); ! 79: emitnum(&zero); ! 80: emitop(LOAD); ! 81: emitop(RETURN); ! 82: emitid(retfrom); ! 83: } ! 84: deffix: if (allok) ! 85: install(&retfrom->globalv.fvalue, pardvec, lpardvec, ! 86: autdvec, lautdvec); ! 87: else { ! 88: remloc(pardvec, lpardvec); ! 89: remloc(autdvec, lautdvec); ! 90: retfrom->globalt = UNDEFINED; ! 91: litfree(cstream, loc); ! 92: } ! 93: mpfree(pardvec); ! 94: lpardvec = 0; ! 95: pardvec = NULL; ! 96: mpfree(autdvec); ! 97: lautdvec = 0; ! 98: autdvec = NULL; ! 99: mpfree(dvec); ! 100: ldvec = 0; ! 101: dvec = NULL; ! 102: loc = cstream; ! 103: allok = TRUE; ! 104: breakloc = contloc = retfrom = NULL; ! 105: } ! 106: | session error '\n' { ! 107: YYERROK; ! 108: if (retfrom != NULL) ! 109: goto deffix; ! 110: else ! 111: goto immfix; ! 112: } ! 113: ; ! 114: ! 115: /* ! 116: * Statements. ! 117: */ ! 118: ! 119: statement: ! 120: /* ! 121: * The code generated for an IF statement with an else part is as ! 122: * follows: ! 123: * if not condition, goto L1 ! 124: * true part of IF statement ! 125: * goto L2 ! 126: * L1: false part of IF statement ! 127: * L2: ! 128: * ! 129: * If there is no ELSE part, then the code generated is as ! 130: * follows: ! 131: * if not condition, goto L1 ! 132: * true part of IF statement ! 133: * L1: ! 134: */ ! 135: IF '(' jump_false ')' /* $1 */ ! 136: statement /* $5 */ ! 137: else_part { /* $6 */ ! 138: patch($3, $6); ! 139: } ! 140: | ! 141: /* ! 142: * The code generated for the WHILE statement is as ! 143: * follows: ! 144: * CONTINUE: if condition, goto L1 ! 145: * BREAK: goto L2 ! 146: * L1: body of WHILE statement ! 147: * goto CONTINUE ! 148: * L2: ! 149: */ ! 150: WHILE save_continue '(' jump_true ')' /* $1 */ ! 151: save_break goto /* $6 */ ! 152: save_loc statement /* $8 */ ! 153: goto { /* $10 */ ! 154: patch($4, $8); ! 155: patch($7, loc); ! 156: patch($10, contloc); ! 157: breakloc = $6; /* restore break */ ! 158: contloc = $2; /* restore continue */ ! 159: } ! 160: | ! 161: /* ! 162: * The code produced for the FOR statement is as ! 163: * follows: ! 164: * initialization expression ! 165: * L1: if condition, goto L3 ! 166: * BREAK: goto L4 ! 167: * CONTINUE: increment expression ! 168: * goto L1 ! 169: * L3: body of FOR statement ! 170: * goto CONTINUE ! 171: * L4: ! 172: */ ! 173: FOR '(' optional_expression_list';' /* $1 */ ! 174: save_loc jump_true ';' /* $5 */ ! 175: save_break goto /* $8 */ ! 176: save_continue optional_expression_list ')' /* $10 */ ! 177: goto /* $13 */ ! 178: save_loc statement /* $14 */ ! 179: goto { /* $16 */ ! 180: patch($6, $14); ! 181: patch($9, loc); ! 182: patch($13, $5); ! 183: patch($16, contloc); ! 184: breakloc = $8; ! 185: contloc = $10; ! 186: } ! 187: | ! 188: /* ! 189: * The code produced for the DO-WHILE statement is as ! 190: * follows: ! 191: * goto L1 ! 192: * BREAK: goto L3 ! 193: * CONTINUE: goto L2 ! 194: * L1: body of DO-WHILE statement ! 195: * L2: if condition, goto L1 ! 196: * L3: ! 197: */ ! 198: DO goto /* $1 */ ! 199: save_break goto /* $3 */ ! 200: save_continue goto /* $5 */ ! 201: save_loc statement WHILE '(' /* $7 */ ! 202: save_loc jump_true ')' end_of_statement { /* $11 */ ! 203: patch($2, $7); ! 204: patch($4, loc); ! 205: patch($6, $11); ! 206: patch($12, $7); ! 207: breakloc = $3; ! 208: contloc = $5; ! 209: } ! 210: | BREAK end_of_statement { ! 211: if (breakloc == NULL) { ! 212: gerror("Break not in loop"); ! 213: YYERROR; ! 214: } ! 215: emitop(BRALW); ! 216: emitaddr(breakloc); ! 217: } ! 218: | CONTINUE end_of_statement { ! 219: if (contloc == NULL) { ! 220: gerror("Continue not in loop"); ! 221: YYERROR; ! 222: } ! 223: emitop(BRALW); ! 224: emitaddr(contloc); ! 225: } ! 226: | RETURN_ end_of_statement { ! 227: if (retfrom == NULL) { ! 228: gerror("Return not in function"); ! 229: YYERROR; ! 230: } ! 231: emitop(PGLSC); ! 232: emitnum(&zero); ! 233: emitop(LOAD); ! 234: emitop(RETURN); ! 235: emitid(retfrom); ! 236: } ! 237: | RETURN_ expression end_of_statement { ! 238: if (retfrom == NULL) { ! 239: gerror("Return not in function"); ! 240: YYERROR; ! 241: } ! 242: emitop(RETURN); ! 243: emitid(retfrom); ! 244: } ! 245: | assignment_expression end_of_statement { ! 246: emitop(POP); ! 247: } ! 248: | non_assignment_expression end_of_statement { ! 249: emitop(PRNUM); ! 250: emitop(PRNL); ! 251: } ! 252: | non_assignment_expression '$' end_of_statement { ! 253: emitop(PRNUM); ! 254: } ! 255: | STRING end_of_statement { ! 256: emitop(PRSTR); ! 257: emitstr($1); ! 258: emitop(PRNL); ! 259: } ! 260: | STRING '$' end_of_statement { ! 261: emitop(PRSTR); ! 262: emitstr($1); ! 263: } ! 264: | '{' statement_list '}' ! 265: | QUIT end_of_statement { ! 266: emitop(EXIT); ! 267: } ! 268: | end_of_statement ! 269: ; ! 270: ! 271: end_of_statement: ! 272: ';' ! 273: | '\n' ! 274: ; ! 275: ! 276: statement_list: ! 277: /* empty */ ! 278: | statement_list statement ! 279: ; ! 280: ! 281: else_part: ! 282: /* empty */ { ! 283: $$ = loc; ! 284: } ! 285: | ELSE goto save_loc statement { ! 286: $$ = $3; ! 287: patch($2, loc); ! 288: } ! 289: ; ! 290: ! 291: optional_expression_list: ! 292: /* empty */ ! 293: | non_empty_expression_list ! 294: ; ! 295: ! 296: non_empty_expression_list: ! 297: expression { ! 298: emitop(POP); ! 299: } ! 300: | non_empty_expression_list ',' expression { ! 301: emitop(POP); ! 302: } ! 303: ; ! 304: ! 305: goto: ! 306: /* empty */ { ! 307: emitop(BRALW); ! 308: $$ = emitzap; ! 309: } ! 310: ; ! 311: ! 312: save_loc: ! 313: /* empty */ { ! 314: $$ = loc; ! 315: } ! 316: ; ! 317: ! 318: save_break: ! 319: /* empty */ { ! 320: $$ = breakloc; ! 321: breakloc = loc; ! 322: } ! 323: ; ! 324: ! 325: save_continue: ! 326: /* empty */ { ! 327: $$ = contloc; ! 328: contloc = loc; ! 329: } ! 330: ; ! 331: ! 332: /* ! 333: * Function definition. ! 334: */ ! 335: ! 336: definition: ! 337: definition_header '(' parameter_list ')' /* $1 */ ! 338: optional_nl '{' '\n' /* $5 */ ! 339: optional_auto statement_list '}' /* $8 */ ! 340: ; ! 341: ! 342: definition_header: ! 343: DEFINE IDENTIFIER { ! 344: if (chkfunc($2)) { ! 345: retfrom = $2; ! 346: } else { ! 347: YYERROR; ! 348: } ! 349: } ! 350: ; ! 351: ! 352: parameter_list: ! 353: /* empty */ ! 354: | non_empty_local_list { ! 355: pardvec = dvec; ! 356: lpardvec = ldvec; ! 357: locaddr(pardvec, lpardvec, 0); ! 358: dvec = NULL; ! 359: ldvec = 0; ! 360: } ! 361: ; ! 362: ! 363: optional_auto: ! 364: /* empty */ ! 365: | AUTO non_empty_local_list end_of_statement { ! 366: autdvec = dvec; ! 367: lautdvec = ldvec; ! 368: locaddr(autdvec, lautdvec, lpardvec); ! 369: dvec = NULL; ! 370: ldvec = 0; ! 371: } ! 372: ; ! 373: ! 374: non_empty_local_list: ! 375: local { ! 376: dvec = (dicent **)mpalc(ldvec * sizeof (*dvec)); ! 377: dvec += ldvec; ! 378: *--dvec = $1; ! 379: } ! 380: | local ',' non_empty_local_list { ! 381: *--dvec = $1; ! 382: } ! 383: ; ! 384: ! 385: local: ! 386: IDENTIFIER { ! 387: if ($1->localt != UNDEFINED) { ! 388: gerror("Attempt to redeclare %s", $1->word); ! 389: YYERROR; ! 390: } ! 391: $1->localt = SCALAR; ! 392: ++ldvec; ! 393: /* $$ = $1 */ ! 394: } ! 395: | IDENTIFIER '[' ']' { ! 396: if ($1->localt != UNDEFINED) { ! 397: gerror("Attempt to redeclare %s", $1->word); ! 398: YYERROR; ! 399: } ! 400: $1->localt = ARRAY; ! 401: ++ldvec; ! 402: /* $$ = $1 */ ! 403: } ! 404: ; ! 405: ! 406: optional_nl: ! 407: /* empty */ ! 408: | '\n' ! 409: ; ! 410: ! 411: /* ! 412: * Expressions. ! 413: */ ! 414: ! 415: expression: ! 416: assignment_expression ! 417: | non_assignment_expression ! 418: ; ! 419: ! 420: assignment_expression: ! 421: l_value '=' expression { ! 422: emitop(STORE); ! 423: } ! 424: | l_value add_r_value assignment_op expression { ! 425: emitop($3); ! 426: emitop(STORE); ! 427: } ! 428: | special_store '=' expression { ! 429: emitop($1); ! 430: } ! 431: | special_load assignment_op expression { ! 432: emitop($2); ! 433: emitop($1); ! 434: } ! 435: ; ! 436: ! 437: non_assignment_expression: ! 438: NUMBER { ! 439: emitop(PLISC); ! 440: emitnum($1); ! 441: emitop(LOAD); ! 442: } ! 443: | l_value { ! 444: emitop(LOAD); ! 445: } ! 446: | special_load ! 447: | IDENTIFIER '(' argument_list ')' { ! 448: if (chkfunc($1)) { ! 449: emitop(CALL); ! 450: emitid($1); ! 451: emitcnt($3); ! 452: } else { ! 453: YYERROR; ! 454: } ! 455: } ! 456: | INCR l_value { ! 457: emitop(PRVAL); ! 458: emitop(INC); ! 459: emitop(STORE); ! 460: } ! 461: | INCR special_load { ! 462: emitop(INC); ! 463: emitop($2); ! 464: } ! 465: | DECR l_value { ! 466: emitop(PRVAL); ! 467: emitop(DEC); ! 468: emitop(STORE); ! 469: } ! 470: | DECR special_load { ! 471: emitop(DEC); ! 472: emitop($2); ! 473: } ! 474: | l_value INCR { ! 475: emitop(PRVAL); ! 476: emitop(INC); ! 477: emitop(STORE); ! 478: emitop(DEC); ! 479: } ! 480: | special_load INCR { ! 481: emitop(INC); ! 482: emitop($1); ! 483: emitop(DEC); ! 484: } ! 485: | l_value DECR { ! 486: emitop(PRVAL); ! 487: emitop(DEC); ! 488: emitop(STORE); ! 489: emitop(INC); ! 490: } ! 491: | special_load DECR { ! 492: emitop(DEC); ! 493: emitop($1); ! 494: emitop(INC); ! 495: } ! 496: | '-' non_assignment_expression %prec UMINUS { ! 497: emitop(NEG); ! 498: } ! 499: | non_assignment_expression '^' non_assignment_expression { ! 500: emitop(EXP); ! 501: } ! 502: | non_assignment_expression '*' non_assignment_expression { ! 503: emitop(MUL); ! 504: } ! 505: | non_assignment_expression '/' non_assignment_expression { ! 506: emitop(DIV); ! 507: } ! 508: | non_assignment_expression '%' non_assignment_expression { ! 509: emitop(REM); ! 510: } ! 511: | non_assignment_expression '+' non_assignment_expression { ! 512: emitop(ADD); ! 513: } ! 514: | non_assignment_expression '-' non_assignment_expression { ! 515: emitop(SUB); ! 516: } ! 517: | '(' expression ')' ! 518: | function_like_primitive '(' expression ')' { ! 519: emitop($1); ! 520: } ! 521: ; ! 522: ! 523: l_value: ! 524: IDENTIFIER { ! 525: if (chktype($1, SCALAR)) ! 526: sload($1); ! 527: else { ! 528: YYERROR; ! 529: } ! 530: } ! 531: | IDENTIFIER '[' expression ']' { ! 532: if (chktype($1, ARRAY)) ! 533: aeload($1); ! 534: else { ! 535: YYERROR; ! 536: } ! 537: } ! 538: | DOT { ! 539: emitop(PGLSC); ! 540: emitnum(&dot); ! 541: } ! 542: ; ! 543: ! 544: argument: ! 545: expression ! 546: | IDENTIFIER '[' ']' { ! 547: if (chktype($1, ARRAY)) ! 548: arload($1); ! 549: else { ! 550: YYERROR; ! 551: } ! 552: } ! 553: ; ! 554: ! 555: argument_list: ! 556: /* empty */ { ! 557: $$ = 0; ! 558: } ! 559: | non_empty_argument_list ! 560: /* $$ = $1 */ ! 561: ; ! 562: ! 563: non_empty_argument_list: ! 564: argument { ! 565: $$ = 1; ! 566: } ! 567: | non_empty_argument_list ',' argument { ! 568: $$ = $1 + 1; ! 569: } ! 570: ; ! 571: ! 572: add_r_value: ! 573: /* empty */ { ! 574: emitop(PRVAL); ! 575: } ! 576: ; ! 577: ! 578: special_store: ! 579: IBASE { ! 580: $$ = SIBASE; ! 581: } ! 582: | OBASE { ! 583: $$ = SOBASE; ! 584: } ! 585: | SCALE_ { ! 586: $$ = SSCALE; ! 587: } ! 588: ; ! 589: ! 590: special_load: ! 591: IBASE { ! 592: emitop(LIBASE); ! 593: $$ = SIBASE; ! 594: } ! 595: | OBASE { ! 596: emitop(LOBASE); ! 597: $$ = SOBASE; ! 598: } ! 599: | SCALE_ { ! 600: emitop(LSCALE); ! 601: $$ = SSCALE; ! 602: } ! 603: ; ! 604: ! 605: assignment_op: ! 606: ADDAB { ! 607: $$ = ADD; ! 608: } ! 609: | SUBAB { ! 610: $$ = SUB; ! 611: } ! 612: | MULAB { ! 613: $$ = MUL; ! 614: } ! 615: | DIVAB { ! 616: $$ = DIV; ! 617: } ! 618: | REMAB { ! 619: $$ = REM; ! 620: } ! 621: | EXPAB { ! 622: $$ = EXP; ! 623: } ! 624: ; ! 625: ! 626: function_like_primitive: ! 627: SQRT_ { ! 628: $$ = SQRT; ! 629: } ! 630: | LENGTH_ { ! 631: $$ = LENGTH; ! 632: } ! 633: | SCALE_ { ! 634: $$ = SCALE; ! 635: } ! 636: ; ! 637: ! 638: /* ! 639: * Conditionals. ! 640: */ ! 641: ! 642: jump_true: ! 643: /* empty */ { ! 644: emitop(BRALW); ! 645: $$ = emitzap; ! 646: } ! 647: | non_assignment_expression relational non_assignment_expression { ! 648: emitop($2); ! 649: $$ = emitzap; ! 650: } ! 651: ; ! 652: ! 653: jump_false: ! 654: /* empty */ { ! 655: emitop(BRNEV); ! 656: $$ = emitzap; ! 657: } ! 658: | non_assignment_expression relational non_assignment_expression { ! 659: emitop(negate($2)); ! 660: $$ = emitzap; ! 661: } ! 662: ; ! 663: ! 664: relational: ! 665: LTP { ! 666: $$ = BRLT; ! 667: } ! 668: | LEP { ! 669: $$ = BRLE; ! 670: } ! 671: | EQP { ! 672: $$ = BREQ; ! 673: } ! 674: | GEP { ! 675: $$ = BRGE; ! 676: } ! 677: | GTP { ! 678: $$ = BRGT; ! 679: } ! 680: | NEP { ! 681: $$ = BRNE; ! 682: } ! 683: ; ! 684: ! 685: %% ! 686: ! 687: /* ! 688: * Yyerror is the error routine called on a syntax error by ! 689: * yyparse. ! 690: */ ! 691: ! 692: yyerror(m) ! 693: char *m; ! 694: { ! 695: register struct yytname *ptr; ! 696: ! 697: for (ptr = yytnames; ptr->tn_name != NULL; ++ptr) ! 698: if (ptr->tn_val == yychar) ! 699: return gerror("%s at %s", m, ptr->tn_name); ! 700: return gerror("%s", m); ! 701: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.