#ifndef lint
static char rcsid[] = "$Header:asscan2.c 12.0$";
#endif
/* $Source: /ibm/acis/usr/src/bin/as_ca/RCS/asscan2.c,v $ */
/*
 *	Copyright (c) 1982 Regents of the University of California
 */
#ifndef lint
static char sccsid[] = "@(#)asscan2.c 4.14 7/6/83";
#endif not lint

#include "asscanl.h"

static	inttoktype	oval = NL;
#define	ASINBUFSIZ	4096
char	inbufunget[8];
char	inbuffer[ASINBUFSIZ];
char	*Ginbufptr = inbuffer;
int	Ginbufcnt = 0;
int	scannerhadeof;

char *fillinbuffer()
{
		int	nread;
		int	goal;
		int	got;

	nread = 0;
	if (scannerhadeof == 0){
		goal = sizeof(inbuffer);
		do {
			got = read(stdin->_file, inbuffer + nread, goal);
			if (got == 0)
				scannerhadeof = 1;
			if (got <= 0)
				break;
			nread += got;
			goal -= got;
		} while (goal);
	} else {
		scannerhadeof = 0;
	}
	/*
	 *	getchar assumes that Ginbufcnt and Ginbufptr
	 *	are adjusted as if one character has been removed
	 *	from the input.
	 */
	if (nread == 0){
		inbuffer[0] = EOFCHAR;
		nread = 1;
	}
	Ginbufcnt = nread - 1;
	Ginbufptr = inbuffer + 1;
	return(Ginbufptr);
}

scan_dot_s(bufferbox)
	struct tokbufdesc *bufferbox;
{
	reg	char	*inbufptr;
	reg	int	inbufcnt;
	reg	int	ryylval;	/* local copy of lexical value */
	extern	int	yylval;		/* global copy of lexical value */
	reg	int	val;		/* the value returned */
		int	i;		/* simple counter */
	reg	char	*rcp;	
		int	ch;		/* treated as a character */
		int	ch1;		/* shadow value */
		struct 	symtab	*op;
	reg	ptrall	bufptr;		/* where to stuff tokens */
		ptrall	bufub;		/* where not to stuff tokens */
		long	intval;		/* value of int */
		int	linescrossed;	/* when doing strings and comments */
		struct	Opcode		opstruct;
	reg	int	strlg;		/* the length of a string */
		int	unwarned;	/* Print string-oflo msg only once */

	bufptr = (ptrall) & (bufferbox->toks[0]);	
	bufub = (ptrall)&(bufferbox->toks[AVAILTOKS]);

	MEMTOREGBUF;			/* set inbufptr and inbufcnt */
	if (newfflag){			/* set to 1 in new_dot_s */
		newfflag = 0;
		ryylval = (int)savestr(newfname, strlen(newfname)+1, STR_BOTH);
					/* save the string in both memory
					   and in the string file */
		ptoken(bufptr, IFILE);	/* first token is .file */
		ptoken(bufptr, STRING);	/* next token is the name */
		pptr(bufptr, ryylval);

		ptoken(bufptr, ILINENO);  /* next token is .lineno */
		ptoken(bufptr, INT);	/* and the number 1 */
		pint(bufptr,  1);
	}

	while (bufptr < bufub){
   loop:
        switch(ryylval = (type+1)[ch = getchar()]) {
					/* access the type array defined
					   in asscan3.c to determine what
					   the next character is */
	case SCANEOF:
	endoffile: ;
		inbufptr = 0;
		ptoken(bufptr, PARSEEOF);
		goto done;

	case DIV:		/*process C style comments*/
		if ( (ch = getchar()) == '*') {  /*comment prelude*/
			int	incomment;
			linescrossed = 0;
			incomment = 1;
			ch = getchar();	/*skip over the * */
			while(incomment){
				switch(ch){
			case EOFCHAR:
					goto endoffile;
			case '*':
					ch = getchar();
					incomment = (ch != '/');
					if (ch != '\n')
					    break;
			case '\n':
					scanlineno++;
					linescrossed++;
			default:
					ch = getchar();
				}
			}
			val = ILINESKIP;
			ryylval = linescrossed;
			goto ret;
		} else {	/*just an ordinary DIV*/
			ungetc(ch);
			val = ryylval = DIV;
			goto ret;
		}
	case SH:				/* hash mark */
		if (oval == NL){
			/*
			 *	Attempt to recognize a C preprocessor
			 *	style comment '^#[ \t]*[0-9]*[ \t]*".*"
			 */
			ch = getchar();	/*bump the #*/
			while (INCHARSET(ch, SPACE))
				ch = getchar();/*bump white */
			if (INCHARSET(ch, DIGIT)){
				intval = 0;
				while(INCHARSET(ch, DIGIT)){
					intval = intval*10 + ch - '0';
					ch = getchar();
				}
				while (INCHARSET(ch, SPACE))
					ch = getchar();
				if (ch == '"'){
					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 ((ch != '\n') && (ch != EOFCHAR)) 
			ch = getchar();
		if (ch == EOFCHAR)
			goto endoffile;
		val = ryylval = oval = NL;
		scanlineno++;
		goto ret;

	case NL:
		scanlineno++;
		val = ryylval;
		goto ret;

	case SP:
		oval = SP;	/*invalidate ^# meta comments*/
		goto loop;

	case REGOP:		/* % , could be used as modulo, or register*/
		ch = getchar();
		if (INCHARSET(ch, DIGIT)){
			ryylval = ch-'0';
			if (ch=='1') {
				if (INCHARSET( (ch = getchar()), REGDIGIT))
					ryylval = 10+ch-'0';
				else
					ungetc(ch);
			}
			/*
			 *	God only knows what the original author
			 *	wanted this undocumented feature to
			 *	do.
			 *		%5++ is really  r7
			 */
			while(INCHARSET( (ch = getchar()), SIGN)) {
				if (ch=='+')
					ryylval++;
				else
					ryylval--;
			}
			ungetc(ch);
			val = REG;
		} else {
			ungetc(ch);
			val = REGOP;
		}
		goto ret;

	case ALPH:
		ch1 = ch;
		if (INCHARSET(ch, SZSPECBEGIN)){
			if( (ch = getchar()) == '`' || ch == '^'){
				ch1 |= 0100;	/*convert to lower*/
				switch(ch1){
				case 'b':	ryylval = 1;	break;
				case 'w':	ryylval = 2;	break;
				case 'l':	ryylval = 4;	break;
				default:	ryylval = d124;	break;
				}
				val = SIZESPEC;
				goto ret;
			} else {
				ungetc(ch);
				ch = ch1;	/*restore first character*/
			}
		}
		rcp = yytext;
		do {
			if (rcp < &yytext[NCPName])
				*rcp++ = ch;
		} while (INCHARSET ( (ch = getchar()), ALPHA | DIGIT));
		*rcp = '\0';
		while (INCHARSET(ch, SPACE))
			ch = getchar();
		ungetc(ch);
	
		switch((op = *lookup(1))->s_tag){
		case 0:
		case LABELID:
			/*
			 *	Its a name... (Labels are subsets of name)
			 */
			ryylval = (int)op;
			val = NAME;
			break;
		case INST0:
		case INSTn:
		case ISPEC:
		case IJXXX:
			opstruct.Op_popcode = ( (struct instab *)op)->i_popcode;
			opstruct.Op_eopcode = ( (struct instab *)op)->i_eopcode;
			val = op->s_tag;
			break;
		default:
			ryylval = ( (struct instab *)op)->i_popcode;
			val = op->s_tag;
			break;
		}
		goto ret;

	case DIG:
		/*
		 *	restore local inbufptr and inbufcnt
		 */
		REGTOMEMBUF;
		val = number(ch);
		MEMTOREGBUF;
		/*
		 *	yylval or yybignum has been stuffed as a side
		 *	effect to number(); get the global yylval
		 *	into our fast local copy in case it was an INT.
		 */
		ryylval = yylval;
		goto ret;

	case LSH:
	case RSH:
		/*
		 *	We allow the C style operators
		 *	<< and >>, as well as < and >
		 */
		if ( (ch1 = getchar()) != ch)
			ungetc(ch1);
		val = ryylval;
		goto ret;

	case SQ:
		if ((ryylval = getchar()) == '\n')
			scanlineno++;		/*not entirely correct*/
		val = INT;
		goto ret;

	case DQ:				/* double quote */
	   eatstr:				/* SH branches here if a 
						   double quote is seen */
		linescrossed = 0;
		unwarned = 1;
		rcp = yytext;			/* put the string in yytext
						   temporarily */
		for (strlg = 0; /*VOID*/; strlg++){
		    switch(ch = getchar()){
	    case '"':
			goto tailDQ;
	    case '\n':
			yywarning("Newline in string constant");
			scanlineno++;
			linescrossed++;
			ch = getchar();
			ungetc(ch);
			if (ch != EOFCHAR) {
				ch = '\n';
				break;
			} 
	    case EOFCHAR:
	    		yyerror("End of file encountered in string");
			goto ret;

	    case '\\':
			ch = getchar();			/* skip the '\'*/
			if (ch == '\n') {
				scanlineno++;
				linescrossed++;
				continue;		/* skip the newline */
			}
			if (ch == '\\' || ch == '"' || ch == '\'')
				break;
			if ( INCHARSET(ch, BSESCAPE)){	/* abfnrtv */
				ch = eschars[ch-'a'];
				break;
			}
			if ( INCHARSET(ch, OCTDIGIT)) {
			    i = 0;
			    intval = 0;
			    while ( (i < 3) && (INCHARSET(ch, OCTDIGIT))){
				    i++;
				    intval <<= 3;
				    intval += ch - '0';
				    ch = getchar();
			    }
			    ungetc(ch);
			    ch = (char) intval;
			    break;
			};
			if ( ch == 'x' ) {
			    i = 0;
			    intval = 0;
			    ch = getchar();
			    while ( (i < 3) && (INCHARSET(ch,
						(DIGIT|HEXLDIGIT|HEXUDIGIT)))){
				i++;
				intval = (intval<<4) + ch -
					( (INCHARSET(ch, DIGIT)) ? '0'
					: (INCHARSET(ch, HEXLDIGIT))? 'a' - 10
					: 'A' - 10
					);
				ch = getchar();
			    }
			    ungetc(ch);
			    ch = (char)intval;
			    break;
			}
			yywarning("Unescapable character \\%03o in string",ch);
	    default:;
		    }
	/* End of switch, fall into here to stuff one character*/

		    if (rcp < &yytext[NCPName]) {
			*rcp++ = ch;	/* put string in yytext */
		    } else {
			if (unwarned) {
				unwarned=0;
				yyerror("Exceeded string length of %d chars",
				NCPName);
			}
		    }   
		}		/* End of for strlg */
	tailDQ: ;
		/*
		 *	account for any lines that were crossed
		 */
		if (linescrossed){
			ptoken(bufptr, ILINESKIP);
			pint(bufptr, linescrossed);
		}
		/*
		 *	Cheat: append a trailing null to the string
		 *	and then adjust the string length to ignore
		 *	the trailing null.  If any STRING client requires
		 *	the trailing null, the client can just change STRLEN
		 */
		*rcp = '\0';
		ryylval = (int) savestr(yytext, strlg+1, STR_BOTH);
		val = STRING;
		((struct strdesc *)ryylval)->sd_strlen -= 1;
		goto ret;

	case BADCHAR:
		linescrossed = lineno;
		lineno = scanlineno;
		yyerror("Illegal character mapped: %d, char read:(octal) %o",
			ryylval, ch);
		lineno = linescrossed;
		val = BADCHAR;
		goto ret;

	default:
		val = ryylval;
		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, ryylval);
				break;
		case	SIZESPEC:
				pchar(bufptr, ryylval);
				break;
		case	BFINT:	plong(bufptr, ryylval);
				break;
		case	INT:	plong(bufptr, ryylval);
				break;
		case 	BIGNUM:	pnumber(bufptr, yybignum);
				break;
		case	STRING:	pptr(bufptr, (int)(char *)ryylval);
				break;
		case	NAME:	pptr(bufptr, (int)(struct symtab *)ryylval);
				break;
		case	REG:	pchar(bufptr, ryylval);
				break;	
		case	ISPEC:
		case	INST0:
		case	INSTn:
				popcode(bufptr, opstruct);
				break;
		case 	IJXXX:
				popcode(bufptr, opstruct);
				pptr(bufptr, (int)(struct symtab *)symalloc());
				break;
		case	ISTAB:
		case	ISTABSTR:
		case	ISTABNONE:
		case	ISTABDOT:
		case	ILTORG:	
		case	IALIGN:
		case	IORG:
				pptr(bufptr, (int)(struct symtab *)symalloc());
				break;
	/*
	 *	default:
	 */
	 }
	 builtval: ;
   }			/*end of the while to stuff the buffer*/
   done:
	bufferbox->tok_count = (bytetoktype *)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);
	REGTOMEMBUF;
}
