1 /* Copyright (c) 1980 Regents of the University of California */ 2 static char sccsid[] = "@(#)asscan.c 4.2 08/15/80"; 3 #include <stdio.h> 4 #include <sys/types.h> 5 #include "as.h" 6 #include "asscan.h" 7 8 /* 9 * NOTE: 10 * This version of the assembler does not use fread and fwrite 11 * for the token buffering. The token buffers are integrals of BUFSIZ 12 * at all times, so we use direct read and write. fread and fwrite 13 * as supplied from BTL in stdio are HORRENDOUSLY inefficient, 14 * as they use putchar for each character, nested two deep in loops. 15 */ 16 #define writeTEST(pointer, size, nelements, ioptr) \ 17 write(ioptr->_file, pointer, nelements * size) != nelements * size 18 19 #define readTEST(pointer, size, nelements, ioptr) \ 20 read(ioptr->_file, pointer, nelements * size) != nelements * size 21 /* 22 * Variables to manage the token buffering. 23 * We scan (lexically analyze) a large number of tokens, and 24 * then parse all of the tokens in the scan buffer. 25 * This reduces procedure call overhead when the parser 26 * demands a token, allows for an efficient reread during 27 * the second pass, and confuses the line number reporting 28 * for errors encountered in the scanner and in the parser. 29 */ 30 #define TOKDALLOP 8 31 struct tokbufdesc *bufstart; /*where the buffer list begins*/ 32 struct tokbufdesc *buftail; /*last one on the list*/ 33 struct tokbufdesc *emptybuf; /*the one being filled*/ 34 /* 35 * If we are using VM, during the second pass we reclaim the used 36 * token buffers for saving the relocation information 37 */ 38 struct tokbufdesc *tok_free; /* free pool */ 39 struct tokbufdesc *tok_temp; /* temporary for doing list manipulation */ 40 /* 41 * Other token buffer managers 42 */ 43 int bufno; /*which buffer number: 0,1 for tmp file*/ 44 struct tokbufdesc tokbuf[2]; /*our initial increment of buffers*/ 45 ptrall tokptr; /*where the current token comes from*/ 46 ptrall tokub; /*the last token in the current token buffer*/ 47 48 /* 49 * Variables to manage the string buffering 50 * declared in asscan.h. 51 */ 52 int strno; /*the current string being filled*/ 53 struct strdesc strbuf[3]; /*the string buffers; the first for nulls*/ 54 struct strdesc *strptr; /*current string buffer being filled*/ 55 56 inittmpfile() 57 { 58 if (passno == 1){ 59 if (useVM){ 60 bufstart = &tokbuf[0]; 61 buftail = &tokbuf[1]; 62 bufstart->tok_next = buftail; 63 buftail->tok_next = 0; 64 } 65 tokbuf[0].tok_count = -1; 66 tokbuf[1].tok_count = -1; 67 } 68 tok_temp = 0; 69 tok_free = 0; 70 bufno = 0; 71 emptybuf = &tokbuf[bufno]; 72 tokptr = 0; 73 tokub = 0; 74 } 75 76 closetmpfile() 77 { 78 if (passno == 1){ 79 if (useVM){ 80 emptybuf->toks[emptybuf->tok_count++] = PARSEEOF; 81 } else { 82 /* 83 * Clean up the buffers that haven't been 84 * written out yet 85 */ 86 if (tokbuf[bufno ^ 1].tok_count >= 0){ 87 if (writeTEST((char *)&tokbuf[bufno ^ 1], sizeof *emptybuf, 1, tmpfil)){ 88 badwrite: 89 yyerror("Unexpected end of file writing the interpass tmp file"); 90 exit(2); 91 } 92 } 93 /* 94 * Ensure that we will read an End of file, 95 * if there are more than one file names 96 * in the argument list 97 */ 98 tokbuf[bufno].toks[tokbuf[bufno].tok_count++] = PARSEEOF; 99 if (writeTEST((char *)&tokbuf[bufno], sizeof *emptybuf, 1, tmpfil)) 100 goto badwrite; 101 } 102 } /*end of being pass 1*/ 103 } 104 105 #define bstrlg(from, length) \ 106 *(lgtype *)from = length; \ 107 (char *)from += sizeof(lgtype) + length 108 109 #define bstrfromto(from,to) \ 110 *(lgtype *)from = (char *)to - (char *)from - sizeof(lgtype); \ 111 (char *)from += sizeof(lgtype) + (char *)to - (char *)from 112 113 #define eatstrlg(from) \ 114 (char *)from += sizeof(lgtype) + *(lgtype *)from 115 116 #define bskiplg(from, length) \ 117 *(lgtype *)from = length; \ 118 (char *)from += sizeof(lgtype) + length 119 120 #define bskipfromto(from, to) \ 121 *(lgtype *)from = (toktype *)to - (toktype *)from - sizeof(lgtype); \ 122 (char *)from += sizeof (lgtype) + (toktype *)to - (toktype *)from 123 124 #define eatskiplg(from) \ 125 (toktype *)from += sizeof(lgtype) + *(lgtype *)from 126 127 #ifdef DEBUG 128 ptrall firsttoken; 129 #endif DEBUG 130 131 extern int yylval; /*global communication with parser*/ 132 133 toktype yylex() 134 { 135 register ptrall bufptr; 136 register toktype val; 137 register struct exp *locxp; 138 139 bufptr = tokptr; /*copy in the global value*/ 140 top: 141 if (bufptr < tokub){ 142 gtoken(val, bufptr); 143 switch(yylval = val){ 144 case PARSEEOF : 145 yylval = val = PARSEEOF; 146 break; 147 case BFINT: 148 case INT: 149 if (xp >= &explist[NEXP]) 150 yyerror("Too many expressions; try simplyfing"); 151 else 152 locxp = xp++; 153 glong(locxp->xvalue, bufptr); 154 locxp->yvalue = 0; 155 makevalue: 156 locxp->xtype = XABS; 157 locxp->xloc = 0; 158 locxp->xname = NULL; 159 yylval = (int)locxp; 160 break; 161 case FLTNUM: 162 if (xp >= &explist[NEXP]) 163 yyerror("Too many expressions; try simplyfing"); 164 else 165 locxp = xp++; 166 gdouble( ( (union Double *)locxp)->dvalue, bufptr); 167 goto makevalue; 168 case QUAD: 169 if (xp >= &explist[NEXP]) 170 yyerror("Too many expressions; try simplyfing"); 171 else 172 locxp = xp++; 173 glong(locxp->xvalue, bufptr); 174 glong(locxp->yvalue, bufptr); 175 yylval = val = INT; 176 goto makevalue; 177 case NAME: 178 gptr(yylval, bufptr); 179 lastnam = (struct symtab *)yylval; 180 break; 181 case SIZESPEC: 182 case REG: 183 case INSTn: 184 case INST0: 185 gchar(yylval, bufptr); 186 break; 187 case IJXXX: 188 gchar(yylval, bufptr); 189 gptr(lastjxxx, bufptr); 190 break; 191 case ILINESKIP: 192 gint(yylval, bufptr); 193 lineno += yylval; 194 goto top; 195 case SKIP: 196 eatskiplg(bufptr); 197 goto top; 198 case VOID: 199 goto top; 200 case STRING: 201 strptr = &strbuf[strno ^= 1]; 202 strptr->str_lg = *((lgtype *)bufptr); 203 movestr(&strptr->str[0], 204 (char *)bufptr + sizeof(lgtype), 205 strptr->str_lg); 206 eatstrlg(bufptr); 207 yylval = (int)strptr; 208 break; 209 case ISTAB: 210 case ISTABSTR: 211 case ISTABNONE: 212 case ISTABDOT: 213 case IALIGN: 214 gptr(yylval, bufptr); 215 break; 216 } 217 #ifdef DEBUG 218 if (toktrace){ 219 char *tok_to_name(); 220 printf("P: %d T#: %4d, %s ", 221 passno, bufptr - firsttoken, tok_to_name(val)); 222 switch(val){ 223 case INT: printf("val %d", 224 ((struct exp *)yylval)->xvalue); 225 break; 226 case BFINT: printf("val %d", 227 ((struct exp *)yylval)->xvalue); 228 break; 229 case QUAD: printf("val[msd] = 0x%x, val[lsd] = 0x%x.", 230 ((struct exp *)yylval)->xvalue, 231 ((struct exp *)yylval)->yvalue); 232 break; 233 case FLTNUM: printf("value %20.17f", 234 ((union Double *)yylval)->dvalue); 235 break; 236 case NAME: printf("\"%.8s\"", 237 ((struct symtab *)yylval)->name); 238 break; 239 case REG: printf(" r%d", 240 yylval); 241 break; 242 case IJXXX: 243 case INST0: 244 case INSTn: printf("%.8s", 245 itab[0xFF &yylval]->name); 246 break; 247 case STRING: printf("length %d ", 248 ((struct strdesc *)yylval)->str_lg); 249 printf("value\"%s\"", 250 ((struct strdesc *)yylval)->str); 251 break; 252 } /*end of the debug switch*/ 253 printf("\n"); 254 } 255 #endif DEBUG 256 257 } else { /* start a new buffer */ 258 if (useVM){ 259 if (passno == 2){ 260 tok_temp = emptybuf->tok_next; 261 emptybuf->tok_next = tok_free; 262 tok_free = emptybuf; 263 emptybuf = tok_temp; 264 } else { 265 emptybuf = emptybuf->tok_next; 266 } 267 bufno += 1; 268 if (emptybuf == 0){ 269 struct tokbufdesc *newdallop; 270 int i; 271 if (passno == 2) 272 goto badread; 273 emptybuf = newdallop = (struct tokbufdesc *) 274 Calloc(TOKDALLOP, sizeof (struct tokbufdesc)); 275 for (i=0; i < TOKDALLOP; i++){ 276 buftail->tok_next = newdallop; 277 buftail = newdallop; 278 newdallop += 1; 279 } 280 buftail->tok_next = 0; 281 } /*end of need to get more buffers*/ 282 (toktype *)bufptr = &(emptybuf->toks[0]); 283 if (passno == 1) 284 scan_dot_s(emptybuf); 285 } else { /*don't use VM*/ 286 bufno ^= 1; 287 emptybuf = &tokbuf[bufno]; 288 ((toktype *)bufptr) = &(emptybuf->toks[0]); 289 if (passno == 1){ 290 /* 291 * First check if there are things to write 292 * out at all 293 */ 294 if (emptybuf->tok_count >= 0){ 295 if (writeTEST((char *)emptybuf, sizeof *emptybuf, 1, tmpfil)){ 296 badwrite: 297 yyerror("Unexpected end of file writing the interpass tmp file"); 298 exit(2); 299 } 300 } 301 scan_dot_s(emptybuf); 302 } else { /*pass 2*/ 303 if (readTEST((char *)emptybuf, sizeof *emptybuf, 1, tmpfil)){ 304 badread: 305 yyerror("Unexpected end of file while reading the interpass tmp file"); 306 exit(1); 307 } 308 } 309 } /*end of using a real live file*/ 310 (char *)tokub = (char *)bufptr + emptybuf->tok_count; 311 #ifdef DEBUG 312 firsttoken = bufptr; 313 if (debug) 314 printf("created buffernumber %d with %d tokens\n", 315 bufno, emptybuf->tok_count); 316 #endif DEBUG 317 goto top; 318 } /*end of reading/creating a new buffer*/ 319 tokptr = bufptr; /*copy back the global value*/ 320 return(val); 321 } /*end of yylex*/ 322 323 324 buildskip(from, to) 325 register ptrall from, to; 326 { 327 int diff; 328 register int frombufno; 329 register struct tokbufdesc *middlebuf; 330 /* 331 * check if from and to are in the same buffer 332 * from and to DIFFER BY AT MOST 1 buffer and to is 333 * always ahead of from, with to being in the buffer emptybuf 334 * points to. 335 * The hard part here is accounting for the case where the 336 * skip is to cross a buffer boundary; we must construct 337 * two skips. 338 * 339 * Figure out where the buffer boundary between from and to is 340 * It's easy in VM, as buffers increase to high memory, but 341 * w/o VM, we alternate between two buffers, and want 342 * to look at the exact middle of the contiguous buffer region. 343 */ 344 middlebuf = useVM ? emptybuf : &tokbuf[1]; 345 if ( ( (toktype *)from > (toktype *)middlebuf) 346 ^ ( (toktype *)to > (toktype *)middlebuf) 347 ){ /*split across a buffer boundary*/ 348 ptoken(from, SKIP); 349 /* 350 * Set the skip so it lands someplace beyond 351 * the end of this buffer. 352 * When we pull this skip out in the second pass, 353 * we will temporarily move the current pointer 354 * out beyond the end of the buffer, but immediately 355 * do a compare and fail the compare, and then reset 356 * all the pointers correctly to point into the next buffer. 357 */ 358 bskiplg(from, TOKBUFLG + 1); 359 /* 360 * Now, force from to be in the same buffer as to 361 */ 362 (toktype *)from = (toktype *)&(emptybuf->toks[0]); 363 } 364 /* 365 * Now, to and from are in the same buffer 366 */ 367 if (from > to) 368 yyerror("Internal error: bad skip construction"); 369 else { 370 if ( (diff = (toktype *)to - (toktype *)from) >= 371 (sizeof(toktype) + sizeof(lgtype) + 1)) { 372 ptoken(from, SKIP); 373 bskipfromto(from, to); 374 } else { 375 for ( ; diff > 0; --diff) 376 ptoken(from, VOID); 377 } 378 } 379 } 380 381 movestr(to, from, lg) 382 register char *to, *from; 383 register int lg; 384 { 385 if (lg <= 0) return; 386 do 387 *to++ = *from++; 388 while (--lg); 389 } 390 static int newfflag = 0; 391 static char *newfname; 392 int scanlineno; /*the scanner's linenumber*/ 393 394 new_dot_s(namep) 395 char *namep; 396 { 397 newfflag = 1; 398 newfname = namep; 399 dotsname = namep; 400 lineno = 1; 401 scanlineno = 1; 402 } 403 404 /* 405 * Maps characters to their use in assembly language 406 */ 407 #define EOFCHAR (-1) 408 #define NEEDCHAR (-2) 409 410 readonly short type[] = { 411 NEEDSBUF, /*fill up the input buffer*/ 412 SCANEOF, /*hit the hard end of file*/ 413 SP, BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR, /*\0..^G*/ 414 BADCHAR,SP, NL, BADCHAR,BADCHAR,SP, BADCHAR,BADCHAR, /*BS..SI*/ 415 BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR, /*DLE..ETB*/ 416 BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR, /*CAN..US*/ 417 SP, ORNOT, DQ, SH, LITOP, REGOP, AND, SQ, /*sp .. '*/ 418 LP, RP, MUL, PLUS, CM, MINUS, ALPH, DIV, /*( .. /*/ 419 DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /*0 .. 7*/ 420 DIG, DIG, COLON, SEMI, LSH, BADCHAR,RSH, BADCHAR, /*8 .. ?*/ 421 BADCHAR,ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*@ .. G*/ 422 ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*H .. BADCHAR*/ 423 ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*P .. V*/ 424 ALPH, ALPH, ALPH, LB, BADCHAR,RB, XOR, ALPH,/*W .. _*/ 425 SIZEQUOTE,ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*` .. g*/ 426 ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*h .. o*/ 427 ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*p .. v*/ 428 ALPH, ALPH, ALPH, BADCHAR,IOR, BADCHAR,TILDE, BADCHAR,/*x .. del*/ 429 }; 430 431 /* 432 * The table of possible uses for each character to test set inclusion. 433 * Different than the above table, which knows about tokens yylex 434 * is to return. 435 */ 436 #define HEXFLAG 01 /* 'x' or 'X' */ 437 #define HEXLDIGIT 02 /* 'a' .. 'f' */ 438 #define HEXUDIGIT 04 /* 'A' .. 'F' */ 439 #define ALPHA 010 /* 'A' .. 'Z', 'a' .. 'z', '_'*/ 440 #define DIGIT 020 /* '0' .. '9' */ 441 #define FLOATEXP 040 /* 'd' 'e' 'D' 'E' */ 442 #define SIGN 0100 /* '+' .. '-'*/ 443 #define REGDIGIT 0200 /* '0' .. '5' */ 444 #define SZSPECBEGIN 0400 /* 'b', 'B', 'l', 'L', 'w', 'W' */ 445 #define POINT 01000 /* '.' */ 446 #define SPACE 02000 /* '\t' or ' ' */ 447 #define BSESCAPE 04000 /* bnrtf */ 448 #define STRESCAPE 010000 /* '"', '\\', '\n' */ 449 #define OCTDIGIT 020000 /* '0' .. '7' */ 450 #define FLOATFLAG 040000 /* 'd', 'D', 'f', 'F' */ 451 /*after leading 0*/ 452 453 readonly short charsets[] = { 454 0, 0, 0, 0, 0, 0, 0, 0, /*\0..^G*/ 455 0, SPACE, STRESCAPE,0, 0, 0, 0, 0, /*BS..SI*/ 456 0, 0, 0, 0, 0, 0, 0, 0, /*DLE..ETB*/ 457 0, 0, 0, 0, 0, 0, 0, 0, /*CAN..US*/ 458 /* dollar is an alpha character */ 459 SPACE, 0, STRESCAPE,0, ALPHA, 0, 0, 0, /*sp.. '*/ 460 0, 0, 0, SIGN, 0, SIGN, POINT+ALPHA,0, /*( .. /*/ 461 DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*0..1*/ 462 DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*2..3*/ 463 DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*4..5*/ 464 DIGIT+OCTDIGIT, DIGIT+OCTDIGIT, /*6..7*/ 465 DIGIT, DIGIT, 0, 0, 0, 0, 0, 0, /*8..?*/ 466 0, /*@*/ 467 ALPHA+HEXUDIGIT,ALPHA+HEXUDIGIT+SZSPECBEGIN, /*A..B*/ 468 ALPHA+HEXUDIGIT,ALPHA+HEXUDIGIT+FLOATEXP+FLOATFLAG, /*C..D*/ 469 ALPHA+HEXUDIGIT+FLOATEXP,ALPHA+HEXUDIGIT+FLOATFLAG, /*E..F*/ 470 ALPHA, /*G*/ 471 ALPHA, ALPHA, ALPHA, ALPHA, /*H..K*/ 472 ALPHA+SZSPECBEGIN, ALPHA, ALPHA, ALPHA, /*L..O*/ 473 ALPHA, ALPHA, ALPHA, ALPHA, /*P..S*/ 474 ALPHA, ALPHA, ALPHA, ALPHA+SZSPECBEGIN, /*T..W*/ 475 ALPHA+HEXFLAG, ALPHA, ALPHA, 0,STRESCAPE,0, 0, ALPHA,/*X.._*/ 476 477 0, 478 ALPHA+HEXLDIGIT,ALPHA+HEXLDIGIT+BSESCAPE+SZSPECBEGIN, /*a..b*/ 479 ALPHA+HEXLDIGIT,ALPHA+HEXLDIGIT+FLOATEXP+FLOATFLAG, /*c..d*/ 480 ALPHA+HEXLDIGIT+FLOATEXP,ALPHA+HEXLDIGIT+BSESCAPE+FLOATFLAG, /*e..f*/ 481 ALPHA, /*g*/ 482 ALPHA, ALPHA, ALPHA, ALPHA, /*h..k*/ 483 ALPHA+SZSPECBEGIN, ALPHA, ALPHA+BSESCAPE, ALPHA, /*l..o*/ 484 ALPHA, ALPHA, ALPHA+BSESCAPE, ALPHA, /*p..s*/ 485 ALPHA+BSESCAPE, ALPHA, ALPHA, ALPHA+SZSPECBEGIN,/*t..w*/ 486 ALPHA+HEXFLAG, ALPHA, ALPHA, 0,0, 0, 0, 0, /*x..del*/ 487 0}; 488 489 #define INCHARSET(val, kind) (charsets[val] & (kind) ) 490 static toktype oval = NL; 491 492 #define NINBUFFERS 2 493 #define INBUFLG NINBUFFERS*BUFSIZ + 2 494 /* 495 * We have two input buffers; the first one is reserved 496 * for catching the tail of a line split across a buffer 497 * boundary; the other one are used for snarfing a buffer 498 * worth of .s source. 499 */ 500 static char inbuffer[INBUFLG]; 501 static char *InBufPtr = 0; 502 503 #ifdef getchar 504 #undef getchar 505 #endif 506 #define getchar() *inbufptr++ 507 508 #ifdef ungetc 509 #undef ungetc 510 #endif 511 #define ungetc(char) *--inbufptr = char 512 513 /* 514 * fill the inbuffer from the standard input. 515 * Assert: there are always n COMPLETE! lines in the buffer area. 516 * Assert: there is always a \n terminating the last line 517 * in the buffer area. 518 * Assert: after the \n, there is an EOFCHAR (hard end of file) 519 * or a NEEDCHAR (end of buffer) 520 * Assert: fgets always null pads the string it reads. 521 * Assert: no ungetc's are done at the end of a line or at the 522 * beginning of a line. 523 * 524 * We read a complete buffer of characters in one single read. 525 * We then back scan within this buffer to find the end of the 526 * last complete line, and force the assertions, and save a pointer 527 * to the incomplete line. 528 * The next call to fillinbuffer will move the unread characters 529 * to the end of the first buffer, and then read another two buffers, 530 * completing the cycle. 531 */ 532 533 static char p_swapped = '\0'; 534 static char *p_start = &inbuffer[NINBUFFERS * BUFSIZ]; 535 static char *p_stop = &inbuffer[NINBUFFERS * BUFSIZ]; 536 char *fillinbuffer() 537 { 538 register char *to; 539 register char *from; 540 char *inbufptr; 541 int nread; 542 543 *p_start = p_swapped; 544 inbufptr = &inbuffer[1*BUFSIZ] - (p_stop - p_start); 545 546 for (to = inbufptr, from = p_start; from < p_stop;) 547 *to++ = *from++; 548 /* 549 * Now, go read two full buffers (hopefully) 550 */ 551 nread = read(stdin->_file, &inbuffer[1*BUFSIZ], (NINBUFFERS - 1)*BUFSIZ); 552 if (nread == 0) 553 return(0); 554 p_stop = from = &inbuffer[1*BUFSIZ + nread]; 555 *from = '\0'; 556 while (*--from != '\n') /* back over the partial line */ 557 continue; 558 from++; /* first char of partial line */ 559 p_start = from; 560 p_swapped = *p_start; 561 *p_start = NEEDCHAR; /* force assertion */ 562 return(inbufptr); 563 } 564 565 scan_dot_s(bufferbox) 566 struct tokbufdesc *bufferbox; 567 { 568 register int yylval;/*lexical value*/ 569 register toktype val; /*the value returned; the character read*/ 570 register int base; /*the base of the number also counter*/ 571 register char *cp; 572 register char *inbufptr; 573 register struct symtab *op; 574 register unsigned char tag; 575 int forb; 576 577 register ptrall bufptr; /*where to stuff tokens*/ 578 ptrall lgbackpatch; /*where to stuff a string length*/ 579 ptrall bufub; /*where not to stuff tokens*/ 580 register int maxstrlg; /*how long a string can be*/ 581 long intval; /*value of int*/ 582 char fltchr[64]; /*buffer for floating values*/ 583 union Double fltval; /*floating value returned*/ 584 struct Quad quadval; /*quad returned from immediate constant */ 585 int linescrossed; /*when doing strings and comments*/ 586 587 (toktype *)bufptr = (toktype *) & (bufferbox->toks[0]); 588 (toktype *)bufub = &(bufferbox->toks[AVAILTOKS]); 589 590 inbufptr = InBufPtr; 591 if (inbufptr == 0){ 592 inbufptr = fillinbuffer(); 593 if (inbufptr == 0){ /*end of file*/ 594 endoffile: 595 inbufptr = 0; 596 ptoken(bufptr, PARSEEOF); 597 goto done; 598 } 599 } 600 601 if (newfflag){ 602 ptoken(bufptr, IFILE); 603 ptoken(bufptr, STRING); 604 val = strlen(newfname) + 1; 605 movestr( (char *)&( ( (lgtype *)bufptr)[1]), newfname, val); 606 bstrlg(bufptr, val); 607 608 ptoken(bufptr, ILINENO); 609 ptoken(bufptr, INT); 610 pint(bufptr, 1); 611 newfflag = 0; 612 } 613 614 while (bufptr < bufub){ 615 loop: 616 switch(yylval = (type+2)[val = getchar()]) { 617 case SCANEOF: 618 inbufptr = 0; 619 goto endoffile; 620 621 case NEEDSBUF: 622 inbufptr = fillinbuffer(); 623 if (inbufptr == 0) 624 goto endoffile; 625 goto loop; 626 627 case DIV: /*process C style comments*/ 628 if ( (val = getchar()) == '*') { /*comment prelude*/ 629 int incomment; 630 linescrossed = 0; 631 incomment = 1; 632 val = getchar(); /*skip over the * */ 633 do{ 634 while ( (val != '*') && 635 (val != '\n') && 636 (val != EOFCHAR) && 637 (val != NEEDCHAR)) 638 val = getchar(); 639 if (val == '\n'){ 640 scanlineno++; 641 linescrossed++; 642 } else 643 if (val == EOFCHAR) 644 goto endoffile; 645 if (val == NEEDCHAR){ 646 inbufptr = fillinbuffer(); 647 if (inbufptr == 0) 648 goto endoffile; 649 lineno++; 650 incomment = 1; 651 val = getchar(); /*pull in the new char*/ 652 } else { /*its a star */ 653 val = getchar(); 654 incomment = val != '/'; 655 } 656 } while (incomment); 657 val = ILINESKIP; 658 yylval = linescrossed; 659 goto ret; 660 } else { /*just an ordinary DIV*/ 661 ungetc(val); 662 val = yylval = DIV; 663 goto ret; 664 } 665 case SH: 666 if (oval == NL){ 667 /* 668 * Attempt to recognize a C preprocessor 669 * style comment '^#[ \t]*[0-9]*[ \t]*".*" 670 */ 671 val = getchar(); /*bump the #*/ 672 while (INCHARSET(val, SPACE)) 673 val = getchar();/*bump white */ 674 if (INCHARSET(val, DIGIT)){ 675 intval = 0; 676 while(INCHARSET(val, DIGIT)){ 677 intval = intval *10 + val - '0'; 678 val = getchar(); 679 } 680 while (INCHARSET(val, SPACE)) 681 val = getchar(); 682 if (val == '"'){ 683 ptoken(bufptr, ILINENO); 684 ptoken(bufptr, INT); 685 pint(bufptr, intval - 1); 686 ptoken(bufptr, IFILE); 687 /* 688 * The '"' has already been 689 * munched 690 * 691 * eatstr will not eat 692 * the trailing \n, so 693 * it is given to the parser 694 * and counted. 695 */ 696 goto eatstr; 697 } 698 } 699 } 700 /* 701 * Well, its just an ordinary decadent comment 702 */ 703 while ((val != '\n') && (val != EOFCHAR)) 704 val = getchar(); 705 if (val == EOFCHAR) 706 goto endoffile; 707 val = yylval = oval = NL; 708 scanlineno++; 709 goto ret; 710 711 case NL: 712 scanlineno++; 713 val = yylval; 714 goto ret; 715 716 case SP: 717 oval = SP; /*invalidate ^# meta comments*/ 718 goto loop; 719 720 case REGOP: /* % , could be used as modulo, or register*/ 721 val = getchar(); 722 if (INCHARSET(val, DIGIT)){ 723 yylval = val-'0'; 724 if (val=='1') { 725 if (INCHARSET( (val = getchar()), REGDIGIT)) 726 yylval = 10+val-'0'; 727 else 728 ungetc(val); 729 } 730 /* 731 * God only knows what the original author 732 * wanted this undocumented feature to 733 * do. 734 * %5++ is really r7 735 */ 736 while(INCHARSET( (val = getchar()), SIGN)) { 737 if (val=='+') 738 yylval++; 739 else 740 yylval--; 741 } 742 ungetc(val); 743 val = REG; 744 } else { 745 ungetc(val); 746 val = REGOP; 747 } 748 goto ret; 749 750 case ALPH: 751 yylval = val; 752 if (INCHARSET(val, SZSPECBEGIN)){ 753 if( (val = getchar()) == '`' || val == '^'){ 754 yylval |= 0100; /*convert to lower*/ 755 if (yylval == 'b') yylval = 1; 756 else if (yylval == 'w') yylval = 2; 757 else if (yylval == 'l') yylval = 4; 758 else yylval = d124; 759 val = SIZESPEC; 760 goto ret; 761 } else { 762 ungetc(val); 763 val = yylval; /*restore first character*/ 764 } 765 } 766 cp = yytext; 767 do { 768 if (cp < &yytext[NCPS]) 769 *cp++ = val; 770 } while (INCHARSET ( (val = getchar()), ALPHA | DIGIT)); 771 *cp = '\0'; 772 while (INCHARSET(val, SPACE)) 773 val = getchar(); 774 ungetc(val); 775 doit: 776 tag = (op = *lookup(1))->tag; 777 if (tag && tag != LABELID){ 778 yylval = ( (struct instab *)op)->opcode; 779 val = op->tag ; 780 goto ret; 781 } else { 782 /* 783 * Its a name... (Labels are subsets ofname) 784 */ 785 yylval = (int)op; 786 val = NAME; 787 goto ret; 788 } 789 790 case DIG: 791 base = 10; 792 cp = fltchr; 793 intval = 0; 794 if (val=='0') { 795 val = getchar(); 796 if (val == 'b') { 797 yylval = -1; 798 val = BFINT; 799 goto ret; 800 } 801 if (INCHARSET(val, HEXFLAG)){ 802 base = 16; 803 } else 804 if (INCHARSET(val, FLOATFLAG)){ 805 double atof(); 806 while ( (cp < &fltchr[63]) && 807 INCHARSET( 808 (val=getchar()), 809 (DIGIT|SIGN|FLOATEXP|POINT) 810 ) 811 ) *cp++ = val; 812 if (cp == fltchr) { 813 yylval = 1; 814 val = BFINT; 815 goto ret; 816 } 817 ungetc(val); 818 *cp++ = '\0'; 819 fltval.dvalue = atof(fltchr); 820 val = FLTNUM; 821 goto ret; 822 } else { 823 ungetc(val); 824 base = 8; 825 } 826 } else { 827 forb = getchar(); 828 if (forb == 'f' || forb == 'b') { 829 yylval = val - '0' + 1; 830 if (forb == 'b') 831 yylval = -yylval; 832 val = BFINT; 833 goto ret; 834 } 835 ungetc(forb); /* put back non zero */ 836 goto middle; 837 } 838 while ( (val = getchar()) == '0') 839 continue; 840 ungetc(val); 841 while ( INCHARSET( (val = getchar()), DIGIT) || 842 (base==16 && (INCHARSET(val, HEXLDIGIT|HEXUDIGIT) ) 843 ) 844 ){ 845 if (base==8) 846 intval <<= 3; 847 else if (base==10) 848 intval *= 10; 849 else { 850 intval <<= 4; 851 if (INCHARSET(val, HEXLDIGIT)) 852 val -= 'a' - 10 - '0'; 853 else if (INCHARSET(val, HEXUDIGIT)) 854 val -= 'A' - 10 - '0'; 855 } 856 middle: 857 *cp++ = (val -= '0'); 858 intval += val; 859 } 860 ungetc(val); 861 *cp = 0; 862 maxstrlg = cp - fltchr; 863 if ( (maxstrlg > 8) 864 && ( ( (base == 8) 865 && ( (maxstrlg>11) 866 || ( (maxstrlg == 11) 867 && (*fltchr > 3) 868 ) 869 ) 870 ) 871 || ( (base == 16) 872 && (maxstrlg > 8) 873 ) 874 || ( (base == 10) 875 && (maxstrlg >= 10) 876 ) 877 ) 878 ) { 879 val = QUAD; 880 get_quad(base, fltchr, cp, &quadval); 881 } else 882 val = INT; 883 goto ret; 884 885 case LSH: 886 case RSH: 887 /* 888 * We allow the C style operators 889 * << and >>, as well as < and > 890 */ 891 if ( (base = getchar()) != val) 892 ungetc(base); 893 val = yylval; 894 goto ret; 895 896 case MINUS: 897 if ( (val = getchar()) =='(') 898 yylval=val=MP; 899 else { 900 ungetc(val); 901 val=MINUS; 902 } 903 goto ret; 904 905 case SQ: 906 if ((yylval = getchar()) == '\n') 907 scanlineno++; /*not entirely correct*/ 908 intval = yylval; 909 val = INT; 910 goto ret; 911 912 case DQ: 913 eatstr: 914 linescrossed = 0; 915 maxstrlg = (char *)bufub - (char *)bufptr; 916 917 if (maxstrlg < MAXSTRLG) { 918 ungetc('"'); 919 *(toktype *)bufptr = VOID ; 920 bufub = bufptr; 921 goto done; 922 } 923 if (maxstrlg > MAXSTRLG) 924 maxstrlg = MAXSTRLG; 925 926 ptoken(bufptr, STRING); 927 lgbackpatch = bufptr; /*this is where the size goes*/ 928 bufptr += sizeof(lgtype); 929 /* 930 * bufptr is now set to 931 * be stuffed with characters from 932 * the input 933 */ 934 935 while ( (maxstrlg > 0) 936 && !(INCHARSET( (val = getchar()), STRESCAPE)) 937 ){ 938 stuff: 939 maxstrlg-= 1; 940 pchar(bufptr, val); 941 } 942 if (maxstrlg <= 0){ /*enough characters to fill a string buffer*/ 943 ungetc('"'); /*will read it next*/ 944 } 945 else if (val == '"'); /*done*/ 946 else if (val == '\n'){ 947 scanlineno++; 948 linescrossed++; 949 val = getchar(); 950 if (val == EOFCHAR){ 951 do_eof: 952 pchar(bufptr, '\n'); 953 ungetc(EOFCHAR); 954 } else 955 if (val == NEEDCHAR){ 956 if ( (inbufptr = fillinbuffer()) == 0) 957 goto do_eof; 958 val = '\n'; 959 goto stuff; 960 } else { /* simple case */ 961 ungetc(val); 962 val = '\n'; 963 goto stuff; 964 } 965 } else { 966 val = getchar(); /*skip the '\\'*/ 967 if ( INCHARSET(val, BSESCAPE)){ 968 switch (val){ 969 case 'b': val = '\b'; goto stuff; 970 case 'f': val = '\f'; goto stuff; 971 case 'n': val = '\n'; goto stuff; 972 case 'r': val = '\r'; goto stuff; 973 case 't': val = '\t'; goto stuff; 974 } 975 } 976 if ( !(INCHARSET(val,OCTDIGIT)) ) goto stuff; 977 base = 0; 978 intval = 0; 979 while ( (base < 3) && (INCHARSET(val, OCTDIGIT))){ 980 base++;intval <<= 3;intval += val - '0'; 981 val = getchar(); 982 } 983 ungetc(val); 984 val = (char)intval; 985 goto stuff; 986 } 987 /* 988 * bufptr now points at the next free slot 989 */ 990 bstrfromto(lgbackpatch, bufptr); 991 if (linescrossed){ 992 val = ILINESKIP; 993 yylval = linescrossed; 994 goto ret; 995 } else 996 goto builtval; 997 998 case BADCHAR: 999 linescrossed = lineno; 1000 lineno = scanlineno; 1001 yyerror("Illegal character mapped: %d, char read:(octal) %o", 1002 yylval, val); 1003 lineno = linescrossed; 1004 val = BADCHAR; 1005 goto ret; 1006 1007 default: 1008 val = yylval; 1009 goto ret; 1010 } /*end of the switch*/ 1011 /* 1012 * here with one token, so stuff it 1013 */ 1014 ret: 1015 oval = val; 1016 ptoken(bufptr, val); 1017 switch(val){ 1018 case ILINESKIP: 1019 pint(bufptr, yylval); 1020 break; 1021 case SIZESPEC: 1022 pchar(bufptr, yylval); 1023 break; 1024 case BFINT: plong(bufptr, yylval); 1025 break; 1026 case INT: plong(bufptr, intval); 1027 break; 1028 case QUAD: plong(bufptr, quadval.quad_low_long); 1029 plong(bufptr, quadval.quad_high_long); 1030 break; 1031 case FLTNUM: pdouble(bufptr, fltval.dvalue); 1032 break; 1033 case NAME: pptr(bufptr, (int)(struct symtab *)yylval); 1034 break; 1035 case REG: pchar(bufptr, yylval); 1036 break; 1037 case INST0: 1038 case INSTn: 1039 pchar(bufptr, yylval); 1040 break; 1041 case IJXXX: 1042 pchar(bufptr, yylval); 1043 pptr(bufptr, (int)(struct symtab *)symalloc()); 1044 break; 1045 case ISTAB: 1046 case ISTABSTR: 1047 case ISTABNONE: 1048 case ISTABDOT: 1049 case IALIGN: 1050 pptr(bufptr, (int)(struct symtab *)symalloc()); 1051 break; 1052 /* 1053 * default: 1054 */ 1055 } 1056 builtval: ; 1057 } /*end of the while to stuff the buffer*/ 1058 done: 1059 bufferbox->tok_count = (toktype *)bufptr - &(bufferbox->toks[0]); 1060 1061 /* 1062 * This is a real kludge: 1063 * 1064 * We put the last token in the buffer to be a MINUS 1065 * symbol. This last token will never be picked up 1066 * in the normal way, but can be looked at during 1067 * a peekahead look that the short circuit expression 1068 * evaluator uses to see if an expression is complicated. 1069 * 1070 * Consider the following situation: 1071 * 1072 * .word 45 + 47 1073 * buffer 1 | buffer 0 1074 * the peekahead would want to look across the buffer, 1075 * but will look in the buffer end zone, see the minus, and 1076 * fail. 1077 */ 1078 ptoken(bufptr, MINUS); 1079 InBufPtr = inbufptr; /*copy this back*/ 1080 } 1081 1082 struct Quad _quadtemp; 1083 get_quad(radix, cp_start, cp_end, quadptr) 1084 int radix; 1085 char *cp_start, *cp_end; 1086 struct Quad *quadptr; 1087 { 1088 register char *cp = cp_start; /* r11 */ 1089 register struct Quad *qp = quadptr; /* r10 */ 1090 register long temp; /* r9 */ 1091 1092 asm("clrq (r10)"); 1093 for (; cp < cp_end; cp++){ 1094 switch (radix) { 1095 case 8: 1096 asm ("ashq $3, (r10), (r10)"); 1097 break; 1098 case 16: 1099 asm ("ashq $4, (r10), (r10)"); 1100 break; 1101 case 10: 1102 asm ("ashq $1, (r10), __quadtemp"); 1103 asm ("ashq $3, (r10), (r10)"); 1104 asm ("addl2 __quadtemp, (r10)"); 1105 asm ("adwc __quadtemp+4, 4(r10)"); 1106 break; 1107 } 1108 asm ("cvtbl (r11), r9"); 1109 asm ("addl2 r9, (r10)"); 1110 asm ("adwc $0, 4(r10)"); 1111 } 1112 } 1113