%{ #include #include #include #include #include "mix.h" %} %union { Sym *sym; long lval; u32int mval; Rune *rbuf; } %type wval apart exp aexp fpart ipart %type wval1 %type loc reflit %token LSYMDEF LSYMREF LOP LEQU LORIG LCON LALF LEND %token LBACK LHERE LFORW %token LNUM %token 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); }