BSD 4 release
[unix-history] / usr / src / cmd / as / asscan.c
/* 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)");
}
}