| 1 | %term NAME 2 |
| 2 | %term STRING 3 |
| 3 | %term ICON 4 |
| 4 | %term FCON 5 |
| 5 | %term PLUS 6 |
| 6 | %term MINUS 8 |
| 7 | %term MUL 11 |
| 8 | %term AND 14 |
| 9 | %term OR 17 |
| 10 | %term ER 19 |
| 11 | %term QUEST 21 |
| 12 | %term COLON 22 |
| 13 | %term ANDAND 23 |
| 14 | %term OROR 24 |
| 15 | |
| 16 | /* special interfaces for yacc alone */ |
| 17 | /* These serve as abbreviations of 2 or more ops: |
| 18 | ASOP =, = ops |
| 19 | RELOP LE,LT,GE,GT |
| 20 | EQUOP EQ,NE |
| 21 | DIVOP DIV,MOD |
| 22 | SHIFTOP LS,RS |
| 23 | ICOP ICR,DECR |
| 24 | UNOP NOT,COMPL |
| 25 | STROP DOT,STREF |
| 26 | |
| 27 | */ |
| 28 | %term ASOP 25 |
| 29 | %term RELOP 26 |
| 30 | %term EQUOP 27 |
| 31 | %term DIVOP 28 |
| 32 | %term SHIFTOP 29 |
| 33 | %term INCOP 30 |
| 34 | %term UNOP 31 |
| 35 | %term STROP 32 |
| 36 | |
| 37 | /* reserved words, etc */ |
| 38 | %term TYPE 33 |
| 39 | %term CLASS 34 |
| 40 | %term STRUCT 35 |
| 41 | %term RETURN 36 |
| 42 | %term GOTO 37 |
| 43 | %term IF 38 |
| 44 | %term ELSE 39 |
| 45 | %term SWITCH 40 |
| 46 | %term BREAK 41 |
| 47 | %term CONTINUE 42 |
| 48 | %term WHILE 43 |
| 49 | %term DO 44 |
| 50 | %term FOR 45 |
| 51 | %term DEFAULT 46 |
| 52 | %term CASE 47 |
| 53 | %term SIZEOF 48 |
| 54 | %term ENUM 49 |
| 55 | |
| 56 | |
| 57 | /* little symbols, etc. */ |
| 58 | /* namely, |
| 59 | |
| 60 | LP ( |
| 61 | RP ) |
| 62 | |
| 63 | LC { |
| 64 | RC } |
| 65 | |
| 66 | LB [ |
| 67 | RB ] |
| 68 | |
| 69 | CM , |
| 70 | SM ; |
| 71 | |
| 72 | */ |
| 73 | |
| 74 | %term LP 50 |
| 75 | %term RP 51 |
| 76 | %term LC 52 |
| 77 | %term RC 53 |
| 78 | %term LB 54 |
| 79 | %term RB 55 |
| 80 | %term CM 56 |
| 81 | %term SM 57 |
| 82 | %term ASSIGN 58 |
| 83 | |
| 84 | /* at last count, there were 7 shift/reduce, 1 reduce/reduce conflicts |
| 85 | /* these involved: |
| 86 | if/else |
| 87 | recognizing functions in various contexts, including declarations |
| 88 | error recovery |
| 89 | */ |
| 90 | |
| 91 | %left CM |
| 92 | %right ASOP ASSIGN |
| 93 | %right QUEST COLON |
| 94 | %left OROR |
| 95 | %left ANDAND |
| 96 | %left OR |
| 97 | %left ER |
| 98 | %left AND |
| 99 | %left EQUOP |
| 100 | %left RELOP |
| 101 | %left SHIFTOP |
| 102 | %left PLUS MINUS |
| 103 | %left MUL DIVOP |
| 104 | %right UNOP |
| 105 | %right INCOP SIZEOF |
| 106 | %left LB LP STROP |
| 107 | %{ |
| 108 | # include "mfile1" |
| 109 | %} |
| 110 | |
| 111 | /* define types */ |
| 112 | %start ext_def_list |
| 113 | |
| 114 | %type <intval> con_e ifelprefix ifprefix whprefix forprefix doprefix switchpart |
| 115 | enum_head str_head name_lp |
| 116 | %type <nodep> e .e term attributes oattributes type enum_dcl struct_dcl |
| 117 | cast_type null_decl funct_idn declarator fdeclarator nfdeclarator |
| 118 | elist |
| 119 | |
| 120 | %token <intval> CLASS NAME STRUCT RELOP CM DIVOP PLUS MINUS SHIFTOP MUL AND OR ER ANDAND OROR |
| 121 | ASSIGN STROP INCOP UNOP ICON |
| 122 | %token <nodep> TYPE |
| 123 | |
| 124 | %% |
| 125 | |
| 126 | %{ |
| 127 | static int fake = 0; |
| 128 | #ifndef FLEXNAMES |
| 129 | static char fakename[NCHNAM+1]; |
| 130 | #else |
| 131 | static char fakename[24]; |
| 132 | #endif |
| 133 | %} |
| 134 | |
| 135 | ext_def_list: ext_def_list external_def |
| 136 | | |
| 137 | =ftnend(); |
| 138 | ; |
| 139 | external_def: data_def |
| 140 | ={ curclass = SNULL; blevel = 0; } |
| 141 | | error |
| 142 | ={ curclass = SNULL; blevel = 0; } |
| 143 | ; |
| 144 | data_def: |
| 145 | oattributes SM |
| 146 | ={ $1->in.op = FREE; } |
| 147 | | oattributes init_dcl_list SM |
| 148 | ={ $1->in.op = FREE; } |
| 149 | | oattributes fdeclarator { |
| 150 | defid( tymerge($1,$2), curclass==STATIC?STATIC:EXTDEF ); |
| 151 | #ifndef LINT |
| 152 | pfstab(stab[$2->tn.rval].sname); |
| 153 | #endif |
| 154 | } function_body |
| 155 | ={ |
| 156 | if( blevel ) cerror( "function level error" ); |
| 157 | if( reached ) retstat |= NRETVAL; |
| 158 | $1->in.op = FREE; |
| 159 | ftnend(); |
| 160 | } |
| 161 | ; |
| 162 | |
| 163 | function_body: arg_dcl_list compoundstmt |
| 164 | ; |
| 165 | arg_dcl_list: arg_dcl_list declaration |
| 166 | | ={ blevel = 1; } |
| 167 | ; |
| 168 | |
| 169 | stmt_list: stmt_list statement |
| 170 | | /* empty */ |
| 171 | ={ bccode(); |
| 172 | locctr(PROG); |
| 173 | } |
| 174 | ; |
| 175 | |
| 176 | r_dcl_stat_list : dcl_stat_list attributes SM |
| 177 | ={ $2->in.op = FREE; |
| 178 | #ifndef LINT |
| 179 | plcstab(blevel); |
| 180 | #endif |
| 181 | } |
| 182 | | dcl_stat_list attributes init_dcl_list SM |
| 183 | ={ $2->in.op = FREE; |
| 184 | #ifndef LINT |
| 185 | plcstab(blevel); |
| 186 | #endif |
| 187 | } |
| 188 | ; |
| 189 | |
| 190 | dcl_stat_list : dcl_stat_list attributes SM |
| 191 | ={ $2->in.op = FREE; } |
| 192 | | dcl_stat_list attributes init_dcl_list SM |
| 193 | ={ $2->in.op = FREE; } |
| 194 | | /* empty */ |
| 195 | ; |
| 196 | declaration: attributes declarator_list SM |
| 197 | ={ curclass = SNULL; $1->in.op = FREE; } |
| 198 | | attributes SM |
| 199 | ={ curclass = SNULL; $1->in.op = FREE; } |
| 200 | | error SM |
| 201 | ={ curclass = SNULL; } |
| 202 | ; |
| 203 | oattributes: attributes |
| 204 | | /* VOID */ |
| 205 | ={ $$ = mkty(INT,0,INT); curclass = SNULL; } |
| 206 | ; |
| 207 | attributes: class type |
| 208 | ={ $$ = $2; } |
| 209 | | type class |
| 210 | | class |
| 211 | ={ $$ = mkty(INT,0,INT); } |
| 212 | | type |
| 213 | ={ curclass = SNULL ; } |
| 214 | | type class type |
| 215 | ={ $1->in.type = types( $1->in.type, $3->in.type, UNDEF ); |
| 216 | $3->in.op = FREE; |
| 217 | } |
| 218 | ; |
| 219 | |
| 220 | |
| 221 | class: CLASS |
| 222 | ={ curclass = $1; } |
| 223 | ; |
| 224 | |
| 225 | type: TYPE |
| 226 | | TYPE TYPE |
| 227 | ={ $1->in.type = types( $1->in.type, $2->in.type, UNDEF ); |
| 228 | $2->in.op = FREE; |
| 229 | } |
| 230 | | TYPE TYPE TYPE |
| 231 | ={ $1->in.type = types( $1->in.type, $2->in.type, $3->in.type ); |
| 232 | $2->in.op = $3->in.op = FREE; |
| 233 | } |
| 234 | | struct_dcl |
| 235 | | enum_dcl |
| 236 | ; |
| 237 | |
| 238 | enum_dcl: enum_head LC moe_list optcomma RC |
| 239 | ={ $$ = dclstruct($1); } |
| 240 | | ENUM NAME |
| 241 | ={ $$ = rstruct($2,0); stwart = instruct; } |
| 242 | ; |
| 243 | |
| 244 | enum_head: ENUM |
| 245 | ={ $$ = bstruct(-1,0); stwart = SEENAME; } |
| 246 | | ENUM NAME |
| 247 | ={ $$ = bstruct($2,0); stwart = SEENAME; } |
| 248 | ; |
| 249 | |
| 250 | moe_list: moe |
| 251 | | moe_list CM moe |
| 252 | ; |
| 253 | |
| 254 | moe: NAME |
| 255 | ={ moedef( $1 ); } |
| 256 | | NAME ASSIGN con_e |
| 257 | ={ strucoff = $3; moedef( $1 ); } |
| 258 | ; |
| 259 | |
| 260 | struct_dcl: str_head LC type_dcl_list optsemi RC |
| 261 | ={ $$ = dclstruct($1); } |
| 262 | | STRUCT NAME |
| 263 | ={ $$ = rstruct($2,$1); } |
| 264 | ; |
| 265 | |
| 266 | str_head: STRUCT |
| 267 | ={ $$ = bstruct(-1,$1); stwart=0; } |
| 268 | | STRUCT NAME |
| 269 | ={ $$ = bstruct($2,$1); stwart=0; } |
| 270 | ; |
| 271 | |
| 272 | type_dcl_list: type_declaration |
| 273 | | type_dcl_list SM type_declaration |
| 274 | ; |
| 275 | |
| 276 | type_declaration: type declarator_list |
| 277 | ={ curclass = SNULL; stwart=0; $1->in.op = FREE; } |
| 278 | | type |
| 279 | ={ if( curclass != MOU ){ |
| 280 | curclass = SNULL; |
| 281 | } |
| 282 | else { |
| 283 | sprintf( fakename, "$%dFAKE", fake++ ); |
| 284 | #ifdef FLEXSTRINGS |
| 285 | /* No need to hash this, we won't look it up */ |
| 286 | defid( tymerge($1, bdty(NAME,NIL,lookup( savestr(fakename), SMOS ))), curclass ); |
| 287 | #else |
| 288 | defid( tymerge($1, bdty(NAME,NIL,lookup( fakename, SMOS ))), curclass ); |
| 289 | #endif |
| 290 | werror("structure typed union member must be named"); |
| 291 | } |
| 292 | stwart = 0; |
| 293 | $1->in.op = FREE; |
| 294 | } |
| 295 | ; |
| 296 | |
| 297 | |
| 298 | declarator_list: declarator |
| 299 | ={ defid( tymerge($<nodep>0,$1), curclass); stwart = instruct; } |
| 300 | | declarator_list CM {$<nodep>$=$<nodep>0;} declarator |
| 301 | ={ defid( tymerge($<nodep>0,$4), curclass); stwart = instruct; } |
| 302 | ; |
| 303 | declarator: fdeclarator |
| 304 | | nfdeclarator |
| 305 | | nfdeclarator COLON con_e |
| 306 | %prec CM |
| 307 | ={ if( !(instruct&INSTRUCT) ) uerror( "field outside of structure" ); |
| 308 | if( $3<0 || $3 >= FIELD ){ |
| 309 | uerror( "illegal field size" ); |
| 310 | $3 = 1; |
| 311 | } |
| 312 | defid( tymerge($<nodep>0,$1), FIELD|$3 ); |
| 313 | $$ = NIL; |
| 314 | } |
| 315 | | COLON con_e |
| 316 | %prec CM |
| 317 | ={ if( !(instruct&INSTRUCT) ) uerror( "field outside of structure" ); |
| 318 | falloc( stab, $2, -1, $<nodep>0 ); /* alignment or hole */ |
| 319 | $$ = NIL; |
| 320 | } |
| 321 | | error |
| 322 | ={ $$ = NIL; } |
| 323 | ; |
| 324 | |
| 325 | /* int (a)(); is not a function --- sorry! */ |
| 326 | nfdeclarator: MUL nfdeclarator |
| 327 | ={ umul: |
| 328 | $$ = bdty( UNARY MUL, $2, 0 ); } |
| 329 | | nfdeclarator LP RP |
| 330 | ={ uftn: |
| 331 | $$ = bdty( UNARY CALL, $1, 0 ); } |
| 332 | | nfdeclarator LB RB |
| 333 | ={ uary: |
| 334 | $$ = bdty( LB, $1, 0 ); } |
| 335 | | nfdeclarator LB con_e RB |
| 336 | ={ bary: |
| 337 | if( (int)$3 <= 0 ) werror( "zero or negative subscript" ); |
| 338 | $$ = bdty( LB, $1, $3 ); } |
| 339 | | NAME |
| 340 | ={ $$ = bdty( NAME, NIL, $1 ); } |
| 341 | | LP nfdeclarator RP |
| 342 | ={ $$=$2; } |
| 343 | ; |
| 344 | fdeclarator: MUL fdeclarator |
| 345 | ={ goto umul; } |
| 346 | | fdeclarator LP RP |
| 347 | ={ goto uftn; } |
| 348 | | fdeclarator LB RB |
| 349 | ={ goto uary; } |
| 350 | | fdeclarator LB con_e RB |
| 351 | ={ goto bary; } |
| 352 | | LP fdeclarator RP |
| 353 | ={ $$ = $2; } |
| 354 | | name_lp name_list RP |
| 355 | ={ |
| 356 | if( blevel!=0 ) uerror("function declaration in bad context"); |
| 357 | $$ = bdty( UNARY CALL, bdty(NAME,NIL,$1), 0 ); |
| 358 | stwart = 0; |
| 359 | } |
| 360 | | name_lp RP |
| 361 | ={ |
| 362 | $$ = bdty( UNARY CALL, bdty(NAME,NIL,$1), 0 ); |
| 363 | stwart = 0; |
| 364 | } |
| 365 | ; |
| 366 | |
| 367 | name_lp: NAME LP |
| 368 | ={ |
| 369 | /* turn off typedefs for argument names */ |
| 370 | stwart = SEENAME; |
| 371 | if( stab[$1].sclass == SNULL ) |
| 372 | stab[$1].stype = FTN; |
| 373 | } |
| 374 | ; |
| 375 | |
| 376 | name_list: NAME |
| 377 | ={ ftnarg( $1 ); stwart = SEENAME; } |
| 378 | | name_list CM NAME |
| 379 | ={ ftnarg( $3 ); stwart = SEENAME; } |
| 380 | | error |
| 381 | ; |
| 382 | /* always preceeded by attributes: thus the $<nodep>0's */ |
| 383 | init_dcl_list: init_declarator |
| 384 | %prec CM |
| 385 | | init_dcl_list CM {$<nodep>$=$<nodep>0;} init_declarator |
| 386 | ; |
| 387 | /* always preceeded by attributes */ |
| 388 | xnfdeclarator: nfdeclarator |
| 389 | ={ defid( $1 = tymerge($<nodep>0,$1), curclass); |
| 390 | beginit($1->tn.rval); |
| 391 | } |
| 392 | | error |
| 393 | ; |
| 394 | /* always preceeded by attributes */ |
| 395 | init_declarator: nfdeclarator |
| 396 | ={ nidcl( tymerge($<nodep>0,$1) ); } |
| 397 | | fdeclarator |
| 398 | ={ defid( tymerge($<nodep>0,$1), uclass(curclass) ); |
| 399 | } |
| 400 | | xnfdeclarator optasgn e |
| 401 | %prec CM |
| 402 | ={ doinit( $3 ); |
| 403 | endinit(); } |
| 404 | | xnfdeclarator optasgn LC init_list optcomma RC |
| 405 | ={ endinit(); } |
| 406 | | error |
| 407 | ; |
| 408 | |
| 409 | init_list: initializer |
| 410 | %prec CM |
| 411 | | init_list CM initializer |
| 412 | ; |
| 413 | initializer: e |
| 414 | %prec CM |
| 415 | ={ doinit( $1 ); } |
| 416 | | ibrace init_list optcomma RC |
| 417 | ={ irbrace(); } |
| 418 | ; |
| 419 | |
| 420 | optcomma : /* VOID */ |
| 421 | | CM |
| 422 | ; |
| 423 | |
| 424 | optsemi : /* VOID */ |
| 425 | | SM |
| 426 | ; |
| 427 | |
| 428 | optasgn : /* VOID */ |
| 429 | ={ werror( "old-fashioned initialization: use =" ); } |
| 430 | | ASSIGN |
| 431 | ; |
| 432 | |
| 433 | ibrace : LC |
| 434 | ={ ilbrace(); } |
| 435 | ; |
| 436 | |
| 437 | /* STATEMENTS */ |
| 438 | |
| 439 | compoundstmt: dcmpstmt |
| 440 | | cmpstmt |
| 441 | ; |
| 442 | |
| 443 | dcmpstmt: begin r_dcl_stat_list stmt_list RC |
| 444 | ={ |
| 445 | #ifndef LINT |
| 446 | prcstab(blevel); |
| 447 | #endif |
| 448 | --blevel; |
| 449 | if( blevel == 1 ) blevel = 0; |
| 450 | clearst( blevel ); |
| 451 | checkst( blevel ); |
| 452 | autooff = *--psavbc; |
| 453 | regvar = *--psavbc; |
| 454 | } |
| 455 | ; |
| 456 | |
| 457 | cmpstmt: begin stmt_list RC |
| 458 | ={ --blevel; |
| 459 | if( blevel == 1 ) blevel = 0; |
| 460 | clearst( blevel ); |
| 461 | checkst( blevel ); |
| 462 | autooff = *--psavbc; |
| 463 | regvar = *--psavbc; |
| 464 | } |
| 465 | ; |
| 466 | |
| 467 | begin: LC |
| 468 | ={ if( blevel == 1 ) dclargs(); |
| 469 | ++blevel; |
| 470 | if( psavbc > &asavbc[BCSZ-2] ) cerror( "nesting too deep" ); |
| 471 | *psavbc++ = regvar; |
| 472 | *psavbc++ = autooff; |
| 473 | } |
| 474 | ; |
| 475 | |
| 476 | statement: e SM |
| 477 | ={ ecomp( $1 ); } |
| 478 | | compoundstmt |
| 479 | | ifprefix statement |
| 480 | ={ deflab($1); |
| 481 | reached = 1; |
| 482 | } |
| 483 | | ifelprefix statement |
| 484 | ={ if( $1 != NOLAB ){ |
| 485 | deflab( $1 ); |
| 486 | reached = 1; |
| 487 | } |
| 488 | } |
| 489 | | whprefix statement |
| 490 | ={ branch( contlab ); |
| 491 | deflab( brklab ); |
| 492 | if( (flostat&FBRK) || !(flostat&FLOOP)) reached = 1; |
| 493 | else reached = 0; |
| 494 | resetbc(0); |
| 495 | } |
| 496 | | doprefix statement WHILE LP e RP SM |
| 497 | ={ deflab( contlab ); |
| 498 | if( flostat & FCONT ) reached = 1; |
| 499 | ecomp( buildtree( CBRANCH, buildtree( NOT, $5, NIL ), bcon( $1 ) ) ); |
| 500 | deflab( brklab ); |
| 501 | reached = 1; |
| 502 | resetbc(0); |
| 503 | } |
| 504 | | forprefix .e RP statement |
| 505 | ={ deflab( contlab ); |
| 506 | if( flostat&FCONT ) reached = 1; |
| 507 | if( $2 ) ecomp( $2 ); |
| 508 | branch( $1 ); |
| 509 | deflab( brklab ); |
| 510 | if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1; |
| 511 | else reached = 0; |
| 512 | resetbc(0); |
| 513 | } |
| 514 | | switchpart statement |
| 515 | ={ if( reached ) branch( brklab ); |
| 516 | deflab( $1 ); |
| 517 | swend(); |
| 518 | deflab(brklab); |
| 519 | if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1; |
| 520 | resetbc(FCONT); |
| 521 | } |
| 522 | | BREAK SM |
| 523 | ={ if( brklab == NOLAB ) uerror( "illegal break"); |
| 524 | else if(reached) branch( brklab ); |
| 525 | flostat |= FBRK; |
| 526 | if( brkflag ) goto rch; |
| 527 | reached = 0; |
| 528 | } |
| 529 | | CONTINUE SM |
| 530 | ={ if( contlab == NOLAB ) uerror( "illegal continue"); |
| 531 | else branch( contlab ); |
| 532 | flostat |= FCONT; |
| 533 | goto rch; |
| 534 | } |
| 535 | | RETURN SM |
| 536 | ={ retstat |= NRETVAL; |
| 537 | branch( retlab ); |
| 538 | rch: |
| 539 | if( !reached ) werror( "statement not reached"); |
| 540 | reached = 0; |
| 541 | } |
| 542 | | RETURN e SM |
| 543 | ={ register NODE *temp; |
| 544 | idname = curftn; |
| 545 | temp = buildtree( NAME, NIL, NIL ); |
| 546 | if(temp->in.type == TVOID) |
| 547 | uerror("void function %s cannot return value", |
| 548 | stab[idname].sname); |
| 549 | temp->in.type = DECREF( temp->in.type ); |
| 550 | temp = buildtree( RETURN, temp, $2 ); |
| 551 | /* now, we have the type of the RHS correct */ |
| 552 | temp->in.left->in.op = FREE; |
| 553 | temp->in.op = FREE; |
| 554 | ecomp( buildtree( FORCE, temp->in.right, NIL ) ); |
| 555 | retstat |= RETVAL; |
| 556 | branch( retlab ); |
| 557 | reached = 0; |
| 558 | } |
| 559 | | GOTO NAME SM |
| 560 | ={ register NODE *q; |
| 561 | q = block( FREE, NIL, NIL, INT|ARY, 0, INT ); |
| 562 | q->tn.rval = idname = $2; |
| 563 | defid( q, ULABEL ); |
| 564 | stab[idname].suse = -lineno; |
| 565 | branch( stab[idname].offset ); |
| 566 | goto rch; |
| 567 | } |
| 568 | | SM |
| 569 | | error SM |
| 570 | | error RC |
| 571 | | label statement |
| 572 | ; |
| 573 | label: NAME COLON |
| 574 | ={ register NODE *q; |
| 575 | q = block( FREE, NIL, NIL, INT|ARY, 0, LABEL ); |
| 576 | q->tn.rval = $1; |
| 577 | defid( q, LABEL ); |
| 578 | reached = 1; |
| 579 | } |
| 580 | | CASE e COLON |
| 581 | ={ addcase($2); |
| 582 | reached = 1; |
| 583 | } |
| 584 | | DEFAULT COLON |
| 585 | ={ reached = 1; |
| 586 | adddef(); |
| 587 | flostat |= FDEF; |
| 588 | } |
| 589 | ; |
| 590 | doprefix: DO |
| 591 | ={ savebc(); |
| 592 | if( !reached ) werror( "loop not entered at top"); |
| 593 | brklab = getlab(); |
| 594 | contlab = getlab(); |
| 595 | deflab( $$ = getlab() ); |
| 596 | reached = 1; |
| 597 | } |
| 598 | ; |
| 599 | ifprefix: IF LP e RP |
| 600 | ={ ecomp( buildtree( CBRANCH, $3, bcon( $$=getlab()) ) ) ; |
| 601 | reached = 1; |
| 602 | } |
| 603 | ; |
| 604 | ifelprefix: ifprefix statement ELSE |
| 605 | ={ if( reached ) branch( $$ = getlab() ); |
| 606 | else $$ = NOLAB; |
| 607 | deflab( $1 ); |
| 608 | reached = 1; |
| 609 | } |
| 610 | ; |
| 611 | |
| 612 | whprefix: WHILE LP e RP |
| 613 | ={ savebc(); |
| 614 | if( !reached ) werror( "loop not entered at top"); |
| 615 | if( $3->in.op == ICON && $3->tn.lval != 0 ) flostat = FLOOP; |
| 616 | deflab( contlab = getlab() ); |
| 617 | reached = 1; |
| 618 | brklab = getlab(); |
| 619 | if( flostat == FLOOP ) tfree( $3 ); |
| 620 | else ecomp( buildtree( CBRANCH, $3, bcon( brklab) ) ); |
| 621 | } |
| 622 | ; |
| 623 | forprefix: FOR LP .e SM .e SM |
| 624 | ={ if( $3 ) ecomp( $3 ); |
| 625 | else if( !reached ) werror( "loop not entered at top"); |
| 626 | savebc(); |
| 627 | contlab = getlab(); |
| 628 | brklab = getlab(); |
| 629 | deflab( $$ = getlab() ); |
| 630 | reached = 1; |
| 631 | if( $5 ) ecomp( buildtree( CBRANCH, $5, bcon( brklab) ) ); |
| 632 | else flostat |= FLOOP; |
| 633 | } |
| 634 | ; |
| 635 | switchpart: SWITCH LP e RP |
| 636 | ={ savebc(); |
| 637 | brklab = getlab(); |
| 638 | ecomp( buildtree( FORCE, $3, NIL ) ); |
| 639 | branch( $$ = getlab() ); |
| 640 | swstart(); |
| 641 | reached = 0; |
| 642 | } |
| 643 | ; |
| 644 | /* EXPRESSIONS */ |
| 645 | con_e: { $<intval>$=instruct; stwart=instruct=0; } e |
| 646 | %prec CM |
| 647 | ={ $$ = icons( $2 ); instruct=$<intval>1; } |
| 648 | ; |
| 649 | .e: e |
| 650 | | |
| 651 | ={ $$=0; } |
| 652 | ; |
| 653 | elist: e |
| 654 | %prec CM |
| 655 | | elist CM e |
| 656 | ={ goto bop; } |
| 657 | ; |
| 658 | |
| 659 | e: e RELOP e |
| 660 | ={ |
| 661 | preconf: |
| 662 | if( yychar==RELOP||yychar==EQUOP||yychar==AND||yychar==OR||yychar==ER ){ |
| 663 | precplaint: |
| 664 | if( hflag ) werror( "precedence confusion possible: parenthesize!" ); |
| 665 | } |
| 666 | bop: |
| 667 | $$ = buildtree( $2, $1, $3 ); |
| 668 | } |
| 669 | | e CM e |
| 670 | ={ $2 = COMOP; |
| 671 | goto bop; |
| 672 | } |
| 673 | | e DIVOP e |
| 674 | ={ goto bop; } |
| 675 | | e PLUS e |
| 676 | ={ if(yychar==SHIFTOP) goto precplaint; else goto bop; } |
| 677 | | e MINUS e |
| 678 | ={ if(yychar==SHIFTOP ) goto precplaint; else goto bop; } |
| 679 | | e SHIFTOP e |
| 680 | ={ if(yychar==PLUS||yychar==MINUS) goto precplaint; else goto bop; } |
| 681 | | e MUL e |
| 682 | ={ goto bop; } |
| 683 | | e EQUOP e |
| 684 | ={ goto preconf; } |
| 685 | | e AND e |
| 686 | ={ if( yychar==RELOP||yychar==EQUOP ) goto preconf; else goto bop; } |
| 687 | | e OR e |
| 688 | ={ if(yychar==RELOP||yychar==EQUOP) goto preconf; else goto bop; } |
| 689 | | e ER e |
| 690 | ={ if(yychar==RELOP||yychar==EQUOP) goto preconf; else goto bop; } |
| 691 | | e ANDAND e |
| 692 | ={ goto bop; } |
| 693 | | e OROR e |
| 694 | ={ goto bop; } |
| 695 | | e MUL ASSIGN e |
| 696 | ={ abop: |
| 697 | $$ = buildtree( ASG $2, $1, $4 ); |
| 698 | } |
| 699 | | e DIVOP ASSIGN e |
| 700 | ={ goto abop; } |
| 701 | | e PLUS ASSIGN e |
| 702 | ={ goto abop; } |
| 703 | | e MINUS ASSIGN e |
| 704 | ={ goto abop; } |
| 705 | | e SHIFTOP ASSIGN e |
| 706 | ={ goto abop; } |
| 707 | | e AND ASSIGN e |
| 708 | ={ goto abop; } |
| 709 | | e OR ASSIGN e |
| 710 | ={ goto abop; } |
| 711 | | e ER ASSIGN e |
| 712 | ={ goto abop; } |
| 713 | | e QUEST e COLON e |
| 714 | ={ $$=buildtree(QUEST, $1, buildtree( COLON, $3, $5 ) ); |
| 715 | } |
| 716 | | e ASOP e |
| 717 | ={ werror( "old-fashioned assignment operator" ); goto bop; } |
| 718 | | e ASSIGN e |
| 719 | ={ goto bop; } |
| 720 | | term |
| 721 | ; |
| 722 | term: term INCOP |
| 723 | ={ $$ = buildtree( $2, $1, bcon(1) ); } |
| 724 | | MUL term |
| 725 | ={ ubop: |
| 726 | $$ = buildtree( UNARY $1, $2, NIL ); |
| 727 | } |
| 728 | | AND term |
| 729 | ={ if( ISFTN($2->in.type) || ISARY($2->in.type) ){ |
| 730 | werror( "& before array or function: ignored" ); |
| 731 | $$ = $2; |
| 732 | } |
| 733 | else goto ubop; |
| 734 | } |
| 735 | | MINUS term |
| 736 | ={ goto ubop; } |
| 737 | | UNOP term |
| 738 | ={ |
| 739 | $$ = buildtree( $1, $2, NIL ); |
| 740 | } |
| 741 | | INCOP term |
| 742 | ={ $$ = buildtree( $1==INCR ? ASG PLUS : ASG MINUS, |
| 743 | $2, |
| 744 | bcon(1) ); |
| 745 | } |
| 746 | | SIZEOF term |
| 747 | ={ $$ = doszof( $2 ); } |
| 748 | | LP cast_type RP term %prec INCOP |
| 749 | ={ $$ = buildtree( CAST, $2, $4 ); |
| 750 | $$->in.left->in.op = FREE; |
| 751 | $$->in.op = FREE; |
| 752 | $$ = $$->in.right; |
| 753 | } |
| 754 | | SIZEOF LP cast_type RP %prec SIZEOF |
| 755 | ={ $$ = doszof( $3 ); } |
| 756 | | term LB e RB |
| 757 | ={ $$ = buildtree( UNARY MUL, buildtree( PLUS, $1, $3 ), NIL ); } |
| 758 | | funct_idn RP |
| 759 | ={ $$=buildtree(UNARY CALL,$1,NIL); } |
| 760 | | funct_idn elist RP |
| 761 | ={ $$=buildtree(CALL,$1,$2); } |
| 762 | | term STROP NAME |
| 763 | ={ if( $2 == DOT ){ |
| 764 | if( notlval( $1 ) )uerror("structure reference must be addressable"); |
| 765 | $1 = buildtree( UNARY AND, $1, NIL ); |
| 766 | } |
| 767 | idname = $3; |
| 768 | $$ = buildtree( STREF, $1, buildtree( NAME, NIL, NIL ) ); |
| 769 | } |
| 770 | | NAME |
| 771 | ={ idname = $1; |
| 772 | /* recognize identifiers in initializations */ |
| 773 | if( blevel==0 && stab[idname].stype == UNDEF ) { |
| 774 | register NODE *q; |
| 775 | #ifndef FLEXNAMES |
| 776 | werror( "undeclared initializer name %.8s", stab[idname].sname ); |
| 777 | #else |
| 778 | werror( "undeclared initializer name %s", stab[idname].sname ); |
| 779 | #endif |
| 780 | q = block( FREE, NIL, NIL, INT, 0, INT ); |
| 781 | q->tn.rval = idname; |
| 782 | defid( q, EXTERN ); |
| 783 | } |
| 784 | $$=buildtree(NAME,NIL,NIL); |
| 785 | stab[$1].suse = -lineno; |
| 786 | } |
| 787 | | ICON |
| 788 | ={ $$=bcon(0); |
| 789 | $$->tn.lval = lastcon; |
| 790 | $$->tn.rval = NONAME; |
| 791 | if( $1 ) $$->fn.csiz = $$->in.type = ctype(LONG); |
| 792 | } |
| 793 | | FCON |
| 794 | ={ $$=buildtree(FCON,NIL,NIL); |
| 795 | $$->fpn.dval = dcon; |
| 796 | } |
| 797 | | STRING |
| 798 | ={ $$ = getstr(); /* get string contents */ } |
| 799 | | LP e RP |
| 800 | ={ $$=$2; } |
| 801 | ; |
| 802 | |
| 803 | cast_type: type null_decl |
| 804 | ={ |
| 805 | $$ = tymerge( $1, $2 ); |
| 806 | $$->in.op = NAME; |
| 807 | $1->in.op = FREE; |
| 808 | } |
| 809 | ; |
| 810 | |
| 811 | null_decl: /* empty */ |
| 812 | ={ $$ = bdty( NAME, NIL, -1 ); } |
| 813 | | LP RP |
| 814 | ={ $$ = bdty( UNARY CALL, bdty(NAME,NIL,-1),0); } |
| 815 | | LP null_decl RP LP RP |
| 816 | ={ $$ = bdty( UNARY CALL, $2, 0 ); } |
| 817 | | MUL null_decl |
| 818 | ={ goto umul; } |
| 819 | | null_decl LB RB |
| 820 | ={ goto uary; } |
| 821 | | null_decl LB con_e RB |
| 822 | ={ goto bary; } |
| 823 | | LP null_decl RP |
| 824 | ={ $$ = $2; } |
| 825 | ; |
| 826 | |
| 827 | funct_idn: NAME LP |
| 828 | ={ if( stab[$1].stype == UNDEF ){ |
| 829 | register NODE *q; |
| 830 | q = block( FREE, NIL, NIL, FTN|INT, 0, INT ); |
| 831 | q->tn.rval = $1; |
| 832 | defid( q, EXTERN ); |
| 833 | } |
| 834 | idname = $1; |
| 835 | $$=buildtree(NAME,NIL,NIL); |
| 836 | stab[idname].suse = -lineno; |
| 837 | } |
| 838 | | term LP |
| 839 | ; |
| 840 | %% |
| 841 | |
| 842 | NODE * |
| 843 | mkty( t, d, s ) unsigned t; { |
| 844 | return( block( TYPE, NIL, NIL, t, d, s ) ); |
| 845 | } |
| 846 | |
| 847 | NODE * |
| 848 | bdty( op, p, v ) NODE *p; { |
| 849 | register NODE *q; |
| 850 | |
| 851 | q = block( op, p, NIL, INT, 0, INT ); |
| 852 | |
| 853 | switch( op ){ |
| 854 | |
| 855 | case UNARY MUL: |
| 856 | case UNARY CALL: |
| 857 | break; |
| 858 | |
| 859 | case LB: |
| 860 | q->in.right = bcon(v); |
| 861 | break; |
| 862 | |
| 863 | case NAME: |
| 864 | q->tn.rval = v; |
| 865 | break; |
| 866 | |
| 867 | default: |
| 868 | cerror( "bad bdty" ); |
| 869 | } |
| 870 | |
| 871 | return( q ); |
| 872 | } |
| 873 | |
| 874 | dstash( n ){ /* put n into the dimension table */ |
| 875 | if( curdim >= DIMTABSZ-1 ){ |
| 876 | cerror( "dimension table overflow"); |
| 877 | } |
| 878 | dimtab[ curdim++ ] = n; |
| 879 | } |
| 880 | |
| 881 | savebc() { |
| 882 | if( psavbc > & asavbc[BCSZ-4 ] ){ |
| 883 | cerror( "whiles, fors, etc. too deeply nested"); |
| 884 | } |
| 885 | *psavbc++ = brklab; |
| 886 | *psavbc++ = contlab; |
| 887 | *psavbc++ = flostat; |
| 888 | *psavbc++ = swx; |
| 889 | flostat = 0; |
| 890 | } |
| 891 | |
| 892 | resetbc(mask){ |
| 893 | |
| 894 | swx = *--psavbc; |
| 895 | flostat = *--psavbc | (flostat&mask); |
| 896 | contlab = *--psavbc; |
| 897 | brklab = *--psavbc; |
| 898 | |
| 899 | } |
| 900 | |
| 901 | addcase(p) NODE *p; { /* add case to switch */ |
| 902 | |
| 903 | p = optim( p ); /* change enum to ints */ |
| 904 | if( p->in.op != ICON ){ |
| 905 | uerror( "non-constant case expression"); |
| 906 | return; |
| 907 | } |
| 908 | if( swp == swtab ){ |
| 909 | uerror( "case not in switch"); |
| 910 | return; |
| 911 | } |
| 912 | if( swp >= &swtab[SWITSZ] ){ |
| 913 | cerror( "switch table overflow"); |
| 914 | } |
| 915 | swp->sval = p->tn.lval; |
| 916 | deflab( swp->slab = getlab() ); |
| 917 | ++swp; |
| 918 | tfree(p); |
| 919 | } |
| 920 | |
| 921 | adddef(){ /* add default case to switch */ |
| 922 | if( swtab[swx].slab >= 0 ){ |
| 923 | uerror( "duplicate default in switch"); |
| 924 | return; |
| 925 | } |
| 926 | if( swp == swtab ){ |
| 927 | uerror( "default not inside switch"); |
| 928 | return; |
| 929 | } |
| 930 | deflab( swtab[swx].slab = getlab() ); |
| 931 | } |
| 932 | |
| 933 | swstart(){ |
| 934 | /* begin a switch block */ |
| 935 | if( swp >= &swtab[SWITSZ] ){ |
| 936 | cerror( "switch table overflow"); |
| 937 | } |
| 938 | swx = swp - swtab; |
| 939 | swp->slab = -1; |
| 940 | ++swp; |
| 941 | } |
| 942 | |
| 943 | swend(){ /* end a switch block */ |
| 944 | |
| 945 | register struct sw *swbeg, *p, *q, *r, *r1; |
| 946 | CONSZ temp; |
| 947 | int tempi; |
| 948 | |
| 949 | swbeg = &swtab[swx+1]; |
| 950 | |
| 951 | /* sort */ |
| 952 | |
| 953 | r1 = swbeg; |
| 954 | r = swp-1; |
| 955 | |
| 956 | while( swbeg < r ){ |
| 957 | /* bubble largest to end */ |
| 958 | for( q=swbeg; q<r; ++q ){ |
| 959 | if( q->sval > (q+1)->sval ){ |
| 960 | /* swap */ |
| 961 | r1 = q+1; |
| 962 | temp = q->sval; |
| 963 | q->sval = r1->sval; |
| 964 | r1->sval = temp; |
| 965 | tempi = q->slab; |
| 966 | q->slab = r1->slab; |
| 967 | r1->slab = tempi; |
| 968 | } |
| 969 | } |
| 970 | r = r1; |
| 971 | r1 = swbeg; |
| 972 | } |
| 973 | |
| 974 | /* it is now sorted */ |
| 975 | |
| 976 | for( p = swbeg+1; p<swp; ++p ){ |
| 977 | if( p->sval == (p-1)->sval ){ |
| 978 | uerror( "duplicate case in switch, %d", tempi=p->sval ); |
| 979 | return; |
| 980 | } |
| 981 | } |
| 982 | |
| 983 | genswitch( swbeg-1, swp-swbeg ); |
| 984 | swp = swbeg-1; |
| 985 | } |