1 /* Copyright (c) 1980 Regents of the University of California */ 2 static char sccsid[] = "@(#)asscan.c 4.4 09/03/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 yylval = 1; 805 val = BFINT; 806 goto ret; 807 } 808 if (INCHARSET(val, HEXFLAG)){ 809 base = 16; 810 } else 811 if (INCHARSET(val, FLOATFLAG)){ 812 double atof(); 813 while ( (cp < &fltchr[63]) && 814 INCHARSET( 815 (val=getchar()), 816 (DIGIT|SIGN|FLOATEXP|POINT) 817 ) 818 ) *cp++ = val; 819 if (cp == fltchr) { 820 yylval = 1; 821 val = BFINT; 822 goto ret; 823 } 824 ungetc(val); 825 *cp++ = '\0'; 826 fltval.dvalue = atof(fltchr); 827 val = FLTNUM; 828 goto ret; 829 } else { 830 ungetc(val); 831 base = 8; 832 } 833 } else { 834 forb = getchar(); 835 if (forb == 'f' || forb == 'b') { 836 yylval = val - '0' + 1; 837 if (forb == 'b') 838 yylval = -yylval; 839 val = BFINT; 840 goto ret; 841 } 842 ungetc(forb); /* put back non zero */ 843 goto middle; 844 } 845 while ( (val = getchar()) == '0') 846 continue; 847 ungetc(val); 848 while ( INCHARSET( (val = getchar()), DIGIT) || 849 (base==16 && (INCHARSET(val, HEXLDIGIT|HEXUDIGIT) ) 850 ) 851 ){ 852 if (base==8) 853 intval <<= 3; 854 else if (base==10) 855 intval *= 10; 856 else { 857 intval <<= 4; 858 if (INCHARSET(val, HEXLDIGIT)) 859 val -= 'a' - 10 - '0'; 860 else if (INCHARSET(val, HEXUDIGIT)) 861 val -= 'A' - 10 - '0'; 862 } 863 middle: 864 *cp++ = (val -= '0'); 865 intval += val; 866 } 867 ungetc(val); 868 *cp = 0; 869 maxstrlg = cp - fltchr; 870 if ( (maxstrlg > 8) 871 && ( ( (base == 8) 872 && ( (maxstrlg>11) 873 || ( (maxstrlg == 11) 874 && (*fltchr > 3) 875 ) 876 ) 877 ) 878 || ( (base == 16) 879 && (maxstrlg > 8) 880 ) 881 || ( (base == 10) 882 && (maxstrlg >= 10) 883 ) 884 ) 885 ) { 886 val = QUAD; 887 get_quad(base, fltchr, cp, &quadval); 888 } else 889 val = INT; 890 goto ret; 891 892 case LSH: 893 case RSH: 894 /* 895 * We allow the C style operators 896 * << and >>, as well as < and > 897 */ 898 if ( (base = getchar()) != val) 899 ungetc(base); 900 val = yylval; 901 goto ret; 902 903 case MINUS: 904 if ( (val = getchar()) =='(') 905 yylval=val=MP; 906 else { 907 ungetc(val); 908 val=MINUS; 909 } 910 goto ret; 911 912 case SQ: 913 if ((yylval = getchar()) == '\n') 914 scanlineno++; /*not entirely correct*/ 915 intval = yylval; 916 val = INT; 917 goto ret; 918 919 case DQ: 920 eatstr: 921 linescrossed = 0; 922 maxstrlg = (char *)bufub - (char *)bufptr; 923 924 if (maxstrlg < MAXSTRLG) { 925 ungetc('"'); 926 *(toktype *)bufptr = VOID ; 927 bufub = bufptr; 928 goto done; 929 } 930 if (maxstrlg > MAXSTRLG) 931 maxstrlg = MAXSTRLG; 932 933 ptoken(bufptr, STRING); 934 lgbackpatch = bufptr; /*this is where the size goes*/ 935 bufptr += sizeof(lgtype); 936 /* 937 * bufptr is now set to 938 * be stuffed with characters from 939 * the input 940 */ 941 942 while ( (maxstrlg > 0) 943 && !(INCHARSET( (val = getchar()), STRESCAPE)) 944 ){ 945 stuff: 946 maxstrlg-= 1; 947 pchar(bufptr, val); 948 } 949 if (maxstrlg <= 0){ /*enough characters to fill a string buffer*/ 950 ungetc('"'); /*will read it next*/ 951 } 952 else if (val == '"'); /*done*/ 953 else if (val == '\n'){ 954 scanlineno++; 955 linescrossed++; 956 val = getchar(); 957 if (val == EOFCHAR){ 958 do_eof: 959 pchar(bufptr, '\n'); 960 ungetc(EOFCHAR); 961 } else 962 if (val == NEEDCHAR){ 963 if ( (inbufptr = fillinbuffer()) == 0) 964 goto do_eof; 965 val = '\n'; 966 goto stuff; 967 } else { /* simple case */ 968 ungetc(val); 969 val = '\n'; 970 goto stuff; 971 } 972 } else { 973 val = getchar(); /*skip the '\\'*/ 974 if ( INCHARSET(val, BSESCAPE)){ 975 switch (val){ 976 case 'b': val = '\b'; goto stuff; 977 case 'f': val = '\f'; goto stuff; 978 case 'n': val = '\n'; goto stuff; 979 case 'r': val = '\r'; goto stuff; 980 case 't': val = '\t'; goto stuff; 981 } 982 } 983 if ( !(INCHARSET(val,OCTDIGIT)) ) goto stuff; 984 base = 0; 985 intval = 0; 986 while ( (base < 3) && (INCHARSET(val, OCTDIGIT))){ 987 base++;intval <<= 3;intval += val - '0'; 988 val = getchar(); 989 } 990 ungetc(val); 991 val = (char)intval; 992 goto stuff; 993 } 994 /* 995 * bufptr now points at the next free slot 996 */ 997 bstrfromto(lgbackpatch, bufptr); 998 if (linescrossed){ 999 val = ILINESKIP; 1000 yylval = linescrossed; 1001 goto ret; 1002 } else 1003 goto builtval; 1004 1005 case BADCHAR: 1006 linescrossed = lineno; 1007 lineno = scanlineno; 1008 yyerror("Illegal character mapped: %d, char read:(octal) %o", 1009 yylval, val); 1010 lineno = linescrossed; 1011 val = BADCHAR; 1012 goto ret; 1013 1014 default: 1015 val = yylval; 1016 goto ret; 1017 } /*end of the switch*/ 1018 /* 1019 * here with one token, so stuff it 1020 */ 1021 ret: 1022 oval = val; 1023 ptoken(bufptr, val); 1024 switch(val){ 1025 case ILINESKIP: 1026 pint(bufptr, yylval); 1027 break; 1028 case SIZESPEC: 1029 pchar(bufptr, yylval); 1030 break; 1031 case BFINT: plong(bufptr, yylval); 1032 break; 1033 case INT: plong(bufptr, intval); 1034 break; 1035 case QUAD: plong(bufptr, quadval.quad_low_long); 1036 plong(bufptr, quadval.quad_high_long); 1037 break; 1038 case FLTNUM: pdouble(bufptr, fltval.dvalue); 1039 break; 1040 case NAME: pptr(bufptr, (int)(struct symtab *)yylval); 1041 break; 1042 case REG: pchar(bufptr, yylval); 1043 break; 1044 case INST0: 1045 case INSTn: 1046 pchar(bufptr, yylval); 1047 break; 1048 case IJXXX: 1049 pchar(bufptr, yylval); 1050 pptr(bufptr, (int)(struct symtab *)symalloc()); 1051 break; 1052 case ISTAB: 1053 case ISTABSTR: 1054 case ISTABNONE: 1055 case ISTABDOT: 1056 case IALIGN: 1057 pptr(bufptr, (int)(struct symtab *)symalloc()); 1058 break; 1059 /* 1060 * default: 1061 */ 1062 } 1063 builtval: ; 1064 } /*end of the while to stuff the buffer*/ 1065 done: 1066 bufferbox->tok_count = (toktype *)bufptr - &(bufferbox->toks[0]); 1067 1068 /* 1069 * This is a real kludge: 1070 * 1071 * We put the last token in the buffer to be a MINUS 1072 * symbol. This last token will never be picked up 1073 * in the normal way, but can be looked at during 1074 * a peekahead look that the short circuit expression 1075 * evaluator uses to see if an expression is complicated. 1076 * 1077 * Consider the following situation: 1078 * 1079 * .word 45 + 47 1080 * buffer 1 | buffer 0 1081 * the peekahead would want to look across the buffer, 1082 * but will look in the buffer end zone, see the minus, and 1083 * fail. 1084 */ 1085 ptoken(bufptr, MINUS); 1086 InBufPtr = inbufptr; /*copy this back*/ 1087 } 1088 1089 struct Quad _quadtemp; 1090 get_quad(radix, cp_start, cp_end, quadptr) 1091 int radix; 1092 char *cp_start, *cp_end; 1093 struct Quad *quadptr; 1094 { 1095 register char *cp = cp_start; /* r11 */ 1096 register struct Quad *qp = quadptr; /* r10 */ 1097 register long temp; /* r9 */ 1098 1099 asm("clrq (r10)"); 1100 for (; cp < cp_end; cp++){ 1101 switch (radix) { 1102 case 8: 1103 asm ("ashq $3, (r10), (r10)"); 1104 break; 1105 case 16: 1106 asm ("ashq $4, (r10), (r10)"); 1107 break; 1108 case 10: 1109 asm ("ashq $1, (r10), __quadtemp"); 1110 asm ("ashq $3, (r10), (r10)"); 1111 asm ("addl2 __quadtemp, (r10)"); 1112 asm ("adwc __quadtemp+4, 4(r10)"); 1113 break; 1114 } 1115 asm ("cvtbl (r11), r9"); 1116 asm ("addl2 r9, (r10)"); 1117 asm ("adwc $0, 4(r10)"); 1118 } 1119 } 1120