%{
#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);
}