shithub: riscv

ref: fb96a050f8a9d5f23da3557ba89251ffb73889bf
dir: /sys/src/games/mix/mixal.y/

View raw version
%{
#include <u.h>
#include <libc.h>
#include <avl.h>
#include <bio.h>
#include "mix.h"
%}

%union {
	Sym *sym;
	long lval;
	u32int mval;
	Rune *rbuf;
}

%type	<lval>	wval apart exp aexp fpart ipart
%type	<mval>	wval1
%type	<sym>	loc reflit

%token	<sym>	LSYMDEF LSYMREF LOP LEQU LORIG LCON LALF LEND
%token	<sym>	LBACK LHERE LFORW
%token	<lval>	LNUM
%token	<rbuf>	LSTR

%left '+' '-' '*' '/' LSS ':' ','

%%

prog:
|	prog inst

inst:
	eol
|	loc LOP apart ipart fpart eol
	{
		defloc($loc, star);
		asm($LOP, $apart, $ipart, $fpart);
	}
|	loc LOP reflit ipart fpart eol
	{
		defloc($loc, star);
		addref($reflit, star);
		refasm($LOP, $ipart, $fpart);
	}
|	loc LEQU wval eol
	{
		defloc($loc, $wval);
	}
|	loc LORIG wval eol
	{
		defloc($loc, star);
		star = $wval;
	}
|	loc LCON wval1 eol
	{
		defloc($loc, star);
		cells[star++] = $wval1;
	}
|	loc LALF LSTR eol
	{
		defloc($loc, star);
		alf(star++, $LSTR);
	}
|	loc LEND wval eol
	{
		endprog($wval);
		defloc($loc, star);
	}

loc:
	{
		$$ = nil;
	}
|	LSYMREF
	{
		$$ = $LSYMREF;
	}
|	LHERE
	{
		Sym *f;
		int l;

		l = ($LHERE)->opc;
		back[l] = star;
		f = forw + l;
		defloc(f, star);
		f->lex = LSYMREF;
		f->refs = nil;
		f->i = f->max = 0;
		$$ = nil;
	}

apart:
	{
		$$ = 0;
	}
|	exp
|	LBACK
	{
		$$ = back[($LBACK)->opc];
	}

reflit:
	LSYMREF
|	'=' wval1 '='
	{
		$$ = con($wval1);
	}
|	LFORW
	{
		$$ = forw + ($LFORW)->opc;
	}

ipart:
	{
		$$ = 0;
	}
|	',' exp
	{
		$$ = $exp;
	}

fpart:
	{
		$$ = -1;
	}
|	'(' exp ')'
	{
		if($exp < 0)
			yyerror("invalid fpart %d\n", $exp);
		$$ = $exp;
	}

exp:
	aexp
|	'+' aexp
	{
		$$ = $aexp;
	}
|	'-' aexp
	{
		$$ = -$aexp;
	}
|	exp '+' aexp
	{
		$$ = $exp + $aexp;
	}
|	exp '-' aexp
	{
		$$ = $exp - $aexp;
	}
|	exp '*' aexp
	{
		$$ = $exp * $aexp;
	}
|	exp '/' aexp
	{
		$$ = ($exp) / $aexp;
	}
|	exp LSS aexp
	{
		$$ = (((vlong)$exp) << 30) / $aexp;
	}
|	exp ':' aexp
	{
		$$ = F($exp, $aexp);
	}

aexp:
	LNUM
|	LSYMDEF
	{
		u32int mval;

		mval = ($LSYMDEF)->mval;
		if(mval & SIGNB) {
			mval &= ~SIGNB;
			$$ = -((long)mval);
		} else
			$$ = mval;
	}
|	'*'
	{
		$$ = star;
	}

wval:
	wval1
	{
		if($wval1 & SIGNB)
			$$ = -(long)($wval1 & MASK5);
		else
			$$ = $wval1;
	}

wval1:
	exp fpart
	{
		$$ = wval(0, $exp, $fpart);
	}
|	wval ',' exp fpart
	{
		$$ = wval($wval, $exp, $fpart);
	}

eol:
	'\n'

%%

int back[10];
Sym forw[10];

void
defrefs(Sym *sym, long apart)
{
	u32int inst, mval;
	int *ref, *ep;

	ep = sym->refs + sym->i;
	for(ref = sym->refs; ref < ep; ref++) {
		inst = cells[*ref];
		inst &= ~(MASK2 << BITS*3);
		if(apart < 0) {
			mval = -apart;
			inst |= SIGNB;
		} else
			mval = apart;
		inst |= (mval&MASK2) << BITS*3;
		cells[*ref] = inst;
	}
}

void
defloc(Sym *sym, long val)
{
	if(sym == nil)
		return;
	defrefs(sym, val);
	free(sym->refs);
	sym->lex = LSYMDEF;
	sym->mval = val < 0 ? -val|SIGNB : val;
}

void
addref(Sym *ref, long star)
{
	if(ref->refs == nil || ref->i == ref->max) {
		ref->max = ref->max == 0 ? 3 : ref->max*2;
		ref->refs = erealloc(ref->refs, ref->max * sizeof(int));
	}
	ref->refs[ref->i++] = star;
}

static void
asm(Sym *op, long apart, long ipart, long fpart)
{
	u32int inst, mval;

	inst = op->opc & MASK1;

	if(fpart == -1)
		inst |= (op->f&MASK1) << BITS;
	else
		inst |= (fpart&MASK1) << BITS;

	inst |= (ipart&MASK1) << BITS*2;

	if(apart < 0) {
		mval = -apart;
		inst |= SIGNB;
	} else
		mval = apart;
	inst |= (mval&MASK2) << BITS*3;

	cells[star++] = inst;
}

void
refasm(Sym *op, long ipart, long fpart)
{
	u32int inst;

	inst = op->opc & MASK1;

	if(fpart == -1)
		inst |= (op->f&MASK1) << BITS;
	else
		inst |= (fpart&MASK1) << BITS;

	inst |= (ipart&MASK1) << BITS*2;

	cells[star++] = inst;
}

Sym*
con(u32int exp)
{
	Con *c;
	static int i;
	static char buf[20];

	seprint(buf, buf+20, "con%d\n", i++);
	c = emalloc(sizeof(*c));
	c->sym = sym(buf);
	c->exp = exp;
	c->link = cons;
	cons = c;
	return c->sym;
}

void
alf(int loc, Rune *b)
{
	u32int w;
	int m;
	Rune *r, *e;

	w = 0;
	e = b + 5;
	for(r = b; r < e; r++) {
		if((m = runetomix(*r)) == -1)
			yyerror("Bad mixchar %C\n", *r);
		w |= m;
		if(r+1 < e)
			w <<= BITS;
	}
	cells[loc] = w;
}

void
endprog(int start)
{
	Con *c, *link;
	for(c = cons; c != nil; c = link) {
		defloc(c->sym, star);
		cells[star++] = c->exp;
		link = c->link;
		free(c);
	}
	cons = nil;
	vmstart = start;
	yydone = 1;
}

u32int
wval(u32int old, int exp, int f)
{
	if(f == -1) {
		if(exp < 0)
			return -exp | SIGNB;
		else
			return exp;
	}

	if(exp < 0)
		return mixst(old, -exp&MASK5 | SIGNB, f);
	return mixst(old, exp & MASK5, f);
}