/* Copyright (c) 1980 Regents of the University of California */ static char sccsid[] = "@(#)asscan.c 4.6 9/8/80"; #include <stdio.h> #include "as.h" #include "asscan.h" /* * NOTE: * This version of the assembler does not use fread and fwrite * for the token buffering. The token buffers are integrals of BUFSIZ * at all times, so we use direct read and write. fread and fwrite * as supplied from BTL in stdio are HORRENDOUSLY inefficient, * as they use putchar for each character, nested two deep in loops. */ #define writeTEST(pointer, size, nelements, ioptr) \ write(ioptr->_file, pointer, nelements * size) != nelements * size #define readTEST(pointer, size, nelements, ioptr) \ read(ioptr->_file, pointer, nelements * size) != nelements * size /* * Variables to manage the token buffering. * We scan (lexically analyze) a large number of tokens, and * then parse all of the tokens in the scan buffer. * This reduces procedure call overhead when the parser * demands a token, allows for an efficient reread during * the second pass, and confuses the line number reporting * for errors encountered in the scanner and in the parser. */ #define TOKDALLOP 8 struct tokbufdesc *bufstart; /*where the buffer list begins*/ struct tokbufdesc *buftail; /*last one on the list*/ struct tokbufdesc *emptybuf; /*the one being filled*/ /* * If we are using VM, during the second pass we reclaim the used * token buffers for saving the relocation information */ struct tokbufdesc *tok_free; /* free pool */ struct tokbufdesc *tok_temp; /* temporary for doing list manipulation */ /* * Other token buffer managers */ int bufno; /*which buffer number: 0,1 for tmp file*/ struct tokbufdesc tokbuf[2]; /*our initial increment of buffers*/ ptrall tokptr; /*where the current token comes from*/ ptrall tokub; /*the last token in the current token buffer*/ /* * Variables to manage the string buffering * declared in asscan.h. */ int strno; /*the current string being filled*/ struct strdesc strbuf[3]; /*the string buffers; the first for nulls*/ struct strdesc *strptr; /*current string buffer being filled*/ inittmpfile() { if (passno == 1){ if (useVM){ bufstart = &tokbuf[0]; buftail = &tokbuf[1]; bufstart->tok_next = buftail; buftail->tok_next = 0; } tokbuf[0].tok_count = -1; tokbuf[1].tok_count = -1; } tok_temp = 0; tok_free = 0; bufno = 0; emptybuf = &tokbuf[bufno]; tokptr = 0; tokub = 0; } closetmpfile() { if (passno == 1){ if (useVM){ emptybuf->toks[emptybuf->tok_count++] = PARSEEOF; } else { /* * Clean up the buffers that haven't been * written out yet */ if (tokbuf[bufno ^ 1].tok_count >= 0){ if (writeTEST((char *)&tokbuf[bufno ^ 1], sizeof *emptybuf, 1, tmpfil)){ badwrite: yyerror("Unexpected end of file writing the interpass tmp file"); exit(2); } } /* * Ensure that we will read an End of file, * if there are more than one file names * in the argument list */ tokbuf[bufno].toks[tokbuf[bufno].tok_count++] = PARSEEOF; if (writeTEST((char *)&tokbuf[bufno], sizeof *emptybuf, 1, tmpfil)) goto badwrite; } } /*end of being pass 1*/ } #define bstrlg(from, length) \ *(lgtype *)from = length; \ (char *)from += sizeof(lgtype) + length #define bstrfromto(from,to) \ *(lgtype *)from = (char *)to - (char *)from - sizeof(lgtype); \ (char *)from += sizeof(lgtype) + (char *)to - (char *)from #define eatstrlg(from) \ (char *)from += sizeof(lgtype) + *(lgtype *)from #define bskiplg(from, length) \ *(lgtype *)from = length; \ (char *)from += sizeof(lgtype) + length #define bskipfromto(from, to) \ *(lgtype *)from = (toktype *)to - (toktype *)from - sizeof(lgtype); \ (char *)from += sizeof (lgtype) + (toktype *)to - (toktype *)from #define eatskiplg(from) \ (toktype *)from += sizeof(lgtype) + *(lgtype *)from #ifdef DEBUG ptrall firsttoken; #endif DEBUG extern int yylval; /*global communication with parser*/ static int Lastjxxx; /*this ONLY shuts up cc; see below*/ toktype yylex() { register ptrall bufptr; register toktype val; register struct exp *locxp; bufptr = tokptr; /*copy in the global value*/ top: if (bufptr < tokub){ gtoken(val, bufptr); switch(yylval = val){ case PARSEEOF : yylval = val = PARSEEOF; break; case BFINT: case INT: if (xp >= &explist[NEXP]) yyerror("Too many expressions; try simplyfing"); else locxp = xp++; glong(locxp->e_xvalue, bufptr); locxp->e_yvalue = 0; makevalue: locxp->e_xtype = XABS; locxp->e_xloc = 0; locxp->e_xname = NULL; yylval = (int)locxp; break; case FLTNUM: if (xp >= &explist[NEXP]) yyerror("Too many expressions; try simplyfing"); else locxp = xp++; gdouble( ( (union Double *)locxp)->dvalue, bufptr); goto makevalue; case QUAD: if (xp >= &explist[NEXP]) yyerror("Too many expressions; try simplyfing"); else locxp = xp++; glong(locxp->e_xvalue, bufptr); glong(locxp->e_yvalue, bufptr); yylval = val = INT; goto makevalue; case NAME: gptr(yylval, bufptr); lastnam = (struct symtab *)yylval; break; case SIZESPEC: case REG: case INSTn: case INST0: gchar(yylval, bufptr); break; case IJXXX: gchar(yylval, bufptr); /* We can't cast Lastjxxx into (int *) here.. */ gptr(Lastjxxx, bufptr); lastjxxx = (struct symtab *)Lastjxxx; break; case ILINESKIP: gint(yylval, bufptr); lineno += yylval; goto top; case SKIP: eatskiplg(bufptr); goto top; case VOID: goto top; case STRING: strptr = &strbuf[strno ^= 1]; strptr->str_lg = *((lgtype *)bufptr); movestr(&strptr->str[0], (char *)bufptr + sizeof(lgtype), strptr->str_lg); eatstrlg(bufptr); yylval = (int)strptr; break; case ISTAB: case ISTABSTR: case ISTABNONE: case ISTABDOT: case IALIGN: gptr(yylval, bufptr); break; } #ifdef DEBUG if (toktrace){ char *tok_to_name(); printf("P: %d T#: %4d, %s ", passno, bufptr - firsttoken, tok_to_name(val)); switch(val){ case INT: printf("val %d", ((struct exp *)yylval)->e_xvalue); break; case BFINT: printf("val %d", ((struct exp *)yylval)->e_xvalue); break; case QUAD: printf("val[msd] = 0x%x, val[lsd] = 0x%x.", ((struct exp *)yylval)->e_xvalue, ((struct exp *)yylval)->e_yvalue); break; case FLTNUM: printf("value %20.17f", ((union Double *)yylval)->dvalue); break; case NAME: printf("\"%.8s\"", ((struct symtab *)yylval)->s_name); break; case REG: printf(" r%d", yylval); break; case IJXXX: case INST0: case INSTn: printf("%.8s", itab[0xFF &yylval]->s_name); break; case STRING: printf("length %d ", ((struct strdesc *)yylval)->str_lg); printf("value\"%s\"", ((struct strdesc *)yylval)->str); break; } /*end of the debug switch*/ printf("\n"); } #endif DEBUG } else { /* start a new buffer */ if (useVM){ if (passno == 2){ tok_temp = emptybuf->tok_next; emptybuf->tok_next = tok_free; tok_free = emptybuf; emptybuf = tok_temp; } else { emptybuf = emptybuf->tok_next; } bufno += 1; if (emptybuf == 0){ struct tokbufdesc *newdallop; int i; if (passno == 2) goto badread; emptybuf = newdallop = (struct tokbufdesc *) Calloc(TOKDALLOP, sizeof (struct tokbufdesc)); for (i=0; i < TOKDALLOP; i++){ buftail->tok_next = newdallop; buftail = newdallop; newdallop += 1; } buftail->tok_next = 0; } /*end of need to get more buffers*/ (toktype *)bufptr = &(emptybuf->toks[0]); if (passno == 1) scan_dot_s(emptybuf); } else { /*don't use VM*/ bufno ^= 1; emptybuf = &tokbuf[bufno]; ((toktype *)bufptr) = &(emptybuf->toks[0]); if (passno == 1){ /* * First check if there are things to write * out at all */ if (emptybuf->tok_count >= 0){ if (writeTEST((char *)emptybuf, sizeof *emptybuf, 1, tmpfil)){ badwrite: yyerror("Unexpected end of file writing the interpass tmp file"); exit(2); } } scan_dot_s(emptybuf); } else { /*pass 2*/ if (readTEST((char *)emptybuf, sizeof *emptybuf, 1, tmpfil)){ badread: yyerror("Unexpected end of file while reading the interpass tmp file"); exit(1); } } } /*end of using a real live file*/ (char *)tokub = (char *)bufptr + emptybuf->tok_count; #ifdef DEBUG firsttoken = bufptr; if (debug) printf("created buffernumber %d with %d tokens\n", bufno, emptybuf->tok_count); #endif DEBUG goto top; } /*end of reading/creating a new buffer*/ tokptr = bufptr; /*copy back the global value*/ return(val); } /*end of yylex*/ buildskip(from, to) register ptrall from, to; { int diff; register int frombufno; register struct tokbufdesc *middlebuf; /* * check if from and to are in the same buffer * from and to DIFFER BY AT MOST 1 buffer and to is * always ahead of from, with to being in the buffer emptybuf * points to. * The hard part here is accounting for the case where the * skip is to cross a buffer boundary; we must construct * two skips. * * Figure out where the buffer boundary between from and to is * It's easy in VM, as buffers increase to high memory, but * w/o VM, we alternate between two buffers, and want * to look at the exact middle of the contiguous buffer region. */ middlebuf = useVM ? emptybuf : &tokbuf[1]; if ( ( (toktype *)from > (toktype *)middlebuf) ^ ( (toktype *)to > (toktype *)middlebuf) ){ /*split across a buffer boundary*/ ptoken(from, SKIP); /* * Set the skip so it lands someplace beyond * the end of this buffer. * When we pull this skip out in the second pass, * we will temporarily move the current pointer * out beyond the end of the buffer, but immediately * do a compare and fail the compare, and then reset * all the pointers correctly to point into the next buffer. */ bskiplg(from, TOKBUFLG + 1); /* * Now, force from to be in the same buffer as to */ (toktype *)from = (toktype *)&(emptybuf->toks[0]); } /* * Now, to and from are in the same buffer */ if (from > to) yyerror("Internal error: bad skip construction"); else { if ( (diff = (toktype *)to - (toktype *)from) >= (sizeof(toktype) + sizeof(lgtype) + 1)) { ptoken(from, SKIP); bskipfromto(from, to); } else { for ( ; diff > 0; --diff) ptoken(from, VOID); } } } movestr(to, from, lg) register char *to, *from; register int lg; { if (lg <= 0) return; do *to++ = *from++; while (--lg); } static int newfflag = 0; static char *newfname; int scanlineno; /*the scanner's linenumber*/ new_dot_s(namep) char *namep; { newfflag = 1; newfname = namep; dotsname = namep; lineno = 1; scanlineno = 1; } /* * Maps characters to their use in assembly language */ #define EOFCHAR (-1) #define NEEDCHAR (-2) readonly short type[] = { NEEDSBUF, /*fill up the input buffer*/ SCANEOF, /*hit the hard end of file*/ SP, BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR, /*\0..^G*/ BADCHAR,SP, NL, BADCHAR,BADCHAR,SP, BADCHAR,BADCHAR, /*BS..SI*/ BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR, /*DLE..ETB*/ BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR,BADCHAR, /*CAN..US*/ SP, ORNOT, DQ, SH, LITOP, REGOP, AND, SQ, /*sp .. '*/ LP, RP, MUL, PLUS, CM, MINUS, ALPH, DIV, /*( .. /*/ DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /*0 .. 7*/ DIG, DIG, COLON, SEMI, LSH, BADCHAR,RSH, BADCHAR, /*8 .. ?*/ BADCHAR,ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*@ .. G*/ ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*H .. BADCHAR*/ ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*P .. V*/ ALPH, ALPH, ALPH, LB, BADCHAR,RB, XOR, ALPH,/*W .. _*/ SIZEQUOTE,ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*` .. g*/ ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*h .. o*/ ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,/*p .. v*/ ALPH, ALPH, ALPH, BADCHAR,IOR, BADCHAR,TILDE, BADCHAR,/*x .. del*/ }; /* * The table of possible uses for each character to test set inclusion. * Different than the above table, which knows about tokens yylex * is to return. */ #define HEXFLAG 01 /* 'x' or 'X' */ #define HEXLDIGIT 02 /* 'a' .. 'f' */ #define HEXUDIGIT 04 /* 'A' .. 'F' */ #define ALPHA 010 /* 'A' .. 'Z', 'a' .. 'z', '_'*/ #define DIGIT 020 /* '0' .. '9' */ #define FLOATEXP 040 /* 'd' 'e' 'D' 'E' */ #define SIGN 0100 /* '+' .. '-'*/ #define REGDIGIT 0200 /* '0' .. '5' */ #define SZSPECBEGIN 0400 /* 'b', 'B', 'l', 'L', 'w', 'W' */ #define POINT 01000 /* '.' */ #define SPACE 02000 /* '\t' or ' ' */ #define BSESCAPE 04000 /* bnrtf */ #define STRESCAPE 010000 /* '"', '\\', '\n' */ #define OCTDIGIT 020000 /* '0' .. '7' */ #define FLOATFLAG 040000 /* 'd', 'D', 'f', 'F' */ /*after leading 0*/ readonly short charsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, /*\0..^G*/ 0, SPACE, STRESCAPE,0, 0, 0, 0, 0, /*BS..SI*/ 0, 0, 0, 0, 0, 0, 0, 0, /*DLE..ETB*/ 0, 0, 0, 0, 0, 0, 0, 0, /*CAN..US*/ /* dollar is an alpha character */ SPACE, 0, STRESCAPE,0, ALPHA, 0, 0, 0, /*sp.. '*/ 0, 0, 0, SIGN, 0, SIGN, POINT+ALPHA,0, /*( .. /*/ DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*0..1*/ DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*2..3*/ DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*4..5*/ DIGIT+OCTDIGIT, DIGIT+OCTDIGIT, /*6..7*/ DIGIT, DIGIT, 0, 0, 0, 0, 0, 0, /*8..?*/ 0, /*@*/ ALPHA+HEXUDIGIT,ALPHA+HEXUDIGIT+SZSPECBEGIN, /*A..B*/ ALPHA+HEXUDIGIT,ALPHA+HEXUDIGIT+FLOATEXP+FLOATFLAG, /*C..D*/ ALPHA+HEXUDIGIT+FLOATEXP,ALPHA+HEXUDIGIT+FLOATFLAG, /*E..F*/ ALPHA, /*G*/ ALPHA, ALPHA, ALPHA, ALPHA, /*H..K*/ ALPHA+SZSPECBEGIN, ALPHA, ALPHA, ALPHA, /*L..O*/ ALPHA, ALPHA, ALPHA, ALPHA, /*P..S*/ ALPHA, ALPHA, ALPHA, ALPHA+SZSPECBEGIN, /*T..W*/ ALPHA+HEXFLAG, ALPHA, ALPHA, 0,STRESCAPE,0, 0, ALPHA,/*X.._*/ 0, ALPHA+HEXLDIGIT,ALPHA+HEXLDIGIT+BSESCAPE+SZSPECBEGIN, /*a..b*/ ALPHA+HEXLDIGIT,ALPHA+HEXLDIGIT+FLOATEXP+FLOATFLAG, /*c..d*/ ALPHA+HEXLDIGIT+FLOATEXP,ALPHA+HEXLDIGIT+BSESCAPE+FLOATFLAG, /*e..f*/ ALPHA, /*g*/ ALPHA, ALPHA, ALPHA, ALPHA, /*h..k*/ ALPHA+SZSPECBEGIN, ALPHA, ALPHA+BSESCAPE, ALPHA, /*l..o*/ ALPHA, ALPHA, ALPHA+BSESCAPE, ALPHA, /*p..s*/ ALPHA+BSESCAPE, ALPHA, ALPHA, ALPHA+SZSPECBEGIN,/*t..w*/ ALPHA+HEXFLAG, ALPHA, ALPHA, 0,0, 0, 0, 0, /*x..del*/ 0}; #define INCHARSET(val, kind) (charsets[val] & (kind) ) static toktype oval = NL; #define NINBUFFERS 2 #define INBUFLG NINBUFFERS*BUFSIZ + 2 /* * We have two input buffers; the first one is reserved * for catching the tail of a line split across a buffer * boundary; the other one are used for snarfing a buffer * worth of .s source. */ static char inbuffer[INBUFLG]; static char *InBufPtr = 0; #ifdef getchar #undef getchar #endif #define getchar() *inbufptr++ #ifdef ungetc #undef ungetc #endif #define ungetc(char) *--inbufptr = char /* * fill the inbuffer from the standard input. * Assert: there are always n COMPLETE! lines in the buffer area. * Assert: there is always a \n terminating the last line * in the buffer area. * Assert: after the \n, there is an EOFCHAR (hard end of file) * or a NEEDCHAR (end of buffer) * Assert: fgets always null pads the string it reads. * Assert: no ungetc's are done at the end of a line or at the * beginning of a line. * * We read a complete buffer of characters in one single read. * We then back scan within this buffer to find the end of the * last complete line, and force the assertions, and save a pointer * to the incomplete line. * The next call to fillinbuffer will move the unread characters * to the end of the first buffer, and then read another two buffers, * completing the cycle. */ static char p_swapped = '\0'; static char *p_start = &inbuffer[NINBUFFERS * BUFSIZ]; static char *p_stop = &inbuffer[NINBUFFERS * BUFSIZ]; char *fillinbuffer() { register char *to; register char *from; char *inbufptr; int nread; *p_start = p_swapped; inbufptr = &inbuffer[1*BUFSIZ] - (p_stop - p_start); for (to = inbufptr, from = p_start; from < p_stop;) *to++ = *from++; /* * Now, go read two full buffers (hopefully) */ nread = read(stdin->_file, &inbuffer[1*BUFSIZ], (NINBUFFERS - 1)*BUFSIZ); if (nread == 0) return(0); p_stop = from = &inbuffer[1*BUFSIZ + nread]; *from = '\0'; while (*--from != '\n') /* back over the partial line */ continue; from++; /* first char of partial line */ p_start = from; p_swapped = *p_start; *p_start = NEEDCHAR; /* force assertion */ return(inbufptr); } scan_dot_s(bufferbox) struct tokbufdesc *bufferbox; { register int yylval;/*lexical value*/ register toktype val; /*the value returned; the character read*/ register int base; /*the base of the number also counter*/ register char *cp; register char *inbufptr; register struct symtab *op; register unsigned char tag; int forb; register ptrall bufptr; /*where to stuff tokens*/ ptrall lgbackpatch; /*where to stuff a string length*/ ptrall bufub; /*where not to stuff tokens*/ register int maxstrlg; /*how long a string can be*/ long intval; /*value of int*/ char fltchr[64]; /*buffer for floating values*/ union Double fltval; /*floating value returned*/ struct Quad quadval; /*quad returned from immediate constant */ int linescrossed; /*when doing strings and comments*/ (toktype *)bufptr = (toktype *) & (bufferbox->toks[0]); (toktype *)bufub = &(bufferbox->toks[AVAILTOKS]); inbufptr = InBufPtr; if (inbufptr == 0){ inbufptr = fillinbuffer(); if (inbufptr == 0){ /*end of file*/ endoffile: inbufptr = 0; ptoken(bufptr, PARSEEOF); goto done; } } if (newfflag){ ptoken(bufptr, IFILE); ptoken(bufptr, STRING); val = strlen(newfname) + 1; movestr( (char *)&( ( (lgtype *)bufptr)[1]), newfname, val); bstrlg(bufptr, val); ptoken(bufptr, ILINENO); ptoken(bufptr, INT); pint(bufptr, 1); newfflag = 0; } while (bufptr < bufub){ loop: switch(yylval = (type+2)[val = getchar()]) { case SCANEOF: inbufptr = 0; goto endoffile; case NEEDSBUF: inbufptr = fillinbuffer(); if (inbufptr == 0) goto endoffile; goto loop; case DIV: /*process C style comments*/ if ( (val = getchar()) == '*') { /*comment prelude*/ int incomment; linescrossed = 0; incomment = 1; val = getchar(); /*skip over the * */ do{ while ( (val != '*') && (val != '\n') && (val != EOFCHAR) && (val != NEEDCHAR)) val = getchar(); if (val == '\n'){ scanlineno++; linescrossed++; } else if (val == EOFCHAR) goto endoffile; if (val == NEEDCHAR){ inbufptr = fillinbuffer(); if (inbufptr == 0) goto endoffile; lineno++; incomment = 1; val = getchar(); /*pull in the new char*/ } else { /*its a star */ val = getchar(); incomment = val != '/'; } } while (incomment); val = ILINESKIP; yylval = linescrossed; goto ret; } else { /*just an ordinary DIV*/ ungetc(val); val = yylval = DIV; goto ret; } case SH: if (oval == NL){ /* * Attempt to recognize a C preprocessor * style comment '^#[ \t]*[0-9]*[ \t]*".*" */ val = getchar(); /*bump the #*/ while (INCHARSET(val, SPACE)) val = getchar();/*bump white */ if (INCHARSET(val, DIGIT)){ intval = 0; while(INCHARSET(val, DIGIT)){ intval = intval *10 + val - '0'; val = getchar(); } while (INCHARSET(val, SPACE)) val = getchar(); if (val == '"'){ ptoken(bufptr, ILINENO); ptoken(bufptr, INT); pint(bufptr, intval - 1); ptoken(bufptr, IFILE); /* * The '"' has already been * munched * * eatstr will not eat * the trailing \n, so * it is given to the parser * and counted. */ goto eatstr; } } } /* * Well, its just an ordinary decadent comment */ while ((val != '\n') && (val != EOFCHAR)) val = getchar(); if (val == EOFCHAR) goto endoffile; val = yylval = oval = NL; scanlineno++; goto ret; case NL: scanlineno++; val = yylval; goto ret; case SP: oval = SP; /*invalidate ^# meta comments*/ goto loop; case REGOP: /* % , could be used as modulo, or register*/ val = getchar(); if (INCHARSET(val, DIGIT)){ yylval = val-'0'; if (val=='1') { if (INCHARSET( (val = getchar()), REGDIGIT)) yylval = 10+val-'0'; else ungetc(val); } /* * God only knows what the original author * wanted this undocumented feature to * do. * %5++ is really r7 */ while(INCHARSET( (val = getchar()), SIGN)) { if (val=='+') yylval++; else yylval--; } ungetc(val); val = REG; } else { ungetc(val); val = REGOP; } goto ret; case ALPH: yylval = val; if (INCHARSET(val, SZSPECBEGIN)){ if( (val = getchar()) == '`' || val == '^'){ yylval |= 0100; /*convert to lower*/ if (yylval == 'b') yylval = 1; else if (yylval == 'w') yylval = 2; else if (yylval == 'l') yylval = 4; else yylval = d124; val = SIZESPEC; goto ret; } else { ungetc(val); val = yylval; /*restore first character*/ } } cp = yytext; do { if (cp < &yytext[NCPS]) *cp++ = val; } while (INCHARSET ( (val = getchar()), ALPHA | DIGIT)); *cp = '\0'; while (INCHARSET(val, SPACE)) val = getchar(); ungetc(val); doit: tag = (op = *lookup(1))->s_tag; if (tag && tag != LABELID){ yylval = ( (struct instab *)op)->i_opcode; val = op->s_tag ; goto ret; } else { /* * Its a name... (Labels are subsets ofname) */ yylval = (int)op; val = NAME; goto ret; } case DIG: base = 10; cp = fltchr; intval = 0; if (val=='0') { val = getchar(); if (val == 'b') { yylval = -1; val = BFINT; goto ret; } if (val == 'f') { /* * Well, it appears to be a local label * reference, but check to see if * the next character makes it a floating * point constant. */ forb = getchar(); ungetc(forb); if (!(INCHARSET(forb,(DIGIT|SIGN|FLOATEXP|POINT)))){ yylval = 1; val = BFINT; goto ret; } } if (INCHARSET(val, HEXFLAG)){ base = 16; } else if (INCHARSET(val, FLOATFLAG)){ double atof(); while ( (cp < &fltchr[63]) && INCHARSET( (val=getchar()), (DIGIT|SIGN|FLOATEXP|POINT) ) ) *cp++ = val; if (cp == fltchr) { yylval = 1; val = BFINT; goto ret; } ungetc(val); *cp++ = '\0'; fltval.dvalue = atof(fltchr); val = FLTNUM; goto ret; } else { ungetc(val); base = 8; } } else { forb = getchar(); if (forb == 'f' || forb == 'b') { yylval = val - '0' + 1; if (forb == 'b') yylval = -yylval; val = BFINT; goto ret; } ungetc(forb); /* put back non zero */ goto middle; } while ( (val = getchar()) == '0') continue; ungetc(val); while ( INCHARSET( (val = getchar()), DIGIT) || (base==16 && (INCHARSET(val, HEXLDIGIT|HEXUDIGIT) ) ) ){ if (base==8) intval <<= 3; else if (base==10) intval *= 10; else { intval <<= 4; if (INCHARSET(val, HEXLDIGIT)) val -= 'a' - 10 - '0'; else if (INCHARSET(val, HEXUDIGIT)) val -= 'A' - 10 - '0'; } middle: *cp++ = (val -= '0'); intval += val; } ungetc(val); *cp = 0; maxstrlg = cp - fltchr; if ( (maxstrlg > 8) && ( ( (base == 8) && ( (maxstrlg>11) || ( (maxstrlg == 11) && (*fltchr > 3) ) ) ) || ( (base == 16) && (maxstrlg > 8) ) || ( (base == 10) && (maxstrlg >= 10) ) ) ) { val = QUAD; get_quad(base, fltchr, cp, &quadval); } else val = INT; goto ret; case LSH: case RSH: /* * We allow the C style operators * << and >>, as well as < and > */ if ( (base = getchar()) != val) ungetc(base); val = yylval; goto ret; case MINUS: if ( (val = getchar()) =='(') yylval=val=MP; else { ungetc(val); val=MINUS; } goto ret; case SQ: if ((yylval = getchar()) == '\n') scanlineno++; /*not entirely correct*/ intval = yylval; val = INT; goto ret; case DQ: eatstr: linescrossed = 0; maxstrlg = (char *)bufub - (char *)bufptr; if (maxstrlg < MAXSTRLG) { ungetc('"'); *(toktype *)bufptr = VOID ; bufub = bufptr; goto done; } if (maxstrlg > MAXSTRLG) maxstrlg = MAXSTRLG; ptoken(bufptr, STRING); lgbackpatch = bufptr; /*this is where the size goes*/ bufptr += sizeof(lgtype); /* * bufptr is now set to * be stuffed with characters from * the input */ while ( (maxstrlg > 0) && !(INCHARSET( (val = getchar()), STRESCAPE)) ){ stuff: maxstrlg-= 1; pchar(bufptr, val); } if (maxstrlg <= 0){ /*enough characters to fill a string buffer*/ ungetc('"'); /*will read it next*/ } else if (val == '"'); /*done*/ else if (val == '\n'){ yywarning("New line embedded in a string constant."); scanlineno++; linescrossed++; val = getchar(); if (val == EOFCHAR){ do_eof: pchar(bufptr, '\n'); ungetc(EOFCHAR); } else if (val == NEEDCHAR){ if ( (inbufptr = fillinbuffer()) == 0) goto do_eof; val = '\n'; goto stuff; } else { /* simple case */ ungetc(val); val = '\n'; goto stuff; } } else { val = getchar(); /*skip the '\\'*/ if ( INCHARSET(val, BSESCAPE)){ switch (val){ case 'b': val = '\b'; goto stuff; case 'f': val = '\f'; goto stuff; case 'n': val = '\n'; goto stuff; case 'r': val = '\r'; goto stuff; case 't': val = '\t'; goto stuff; } } if ( !(INCHARSET(val,OCTDIGIT)) ) goto stuff; base = 0; intval = 0; while ( (base < 3) && (INCHARSET(val, OCTDIGIT))){ base++;intval <<= 3;intval += val - '0'; val = getchar(); } ungetc(val); val = (char)intval; goto stuff; } /* * bufptr now points at the next free slot */ bstrfromto(lgbackpatch, bufptr); if (linescrossed){ val = ILINESKIP; yylval = linescrossed; goto ret; } else goto builtval; case BADCHAR: linescrossed = lineno; lineno = scanlineno; yyerror("Illegal character mapped: %d, char read:(octal) %o", yylval, val); lineno = linescrossed; val = BADCHAR; goto ret; default: val = yylval; goto ret; } /*end of the switch*/ /* * here with one token, so stuff it */ ret: oval = val; ptoken(bufptr, val); switch(val){ case ILINESKIP: pint(bufptr, yylval); break; case SIZESPEC: pchar(bufptr, yylval); break; case BFINT: plong(bufptr, yylval); break; case INT: plong(bufptr, intval); break; case QUAD: plong(bufptr, quadval.quad_low_long); plong(bufptr, quadval.quad_high_long); break; case FLTNUM: pdouble(bufptr, fltval.dvalue); break; case NAME: pptr(bufptr, (int)(struct symtab *)yylval); break; case REG: pchar(bufptr, yylval); break; case INST0: case INSTn: pchar(bufptr, yylval); break; case IJXXX: pchar(bufptr, yylval); pptr(bufptr, (int)(struct symtab *)symalloc()); break; case ISTAB: case ISTABSTR: case ISTABNONE: case ISTABDOT: case IALIGN: pptr(bufptr, (int)(struct symtab *)symalloc()); break; /* * default: */ } builtval: ; } /*end of the while to stuff the buffer*/ done: bufferbox->tok_count = (toktype *)bufptr - &(bufferbox->toks[0]); /* * This is a real kludge: * * We put the last token in the buffer to be a MINUS * symbol. This last token will never be picked up * in the normal way, but can be looked at during * a peekahead look that the short circuit expression * evaluator uses to see if an expression is complicated. * * Consider the following situation: * * .word 45 + 47 * buffer 1 | buffer 0 * the peekahead would want to look across the buffer, * but will look in the buffer end zone, see the minus, and * fail. */ ptoken(bufptr, MINUS); InBufPtr = inbufptr; /*copy this back*/ } struct Quad _quadtemp; get_quad(radix, cp_start, cp_end, quadptr) int radix; char *cp_start, *cp_end; struct Quad *quadptr; { register char *cp = cp_start; /* r11 */ register struct Quad *qp = quadptr; /* r10 */ register long temp; /* r9 */ asm("clrq (r10)"); for (; cp < cp_end; cp++){ switch (radix) { case 8: asm ("ashq $3, (r10), (r10)"); break; case 16: asm ("ashq $4, (r10), (r10)"); break; case 10: asm ("ashq $1, (r10), __quadtemp"); asm ("ashq $3, (r10), (r10)"); asm ("addl2 __quadtemp, (r10)"); asm ("adwc __quadtemp+4, 4(r10)"); break; } asm ("cvtbl (r11), r9"); asm ("addl2 r9, (r10)"); asm ("adwc $0, 4(r10)"); } }