File:  [MW Coherent from dump] / coherent / b / bin / as / cmd.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:36 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * 80386 assembler commands.
 * ytype	function	args
 * CMD		docmd		parms
 * DCMD		docmd		names
 * ECMD		ecmd		name, expr
 * NCMD		docmd
 * ICMD		ncmd		expr
 * DATA		dcmd		data list
 */
#include <asm.h>
#include <symtab.h>

static unsigned short ct;

/*
 * Check parm count. Print msg if one required.
 */
static
ckCount(no)
{
	if(no == ct)
		return(0);
	yyerror("Found %d parms expected %d", ct, no); /**/
	return(1);
}

/*
 * Set up while
 */
static void
setUpWhile()
{
	register macro *tmp;
	macline *newl;

	newl = (macline *)alloc((unsigned)(sizeof(*newl) + strlen(lastL)));
	strcpy(newl->line, lastL);

	newLevel(INWDEF);

	tmp = new(macro);
	inMacDef = tmp;
	lastDef = inMacDef->first = newl;
}

/*
 * Do commands with name, expr.
 */
ecmd(label, op, p, item)
opc *op;
parm *label, *p;
data *item;
{
	long n = 0;

	labelIgnored(label);

	if (NULL != item) {
		switch (item->type) {
		case 'l':
			n = item->d.l;
			break;
		case 'y':
			if (op->kind == S_SET)
				break;
		default:
			yyerror("Invalid operand type"); /**/
			return;
		}
	}

	switch (op->kind) {
	case S_SEGMENT:	/* change segments */
		segment(op, p, n);
		break;

	case S_COMM:	/* allocate data in a segment */
		comm(op, p, n);
		break;

	case S_SET:
		if(NULL == p)
			yyerror("Name required");
			/* The format of \fBset\fR is
			 * \fB.set name, value\fR */
		else if (!strcmp(p->str, "."))
			doOrg(NULL, item);
		else if (item->type == 'l')
			symLookUp(p->str, S_XSYM, n, 0);
		else
			symLookUp(p->str, S_LOCAL, 
				  item->d.y->loc, item->d.y->sg);
		break;

	}
	return 0;
}

/*
 * Do commands with string parms.
 */
docmd(label, op, p)
opc *op;
parm *p, *label;
{
	ct = countList(p);

	switch(op->kind) {
	/*
	 * This may be name value in some formats to avoid syntax error
	 * we bring it in as ytype CMD. We don't do dubug for those formats.
	 */
	case S_DEF:
		labelIgnored(label);
		coffDef(p);
		break;

	case S_TAG:
		labelIgnored(label);
		coffTag(p);
		break;

	case S_FILE:
		labelIgnored(label);
		coffFile(p);		
		break;

	case S_ENDF:
		coffEndef();
		break;

	case S_INCLUDE:
		if(ckCount(1))
			return(1);
		fileOpen(p->str);
		break;

	case S_MACRO:
		if(NULL == label) {
			yyerror("Macro definition must have a label"); /**/
			defMac("***", p, MACTYPE);
		}
		else
			defMac(label->str, p, MACTYPE);
		break;

	case S_EQUS:
		defCt++;
		if(NULL == label) {
			yyerror(".define must have a label"); /**/
			defMac("***", p, MACSTR);
		}
		else
			defMac(label->str, p, MACSTR);
		break;

	case S_UNDEFINE:	/* kill macro or define */
		for(; NULL != p; p = p->next) {
			opDelete(p->str);
			macDelete(p->str, MACSTR);
			macDelete(p->str, MACTYPE);
		}
		break;

	case S_MEXIT: {
		macctl *m;

		if(NULL == trueMac) {
			yyerror(".mexit not in macro"); /**/
			break;
		}
		m = macExp;	/* break out of any whiles */
		do {
			m->curr = NULL;	/* no more lines */
		} while(m->type != MACTYPE);
		break;
		}

	case S_ENDM:
		yyerror("Unexpected .endm ignored"); /**/
		break;

	case S_MAC:
		{
		register macctl *tmp;

		umList(p);	/* dont trash parms at end of line */
		tmp = new(macctl);
		tmp->curr = macFound->first;
		tmp->parms = p;
		tmp->names = macFound->names;
		tmp->expno = ++macNo;	/* unique non zero macro expansion ct */
		tmp->type  = MACTYPE;
		tmp->prev = macExp;
		trueMac = macExp = tmp;
		if(NULL != label)
			symLookUp(label->str, S_LOCAL, dot.loc, dot.sg);
		}
		break;

	case S_ERRATA:
		nswitch = op->code;
		break;

	case S_WARNINGS:
		wswitch = op->code;
		break;

	case S_OPORDER:
		fswitch = op->code;
		break;

	case S_BORDER:
		bswitch = op->code;
		break;

	case S_LMODE:
		longMode = op->code;
		break;

	case S_LIST:
		if (pass == 2)
			lswitch = op->code & lswitchX;
		break;

	case S_ALIGNON:
		alignon = op->code;
		break;

	case S_EJECT:
		if (lswitch && (2 == pass) && pswitch)
			while (linect) {
				sTitle();
				putchar('\n');
			}
		break;

	case S_PAGE:
		pswitch = op->code;
		break;

	case S_MLIST:
		if (pass == 2) {
			if(!strcmp("on", p->str))
				mlistsw = 1;
			else if(!strcmp("off", p->str))
				mlistsw = 0;
			else
				yyerror(
				"Invalid .mlist option must be on or off");
				/**/
		}
		break;

	case S_ERROR:
		if (op->code)
			yyerror("%s", p->str); /* NODOC */
		else
			yywarn("%s", p->str); /* NODOC */
		break;

	case S_CMNT:	/* ident and version */
		if (2 == pass)
			cmnt(op, p);
		break;

	case S_SECTION:
		if (!ct) {
			yyerror(".section must have name");	/**/
			return;
		}
		section(p->str);
		break;

	case S_TITLE: {
		static short i = 0;

		/* Ignore all but first title on pass 0 */
		if((2 == pass) || !i) {
			pswitch = i = 1;
			free(title);
			title = scpy(p->str, 0);
		}
		break;
	}

	case S_ENDW:
		if((NULL != macExp) && (WHILETYPE == macExp->type))
			macExp->curr = macExp->first;
		else
			yyerror("Unexpected .endw"); /**/
		break;

	case S_ENDI:
		switch(logic->type) {
		case INIF1:
			freeLevel();
			break;
		case NORMAL:
			yyerror("Unexpected .endi statement"); /**/
			break;
		default:
			fatal(".endi detected logic type %d", logic->type);
			/* TECH */
		}
		break;

	case S_ELSE:
		switch(logic->type) {
		case INIF1:
			logic->type = INIF0;
			break;
		case NORMAL:
			yyerror("Unexpected .else statement"); /**/
			break;
		default:
			fatal(".else detected logic type %d", logic->type);
			/* TECH */
		}
		break;

	default:
		kindErr((unsigned short)op->kind);
	}

	return(0);
}

/*
 * Commands with a numexp as parm.
 */
ncmd(label, op, item)
parm *label;
opc *op;
data *item;
{
	long n;
	data oper;

	switch (item->type) {
	case 'l':
		n = item->d.l;
		break;
	case 'y':
		if ((op->kind == S_EQU) || (op->kind == S_VAL))
			break;
	default:
		yyerror("Invalid operand type"); /* NODOC */
		return;
	}

	switch(op->kind) {
	case S_TYPE:
		coffType(n);
		break;		
	case S_VAL:
		coffVal(item);
		break;
	case S_LN:
		coffLn(n);
		break;
	case S_LINE:
		coffLine(n);
		break;
	case S_SIZE:
		coffSize(n);
		break;
	case S_SCL:
		coffScl(n);
		break;
	case S_ZERO:
		buildlab(label);
		while(n--)
			outab(0);
		break;

	case S_BLKB:
		buildlab(label);
		oper.d.l = dot.loc + n;
		oper.type = 'l';
		doOrg(NULL, &oper);
		return;
	case S_SHIFT:
		doShift((short)n);
		break;
	case S_EQU:
		if (NULL == label)
			yyerror("Label required"); /**/
		else if (!strcmp(label->str, "."))
			doOrg(NULL, item);
		else if (item->type == 'l')
			symLookUp(label->str, S_XSYM, n, 0);
		else {
			symLookUp(label->str, S_LOCAL, 
				  item->d.y->loc, item->d.y->sg);

			/* forward equate make sure there is an extra pass */
			if (!pass && (item->d.y->flag & S_UNDEF))
				xpass = 1;

			if (item->d.y->flag & (S_COMMON|S_EXREF))
			  yyerror("Cannot equate to externally defined symbol");
			  /* This would mean creating another symbol.
			   * Try using \fB.define\fR. */
		}
		return;
	case S_PLEN:	/* set page length */
		nlpp = n - 10;
		break;
	case S_LLEN:	/* set line length */
		lineSize = n;
		break;
	case S_IF:
		newLevel(n ? INIF1 : INIF0);
		break;
	case S_WHILE:
		if((NULL != macExp) &&
		   (WHILETYPE == macExp->type) &&
		   (macExp->curr == macExp->first->next)) {
			if(!n) {
				freeList((parm *)macExp->first);
				macExp->curr = NULL;
			}
		}
		else
			setUpWhile();
		break;
	default:
		kindErr((unsigned short)op->kind);
	}

	labelIgnored(label);
}
/*
 * Make an expression for dataOut.
 */
expr *
makeExp(addr)
data *addr;
{
	static expr x;

	x.ref = addr->d.y;
	x.exp = x.ref->loc;
	if (x.ref->flag & (S_COMMON|S_EXREF))
		x.exp <<= 1;	/* double we will loose it back */
	return(&x);
}

/*
 * Data output for .byte .word .long .string .float .double
 */
static void
dataOut(op, oper)
opc *op;
data *oper;
{
	register char *str, c;
	union {
		long l[2];
		float f[2];
		double d;
	} u;

	if(op->code && (op->code != 5) && ('s' == oper->type)) {
		yyerror("String must be on .byte");
		/* For example:
		 * .DM
		 * 	.byte "This is how we place a string", 0
		 * .DE */
		return;
	}
	while(oper->count--) {	/* honor repeat count */
		switch(op->code) {	/* set by option */
		case 5:			/* .string */
			if ('s' != oper->type) {
				yyerror("Improper .string operand");
				return;
			}
			for(str = oper->d.s; c = *str++; )
				outab((unsigned short)c);
			outab(0);
			break;
		case 0:			/* .byte */
			switch(oper->type) {
			case 's':
				for(str = oper->d.s; c = *str++; )
					outab((unsigned short)c);
				break;
			case 'y':
				outrb(makeExp(oper), 0);
				break;
			case 'l':
				outab((unsigned)oper->d.l);
				break;
			case 'd':
				outab((unsigned)oper->d.d);
				break;
			}
			break;
		case 1: 	/* .word or .value */
			switch(oper->type) {
			case 'y':
				outrw(makeExp(oper), 0);
				break;
			case 'l':
				outaw((unsigned)oper->d.l);
				break;
			case 'd':
				outaw((unsigned)oper->d.d);
				break;
			}
			break;
		case 2:		/* .long */
			switch(oper->type) {
			case 'y':
				outrl(makeExp(oper), 0);
				break;
			case 'l':
				outal(oper->d.l);
				break;
			case 'd':
				outal((long)oper->d.d);
				break;
			}
			break;
		case 3:		/* .float */
			switch(oper->type) {
			case 'y':
				yyerror("Symbol may not be float");
				/* You may not convert a symbol to
				 * a floating-point value. */
				return;
			case 'l':
				u.f[0] = oper->d.l;
				break;
			case 'd':
				u.f[0] = oper->d.d;
			}
#if _DECVAX
			ieee_f(u.f, u.f);	/* DECVAX to IEEE */
#endif
			outal(u.l[0]);
			break;
		case 4:		/* .double */
			switch(oper->type) {
			case 'y':
				yyerror("Symbol may not be double");
				/* You may not convert a symbol to
				 * a floating-point value. */
				return;
			case 'l':
				u.d = oper->d.l;
				break;
			case 'd':
				u.d = oper->d.d;
			}
#if _DECVAX
			ieee_d(&u.d, &u.d);	/* DECVAX to IEEE */
#endif
			outal(u.l[0]);
			outal(u.l[1]);

			break;
		}
	}
}

/*
 * Output alignment bytes.
 */
static int
alignOut(seg, byte, n)
{
	int rv = 0;

	switch (seg) {
	case 0:	/* fill selected by user */
		while (dot.loc & n) {
			rv = 1;
			outab(byte);
		}
		break;
	case 1:	/* text */
		while (dot.loc & n) {
			rv = 1;
			outab(0x90);
		}
		break;
	case 2:	/* data */
		while (dot.loc & n) {
			rv = 1;
			outab(0);
		}
		break;
	}
	return rv;
}

/*
 * Commands with a list of data as parm.
 */
dcmd(label, op, oper)
parm *label;
opc *op;
data *oper;
{
	register sym *sp = NULL;
	register sym *y;
	long start, n;
	char b, s;

	switch (op->kind) {
	case S_ORG:
		return(doOrg(label, oper));

	case S_EVEN:	/* this is here to fall into .align */
		s = dot.sg;
		n = 1;
		goto even;

	case S_ALIGN:
		if (NULL == oper) {
			yyerror("Missing operand");
			/* \fB\&.align\fR must have 1 or 2 operands */
			return(1);
		}
		switch (oper->type) {
		case 'l':
			n = oper->d.l;
			break;
		default:
			yyerror("Invalid operand type"); /* NODOC */
			return(1);
		}
		if ((3 != (s = dot.sg)) && (NULL != (oper = oper->next))) {
			switch (oper->type) {
			case 'l':
				s = 0;
				b = oper->d.l;
				break;
			default:
				yyerror("Invalid operand type"); /* NODOC */
				return(1);
			}
		}

		if (!--n)
			return;
		if ((1 != n) && (3 != n)) {
			yyerror(".align must be 1, 2 or 4");
		/* \fB\&.align\fR must work after the link.
		 * These are the only values for which this can be true. */
			return(1);
		}

	even:	if (3 == dot.sg) {
			oper.d.l = (dot.loc + n) & ~n;
			oper.type = 'l';
			doOrg(NULL, &oper);
		}
		else
			alignOut(s, b, n);
		return(0);

	case S_DATA:
		/* If alignment on and data and not .string or .byte */
		if (!alignon)
			break;
		switch (op->code) {
		case 1:
			s = alignOut(dot.sg, 0, 1);
			break;
		case 2:
		case 3:
		case 4:
			s = alignOut(dot.sg, 0, 3);
		}
		if (s)	/* Alignment stuff went out */
			outLine("", ' ');
	}

	if(NULL != label) {
		switch (op->kind) {
		case S_DATA:
		case S_UDATA:
			sp = symLookUp(label->str, S_LOCAL,
				(start = dot.loc), dot.sg);
			break;
		default:
			labelIgnored(label);
		}
	}

	for(b = 0; NULL != oper; oper = oper->next) {
		switch (op->kind) {
		case S_DATA:
		case S_UDATA:
			dataOut(op, oper);
			continue;
		case S_DIM:
			if ('l' != oper->type) {
				yyerror("Invalid data type, must be number");
					 /**/
				continue;
			}
			coffDim(oper->d.l, b++);
			continue;
		case S_GLOBL:	/* .globl */
			if('y' != oper->type) {
				yyerror("Invalid data type, must be symbol");
					 /**/
				continue;
			}
			y = oper->d.y;
			if(!(y->flag & S_ASYM)) {
				yyerror("Illegal use of of predefined symbol %s.",
					(psym *)y->name); /**/
				continue;
			}
			if (NULL != strchr(y->name, ';')) {
				yyerror("Illegal use of local symbol"); /**/
				continue;
			}
			if (y->flag & S_UNDEF) {
				y->loc = 0;
				y->sg = 0;
				y->flag = S_EXREF;
			}
			else
				y->flag |= S_EXDEF;
			continue;
			default:
				kindErr((unsigned short)op->kind);
				return(1);
		}
	}

	if(NULL != sp) /* finish label building */
		sp->size = dot.loc - start;
	return(0);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.