1 /* Copyright (c) 1980 Regents of the University of California */ 2 static char sccsid[] = "@(#)asscan.c 4.1 08/13/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 /*exponent field*/ 443 #define SIGN 0100 /* '+' .. '-'*/ 444 #define REGDIGIT 0200 /* '0' .. '5' */ 445 #define SZSPECBEGIN 0400 /* 'b', 'B', 'l', 'L', 'w', 'W' */ 446 #define POINT 01000 /* '.' */ 447 #define SPACE 02000 /* '\t' or ' ' */ 448 #define BSESCAPE 04000 /* bnrtf */ 449 #define STRESCAPE 010000 /* '"', '\\', '\n' */ 450 #define OCTDIGIT 020000 /* '0' .. '7' */ 451 #define FLOATFLAG 040000 /* 'd', 'D', 'f', 'F' */ 452 /*after leading 0*/ 453 454 readonly short charsets[] = { 455 0, 0, 0, 0, 0, 0, 0, 0, /*\0..^G*/ 456 0, SPACE, STRESCAPE,0, 0, 0, 0, 0, /*BS..SI*/ 457 0, 0, 0, 0, 0, 0, 0, 0, /*DLE..ETB*/ 458 0, 0, 0, 0, 0, 0, 0, 0, /*CAN..US*/ 459 /* dollar is an alpha character */ 460 SPACE, 0, STRESCAPE,0, ALPHA, 0, 0, 0, /*sp.. '*/ 461 0, 0, 0, SIGN, 0, SIGN, POINT+ALPHA,0, /*( .. /*/ 462 DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*0..1*/ 463 DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*2..3*/ 464 DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*4..5*/ 465 DIGIT+OCTDIGIT, DIGIT+OCTDIGIT, /*6..7*/ 466 DIGIT, DIGIT, 0, 0, 0, 0, 0, 0, /*8..?*/ 467 0, /*@*/ 468 ALPHA+HEXUDIGIT,ALPHA+HEXUDIGIT+SZSPECBEGIN, /*A..B*/ 469 ALPHA+HEXUDIGIT,ALPHA+HEXUDIGIT+FLOATEXP+FLOATFLAG, /*C..D*/ 470 ALPHA+HEXUDIGIT+FLOATEXP,ALPHA+HEXUDIGIT+FLOATFLAG, /*E..F*/ 471 ALPHA, /*G*/ 472 ALPHA, ALPHA, ALPHA, ALPHA, /*H..K*/ 473 ALPHA+SZSPECBEGIN, ALPHA, ALPHA, ALPHA, /*L..O*/ 474 ALPHA, ALPHA, ALPHA, ALPHA, /*P..S*/ 475 ALPHA, ALPHA, ALPHA, ALPHA+SZSPECBEGIN, /*T..W*/ 476 ALPHA+HEXFLAG, ALPHA, ALPHA, 0,STRESCAPE,0, 0, ALPHA,/*X.._*/ 477 478 0, 479 ALPHA+HEXLDIGIT,ALPHA+HEXLDIGIT+BSESCAPE+SZSPECBEGIN, /*a..b*/ 480 ALPHA+HEXLDIGIT,ALPHA+HEXLDIGIT+FLOATEXP+FLOATFLAG, /*c..d*/ 481 ALPHA+HEXLDIGIT+FLOATEXP,ALPHA+HEXLDIGIT+BSESCAPE+FLOATFLAG, /*e..f*/ 482 ALPHA, /*g*/ 483 ALPHA, ALPHA, ALPHA, ALPHA, /*h..k*/ 484 ALPHA+SZSPECBEGIN, ALPHA, ALPHA+BSESCAPE, ALPHA, /*l..o*/ 485 ALPHA, ALPHA, ALPHA+BSESCAPE, ALPHA, /*p..s*/ 486 ALPHA+BSESCAPE, ALPHA, ALPHA, ALPHA+SZSPECBEGIN,/*t..w*/ 487 ALPHA+HEXFLAG, ALPHA, ALPHA, 0,0, 0, 0, 0, /*x..del*/ 488 0}; 489 490 #define INCHARSET(val, kind) (charsets[val] & (kind) ) 491 static toktype oval = NL; 492 493 #define NINBUFFERS 2 494 #define INBUFLG NINBUFFERS*BUFSIZ + 2 495 /* 496 * We have two input buffers; the first one is reserved 497 * for catching the tail of a line split across a buffer 498 * boundary; the other one are used for snarfing a buffer 499 * worth of .s source. 500 */ 501 static char inbuffer[INBUFLG]; 502 static char *InBufPtr = 0; 503 504 #ifdef getchar 505 #undef getchar 506 #endif 507 #define getchar() *inbufptr++ 508 509 #ifdef ungetc 510 #undef ungetc 511 #endif 512 #define ungetc(char) *--inbufptr = char 513 514 /* 515 * fill the inbuffer from the standard input. 516 * Assert: there are always n COMPLETE! lines in the buffer area. 517 * Assert: there is always a \n terminating the last line 518 * in the buffer area. 519 * Assert: after the \n, there is an EOFCHAR (hard end of file) 520 * or a NEEDCHAR (end of buffer) 521 * Assert: fgets always null pads the string it reads. 522 * Assert: no ungetc's are done at the end of a line or at the 523 * beginning of a line. 524 * 525 * We read a complete buffer of characters in one single read. 526 * We then back scan within this buffer to find the end of the 527 * last complete line, and force the assertions, and save a pointer 528 * to the incomplete line. 529 * The next call to fillinbuffer will move the unread characters 530 * to the end of the first buffer, and then read another two buffers, 531 * completing the cycle. 532 */ 533 534 static char p_swapped = '\0'; 535 static char *p_start = &inbuffer[NINBUFFERS * BUFSIZ]; 536 static char *p_stop = &inbuffer[NINBUFFERS * BUFSIZ]; 537 char *fillinbuffer() 538 { 539 register char *to; 540 register char *from; 541 char *inbufptr; 542 int nread; 543 544 *p_start = p_swapped; 545 inbufptr = &inbuffer[1*BUFSIZ] - (p_stop - p_start); 546 547 for (to = inbufptr, from = p_start; from < p_stop;) 548 *to++ = *from++; 549 /* 550 * Now, go read two full buffers (hopefully) 551 */ 552 nread = read(stdin->_file, &inbuffer[1*BUFSIZ], (NINBUFFERS - 1)*BUFSIZ); 553 if (nread == 0) 554 return(0); 555 p_stop = from = &inbuffer[1*BUFSIZ + nread]; 556 *from = '\0'; 557 while (*--from != '\n') /* back over the partial line */ 558 continue; 559 from++; /* first char of partial line */ 560 p_start = from; 561 p_swapped = *p_start; 562 *p_start = NEEDCHAR; /* force assertion */ 563 return(inbufptr); 564 } 565 566 scan_dot_s(bufferbox) 567 struct tokbufdesc *bufferbox; 568 { 569 register int yylval;/*lexical value*/ 570 register toktype val; /*the value returned; the character read*/ 571 register int base; /*the base of the number also counter*/ 572 register char *cp; 573 register char *inbufptr; 574 register struct symtab *op; 575 register unsigned char tag; 576 int forb; 577 578 register ptrall bufptr; /*where to stuff tokens*/ 579 ptrall lgbackpatch; /*where to stuff a string length*/ 580 ptrall bufub; /*where not to stuff tokens*/ 581 register int maxstrlg; /*how long a string can be*/ 582 long intval; /*value of int*/ 583 char fltchr[64]; /*buffer for floating values*/ 584 union Double fltval; /*floating value returned*/ 585 struct Quad quadval; /*quad returned from immediate constant */ 586 int linescrossed; /*when doing strings and comments*/ 587 588 (toktype *)bufptr = (toktype *) & (bufferbox->toks[0]); 589 (toktype *)bufub = &(bufferbox->toks[AVAILTOKS]); 590 591 inbufptr = InBufPtr; 592 if (inbufptr == 0){ 593 inbufptr = fillinbuffer(); 594 if (inbufptr == 0){ /*end of file*/ 595 endoffile: 596 inbufptr = 0; 597 ptoken(bufptr, PARSEEOF); 598 goto done; 599 } 600 } 601 602 if (newfflag){ 603 ptoken(bufptr, IFILE); 604 ptoken(bufptr, STRING); 605 val = strlen(newfname) + 1; 606 movestr( (char *)&( ( (lgtype *)bufptr)[1]), newfname, val); 607 bstrlg(bufptr, val); 608 609 ptoken(bufptr, ILINENO); 610 ptoken(bufptr, INT); 611 pint(bufptr, 1); 612 newfflag = 0; 613 } 614 615 while (bufptr < bufub){ 616 loop: 617 switch(yylval = (type+2)[val = getchar()]) { 618 case SCANEOF: 619 inbufptr = 0; 620 goto endoffile; 621 622 case NEEDSBUF: 623 inbufptr = fillinbuffer(); 624 if (inbufptr == 0) 625 goto endoffile; 626 goto loop; 627 628 case DIV: /*process C style comments*/ 629 if ( (val = getchar()) == '*') { /*comment prelude*/ 630 int incomment; 631 linescrossed = 0; 632 incomment = 1; 633 val = getchar(); /*skip over the * */ 634 do{ 635 while ( (val != '*') && 636 (val != '\n') && 637 (val != EOFCHAR) && 638 (val != NEEDCHAR)) 639 val = getchar(); 640 if (val == '\n'){ 641 scanlineno++; 642 linescrossed++; 643 } else 644 if (val == EOFCHAR) 645 goto endoffile; 646 if (val == NEEDCHAR){ 647 inbufptr = fillinbuffer(); 648 if (inbufptr == 0) 649 goto endoffile; 650 lineno++; 651 incomment = 1; 652 val = getchar(); /*pull in the new char*/ 653 } else { /*its a star */ 654 val = getchar(); 655 incomment = val != '/'; 656 } 657 } while (incomment); 658 val = ILINESKIP; 659 yylval = linescrossed; 660 goto ret; 661 } else { /*just an ordinary DIV*/ 662 ungetc(val); 663 val = yylval = DIV; 664 goto ret; 665 } 666 case SH: 667 if (oval == NL){ 668 /* 669 * Attempt to recognize a C preprocessor 670 * style comment '^#[ \t]*[0-9]*[ \t]*".*" 671 */ 672 val = getchar(); /*bump the #*/ 673 while (INCHARSET(val, SPACE)) 674 val = getchar();/*bump white */ 675 if (INCHARSET(val, DIGIT)){ 676 intval = 0; 677 while(INCHARSET(val, DIGIT)){ 678 intval = intval *10 + val - '0'; 679 val = getchar(); 680 } 681 while (INCHARSET(val, SPACE)) 682 val = getchar(); 683 if (val == '"'){ 684 ptoken(bufptr, ILINENO); 685 ptoken(bufptr, INT); 686 pint(bufptr, intval - 1); 687 ptoken(bufptr, IFILE); 688 /* 689 * The '"' has already been 690 * munched 691 * 692 * eatstr will not eat 693 * the trailing \n, so 694 * it is given to the parser 695 * and counted. 696 */ 697 goto eatstr; 698 } 699 } 700 } 701 /* 702 * Well, its just an ordinary decadent comment 703 */ 704 while ((val != '\n') && (val != EOFCHAR)) 705 val = getchar(); 706 if (val == EOFCHAR) 707 goto endoffile; 708 val = yylval = oval = NL; 709 scanlineno++; 710 goto ret; 711 712 case NL: 713 scanlineno++; 714 val = yylval; 715 goto ret; 716 717 case SP: 718 oval = SP; /*invalidate ^# meta comments*/ 719 goto loop; 720 721 case REGOP: /* % , could be used as modulo, or register*/ 722 val = getchar(); 723 if (INCHARSET(val, DIGIT)){ 724 yylval = val-'0'; 725 if (val=='1') { 726 if (INCHARSET( (val = getchar()), REGDIGIT)) 727 yylval = 10+val-'0'; 728 else 729 ungetc(val); 730 } 731 /* 732 * God only knows what the original author 733 * wanted this undocumented feature to 734 * do. 735 * %5++ is really r7 736 */ 737 while(INCHARSET( (val = getchar()), SIGN)) { 738 if (val=='+') 739 yylval++; 740 else 741 yylval--; 742 } 743 ungetc(val); 744 val = REG; 745 } else { 746 ungetc(val); 747 val = REGOP; 748 } 749 goto ret; 750 751 case ALPH: 752 yylval = val; 753 if (INCHARSET(val, SZSPECBEGIN)){ 754 if( (val = getchar()) == '`' || val == '^'){ 755 yylval |= 0100; /*convert to lower*/ 756 if (yylval == 'b') yylval = 1; 757 else if (yylval == 'w') yylval = 2; 758 else if (yylval == 'l') yylval = 4; 759 else yylval = d124; 760 val = SIZESPEC; 761 goto ret; 762 } else { 763 ungetc(val); 764 val = yylval; /*restore first character*/ 765 } 766 } 767 cp = yytext; 768 do { 769 if (cp < &yytext[NCPS]) 770 *cp++ = val; 771 } while (INCHARSET ( (val = getchar()), ALPHA | DIGIT)); 772 *cp = '\0'; 773 while (INCHARSET(val, SPACE)) 774 val = getchar(); 775 ungetc(val); 776 doit: 777 tag = (op = *lookup(1))->tag; 778 if (tag && tag != LABELID){ 779 yylval = ( (struct instab *)op)->opcode; 780 val = op->tag ; 781 goto ret; 782 } else { 783 /* 784 * Its a name... (Labels are subsets ofname) 785 */ 786 yylval = (int)op; 787 val = NAME; 788 goto ret; 789 } 790 791 case DIG: 792 base = 10; 793 cp = fltchr; 794 intval = 0; 795 if (val=='0') { 796 val = getchar(); 797 if (val == 'b') { 798 yylval = -1; 799 val = BFINT; 800 goto ret; 801 } 802 if (INCHARSET(val, HEXFLAG)){ 803 base = 16; 804 } else 805 if (INCHARSET(val, FLOATFLAG)){ 806 double atof(); 807 while ( (cp < &fltchr[63]) && 808 INCHARSET( 809 (val=getchar()), 810 (DIGIT|SIGN|FLOATEXP|POINT) 811 ) 812 ) *cp++ = val; 813 if (cp == fltchr) { 814 yylval = 1; 815 val = BFINT; 816 goto ret; 817 } 818 ungetc(val); 819 *cp++ = '\0'; 820 fltval.dvalue = atof(fltchr); 821 val = FLTNUM; 822 goto ret; 823 } else { 824 ungetc(val); 825 base = 8; 826 } 827 } else { 828 forb = getchar(); 829 if (forb == 'f' || forb == 'b') { 830 yylval = val - '0' + 1; 831 if (forb == 'b') 832 yylval = -yylval; 833 val = BFINT; 834 goto ret; 835 } 836 ungetc(forb); /* put back non zero */ 837 goto middle; 838 } 839 while ( (val = getchar()) == '0') 840 continue; 841 ungetc(val); 842 while ( INCHARSET( (val = getchar()), DIGIT) || 843 (base==16 && (INCHARSET(val, HEXLDIGIT|HEXUDIGIT) ) 844 ) 845 ){ 846 if (base==8) 847 intval <<= 3; 848 else if (base==10) 849 intval *= 10; 850 else { 851 intval <<= 4; 852 if (INCHARSET(val, HEXLDIGIT)) 853 val -= 'a' - 10 - '0'; 854 else if (INCHARSET(val, HEXUDIGIT)) 855 val -= 'A' - 10 - '0'; 856 } 857 middle: 858 *cp++ = (val -= '0'); 859 intval += val; 860 } 861 ungetc(val); 862 *cp = 0; 863 maxstrlg = cp - fltchr; 864 if ( (maxstrlg > 8) 865 && ( ( (base == 8) 866 && ( (maxstrlg>11) 867 || ( (maxstrlg == 11) 868 && (*fltchr > 3) 869 ) 870 ) 871 ) 872 || ( (base == 16) 873 && (maxstrlg > 8) 874 ) 875 || ( (base == 10) 876 && (maxstrlg >= 10) 877 ) 878 ) 879 ) { 880 val = QUAD; 881 get_quad(base, fltchr, cp, &quadval); 882 } else 883 val = INT; 884 goto ret; 885 886 case LSH: 887 case RSH: 888 /* 889 * We allow the C style operators 890 * << and >>, as well as < and > 891 */ 892 if ( (base = getchar()) != val) 893 ungetc(base); 894 val = yylval; 895 goto ret; 896 897 case MINUS: 898 if ( (val = getchar()) =='(') 899 yylval=val=MP; 900 else { 901 ungetc(val); 902 val=MINUS; 903 } 904 goto ret; 905 906 case SQ: 907 if ((yylval = getchar()) == '\n') 908 scanlineno++; /*not entirely correct*/ 909 intval = yylval; 910 val = INT; 911 goto ret; 912 913 case DQ: 914 eatstr: 915 linescrossed = 0; 916 maxstrlg = (char *)bufub - (char *)bufptr; 917 918 if (maxstrlg < MAXSTRLG) { 919 ungetc('"'); 920 *(toktype *)bufptr = VOID ; 921 bufub = bufptr; 922 goto done; 923 } 924 if (maxstrlg > MAXSTRLG) 925 maxstrlg = MAXSTRLG; 926 927 ptoken(bufptr, STRING); 928 lgbackpatch = bufptr; /*this is where the size goes*/ 929 bufptr += sizeof(lgtype); 930 /* 931 * bufptr is now set to 932 * be stuffed with characters from 933 * the input 934 */ 935 936 while ( (maxstrlg > 0) 937 && !(INCHARSET( (val = getchar()), STRESCAPE)) 938 ){ 939 stuff: 940 maxstrlg-= 1; 941 pchar(bufptr, val); 942 } 943 if (maxstrlg <= 0){ /*enough characters to fill a string buffer*/ 944 ungetc('"'); /*will read it next*/ 945 } 946 else if (val == '"'); /*done*/ 947 else if (val == '\n'){ 948 scanlineno++; 949 linescrossed++; 950 val = getchar(); 951 if (val == EOFCHAR){ 952 do_eof: 953 pchar(bufptr, '\n'); 954 ungetc(EOFCHAR); 955 } else 956 if (val == NEEDCHAR){ 957 if ( (inbufptr = fillinbuffer()) == 0) 958 goto do_eof; 959 val = '\n'; 960 goto stuff; 961 } else { /* simple case */ 962 ungetc(val); 963 val = '\n'; 964 goto stuff; 965 } 966 } else { 967 val = getchar(); /*skip the '\\'*/ 968 if ( INCHARSET(val, BSESCAPE)){ 969 switch (val){ 970 case 'b': val = '\b'; goto stuff; 971 case 'f': val = '\f'; goto stuff; 972 case 'n': val = '\n'; goto stuff; 973 case 'r': val = '\r'; goto stuff; 974 case 't': val = '\t'; goto stuff; 975 } 976 } 977 if ( !(INCHARSET(val,OCTDIGIT)) ) goto stuff; 978 base = 0; 979 intval = 0; 980 while ( (base < 3) && (INCHARSET(val, OCTDIGIT))){ 981 base++;intval <<= 3;intval += val - '0'; 982 val = getchar(); 983 } 984 ungetc(val); 985 val = (char)intval; 986 goto stuff; 987 } 988 /* 989 * bufptr now points at the next free slot 990 */ 991 bstrfromto(lgbackpatch, bufptr); 992 if (linescrossed){ 993 val = ILINESKIP; 994 yylval = linescrossed; 995 goto ret; 996 } else 997 goto builtval; 998 999 case BADCHAR: 1000 linescrossed = lineno; 1001 lineno = scanlineno; 1002 yyerror("Illegal character mapped: %d, char read:(octal) %o", 1003 yylval, val); 1004 lineno = linescrossed; 1005 val = BADCHAR; 1006 goto ret; 1007 1008 default: 1009 val = yylval; 1010 goto ret; 1011 } /*end of the switch*/ 1012 /* 1013 * here with one token, so stuff it 1014 */ 1015 ret: 1016 oval = val; 1017 ptoken(bufptr, val); 1018 switch(val){ 1019 case ILINESKIP: 1020 pint(bufptr, yylval); 1021 break; 1022 case SIZESPEC: 1023 pchar(bufptr, yylval); 1024 break; 1025 case BFINT: plong(bufptr, yylval); 1026 break; 1027 case INT: plong(bufptr, intval); 1028 break; 1029 case QUAD: plong(bufptr, quadval.quad_low_long); 1030 plong(bufptr, quadval.quad_high_long); 1031 break; 1032 case FLTNUM: pdouble(bufptr, fltval.dvalue); 1033 break; 1034 case NAME: pptr(bufptr, (int)(struct symtab *)yylval); 1035 break; 1036 case REG: pchar(bufptr, yylval); 1037 break; 1038 case INST0: 1039 case INSTn: 1040 pchar(bufptr, yylval); 1041 break; 1042 case IJXXX: 1043 pchar(bufptr, yylval); 1044 pptr(bufptr, (int)(struct symtab *)symalloc()); 1045 break; 1046 case ISTAB: 1047 case ISTABSTR: 1048 case ISTABNONE: 1049 case ISTABDOT: 1050 case IALIGN: 1051 pptr(bufptr, (int)(struct symtab *)symalloc()); 1052 break; 1053 /* 1054 * default: 1055 */ 1056 } 1057 builtval: ; 1058 } /*end of the while to stuff the buffer*/ 1059 done: 1060 bufferbox->tok_count = (toktype *)bufptr - &(bufferbox->toks[0]); 1061 1062 /* 1063 * This is a real kludge: 1064 * 1065 * We put the last token in the buffer to be a MINUS 1066 * symbol. This last token will never be picked up 1067 * in the normal way, but can be looked at during 1068 * a peekahead look that the short circuit expression 1069 * evaluator uses to see if an expression is complicated. 1070 * 1071 * Consider the following situation: 1072 * 1073 * .word 45 + 47 1074 * buffer 1 | buffer 0 1075 * the peekahead would want to look across the buffer, 1076 * but will look in the buffer end zone, see the minus, and 1077 * fail. 1078 */ 1079 ptoken(bufptr, MINUS); 1080 InBufPtr = inbufptr; /*copy this back*/ 1081 } 1082 1083 struct Quad _quadtemp; 1084 get_quad(radix, cp_start, cp_end, quadptr) 1085 int radix; 1086 char *cp_start, *cp_end; 1087 struct Quad *quadptr; 1088 { 1089 register char *cp = cp_start; /* r11 */ 1090 register struct Quad *qp = quadptr; /* r10 */ 1091 register long temp; /* r9 */ 1092 1093 asm("clrq (r10)"); 1094 for (; cp < cp_end; cp++){ 1095 switch (radix) { 1096 case 8: 1097 asm ("ashq $3, (r10), (r10)"); 1098 break; 1099 case 16: 1100 asm ("ashq $4, (r10), (r10)"); 1101 break; 1102 case 10: 1103 asm ("ashq $1, (r10), __quadtemp"); 1104 asm ("ashq $3, (r10), (r10)"); 1105 asm ("addl2 __quadtemp, (r10)"); 1106 asm ("adwc __quadtemp+4, 4(r10)"); 1107 break; 1108 } 1109 asm ("cvtbl (r11), r9"); 1110 asm ("addl2 r9, (r10)"); 1111 asm ("adwc $0, 4(r10)"); 1112 } 1113 } 1114