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

#include <stdio.h>
#include "as.h"
#include "asscan.h"
#include "assyms.h"
#include "asexpr.h"

int	lgensym[11];
char	genref[11];

long	bitfield;
int	bitoff;
int	curlen;			/* current length of literals */
int	extendedop;		/* Flag for extended mnemonics */

/*
 *	The following three variables are communication between various
 *	modules to special case a number of things.  They are properly
 *	categorized as hacks.
 */
extern	struct	symtab *lastnam;/*last name seen by the lexical analyzer*/
int	droppedLP;		/*analyzing an expression beginning with*/
				/*a left parenthesis, which has already been*/
				/*shifted. (Used to parse (<expr>)(rn)*/

char	yytext[NCPName+2];	/*the lexical image*/
int	yylval;			/*the lexical value; sloppy typing*/
struct	Opcode		yyopcode;	/* lexical value for an opcode */
Bignum	yybignum;		/* lexical value for a big number */
/*
 *	Expression and argument managers
 */
struct	exp	*xp;		/*next free expression slot, used by expr.c*/
struct	exp	explist[NEXP];	/*max of 20 expressions in one opcode*/
struct	arg	arglist[NARG];	/*building up operands in instructions*/
/*
 *	Sets to accelerate token discrimination
 */
char	tokensets[(LASTTOKEN) - (FIRSTTOKEN) + 1];

static	char	UDotsname[64];	/*name of the assembly source*/

/*
 *   defs for literal processing..
 */
struct	litdesc	litpool[NLIT];	
struct	litdesc	*litptr;
struct	symtab	*noltorg_alignptr;
	int	litmsgsw;

/* The following defines the order emitting literals */
char	toklist[] = { IHFLOAT, IDFLOAT, IDLONG, IFFLOAT, ILONG, IINT, ISHORT,
			IBYTE, IASCII, IASCIZ, 0 }; 

/* A buffer to collect the literal token string */
char	litbuffer[LITBUFSIZE];

extern	int	dseterr;	/* a .set value changes */

/* 		Tell expr we're processing a stab.  The design decision to
 * process stabs during pass 1 overlooked the fact that labels don't have
 * final values until the start of pass 2.  The only way we can get correct
 * expression evaluation is to use the "floating stab" mechanism (intended
 * only for forward-defined labels) for all stabs with label+const expressions.
 * Kluges beget kluges.  Even this doesn't work for symbols defined via .set,
 * which aren't corrected during pass 1.5.
 */
int	stabbing = 0;	/* I have this pain in my first pass, doctor */

yyparse()
{
	reg	struct	exp	*locxp;
		/*
		 *	loc1xp and ptrloc1xp are used in the
		 * 	expression lookahead
		 */
		struct	exp	*loc1xp;	/*must be non register*/
		struct	exp	**ptrloc1xp = & loc1xp;

	reg	struct	symtab	*np;
	reg	int		argcnt;

	reg	inttoktype	val;		/*what yylex gives*/
	reg	inttoktype	auxval;		/*saves val*/

	reg	struct 	arg	*ap;		/*first free argument*/

	reg	struct	symtab	*p;
	reg	struct	symtab	*stpt;

		struct	strdesc *stringp;	/*handles string lists*/

		struct	basereg	*brp;		/*handles base registers*/

		int	regno;		/*handles arguments*/
		int	*ptrregno = &regno;
		int	sawindex;	/*saw [rn]*/
		int	sawsize;
		int	seg_type; 	/*the kind of segment: data or text*/
		int	seg_number;	/*the segment number*/
		int	space_value;	/*how much .space needs*/
		int	space_byte;	/*value to stuff in each byte*/
		int	fill_rep;	/*how many reps for .fill */
		int	fill_size;	/*how many bytes for .fill */

		char	*stabname;	/*name of stab dealing with*/
		ptrall	stabstart;	/*where the stab starts in the buffer*/
		int	toconv;		/* how to convert bignums */
		int	savesymno;	/* temp save for lgensym[] */
		int	curlitno;	/* symno chosen by lit copy routine */
		inttoktype	axval;	/* save or hold a val */

	xp = explist;
	ap = arglist;

	litmsgsw = 0;

	val = yylex();

    while (val != PARSEEOF){	/* primary loop */

	while (INTOKSET(val, LINSTBEGIN)){
		if (val == INT) {
			int i = ((struct exp *)yylval)->e_xvalue;
			shift;
			if (val != COLON){
				yyerror("Local label %d is not followed by a ':' for a label definition",
					i);
				goto  errorfix;
			}
			if (i < 0 || i > 9) {
				yyerror("Local labels are 0-9");
				goto errorfix;
			}
			(void)sprintf(yytext, "L%d\001%d", i, lgensym[i]);
			lgensym[i]++;
			genref[i] = 0;
			yylval = (int)*lookup(passno == 1);
			val = NAME;
			np = (struct symtab *)yylval;
			goto restlab;
		}
		if (val == NL){
			lineno++;
			shift;
		} else
		if (val == SEMI) 
			shift;
		else {	/*its a name, so we have a label or def */
			if (val != NAME){
				ERROR("Name expected for a label");
			}
			np = (struct symtab *)yylval;
			shiftover(NAME);
			if (val != COLON) {
				yyerror("\"%s\" is not followed by a ':' for a label definition",
					FETCHNAME(np));
				goto  errorfix;
			}
restlab:
			shift;
			flushfield(NBWD/4);
			if ((np->s_type&XTYPE)!=XUNDEF) {
				if(  (np->s_type&XTYPE)!=dotp->e_xtype 
				   || np->s_value!=dotp->e_xvalue
				   || (  passno==1
				       && np->s_index != dotp->e_xloc) ) {
						if (passno == 1)
						  yyerror("%s redefined",
							FETCHNAME(np));
						else
						  yyerror("%s redefined: PHASE ERROR, 1st: %d, 2nd: %d",
							FETCHNAME(np),
							np->s_value,
							dotp->e_xvalue);
				}
			}
/*			np->s_type &= ~(XTYPE|XFORW);  bug?? it sure ruins
							what i need */
			np->s_type &= ~XTYPE;
			np->s_type |= dotp->e_xtype;
			np->s_value = dotp->e_xvalue;
			if (passno == 1){
				np->s_index = dotp-usedot;
				if (FETCHNAME(np)[0] == 'L'){
					nlabels++;
				}
				np->s_tag = LABELID;
			}
		}	/*end of this being a label*/
	}	/*end of consuming all labels, NLs and SEMIS */ 

	xp = explist;
	ap = arglist;

	/*
	 *	process the INSTRUCTION body
	 */
	switch(val){

    default:
	ERROR("Unrecognized instruction or directive");

   case IABORT:
	shift;
	sawabort();
	/*NOTREACHED*/
	break;

   case PARSEEOF:
	tokptr -= sizeof(bytetoktype);
	*tokptr++ = VOID;
	tokptr[1] = VOID;
	tokptr[2] = PARSEEOF;
	break;

   case IFILE:
	shift;
	stringp = (struct strdesc *)yylval;
	shiftover(STRING);
	dotsname = &UDotsname[0];
	movestr(dotsname, stringp->sd_string,
		min(stringp->sd_strlen+1, sizeof(UDotsname)-1)); /* +1 for \0 */
		/* (2nd hack:)  -1 to let static init. put \0 in last place */
	break;

   case ILINENO:
	shift;		/*over the ILINENO*/
	expr(locxp, val);
	lineno = locxp->e_xvalue;
	break;

   case ISET: 	/* .set  <name> , <expr> */
	shift;
	np = (struct symtab *)yylval;
	shiftover(NAME);
	shiftover(CM);
	expr(locxp, val);
	/* the expr macro lets some things slip thru that shouldn't! */
	if ( (int)locxp < (int)explist ) {
		yyerror("Invalid expression for .set");
		break;
	}
	np->s_type &= (XXTRN|XFORW);
	np->s_type |= locxp->e_xtype&(XTYPE|XFORW);
	if (locxp->e_xtype&XBSS && passno==1) {
			locxp->e_xvalue=0; /* don't dup the space */
	}
	if (passno==2 && (np->s_value!=locxp->e_xvalue) 
				&& (locxp->e_xtype&XBSS)==0) {
		yywarning("A .set value has changed.");
		dseterr++;
	}
	np->s_value = locxp->e_xvalue;
	if (passno==1)
		np->s_index = locxp->e_xloc;	/* Bug ? e_xloc is not initialized  */
		/* (except by code that I have added)   SFZ */
		/* I think asexpr will have to be changed for this to work */
	if ((locxp->e_xtype&XTYPE) == XUNDEF)
		yyerror("Illegal set?");
	break;

   case ILSYM: 	/*.lsym name , expr */
	shift;
	np = (struct symtab *)yylval;
	shiftover(NAME);
	shiftover(CM);
	expr(locxp, val);
	/*
	 *	Build the unique occurance of the
	 *	symbol.
	 *	The character scanner will have
	 *	already entered it into the symbol
	 *	table, but we should remove it
	 */
	if (passno == 1){
		stpt = (struct symtab *)symalloc();
		stpt->s_name = np->s_name;
		np->s_tag = OBSOLETE;	/*invalidate original */
		nforgotten++;
		np = stpt;
		if ( (locxp->e_xtype & XTYPE) != XABS)
			yyerror("Illegal second argument to lsym");
		np->s_value = locxp->e_xvalue;
		np->s_type = XABS;
		np->s_tag = ILSYM;
	}
	break;

   case IGLOBAL: 	/*.globl <name> */
	shift;
	np = (struct symtab *)yylval;
	shiftover(NAME);
	np->s_type |= XXTRN;
	break;

   case IDATA: 	/*.data [ <expr> ] */
   case ITEXT: 	/*.text [ <expr> ] */
	seg_type = -val;
	shift;
	if (INTOKSET(val, EBEGOPS+YUKKYEXPRBEG+SAFEEXPRBEG)){
		expr(locxp, val);
		seg_type = -seg_type;   /*now, it is positive*/
	}

	if (seg_type < 0) {	/*there wasn't an associated expr*/
		seg_number = 0;
		seg_type = -seg_type;
	} else {
		if (   ((locxp->e_xtype & XTYPE) != XABS)	/* tekmdp */
		    || (seg_number = locxp->e_xvalue) >= NLOC) {
			yyerror("illegal location counter");
			seg_number = 0;
		}
	}
	if (seg_type == IDATA)
		seg_number += NLOC;
	flushfield(NBWD/4);
	dotp = &usedot[seg_number];
	if (passno==2) {	/* go salt away in pass 2*/
		txtfil = usefile[seg_number];
		relfil = rusefile[seg_number];
	}
	break;

	/*
	 *	Storage filler directives:
	 *
	 *	.byte	[<exprlist>]
	 *
	 *	exprlist:  empty | exprlist outexpr
	 *	outexpr:   <expr> | <expr> : <expr>
	 */
   case IBYTE:	curlen = NBWD/4; goto elist;
   case ISHORT:	curlen = NBWD/2; goto elist;
   case IINT:	curlen = NBWD;   goto elist;
   case ILONG:	curlen = NBWD;   goto elist;

   elist:
	seg_type = val;
	shift;

	/*
	 *	Expression List processing
	 */
	if (INTOKSET(val, EBEGOPS+YUKKYEXPRBEG+SAFEEXPRBEG)){
	    do{
		/*
		 *	expression list consists of a list of :
		 *	<expr>
		 *	<expr> : <expr> 
		 *		(pack expr2 into expr1 bits
		 */
		 val = filexpr(locxp, val);
		xp = explist;
		if (auxval = (val == CM))
			shift;
	    } while (auxval);
	}	/* there existed an expression at all */

	flushfield(curlen);
	if ( ( curlen == NBWD/4) && bitoff)
		dotp->e_xvalue ++;
	break;
	/*end of case IBYTE, ISHORT, ILONG, IINT*/

   case ISPACE: 	/* .space <expr> [,<expr>] */
	shift;
    	expr(locxp, val);
	if ((locxp->e_xtype & XTYPE) != XABS)	/* tekmdp */
		yyerror("Space size not absolute");
	space_value = locxp->e_xvalue; 	
  ospace:
	if (val != CM) {
		space_byte = 0;		/* default is to pad with zeros */
	} else {			/* a fill expression is specified */
		shift;			/* get next token */
		expr(locxp, val);
		if ((locxp->e_xtype & XTYPE) != XABS)
			yyerror("Fill value not absolute");
		space_byte = locxp->e_xvalue;
	}
	flushfield(NBWD/4);
	while (space_value-- > 0) {	/* write space_value bytes */
		dotp->e_xvalue++;
		if (passno == 2) {
			bputc(space_byte, txtfil);
		}
	}
	break;

	/*
	 *	.fill rep, size, value
	 *	repeat rep times: fill size bytes with (truncated) value
	 *	size must be between 1 and 8
	 */
   case	IFILL:		/* .fill <expr>,<expr>,<expr> */
	shift;
	expr(locxp, val);
	if ( (locxp->e_xtype & XTYPE) != XABS)	/* tekmdp */
		yyerror("Fill repetition count not absolute");
	fill_rep = locxp->e_xvalue;
	shiftover(CM);
	expr(locxp, val);
	if ( (locxp->e_xtype & XTYPE) != XABS)	/* tekmdp */
		yyerror("Fill size not absolute");
	fill_size = locxp->e_xvalue;
	if (fill_size <= 0 || fill_size > 8)
		yyerror("Fill count not in in 1..8");
	shiftover(CM);
	expr(locxp, val);
	if (passno == 2 && (locxp->e_xtype & XTYPE) != XABS)	/* tekmdp */
		yyerror("Fill value not absolute");
	flushfield(NBWD/4);
	dotp->e_xvalue += fill_rep * fill_size;
	if (passno == 2 ) {
		while(fill_rep-- > 0)
			bwrite((char *)&locxp->e_xvalue, fill_size, txtfil);
	}
	break;

   case IASCII:		/* .ascii [ <stringlist> ] */
   case IASCIZ: 	/* .asciz [ <stringlist> ] */
	auxval = val;
	shift;
	/*
	 *	Code to consume a string list
	 *
	 *	stringlist: empty | STRING | stringlist STRING
	 */
	while (val == STRING){
		flushfield(NBWD/4);
		if (bitoff)
			dotp->e_xvalue++;
		stringp = (struct strdesc *)yylval;

		val = genstr(stringp,auxval);

		shift;		/*over the STRING*/
		if (val == CM)	/*could be a split string*/
			shift;
	}
	break;
	
   case IORG: 	/* .org <expr> [,<expr>] */
	stpt = (struct symtab *)yylval;
	shift;
	expr(locxp, val);	
     	if ((locxp->e_xtype & XTYPE) == XABS)	/* tekmdp */
		orgwarn++;
	else if ((locxp->e_xtype & XTYPE) != dotp->e_xtype) {
		yyerror("Illegal expression to set origin");
		goto errorfix;
	}
	/* let jxxx know about the .org */
	jxorg(locxp, stpt);
	space_value = locxp->e_xvalue - dotp->e_xvalue;
	if (space_value < 0)
		yyerror("Backwards 'org'");
	goto ospace;

   case IUSING: 	/* .using <expr>,register,... */
	shift;
	expr(locxp, val);	
	seg_type = locxp->e_xtype&XTYPE;
    	if (passno == 2) {
		if (seg_type == XABS) { 
			yyerror("First argument is absolute");
			goto errorfix;
		} else if (seg_type == XUNDEF) {
			yyerror("First argument is undefined");
			goto errorfix;
		} else if (seg_type != XTEXT && seg_type != XDATA) {
			yyerror("First argument is not text or data");
			goto errorfix;
		} else {
			seg_number = locxp->e_xloc;     
			brp = &usebreg[seg_number];
			brp->b_rvalue = locxp->e_xvalue;
		}
	}
	if (val != CM ) {
		if (passno == 2)
			brp->b_rno = 0;
		break;
	}

	shiftover(CM);
	for (argcnt=0; argcnt<NBREG; argcnt++ ) {
		findreg(regno);
		if (passno == 2) {
			brp->b_rreg[argcnt] = regno;
			brp->b_rno = argcnt+1;
		}
		if (val != CM) break;
		shiftover(CM);
	}
	break;   

   case ILTORG: 	/* .ltorg */
	stpt = (struct symtab *)yylval;
	shift;
	regno = processlit(stpt);
	break;

/*
 *
 *	Process stabs.  Stabs are created only by the f77
 *	and the C compiler with the -g flag set.
 *	We only look at the stab ONCE, during pass 1, and
 *	virtually remove the stab from the intermediate file
 *	so it isn't seen during pass2.  This makes for some
 *	hairy processing to handle labels occuring in
 *	stab entries, but since most expressions in the
 *	stab are integral we save lots of time in the second
 *	pass by not looking at the stabs.
 *	A stab that is tagged floating will be bumped during
 *	the jxxx resolution phase.  A stab tagged fixed will
 *	not be be bumped.
 *
 *	.stab:	Old fashioned stabs
 *	.stabn: For stabs without names
 *	.stabs:	For stabs with string names
 *	.stabd: For stabs for line numbers or bracketing,
 *		without a string name, without
 *		a final expression.  The value of the
 *		final expression is taken to be  the current
 *		location counter, and is patched by the 2nd pass
 *
 *	.stab{<expr>,}*NCPName,<expr>, <expr>, <expr>, <expr>
 *	.stabn		 <expr>, <expr>, <expr>, <expr>
 *	.stabs   STRING, <expr>, <expr>, <expr>, <expr>
 *	.stabd		 <expr>, <expr>, <expr> # . 
 */
   case ISTAB: 
	yyerror(".stab directive no longer supported");
	goto errorfix;

  tailstab:
	expr(locxp, val);
	if (! (locxp->e_xvalue & STABTYPS)){
		yyerror("Invalid type in %s", stabname);
		goto errorfix;
	}
	stpt->s_ptype = locxp->e_xvalue;
	shiftover(CM);
	expr(locxp, val);
	stpt->s_other = locxp->e_xvalue;
	shiftover(CM);
	expr(locxp, val);
	stpt->s_desc = locxp->e_xvalue;
	shiftover(CM);
stabbing=1;
	expr(locxp, val);
	p = locxp->e_xname;
stabbing=0;
#if DEBUG
	if (debug) printstab(stpt, 10);
#endif
	if (p == NULL) {	/*const expr, or definedsym[+const] */
		stpt->s_value = locxp->e_xvalue;
		stpt->s_index = locxp->e_xloc;
		stpt->s_type = locxp->e_xtype;
		stpt->s_tag = STABFIXED;
	}
	else 
	{		/* expr involves non-absolute symbol; can't trust
			 * its value during pass 1.
			 */
		stpt->s_dest = locxp->e_xname;
		stpt->s_index = p->s_index; 
		stpt->s_type = p->s_type | STABFLAG;
		/*
		 *	We will assign a more accurate
		 *	guess of locxp's location when
		 *	we sort the symbol table
		 *	The final value of value is
		 *	given by stabfix()
		 */
/*
 * For exprs of the form (name + value) one needs to remember locxp->e_xvalue
 * for use in stabfix. The right place to keep this is in stpt->s_value
 * however this gets corrupted by sortsymtab().
 * As a bandaid hack the value is preserved in s_desc and s_other (a
 * short and a char). This destroys these two values and will
 * be fixed. May 19 ,1983 Alastair Fyfe
 */
		if(locxp->e_xvalue) {
			stpt->s_other = (locxp->e_xvalue >> 16);
			stpt->s_desc =  (locxp->e_xvalue  & 0x0000ffff);
			stpt->s_tag = STABFLOATING;
		}
		else stpt->s_tag = STABFIXED;
	}
#if DEBUG
	if (debug) printstab(stpt, 11);
#endif
	/*
	 *	tokptr now points at one token beyond
	 *	the current token stored in val and yylval,
	 *	which are the next tokens after the end of
	 *	this .stab directive.  This next token must
	 *	be either a SEMI or NL, so is of width just
	 *	one.  Therefore, to point to the next token
	 *	after the end of this stab, just back up one..
	 */
	buildskip(stabstart, (bytetoktype *)tokptr - sizeof(bytetoktype));
	break;	/*end of the .stab*/

   case ISTABDOT:	
	stabname = ".stabd";
	stpt = (struct symtab *)yylval;
	/*
	 *	We clobber everything after the
	 *	.stabd and its pointer... we MUST
	 *	be able to get back to this .stabd
	 *	so that we can resolve its final value
	 */
	stabstart = tokptr;
	shift;		/*over the ISTABDOT*/
	if (passno == 1){
		expr(locxp, val);
		if (! (locxp->e_xvalue & STABTYPS)){
			yyerror("Invalid type in .stabd");
			goto errorfix;
		}
		stpt->s_ptype = locxp->e_xvalue;
		shiftover(CM);
		expr(locxp, val);
		stpt->s_other = locxp->e_xvalue;
		shiftover(CM);
		expr(locxp, val);
		stpt->s_desc = locxp->e_xvalue;
		/*
		 *
		 *	Now, clobber everything but the
		 *	.stabd pseudo and the pointer
		 *	to its symbol table entry
		 *	tokptr points to the next token,
		 *	build the skip up to this
		 */
		buildskip(stabstart, (bytetoktype *)tokptr - sizeof(bytetoktype));
	}
	/*
	 *	pass 1:	Assign a good guess for its position
	 *		(ensures they are sorted into right place)/
	 *	pass 2:	Fix the actual value
	 */
	stpt->s_value = dotp->e_xvalue;
	stpt->s_index = dotp - usedot; 
	stpt->s_tag = STABFLOATING;	/*although it has no effect in pass 2*/
	break;

   case ISTABNONE:	stabname = ".stabn"; goto shortstab;

   case ISTABSTR: 	stabname = ".stabs";
   shortstab:
	auxval = val;
	if (passno == 2) goto errorfix;
	stpt = (struct symtab *)yylval;
	stabstart = tokptr;
	stabstart -= sizeof(struct symtab *);
/* 
	stabstart -= (ptrall)sizeof(struct symtab *);
	stabstart -= (ptrall)sizeof(bytetoktype);
*/
	shift;
	if (auxval == ISTABSTR){
		stringp = (struct strdesc *)yylval;
		shiftover(STRING);
		stpt->s_name = (char *)stringp;
		/*
		 *	We want the trailing null included in this string.
		 *	We utilize the cheat the string scanner used,
		 *	and merely increment the string length
		 */
		stringp->sd_strlen += 1;
		shiftover(CM);
	} else {
		stpt->s_name = (char *)savestr("\0", 0, STR_BOTH);
	}
	goto tailstab;

   case ICOMM:		/* .comm  <name> , <expr> */
   case ILCOMM: 	/* .lcomm <name> , <expr> */
	auxval = val;
	shift;
	np = (struct symtab *)yylval;
	shiftover(NAME);
	shiftover(CM);
	expr(locxp, val);

	if ( (locxp->e_xtype & XTYPE) != XABS)	/* tekmdp */
		yyerror("comm size not absolute");
	if (passno == 1 && (np->s_type&XTYPE) != XUNDEF)
		yyerror("Redefinition of %s", FETCHNAME(np));
	if (passno==1) {
		np->s_value = locxp->e_xvalue;
		if (auxval == ICOMM)
			np->s_type |= XXTRN;
		else {
			np->s_type &= ~XTYPE;
			np->s_type |= XBSS;
		}
	}
	break;

   case IALIGN: 		/* .align <expr> */
	stpt = (struct symtab *)yylval;
	shift;
	expr(locxp, val);
	jalign(locxp, stpt);
	break;

   case INST0: 		/* instructions w/o arguments*/
	insout(yyopcode, (struct arg *)0, 0, INST0);
	shift;	
	break;

   case IJXXX:		/* extended branch mnemonics */

			/* The primary op code for extended branch mnemonics
			   is really the extended branch type field defined
			   in instrs.h.  It contains both the condition status
			   bit mask and bits defining the correct op code. */
	ap = arglist;
	xp = explist;
	ap->a_xp = xp++;
	ap->a_atype = AEXP;  	/* Prepare the condition status bit mask to be
				   the first operand of the branch instruction */
	(ap->a_xp)->e_xvalue = yyopcode.Op_popcode & CSB_MASK;
				/* Save the condition status mask */
	(ap->a_xp)->e_xtype = XABS;
	ap->a_dispsize = d124;
	extendedop = 1;		/* Set flag for putins to indicate that
				   the second argument in the argument
				   list is actually the first coded argument */
	yyopcode.Op_eopcode = ESBI;  /* default is BI format instruction */

		/* If the instruction to be generated contains the */
		/* branch address in a register, treat the instruction */
		/* as if it were not a branch. */
		/* Ditto for execute forms as well */
	if (yyopcode.Op_popcode & BBR_MASK 	/* Treat as if not a branch */
			|| yyopcode.Op_popcode & BBX_MASK ) {
		if (yyopcode.Op_popcode & BBR_MASK)
		  yyopcode.Op_eopcode = CORE; /* make it a 2 byte instruction */
		val = INSTn;
		/* scan has allocated a symbol, let's remove it */
		if (passno==1) {
			lastjxxx->s_tag = IGNOREBOUND ;
			nforgotten++;
		}
	}
	/*
	 * We should now only have macros that will become bb or bnb that will
	 * go thru ijxxx.
	 */

			/* Overlay the extended branch type field with the
			   correct op code. */ 
	switch(yyopcode.Op_popcode & OPCODE_MASK) {

	case (BB_MASK):
		yyopcode.Op_popcode = BB_OP;
		break;

	case (BBX_MASK):
		yyopcode.Op_popcode = BBX_OP;
		break;

	case (BBR_MASK):
		yyopcode.Op_popcode = BBR_OP;
		break;

	case (BBRX_MASK):
		yyopcode.Op_popcode = BBRX_OP;
		break;

	case (BNB_MASK):
		yyopcode.Op_popcode = BNB_OP;
		break;

	case (BNBX_MASK):
		yyopcode.Op_popcode = BNBX_OP;
		break;

	case (BNBR_MASK):
		yyopcode.Op_popcode = BNBR_OP;
		break;

	case (BNBRX_MASK):
		yyopcode.Op_popcode = BNBRX_OP;
		break;

	}

	/*
	 * The second operand for BB is a branch destination.
	 * ijxout() should know about it and check it.
	 * HOWEVER, this needs more work than a simple route through
	 * ijxout: either scan must insert more in token stream or,
	 * bb should be coded as a macro in instrs, and the number of          
	 * arguments specialed in here.
	 */
	ap++;		/* point to the next argument */
	argcnt = 2;	/* start with the second argument */
	goto process_args;

   case ISPEC:
   case INSTn:		/* instructions with arguments*/
	ap = arglist;	/* point to the first argument */
	xp = explist;
	extendedop = 0;	/* indicate that the first argument in the
			   argument list is the first coded argument */
	argcnt = 1;	/* start with the first one */
	/*
	 *	Code to process an argument list
	 */
process_args:
	auxval = val;

	shift;		/* bring in the first token for the arg list*/

	if (val==COLON) {
		yyerror("Label is same as instruction mnemonic");
		goto errorfix;
	}

	for ( ; argcnt <= 6; argcnt++, ap++){
		/*
		 *	code to process an argument proper
		 */
	    	sawindex  = sawsize = 0;
	     
	get_arg:
		switch(val) {

		   default:
		     disp:
			if( !(INTOKSET(val,
				 EBEGOPS
				+YUKKYEXPRBEG
				+SAFEEXPRBEG)) ) {
				ERROR("expression expected");
			}
			expr(ap->a_xp,val);
		     overdisp:
			if ( val == LP ) {
				shiftover(LP);
				findreg(regno);
				shiftover(RP);
				ap->a_atype = ADISP ;
				ap->a_areg1=regno;
			} else {
				ap->a_atype = AEXP;
				ap->a_areg1 = 0;
			}
			goto index;

		   case SIZESPEC: 
		     sizespec:
			sawsize = yylval;
			shift;
			goto get_arg;

		   case REG:
		   case REGOP: 
			findreg(regno);
			ap->a_atype = AREG;
			ap->a_areg1 = regno;
			break;
		    
		   case MUL: 
			ERROR("* indirection is not supported.");

		   case LP: 
			shift;	/* consume the LP */
			droppedLP = 1;
			val = exprparse(val, &(ap->a_xp));
			droppedLP = 0;
			goto overdisp;

		   case LITOP: 
			shift;
			if (INTOKSET( val, LITBEGIN) ) {
				val=copylit(val, &curlitno);
				if (!val) goto errorfix;
				/* Use yukkyexpr to get value or */
				/* gen a label for later use */
				savesymno = lgensym[LITSYMNO];
				lgensym[LITSYMNO] = curlitno;
				locxp=xp++;
				locxp->e_xvalue = LITSYMNO+1;
				axval=BFINT;
				ap->a_xp = yukkyexpr(axval,locxp);
				lgensym[LITSYMNO] = savesymno;
				/* Move on */
				ap->a_atype = ALIT;
				ap->a_areg1 = 0;
			} 
			else {
				expr(locxp, val);
				ap->a_atype = AIMM;
				ap->a_areg1 = 0;
				ap->a_xp = locxp;
				/* JSW - check for $expr(rx) case */
				if (val == LP)
					{
					shiftover(LP);
					if( val == REG || val == REGOP )
						{
						findreg(regno);
						}
					else
						{
						ERROR( "register expected");
						}
					ap->a_areg1 = regno;
					shiftover(RP);
					ap->a_atype = AIMIND;
					}
			}
	  index:			/*look for [reg] */
			if (val == LB){
				shift;
				findreg(regno);
				shiftover(RB);
				sawindex = 1;
				ap->a_areg2 = regno;
			}
			break;

		}	/*end of the switch to process an arg*/

	    	if (sawindex){
			sawindex = 0;
			yywarning("Index ignored, operand %d.", argcnt);
	    	}
	    	ap->a_dispsize = sawsize == 0 ? d124 : sawsize;
		if (val != CM) break;
		shiftover(CM);
	}	/*processing all the arguments*/

	if (argcnt > 6){
		yyerror("More than 6 arguments");
		goto errorfix;
	}


	insout(yyopcode, arglist, argcnt, auxval);   
	break;

   case IDLONG:		toconv = TYPU;	goto bignumlist;

   case IFFLOAT:	toconv = TYPF;	goto bignumlist;
   case IDFLOAT:	toconv = TYPD;	goto bignumlist;
   case IHFLOAT:	yyerror(".hfloat (extended precision floating point) is not supported");
   	/* was:	 	toconv = TYPH;	goto bignumlist;	*/
   bignumlist:	
	/*
	 *	Eat a list of non 32 bit numbers.
	 *	IDLONG can, possibly, return an
	 *	INT, if the number is "small".
	 *
	 *	The value of the numbercomes back
	 *	as an expression, NOT in yybignum.
	 */
	shift;	/* over the opener */
	if ((val == BIGNUM) || (val == INT)){
		do{
			if ((val != BIGNUM) && (val != INT)){
				ERROR(ty_float[toconv]
				   ? "floating number expected"
				   : "integer number expected" );
			}
			dotp->e_xvalue += ty_nbyte[toconv];
			if (passno == 2){
				bignumwrite(
					((struct exp *)yylval)->e_number,
					toconv);
			}
			xp = explist;
			shift;		/* over this number */
			if (auxval = (val == CM))
				shift;	/* over the comma */
		} while (auxval);	/* as long as there are commas */
	}
	break;
	/* end of the case for initialized big numbers */
    }	/*end of the switch for looking at each reserved word*/

	continue;

   errorfix: 
	/*
	 *	got here by either requesting to skip to the
	 *	end of this statement, or by erroring out and
	 *	wanting to apply panic mode recovery
	 */
	while (    (val != NL) 
		&& (val != SEMI) 
		&& (val != PARSEEOF)
	      ){
		shift;
	}
	if (val == NL)
		lineno++;
	shift;

    }	/*end of the loop to read the entire file, line by line*/

}	/*end of yyparse*/

int	litwrapup()
{
	int	i;
   	if (litptr == litpool) 
		return(0);
   	 /* Do a .text 0 */
	flushfield(NBWD/4);
	dotp = &usedot[0];
	if (passno==2) {	/* go salt away in pass 2*/
		txtfil = usefile[0];
		relfil = rusefile[0];
	}
  	 /* Get a symbol entry for .align and emit the lits */
	 if (passno == 1) {
    		 yywarning("Literals without a .ltorg");
		 noltorg_alignptr = (struct symtab *)symalloc();
	 }
	 i = processlit(noltorg_alignptr);
	 return(i);
}
inttoktype	filexpr(locxp, val)
	struct	exp	*locxp;
	inttoktype	val;
{
		/*
		 *	loc1xp and ptrloc1xp are used in the
		 * 	expression lookahead
		 */
		struct	exp	*loc1xp;	/*must be non register*/
		struct	exp	**ptrloc1xp = & loc1xp;
		struct	exp	*pval;		/*hacking expr:expr*/
		int	field_width;	/*how wide a field is to be*/
		int	field_value;	/*the value to stuff in a field*/
		int	reloc_how;	/* how to relocate expressions */

		expr(locxp, val);
		/*
		 *	now, pointing at the next token
		 */
		if (val == COLON){ shiftover(COLON); expr(pval, val);
			if ((locxp->e_xtype & XTYPE) != XABS) /* tekmdp */
				yyerror("Width not absolute");
			field_width = locxp->e_xvalue;
			locxp = pval;
			if (bitoff + field_width > curlen)
				flushfield(curlen);
			if (field_width > curlen)
				yyerror("Expression crosses field boundary");
		} else {
			field_width = curlen;
			flushfield(curlen);
		}

		if ((locxp->e_xtype & XTYPE) != XABS) {
		/*	if (bitoff)	*/
			if (field_width != curlen)
				yyerror("Illegal relocation in field");
			switch(curlen){
				case NBWD/4:	reloc_how = TYPB; break;
				case NBWD/2:	reloc_how = TYPS; break;
				case NBWD:	reloc_how = TYPL; break;
			}
			if (passno == 1){
				dotp->e_xvalue += ty_nbyte[reloc_how];
			} else {
				outrel(locxp, reloc_how);
			}
		} else {
			field_value = locxp->e_xvalue & ((1L << field_width)-1);
		/*	bitfield |= field_value << bitoff;	*/
			bitfield |= field_value << curlen-bitoff-field_width;
			bitoff += field_width;
		}
	return(val);
   errorfix: 
	/*
	 *	got here by either requesting to skip to the
	 *	end of this statement, or by erroring out and
	 *	wanting to apply panic mode recovery
	 */
	while (    (val != NL) 
		&& (val != SEMI) 
		&& (val != PARSEEOF)
		&& (val != CM)
	      ){
		shift;
	}
	return(val);
}
	
inttoktype	copylit(val,cursymno)
	inttoktype	val;
	int		*cursymno;
{    
	ptrall		scanptr;
	ptrall		toptr;
	ptrall		oldptr;
	inttoktype	axval; 
	int		lpcount;
	int		i;
	struct	litdesc	*litwalk;

	toptr=litbuffer;
	axval = val;
	lpcount = 0;
	shift;
	if (val == STRING ) {
		*toptr++ = val;
		pptr(toptr, (int)(char *)yylval);
		shift;
	} else {
	    while(INTOKSET(val,ANYEXPRTOKS) || val == RP ) {
		*toptr++ =val;
		switch (val) {
		   case BFINT:
		   case INT:
			i = ((struct exp *)yylval)->e_xvalue;
			plong(toptr, i);
			break;
		   case NAME:
			pptr(toptr, (int)(struct symtab *)yylval);
			break;
		   case LP:
			lpcount++;
			break;
		   case RP:
			lpcount--;
			break;
		   case INSTn:
		   case INST0:
			popcode(toptr, yyopcode);
			break;
		   case REG:
			pchar(toptr, yylval);
			break;
		   case BIGNUM:
			pnumber(toptr, ((struct exp *)yylval)->e_number);
			break;
		}
		if (toptr >= &litbuffer[LITBUFSIZE-1-sizeof(Bignum)]) {
			yyerror("Too many terms in one literal");
			return(0);
		}
		shift;
	    }
	    if (!INTOKSET(val,LINSTBEGIN)) {
		yyerror("Illegal literal syntax?");
		while (!INTOKSET(val,LINSTBEGIN)) shift;
	    }
	}
	while (lpcount-- > 0) 
		*toptr++ = RP;
	*toptr++ = SEMI;
	if (axval == IINT)
		axval = ILONG;
	/*
	 *    Look for a duplicate literal by scanning the saved token strings.
	 */
	*cursymno = 0;
	if (axval != IASCII || axval != IASCIZ) {
		for (litwalk = litpool; litwalk < litptr; litwalk++) {
		    if (axval == litwalk->lit_type) {  /* look for equal */
			scanptr = litbuffer;
			oldptr = litwalk->lit_str->sd_string;
			while (scanptr < toptr && *scanptr++ == *oldptr++)
				continue;
			if (scanptr == toptr) {
				*cursymno = litwalk->lit_gensymno;
				break;
			}
		    }
		}
	}
	if (!*cursymno) {
		litptr->lit_str = savestr(litbuffer, toptr-litbuffer, STR_CORE);
		litptr->lit_type = axval;
		litptr->lit_srcline = lineno;
		litptr->lit_gensymno = *cursymno = lgensym[LITSYMNO]++;  
	   if (++litptr >= &litpool[NLIT]) {
		if (!litmsgsw++)
			yyerror("Too many literals for one .ltorg");
		litptr--;
	   }
	}
	return(val);
}

int	processlit(stp)
struct	symtab	*stp;
{
	inttoktype	val; 
	ptrall		toptr;
	ptrall		savetokptr;
	ptrall		savetokub;
	struct	litdesc	*endptr;
	struct	symtab	*np;
	struct	strdesc	*stringp;
	struct 	exp	*locxp;
	struct	litdesc	*litsort[NLIT];
	int		savelineno;
	int 		i,j,topi;
	int		toconv;

	if (litptr == litpool) { 
		/* scan has allocated a symbol: */
		if (passno == 1) {
			stp->s_tag = IGNOREBOUND;
			nforgotten++;
		}
		return(1);  
	}
	endptr = litptr;

	/* Sort pool by lit-type, longest first */
	for (i=0, j=0; toklist[i]; i++) {
		for ( litptr = litpool; litptr<endptr; litptr++) {
			if (litptr->lit_type == toklist[i]) 
				litsort[j++] = litptr;
		}
	}
	topi = j;

	/* Do a .align for the first literal */
	if (ltorg_noalign) {
		if (passno == 1) {
			stp->s_tag = IGNOREBOUND;
			nforgotten++;
		}
	} else {
	xp = explist;
	litptr = litsort[0];
	switch (litptr->lit_type) {
	   case IHFLOAT:
	   case IDFLOAT:
	   case IDLONG:
		j=3;
		break;
	   case IFFLOAT:
	   case ILONG:
	   case IINT:
		j=2;
		break;
	   case ISHORT:		
		j=1;
		break;
	   default:
		j=0;
	}
	xp->e_xvalue = j;
	xp->e_xtype = XABS;
	jalign(xp, stp);
	}

	/* Assign values to gened labels and process the literals */
	for ( i=0; i<topi; i++ ) {
		xp = explist;  	/* reset global pointer */
		litptr = litsort[i];
		if (passno == 1) {
			(void)sprintf(yytext, "L%d\001%d", LITSYMNO, litptr->lit_gensymno);
			yylval = (int)*lookup(0);
			np = (struct symtab *)yylval;
			np->s_type &= ~(XTYPE|XFORW);
			np->s_type |= dotp->e_xtype;
			np->s_value = dotp->e_xvalue;
			np->s_index = dotp-usedot;
			nlabels++;
			np->s_tag = LABELID;
		}
		toptr = (litptr->lit_str)->sd_string ;
		/* fool the lex routine */
		savetokptr = tokptr;
		savetokub = tokub;
		savelineno = lineno;
		tokptr =  toptr;
		tokub = tokptr + (litptr->lit_str)->sd_strlen;
		lineno = litptr->lit_srcline;
		shift;
		switch( litptr->lit_type ) {
		   case IBYTE:
			curlen = 8;
			goto plit;
		   case ISHORT:		/* TOKS */
			curlen = 16;
			goto plit;
		   case IINT:
			curlen = 32;
			goto plit;
		   case ILONG:
			curlen = 32;
	plit:
			val = filexpr(locxp, val);
			xp = explist;  	/* reset global pointer */
			flushfield(curlen);
			break;
		   case IHFLOAT:  toconv = TYPH; goto pbign;
		   case IDFLOAT:  toconv = TYPD; goto pbign;
		   case IFFLOAT:  toconv = TYPF; goto pbign;
		   case IDLONG:   toconv = TYPU;
	pbign:
			if ((val != BIGNUM) && (val != INT)){
				yyerror("Literal value not a number");
			}
			dotp->e_xvalue += ty_nbyte[toconv];
			if (passno == 2){
				bignumwrite(
					((struct exp *)yylval)->e_number,
					toconv);
			}
			xp = explist;  	/* reset global pointer */
			break;
		   case IASCII:
		   case IASCIZ:
			stringp = (struct strdesc *)yylval;
			val = genstr(stringp,litptr->lit_type);
			break;
		   default:
			panic("Literal type not recognized");
		}
		tokptr = savetokptr;
		tokub = savetokub;
		lineno = savelineno;

	;
	}
	litptr = litpool;
	if (litmsgsw) 
		yyerror("There were %d excess literals",litmsgsw);
	litmsgsw = 0;
	return(1);

}
inttoktype	genstr(stringp,auxval)
struct	strdesc	*stringp;
inttoktype	auxval;
{
	int		mystrlen;
		/*
		 *	utilize the string scanner cheat;
		 *	the scanner appended a null byte on the string,
		 *	but didn't charge it to sd_strlen
		 */
		mystrlen = stringp->sd_strlen;
		mystrlen += (auxval == IASCIZ) ? 1 : 0;
		if (passno == 2){
			if (stringp->sd_place & STR_CORE){
				outs(stringp->sd_string, mystrlen);
			} else {
				int	i, nread;
				fseek(strfile, stringp->sd_stroff, 0);
				for (i = 0; i < mystrlen;/*VOID*/){
					nread = fread(yytext, 1,
						min(mystrlen - i,
						  sizeof(yytext)), strfile);
					outs(yytext, nread);
					i += nread;
				}
			}
		} else {
			dotp->e_xvalue += mystrlen;
		}
		return(1);

}
/*
 *	Process a register declaration of the form
 *	% <expr>
 *
 *	Note:
 *		The scanner has already processed funny registers of the form
 *	%dd[+-]*, where dd is a decimal number in the range 00 to 15 (optional
 *	preceding zero digit).  If there was any space between the % and
 *	the digit, the scanner wouldn't have recognized it, so we
 *	hack it out here.
 */
inttoktype funnyreg(val, regnoback)	/*what the read head will sit on*/
	inttoktype	val;		/*what the read head is sitting on*/
	int	*regnoback;		/*call by return*/
{
	reg	struct	exp *locxp;
		struct	exp *loc1xp;
		struct	exp **ptrloc1xp = & loc1xp;

	expr(locxp, val);	/*and leave the current read head with value*/
	if ( (passno == 2) &&
	    (   (locxp->e_xtype & XTYPE) != XABS
	     || (locxp->e_xvalue < 0)
	     || (locxp->e_xvalue >= 16)
	    )
	  ){
		yyerror("Illegal register");
		return(0);
	}
	*regnoback = locxp->e_xvalue;
	return(val);
} 
/* see above for comments */  /* SFZ */
inttoktype getlength(val, regnoback)
	inttoktype	val;
	int	*regnoback;
{
	reg	struct	exp *locxp;
		struct	exp *loc1xp;
		struct	exp **ptrloc1xp = & loc1xp;
	expr(locxp, val);
	if ( (passno == 2) &&
		(   (locxp->e_xtype & XTYPE) != XABS
		 || (locxp->e_xvalue < 0)
		 || (locxp->e_xvalue > 256 )
		)
	   ){
		yyerror("Illegal length expression");
		return(0);
	}
	*regnoback = locxp->e_xvalue;
	return(val);
}
/*
 *	Shift over error
 */
shiftoerror(token)
	int	token;
{
	char	*tok_to_name();
	yyerror("%s expected", tok_to_name(token));
}

/*VARARGS1*/
yyerror(s, a1, a2,a3,a4,a5)
	char	*s;
{

#define	sink stdout

	if (anyerrs == 0 && anywarnings == 0 && ! silent) 
		fprintf(sink, "Assembler:\n");
	anyerrs++;
	if (silent)
		return;
	fprintf(sink, "\"%s\", line %d: ", dotsname, lineno);
	fprintf(sink, s, a1, a2,a3,a4,a5);
	fprintf(sink, "\n");
#undef sink
}

/*VARARGS1*/
yywarning(s, a1, a2,a3,a4,a5)
	char	*s;
{
#define	sink stdout
	if (anyerrs == 0 && anywarnings == 0 && ! silent) 
		fprintf(sink, "Assembler:\n");
	anywarnings++;
	if (silent)
		return;
	fprintf(sink, "\"%s\", line %d: WARNING: ", dotsname, lineno);
	fprintf(sink, s, a1, a2,a3,a4,a5);
	fprintf(sink, "\n");
#undef sink
}

#ifdef DEBUG
printstab(stpt, i)
reg struct symtab *stpt;
int i;
{
	printf("file%1d symtab %08x: tag %02x ptype %02x jx %02x index %04x "
	    "dest %08x\n"
	"\tn_t %02x n_o %02x n_d %04x n_v %08x %s\n\n",
	i, stpt, stpt->s_tag, stpt->s_ptype, stpt->s_jxoveralign, stpt->s_index,
	    stpt->s_dest,
	stpt->s_nm.n_type, stpt->s_nm.n_other, stpt->s_nm.n_desc,
		stpt->s_nm.n_value, FETCHNAME(stpt));
}
#endif
