shithub: riscv

ref: 57f8b3d1acf273a88568c49d0b83b6863485b9e0
dir: /sys/src/cmd/cc/lexbody/

View raw version
/*
 * common code for all the assemblers
 */

void
pragpack(void)
{
	while(getnsc() != '\n')
		;
}

void
pragvararg(void)
{
	while(getnsc() != '\n')
		;
}

void
pragfpround(void)
{
	while(getnsc() != '\n')
		;
}

void
pragprofile(void)
{
	while(getnsc() != '\n')
		;
}

void
pragincomplete(void)
{
	while(getnsc() != '\n')
		;
}

void
setinclude(char *p)
{
	int i;

	if(p == 0)
		return;
	for(i=1; i < ninclude; i++)
		if(strcmp(p, include[i]) == 0)
			return;

	if(ninclude >= nelem(include)) {
		yyerror("ninclude too small %d", nelem(include));
		exits("ninclude");
	}
	include[ninclude++] = p;
}

void
errorexit(void)
{

	if(outfile)
		remove(outfile);
	exits("error");
}

void
pushio(void)
{
	Io *i;

	i = iostack;
	if(i == I) {
		yyerror("botch in pushio");
		errorexit();
	}
	i->p = fi.p;
	i->c = fi.c;
}

void
newio(void)
{
	Io *i;
	static int pushdepth = 0;

	i = iofree;
	if(i == I) {
		pushdepth++;
		if(pushdepth > 1000) {
			yyerror("macro/io expansion too deep");
			errorexit();
		}
		i = alloc(sizeof(*i));
	} else
		iofree = i->link;
	i->c = 0;
	i->f = -1;
	ionext = i;
}

void
newfile(char *s, int f)
{
	Io *i;

	i = ionext;
	i->link = iostack;
	iostack = i;
	i->f = f;
	if(f < 0)
		i->f = open(s, 0);
	if(i->f < 0) {
		yyerror("%Ca: %r: %s", thechar, s);
		errorexit();
	}
	fi.c = 0;
	linehist(s, 0);
}

Sym*
slookup(char *s)
{
	strncpy(symb, s, NSYMB);
	if(symb[NSYMB-1] != '\0'){
		yyerror("symbol too long: %s", s);
		errorexit();
	}
	return lookup();
}

Sym*
lookup(void)
{
	Sym *s;
	ulong h;
	char *p;
	int c, n;

	h = 0;
	for(p=symb; *p;) {
		h = h * 3;
		h += *p++;
	}
	n = (p - symb) + 1;
	if((long)h < 0)
		h = ~h;
	h %= NHASH;
	c = symb[0];
	for(s = hash[h]; s != S; s = s->link) {
		if(s->name[0] != c)
			continue;
		if(strcmp(s->name, symb) == 0)
			return s;
	}
	s = alloc(sizeof(*s));
	s->name = alloc(n);
	memmove(s->name, symb, n);

	s->link = hash[h];
	hash[h] = s;
	syminit(s);

	return s;
}

long
yylex(void)
{
	int c, c1;
	char *cp;
	Sym *s;

	c = peekc;
	if(c != IGN) {
		peekc = IGN;
		goto l1;
	}
l0:
	c = GETC();

l1:
	if(c == EOF) {
		peekc = EOF;
		return -1;
	}
	if(isspace(c)) {
		if(c == '\n') {
			lineno++;
			return ';';
		}
		goto l0;
	}
	if(isalpha(c))
		goto talph;
	if(isdigit(c))
		goto tnum;
	switch(c)
	{
	case '\n':
		lineno++;
		return ';';

	case '#':
		domacro();
		goto l0;

	case '.':
		c = GETC();
		if(isalpha(c)) {
			cp = symb;
			*cp++ = '.';
			goto aloop;
		}
		if(isdigit(c)) {
			cp = symb;
			*cp++ = '.';
			goto casedot;
		}
		peekc = c;
		return '.';

	talph:
	case '_':
	case '@':
		cp = symb;

	aloop:
		if(cp >= &symb[NSYMB-1])
			goto toolong;
		*cp++ = c;
		c = GETC();
		if(isalpha(c) || isdigit(c) || c == '_' || c == '$')
			goto aloop;
		*cp = 0;
		peekc = c;
		s = lookup();
		if(s->macro) {
			newio();
			cp = ionext->b;
			if(macexpand(s, cp, sizeof(ionext->b)-1)){
				pushio();
				ionext->link = iostack;
				iostack = ionext;
				fi.p = cp;
				fi.c = strlen(cp);
				if(peekc != IGN) {
					cp[fi.c++] = peekc;
					cp[fi.c] = 0;
					peekc = IGN;
				}
				goto l0;
			} else {
				ionext->link = iofree;
				iofree = ionext;
			}
		}
		if(s->type == 0)
			s->type = LNAME;
		if(s->type == LNAME ||
		   s->type == LVAR ||
		   s->type == LLAB) {
			yylval.sym = s;
			return s->type;
		}
		yylval.lval = s->value;
		return s->type;

	tnum:
		cp = symb;
		if(c != '0')
			goto dc;
		*cp++ = c;
		c = GETC();
		c1 = 3;
		if(c == 'x' || c == 'X') {
			c1 = 4;
			c = GETC();
		} else
		if(c < '0' || c > '7')
			goto dc;
		yylval.lval = 0;
		for(;;) {
			if(c >= '0' && c <= '9') {
				if(c > '7' && c1 == 3)
					break;
				yylval.lval <<= c1;
				yylval.lval += c - '0';
				c = GETC();
				continue;
			}
			if(c1 == 3)
				break;
			if(c >= 'A' && c <= 'F')
				c += 'a' - 'A';
			if(c >= 'a' && c <= 'f') {
				yylval.lval <<= c1;
				yylval.lval += c - 'a' + 10;
				c = GETC();
				continue;
			}
			break;
		}
		goto ncu;

	dc:
		for(;;) {
			if(!isdigit(c))
				break;
			if(cp >= &symb[NSYMB-1])
				goto toolong;
			*cp++ = c;
			c = GETC();
		}
		if(c == '.')
			goto casedot;
		if(c == 'e' || c == 'E')
			goto casee;
		*cp = 0;
		if(sizeof(yylval.lval) == sizeof(vlong))
			yylval.lval = strtoull(symb, nil, 10);
		else
			yylval.lval = strtoul(symb, nil, 10);

	ncu:
		while(c == 'U' || c == 'u' || c == 'l' || c == 'L')
			c = GETC();
		peekc = c;
		return LCONST;

	casedot:
		for(;;) {
			if(cp >= &symb[NSYMB-1])
				goto toolong;
			*cp++ = c;
			c = GETC();
			if(!isdigit(c))
				break;
		}
		if(c == 'e' || c == 'E')
			goto casee;
		goto caseout;

	casee:
		if(cp >= &symb[NSYMB-1])
			goto toolong;
		*cp++ = 'e';
		c = GETC();
		if(c == '+' || c == '-') {
			if(cp >= &symb[NSYMB-1])
				goto toolong;
			*cp++ = c;
			c = GETC();
		}
		while(isdigit(c)) {
			if(cp >= &symb[NSYMB-1])
				goto toolong;
			*cp++ = c;
			c = GETC();
		}

	caseout:
		*cp = 0;
		peekc = c;
		if(FPCHIP) {
			yylval.dval = atof(symb);
			return LFCONST;
		}
		yyerror("assembler cannot interpret fp constants");
		yylval.lval = 1L;
		return LCONST;

	case '"':
		memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval));
		cp = yylval.sval;
		c1 = 0;
		for(;;) {
			c = escchar('"');
			if(c == EOF)
				break;
			if(c1 < sizeof(yylval.sval))
				*cp++ = c;
			c1++;
		}
		if(c1 > sizeof(yylval.sval))
			yyerror("string constant too long");
		return LSCONST;

	case '\'':
		c = escchar('\'');
		if(c == EOF)
			c = '\'';
		if(escchar('\'') != EOF)
			yyerror("missing '");
		yylval.lval = c;
		return LCONST;

	case '/':
		c1 = GETC();
		if(c1 == '/') {
			for(;;) {
				c = GETC();
				if(c == '\n')
					goto l1;
				if(c == EOF) {
					yyerror("eof in comment");
					errorexit();
				}
			}
		}
		if(c1 == '*') {
			for(;;) {
				c = GETC();
				while(c == '*') {
					c = GETC();
					if(c == '/')
						goto l0;
				}
				if(c == EOF) {
					yyerror("eof in comment");
					errorexit();
				}
				if(c == '\n')
					lineno++;
			}
		}
		break;

	default:
		return c;
	}
	peekc = c1;
	return c;
toolong:
	yyerror("token too long: %.*s...", utfnlen(symb, cp-symb), symb);
	errorexit();
	return -1;
}

int
getc(void)
{
	int c;

	c = peekc;
	if(c != IGN) {
		peekc = IGN;
		if(c == '\n')
			lineno++;
		return c;
	}
	c = GETC();
	if(c == '\n')
		lineno++;
	if(c == EOF) {
		yyerror("End of file");
		errorexit();
	}
	return c;
}

int
getnsc(void)
{
	int c;

	for(;;) {
		c = getc();
		if(!isspace(c) || c == '\n')
			return c;
	}
}

void
unget(int c)
{

	peekc = c;
	if(c == '\n')
		lineno--;
}

int
escchar(int e)
{
	int c, l;

loop:
	c = getc();
	if(c == '\n') {
		yyerror("newline in string");
		return EOF;
	}
	if(c != '\\') {
		if(c == e)
			return EOF;
		return c;
	}
	c = getc();
	if(c >= '0' && c <= '7') {
		l = c - '0';
		c = getc();
		if(c >= '0' && c <= '7') {
			l = l*8 + c-'0';
			c = getc();
			if(c >= '0' && c <= '7') {
				l = l*8 + c-'0';
				return l;
			}
		}
		peekc = c;
		return l;
	}
	switch(c)
	{
	case '\n':	goto loop;
	case 'n':	return '\n';
	case 't':	return '\t';
	case 'b':	return '\b';
	case 'r':	return '\r';
	case 'f':	return '\f';
	case 'a':	return 0x07;
	case 'v':	return 0x0b;
	case 'z':	return 0x00;
	}
	return c;
}

void
pinit(char *f)
{
	int i;
	Sym *s;

	lineno = 1;
	newio();
	newfile(f, -1);
	pc = 0;
	peekc = IGN;
	sym = 1;
	for(i=0; i<NSYM; i++) {
		h[i].type = 0;
		h[i].sym = S;
	}
	for(i=0; i<NHASH; i++)
		for(s = hash[i]; s != S; s = s->link)
			s->macro = 0;
}

int
filbuf(void)
{
	Io *i;

loop:
	i = iostack;
	if(i == I)
		return EOF;
	if(i->f < 0)
		goto pop;
	fi.c = read(i->f, i->b, BUFSIZ) - 1;
	if(fi.c < 0) {
		close(i->f);
		linehist(0, 0);
		goto pop;
	}
	fi.p = i->b + 1;
	return i->b[0];

pop:
	iostack = i->link;
	i->link = iofree;
	iofree = i;
	i = iostack;
	if(i == I)
		return EOF;
	fi.p = i->p;
	fi.c = i->c;
	if(--fi.c < 0)
		goto loop;
	return *fi.p++;
}

void
yyerror(char *a, ...)
{
	char buf[200];
	va_list arg;

	/*
	 * hack to intercept message from yaccpar
	 */
	if(strcmp(a, "syntax error") == 0) {
		yyerror("syntax error, last name: %s", symb);
		return;
	}
	prfile(lineno);
	va_start(arg, a);
	vseprint(buf, buf+sizeof(buf), a, arg);
	va_end(arg);
	print("%s\n", buf);
	nerrors++;
	if(nerrors > 10) {
		print("too many errors\n");
		errorexit();
	}
}

void
prfile(long l)
{
	int i, n;
	Hist a[HISTSZ], *h;
	long d;

	n = 0;
	for(h = hist; h != H; h = h->link) {
		if(l < h->line)
			break;
		if(h->name) {
			if(h->offset == 0) {
				if(n >= 0 && n < HISTSZ)
					a[n] = *h;
				n++;
				continue;
			}
			if(n > 0 && n < HISTSZ)
				if(a[n-1].offset == 0) {
					a[n] = *h;
					n++;
				} else
					a[n-1] = *h;
			continue;
		}
		n--;
		if(n >= 0 && n < HISTSZ) {
			d = h->line - a[n].line;
			for(i=0; i<n; i++)
				a[i].line += d;
		}
	}
	if(n > HISTSZ)
		n = HISTSZ;
	for(i=0; i<n; i++)
		print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
}

void
ieeedtod(Ieee *ieee, double native)
{
	double fr, ho, f;
	int exp;

	if(native < 0) {
		ieeedtod(ieee, -native);
		ieee->h |= 0x80000000L;
		return;
	}
	if(native == 0) {
		ieee->l = 0;
		ieee->h = 0;
		return;
	}
	fr = frexp(native, &exp);
	f = 2097152L;		/* shouldnt use fp constants here */
	fr = modf(fr*f, &ho);
	ieee->h = ho;
	ieee->h &= 0xfffffL;
	ieee->h |= (exp+1022L) << 20;
	f = 65536L;
	fr = modf(fr*f, &ho);
	ieee->l = ho;
	ieee->l <<= 16;
	ieee->l |= (long)(fr*f);
}