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