This takes literal integers, not expressions, because each machine defines its own valu_t for expressions, but valu_t can be too narrow for an 8-byte integer, and I don't want to change all the machines to use a wider valu_t. Instead, change how the assembler parses literal integers. Remove the NUMBER token and add a NUMBER8 token for an int64_t. The new .data8 pseudo emits all 8 bytes of the int64_t; expressions narrow the int64_t to a valu_t. Don't add any checks for integer overflow; expressions and .data* pseudos continue to ignore overflow when a number is too wide. This commit requires int64_t and uint64_t in the C compiler to build the assembler. The ACK's own C compiler doesn't have these. For the assembler's temporary file, add NUMBER4 to store 4-byte integers. NUMBER4 acts like NUMBER[0-3] and only stores a non-negative integer. Each negative integer now takes 8 bytes (up from 4) in the temporary file. Move the `\fI` and `\fP` in the uni_ass(6) manual, so the square brackets in `thing [, thing]*` are not italic. This looks nicer in my terminal, where italic text is underlined.
		
			
				
	
	
		
			478 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			478 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* $Id$ */
 | |
| /*
 | |
|  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | |
|  * See the copyright notice in the ACK home directory, in the file "Copyright".
 | |
|  */
 | |
| /* @(#)comm7.c	1.10 */
 | |
| /*
 | |
|  * miscellaneous
 | |
|  */
 | |
| 
 | |
| #include <errno.h>
 | |
| #include "comm0.h"
 | |
| #include "comm1.h"
 | |
| #include "y.tab.h"
 | |
| #include <stdarg.h>
 | |
| #include "object.h"
 | |
| 
 | |
| valu_t load(const item_t* ip)
 | |
| {
 | |
| #ifdef ASLD
 | |
| 	int typ;
 | |
| 
 | |
| 	typ = ip->i_type & S_TYP;
 | |
| 	if ((typ -= S_MIN) < 0) /* S_UND or S_ABS */
 | |
| 		return (ip->i_valu);
 | |
| 	return (ip->i_valu + sect[typ].s_base);
 | |
| #else
 | |
| 	if ((ip->i_type & S_TYP) == S_UND || (ip->i_type & S_COM))
 | |
| 	{
 | |
| 		if (pass == PASS_3)
 | |
| 		{
 | |
| 			if (relonami != 0)
 | |
| 				serror("relocation error (relonami=%d, type=%08x)", relonami, ip->i_type);
 | |
| 			relonami = ip->i_valu + 1;
 | |
| 		}
 | |
| 		return (0);
 | |
| 	}
 | |
| 	return (ip->i_valu);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| int store(item_t* ip, valu_t val)
 | |
| {
 | |
| #ifdef ASLD
 | |
| 	int typ;
 | |
| 
 | |
| 	typ = ip->i_type & S_TYP;
 | |
| 	if ((typ -= S_MIN) >= 0)
 | |
| 		val -= sect[typ].s_base;
 | |
| #else
 | |
| 	if ((ip->i_type & S_TYP) == S_UND)
 | |
| 		return (0);
 | |
| #endif
 | |
| 	assert(pass != PASS_3 || (ip->i_type & S_VAR) || ip->i_valu == val);
 | |
| 	ip->i_valu = val;
 | |
| 	return (1);
 | |
| }
 | |
| 
 | |
| char* remember(char* s)
 | |
| {
 | |
| 	char* p;
 | |
| 	int n;
 | |
| 	static int nleft = 0;
 | |
| 	static char* next;
 | |
| 
 | |
| 	p = s;
 | |
| 	n = 0;
 | |
| 	do
 | |
| 		n++;
 | |
| 	while (*p++);
 | |
| 	if ((nleft -= n) < 0)
 | |
| 	{
 | |
| 		next = malloc(MEMINCR);
 | |
| 		if (next == 0)
 | |
| 			fatal("out of memory");
 | |
| 		nleft = (MEMINCR / sizeof(char)) - n;
 | |
| 		assert(nleft >= 0);
 | |
| 	}
 | |
| 	p = next;
 | |
| 	while ((*p++ = *s++))
 | |
| 		;
 | |
| 	s = next;
 | |
| 	next = p;
 | |
| 	return (s);
 | |
| }
 | |
| 
 | |
| int combine(int typ1, int typ2, int op)
 | |
| {
 | |
| 	switch (op)
 | |
| 	{
 | |
| 		case '+':
 | |
| 			if (typ1 == S_ABS)
 | |
| 				return (typ2);
 | |
| 			if (typ2 == S_ABS)
 | |
| 				return (typ1);
 | |
| 			break;
 | |
| 		case '-':
 | |
| 			if (typ2 == S_ABS)
 | |
| 				return (typ1);
 | |
| 			if ((typ1 & ~S_DOT) == (typ2 & ~S_DOT) && typ1 != S_UND)
 | |
| 				return (S_ABS | S_VAR);
 | |
| 			break;
 | |
| 		case '>':
 | |
| 			if (typ1 == S_ABS && typ2 == S_ABS)
 | |
| 				return (S_ABS);
 | |
| 			if (((typ1 & ~S_DOT) == (typ2 & ~S_DOT) && typ1 != S_UND) || (typ1 == S_ABS)
 | |
| 			    || (typ2 == S_ABS))
 | |
| 				return (S_ABS | S_VAR);
 | |
| 			break;
 | |
| 		default:
 | |
| 			if (typ1 == S_ABS && typ2 == S_ABS)
 | |
| 				return (S_ABS);
 | |
| 			break;
 | |
| 	}
 | |
| 	if (pass != PASS_1)
 | |
| 		serror("illegal operator");
 | |
| 	return (S_UND);
 | |
| }
 | |
| 
 | |
| #ifdef LISTING
 | |
| int printx(int ndig, valu_t val)
 | |
| {
 | |
| 	static char buf[8];
 | |
| 	char* p;
 | |
| 	int c, n;
 | |
| 
 | |
| 	p = buf;
 | |
| 	n = ndig;
 | |
| 	do
 | |
| 	{
 | |
| 		*p++ = (int)val & 017;
 | |
| 		val >>= 4;
 | |
| 	} while (--n);
 | |
| 	do
 | |
| 	{
 | |
| 		c = "0123456789ABCDEF"[(unsigned char)*--p];
 | |
| 		putchar(c);
 | |
| 	} while (p > buf);
 | |
| 	return (ndig);
 | |
| }
 | |
| 
 | |
| void listline(int textline)
 | |
| {
 | |
| 	int c;
 | |
| 
 | |
| 	if ((listflag & 4) && (c = getc(listfile)) != '\n' && textline)
 | |
| 	{
 | |
| 		if (listcolm >= 24)
 | |
| 			printf(" \\\n\t\t\t");
 | |
| 		else
 | |
| 			do
 | |
| 			{
 | |
| 				putchar('\t');
 | |
| 				listcolm += 8;
 | |
| 			} while (listcolm < 24);
 | |
| 		do
 | |
| 		{
 | |
| 			assert(c != EOF);
 | |
| 			putchar(c);
 | |
| 		} while ((c = getc(listfile)) != '\n');
 | |
| 	}
 | |
| 	if (listflag & 7)
 | |
| 	{
 | |
| 		putchar('\n');
 | |
| 		fflush(stdout);
 | |
| 	}
 | |
| 	listeoln = 1;
 | |
| 	listcolm = 0;
 | |
| 	listflag = listtemp;
 | |
| }
 | |
| #endif /* LISTING */
 | |
| 
 | |
| /* ---------- code optimization ---------- */
 | |
| 
 | |
| #ifdef THREE_PASS
 | |
| #define PBITTABSZ 128
 | |
| static char* pbittab[PBITTABSZ];
 | |
| 
 | |
| int small(int fitsmall, int gain)
 | |
| {
 | |
| 	int bit;
 | |
| 	char* p;
 | |
| 
 | |
| 	if (DOTSCT == NULL)
 | |
| 		nosect();
 | |
| 	if (bflag)
 | |
| 		return (0);
 | |
| 	if (nbits == BITCHUNK)
 | |
| 	{
 | |
| 		bitindex++;
 | |
| 		nbits = 0;
 | |
| 		if (bitindex == PBITTABSZ)
 | |
| 		{
 | |
| 			static int w_given;
 | |
| 			if (pass == PASS_1 && !w_given)
 | |
| 			{
 | |
| 				w_given = 1;
 | |
| 				warning("bit table overflow");
 | |
| 			}
 | |
| 			return (0);
 | |
| 		}
 | |
| 		if (pbittab[bitindex] == 0 && pass == PASS_1)
 | |
| 		{
 | |
| 			if ((pbittab[bitindex] = calloc(MEMINCR, 1)) == 0)
 | |
| 			{
 | |
| 				static int w2_given;
 | |
| 
 | |
| 				if (!w2_given)
 | |
| 				{
 | |
| 					w2_given = 1;
 | |
| 					warning("out of space for bit table");
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		if (pbittab[bitindex] == 0)
 | |
| 			return (0);
 | |
| 	}
 | |
| 	bit = 1 << (nbits & 7);
 | |
| 	p = pbittab[bitindex] + (nbits >> 3);
 | |
| 	nbits++;
 | |
| 	switch (pass)
 | |
| 	{
 | |
| 		case PASS_1:
 | |
| 			return (0);
 | |
| 		case PASS_2:
 | |
| 			if (fitsmall)
 | |
| 			{
 | |
| 				DOTGAIN += gain;
 | |
| 				*p |= bit;
 | |
| 			}
 | |
| 			return (fitsmall);
 | |
| 		case PASS_3:
 | |
| 			assert(fitsmall || (*p & bit) == 0);
 | |
| 			return (*p & bit);
 | |
| 		default:
 | |
| 			assert(0);
 | |
| 	}
 | |
| 	/*NOTREACHED*/
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /* ---------- output ---------- */
 | |
| 
 | |
| void emit1(int arg)
 | |
| {
 | |
| 	static int olddottyp = -1;
 | |
| #ifdef LISTING
 | |
| 	if (listeoln)
 | |
| 	{
 | |
| 		if (listflag & 1)
 | |
| 		{
 | |
| 			listcolm += printx(VALWIDTH, (valu_t)DOTVAL);
 | |
| 			listcolm++;
 | |
| 			putchar(' ');
 | |
| 		}
 | |
| 		listeoln = 0;
 | |
| 	}
 | |
| 	if (listflag & 2)
 | |
| 		listcolm += printx(2, (valu_t)arg);
 | |
| #endif
 | |
| 	switch (pass)
 | |
| 	{
 | |
| 		case PASS_1:
 | |
| 			if (DOTSCT == NULL)
 | |
| 				nosect();
 | |
| 			/* no break */
 | |
| 		case PASS_2:
 | |
| 			DOTSCT->s_zero = 0;
 | |
| 			break;
 | |
| 		case PASS_3:
 | |
| 			if (DOTTYP != olddottyp)
 | |
| 			{
 | |
| 				wr_outsect(DOTTYP - S_MIN);
 | |
| 				olddottyp = DOTTYP;
 | |
| 			}
 | |
| 			while (DOTSCT->s_zero)
 | |
| 			{
 | |
| 				wr_putc(0);
 | |
| 				DOTSCT->s_zero--;
 | |
| 			}
 | |
| 			wr_putc(arg);
 | |
| 			break;
 | |
| 	}
 | |
| 	DOTVAL++;
 | |
| }
 | |
| 
 | |
| void emit2(int arg)
 | |
| {
 | |
| #ifdef BYTES_REVERSED
 | |
| 	emit1((arg >> 8));
 | |
| 	emit1(arg);
 | |
| #else
 | |
| 	emit1(arg);
 | |
| 	emit1((arg >> 8));
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void emit4(long arg)
 | |
| {
 | |
| #ifdef WORDS_REVERSED
 | |
| 	emit2((int)(arg >> 16));
 | |
| 	emit2((int)(arg));
 | |
| #else
 | |
| 	emit2((int)(arg));
 | |
| 	emit2((int)(arg >> 16));
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void emitx(valu_t val, int n)
 | |
| {
 | |
| 	switch (n)
 | |
| 	{
 | |
| 		case RELO1:
 | |
| 			emit1((int)val);
 | |
| 			break;
 | |
| 		case RELO2:
 | |
| #ifdef BYTES_REVERSED
 | |
| 			emit1(((int)val >> 8));
 | |
| 			emit1((int)val);
 | |
| #else
 | |
| 			emit1((int)val);
 | |
| 			emit1(((int)val >> 8));
 | |
| #endif
 | |
| 			break;
 | |
| 		case RELO4:
 | |
| #ifdef WORDS_REVERSED
 | |
| 			emit2((int)(val >> 16));
 | |
| 			emit2((int)(val));
 | |
| #else
 | |
| 			emit2((int)(val));
 | |
| 			emit2((int)(val >> 16));
 | |
| #endif
 | |
| 			break;
 | |
| 		default:
 | |
| 			assert(0);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void emit8(int64_t arg)
 | |
| {
 | |
| #ifdef WORDS_REVERSED
 | |
| 	emit2((int)(arg >> 48));
 | |
| 	emit2((int)(arg >> 32));
 | |
| 	emit2((int)(arg >> 16));
 | |
| 	emit2((int)(arg));
 | |
| #else
 | |
| 	emit2((int)(arg));
 | |
| 	emit2((int)(arg >> 16));
 | |
| 	emit2((int)(arg >> 32));
 | |
| 	emit2((int)(arg >> 48));
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void emitstr(int zero)
 | |
| {
 | |
| 	int i;
 | |
| 	char* p;
 | |
| 
 | |
| 	p = stringbuf;
 | |
| 	i = stringlen;
 | |
| 	while (--i >= 0)
 | |
| 		emit1(*p++);
 | |
| 	if (zero)
 | |
| 		emit1(0);
 | |
| }
 | |
| 
 | |
| #define CODE_EXPANDER
 | |
| 
 | |
| #if !defined IEEEFLOAT && !defined PDPFLOAT
 | |
| 	#define IEEEFLOAT
 | |
| #endif
 | |
| 
 | |
| #if defined WORDS_REVERSED
 | |
| 	#define FL_MSL_AT_LOW_ADDRESS 1
 | |
| 	#define FL_MSW_AT_LOW_ADDRESS 1
 | |
| #else
 | |
| 	#define FL_MSL_AT_LOW_ADDRESS 0
 | |
| 	#define FL_MSW_AT_LOW_ADDRESS 0
 | |
| #endif
 | |
| 
 | |
| #if defined BYTES_REVERSED
 | |
| 	#define FL_MSB_AT_LOW_ADDRESS 1
 | |
| #else
 | |
| 	#define FL_MSB_AT_LOW_ADDRESS 0
 | |
| #endif
 | |
| 
 | |
| #define gen1 emit1
 | |
| #include "con_float"
 | |
| 
 | |
| void emitf(int size, int negative)
 | |
| {
 | |
| 	char buffer[40];
 | |
| 
 | |
| 	if (stringlen > sizeof(buffer)-1)
 | |
| 		fatal("floating point constant too long");
 | |
| 
 | |
| 	if (negative)
 | |
| 	{
 | |
| 		buffer[0] = '-';
 | |
| 		strcpy(buffer+1, stringbuf);
 | |
| 		con_float(buffer, size);
 | |
| 	}
 | |
| 	else
 | |
| 		con_float(stringbuf, size);
 | |
| }
 | |
| 
 | |
| /* ---------- Error handling ---------- */
 | |
| 
 | |
| /* ARGSUSED */
 | |
| void yyerror(const char* message)
 | |
| {
 | |
| } /* we will do our own error printing */
 | |
| 
 | |
| void nosect(void)
 | |
| {
 | |
| 	fatal("no sections");
 | |
| }
 | |
| 
 | |
| void wr_fatal(void)
 | |
| {
 | |
| 	fatal("write error");
 | |
| }
 | |
| 
 | |
| static void diag(const char* tail, const char* s, va_list ap)
 | |
| {
 | |
| 	fflush(stdout);
 | |
| 	if (modulename)
 | |
| 		fprintf(stderr, "\"%s\", line %ld: ", modulename, lineno);
 | |
| 	else
 | |
| 		fprintf(stderr, "%s: ", progname);
 | |
| 	vfprintf(stderr, s, ap);
 | |
| 	fprintf(stderr, "%s", tail);
 | |
| }
 | |
| 
 | |
| /* VARARGS1 */
 | |
| void fatal(const char* s, ...)
 | |
| {
 | |
| 	va_list ap;
 | |
| 	va_start(ap, s);
 | |
| 
 | |
| 	nerrors++;
 | |
| 	diag(" (fatal)\n", s, ap);
 | |
| 	stop();
 | |
| 
 | |
| 	va_end(ap);
 | |
| }
 | |
| 
 | |
| /* VARARGS1 */
 | |
| void serror(const char* s, ...)
 | |
| {
 | |
| 	va_list ap;
 | |
| 	va_start(ap, s);
 | |
| 
 | |
| 	nerrors++;
 | |
| 	diag("\n", s, ap);
 | |
| 	stop();
 | |
| 
 | |
| 	va_end(ap);
 | |
| }
 | |
| 
 | |
| /* VARARGS1 */
 | |
| void warning(const char* s, ...)
 | |
| {
 | |
| 	va_list ap;
 | |
| 	va_start(ap, s);
 | |
| 
 | |
| 	nerrors++;
 | |
| 	diag(" (warning)\n", s, ap);
 | |
| 	stop();
 | |
| 
 | |
| 	va_end(ap);
 | |
| }
 | |
| 
 | |
| void nofit(void)
 | |
| {
 | |
| 	if (pass == PASS_3)
 | |
| 		warning("too big");
 | |
| }
 |