diff options
| author | Charles Forsyth <charles.forsyth@gmail.com> | 2015-04-25 19:46:27 +0100 |
|---|---|---|
| committer | Charles Forsyth <charles.forsyth@gmail.com> | 2015-04-25 19:46:27 +0100 |
| commit | 70a234d0b5dd59660347742b2c5f3098522e5a80 (patch) | |
| tree | aa2ddd771078131065e987bb72a8517f14ced57e /appl/cmd/asm/asm.y | |
| parent | 4ba871f66a3cfb31efe38493d249f6946092da9b (diff) | |
add Limbo version of asm(1)
Diffstat (limited to 'appl/cmd/asm/asm.y')
| -rw-r--r-- | appl/cmd/asm/asm.y | 1907 |
1 files changed, 1907 insertions, 0 deletions
diff --git a/appl/cmd/asm/asm.y b/appl/cmd/asm/asm.y new file mode 100644 index 00000000..d1464002 --- /dev/null +++ b/appl/cmd/asm/asm.y @@ -0,0 +1,1907 @@ +%{ + +include "sys.m"; + sys: Sys; + +include "draw.m"; + +include "bufio.m"; + bufio: Bufio; + Iobuf: import bufio; + +include "math.m"; + math: Math; + export_real: import math; + +include "string.m"; + str: String; + +include "arg.m"; + +include "../limbo/isa.m"; + +YYSTYPE: adt { + inst: ref Inst; + addr: ref Addr; + op: int; + ival: big; + fval: real; + str: string; + sym: ref Sym; + listv: ref List; +}; + +YYLEX: adt { + lval: YYSTYPE; + EOF: con -1; + lex: fn(l: self ref YYLEX): int; + error: fn(l: self ref YYLEX, msg: string); + + numsym: fn(l: self ref YYLEX, first: int): int; + eatstring: fn(l: self ref YYLEX); +}; + +Eof: con -1; +False: con 0; +True: con 1; +Strsize: con 1024; +Hashsize: con 128; + +Addr: adt +{ + mode: int; + off: int; + val: int; + sym: ref Sym; + + text: fn(a: self ref Addr): string; +}; + +List: adt +{ + link: cyclic ref List; + addr: int; + typ: int; + pick{ + Int => ival: big; # DEFB, DEFW, DEFL + Bytes => b: array of byte; # DEFF, DEFS + Array => a: ref Array; # DEFA + } +}; + +Inst: adt +{ + op: int; + typ: int; + size: int; + reg: ref Addr; + src: ref Addr; + dst: ref Addr; + pc: int; + sym: ref Sym; + link: cyclic ref Inst; + + text: fn(i: self ref Inst): string; +}; + +Sym: adt +{ + name: string; + lexval: int; + value: int; + ds: int; +}; + +Desc: adt +{ + id: int; + size: int; + np: int; + map: array of byte; + link: cyclic ref Desc; +}; + +Array: adt +{ + i: int; + size: int; +}; + +Link: adt +{ + desc: int; + addr: int; + typ: int; + name: string; + link: cyclic ref Link; +}; + +Keywd: adt +{ + name: string; + op: int; + terminal: int; +}; + +Ldts: adt +{ + n: int; + ldt: list of ref Ldt; +}; + +Ldt: adt +{ + sign: int; + name: string; +}; + +Exc: adt +{ + n1, n2, n3, n4, n5, n6: int; + etab: list of ref Etab; +}; + +Etab: adt +{ + n: int; + name: string; +}; + +%} + +%module Asm { + init: fn(nil: ref Draw->Context, nil: list of string); +} + +%left '|' +%left '^' +%left '&' +%left '<' '>' +%left '+' '-' +%left '*' '/' '%' + +%type<inst> label ilist inst +%type<ival> con expr heapid +%type<addr> addr raddr mem roff +%type<listv> elist +%type<str> ptrs +%token<op> TOKI0 TOKI1 TOKI2 TOKI3 +%token <ival> TCONST +%token TOKSB TOKFP TOKHEAP TOKDB TOKDW TOKDL TOKDF TOKDS TOKVAR +%token TOKEXT TOKMOD TOKLINK TOKENTRY TOKARRAY TOKINDIR TOKAPOP TOKLDTS TOKEXCS TOKEXC TOKETAB TOKSRC +%token<sym> TID +%token<fval> TFCONST +%token<str> TSTRING + +%% +prog : ilist + { + assem($1); + } + ; + +ilist : + { $$ = nil; } + | ilist label + { + if($2 != nil) { + $2.link = $1; + $$ = $2; + } + else + $$ = $1; + } + ; + +label : TID ':' inst + { + $3.sym = $1; + $$ = $3; + } + | TOKHEAP heapid ',' expr ptrs + { + heap(int $2, int $4, $5); + $$ = nil; + } + | data + { + $$ = nil; + } + | inst + ; + +heapid : '$' expr + { + $$ = $2; + } + | TID + { + $1.value = heapid++; + $$ = big $1.value; + } + ; + +ptrs : + { $$ = nil; } + | ',' TSTRING + { + $$ = $2; + } + ; + +elist : expr + { + $$ = newi($1, nil); + } + | elist ',' expr + { + $$ = newi($3, $1); + } + ; + +inst : TOKI3 addr ',' addr + { + $$ = ai($1); + $$.src = $2; + $$.dst = $4; + } + | TOKI3 addr ',' raddr ',' addr + { + $$ = ai($1); + $$.src = $2; + $$.reg = $4; + $$.dst = $6; + } + | TOKI2 addr ',' addr + { + $$ = ai($1); + $$.src = $2; + $$.dst = $4; + } + | TOKI1 addr + { + $$ = ai($1); + $$.dst = $2; + } + | TOKI0 + { + $$ = ai($1); + } + ; + +data : TOKDB expr ',' elist + { + data(DEFB, $2, $4); + } + | TOKDW expr ',' elist + { + data(DEFW, $2, $4); + } + | TOKDL expr ',' elist + { + data(DEFL, $2, $4); + } + | TOKDF expr ',' TCONST + { + data(DEFF, $2, newb(dtocanon(real $4), nil)); + } + | TOKDF expr ',' TFCONST + { + data(DEFF, $2, newb(dtocanon($4), nil)); + } + | TOKDF expr ',' TID + { + case $4.name { + "Inf" or "Infinity" => + b := array[] of {byte 16r7F, byte 16rF0, byte 0, byte 0, byte 0, byte 0, byte 0, byte 0}; + data(DEFF, $2, newb(b, nil)); + "NaN" => + b := array[] of {byte 16r7F, byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF}; + data(DEFF, $2, newb(b, nil)); + * => + diag(sys->sprint("bad value for real: %s", $4.name)); + } + } + | TOKDF expr ',' '-' TCONST + { + data(DEFF, $2, newb(dtocanon(-real $5), nil)); + } + | TOKDF expr ',' '-' TFCONST + { + data(DEFF, $2, newb(dtocanon(-$5), nil)); + } + | TOKDF expr ',' '-' TID + { + case $5.name { + "Inf" or "Infinity" => + b := array[] of {byte 16rFF, byte 16rF0, byte 0, byte 0, byte 0, byte 0, byte 0, byte 0}; + data(DEFF, $2, newb(b, nil)); + * => + diag(sys->sprint("bad value for real: %s", $5.name)); + } + } + | TOKDS expr ',' TSTRING + { + data(DEFS, $2, news($4, nil)); + } + | TOKVAR TID ',' expr + { + if($2.ds != 0) + diag(sys->sprint("%s declared twice", $2.name)); + $2.ds = int $4; + $2.value = dseg; + dseg += int $4; + } + | TOKEXT expr ',' expr ',' TSTRING + { + ext(int $2, int $4, $6); + } + | TOKLINK expr ',' expr ',' expr ',' TSTRING + { + mklink(int $2, int $4, int $6, $8); + } + | TOKMOD TID + { + if(amodule != nil) + diag(sys->sprint("this module already defined as %s", $2.name)); + else + amodule = $2; + } + | TOKENTRY expr ',' expr + { + if(pcentry >= 0) + diag(sys->sprint("this module already has entry point %d, %d" , pcentry, dentry)); + pcentry = int $2; + dentry = int $4; + } + | TOKARRAY expr ',' heapid ',' expr + { + data(DEFA, $2, newa(int $4, int $6)); + } + | TOKINDIR expr ',' expr + { + data(DIND, $2, newa(int $4, 0)); + } + | TOKAPOP + { + data(DAPOP, big 0, newa(0, 0)); + } + | TOKLDTS TID ',' expr + { + ldts(int $4); + } + | TOKEXCS expr + { + excs(int $2); + } + | TOKEXC expr ',' expr ',' expr ',' expr ',' expr ',' expr + { + exc(int $2, int $4, int $6, int $8, int $10, int $12); + } + | TOKETAB TSTRING ',' expr + { + etab($2, int $4); + } + | TOKETAB '*' ',' expr + { + etab(nil, int $4); + } + | TOKSRC TSTRING + { + source($2); + } + ; + +raddr : '$' expr + { + $$ = aa($2); + $$.mode = AXIMM; + if($$.val > 16r7FFF || $$.val < -16r8000) + diag(sys->sprint("immediate %d too large for middle operand", $$.val)); + } + | roff + { + if($1.mode == AMP) + $1.mode = AXINM; + else + $1.mode = AXINF; + if($1.mode == AXINM && isoff2big($1.val)) + diag(sys->sprint("register offset %d(mp) too large", $1.val)); + if($1.mode == AXINF && isoff2big($1.val)) + diag(sys->sprint("register offset %d(fp) too large", $1.val)); + $$ = $1; + } + ; + +addr : '$' expr + { + $$ = aa($2); + $$.mode = AIMM; + } + | TID + { + $$ = aa(big 0); + $$.sym = $1; + } + | mem + ; + +mem : '*' roff + { + $2.mode |= AIND; + $$ = $2; + } + | expr '(' roff ')' + { + $3.mode |= AIND; + if($3.val & 3) + diag("indirect offset must be word size"); + if($3.mode == (AMP|AIND) && (isoff2big($3.val) || isoff2big(int $1))) + diag(sys->sprint("indirect offset %bd(%d(mp)) too large", $1, $3.val)); + if($3.mode == (AFP|AIND) && (isoff2big($3.val) || isoff2big(int $1))) + diag(sys->sprint("indirect offset %bd(%d(fp)) too large", $1, $3.val)); + $3.off = $3.val; + $3.val = int $1; + $$ = $3; + } + | roff + ; + +roff : expr '(' TOKSB ')' + { + $$ = aa($1); + $$.mode = AMP; + } + | expr '(' TOKFP ')' + { + $$ = aa($1); + $$.mode = AFP; + } + ; + +con : TCONST + | TID + { + $$ = big $1.value; + } + | '-' con + { + $$ = -$2; + } + | '+' con + { + $$ = $2; + } + | '~' con + { + $$ = ~$2; + } + | '(' expr ')' + { + $$ = $2; + } + ; + +expr: con + | expr '+' expr + { + $$ = $1 + $3; + } + | expr '-' expr + { + $$ = $1 - $3; + } + | expr '*' expr + { + $$ = $1 * $3; + } + | expr '/' expr + { + $$ = $1 / $3; + } + | expr '%' expr + { + $$ = $1 % $3; + } + | expr '<' '<' expr + { + $$ = $1 << int $4; + } + | expr '>' '>' expr + { + $$ = $1 >> int $4; + } + | expr '&' expr + { + $$ = $1 & $3; + } + | expr '^' expr + { + $$ = $1 ^ $3; + } + | expr '|' expr + { + $$ = $1 | $3; + } + ; +%% + +kinit() +{ + for(i := 0; keywds[i].name != nil; i++) { + s := enter(keywds[i].name, keywds[i].terminal); + s.value = keywds[i].op; + } + + enter("desc", TOKHEAP); + enter("mp", TOKSB); + enter("fp", TOKFP); + + enter("byte", TOKDB); + enter("word", TOKDW); + enter("long", TOKDL); + enter("real", TOKDF); + enter("string", TOKDS); + enter("var", TOKVAR); + enter("ext", TOKEXT); + enter("module", TOKMOD); + enter("link", TOKLINK); + enter("entry", TOKENTRY); + enter("array", TOKARRAY); + enter("indir", TOKINDIR); + enter("apop", TOKAPOP); + enter("ldts", TOKLDTS); + enter("exceptions", TOKEXCS); + enter("exception", TOKEXC); + enter("exctab", TOKETAB); + enter("source", TOKSRC); + + cmap['0'] = '\0'+1; + cmap['z'] = '\0'+1; + cmap['n'] = '\n'+1; + cmap['r'] = '\r'+1; + cmap['t'] = '\t'+1; + cmap['b'] = '\b'+1; + cmap['f'] = '\f'+1; + cmap['a'] = '\a'+1; + cmap['v'] = '\v'+1; + cmap['\\'] = '\\'+1; + cmap['"'] = '"'+1; +} + +Bgetc(b: ref Iobuf): int +{ + return b.getb(); +} + +Bungetc(b: ref Iobuf) +{ + b.ungetb(); +} + +Bgetrune(b: ref Iobuf): int +{ + return b.getc(); +} + +Bputc(b: ref Iobuf, c: int) +{ + b.putb(byte c); +} + +strchr(s: string, c: int): string +{ + for(i := 0; i < len s; i++) + if(s[i] == c) + return s[i:]; + return nil; +} + +escchar(c: int): int +{ + buf := array[32] of byte; + if(c >= '0' && c <= '9') { + n := 1; + buf[0] = byte c; + for(;;) { + c = Bgetc(bin); + if(c == Eof) + fatal(sys->sprint("%d: <eof> in escape sequence", line)); + if(strchr("0123456789xX", c) == nil) { + Bungetc(bin); + break; + } + buf[n++] = byte c; + } + return int string buf[0:n]; + } + + n := cmap[c]; + if(n == 0) + return c; + return n-1; +} + +strbuf := array[Strsize] of byte; + +resizebuf() +{ + t := array[len strbuf+Strsize] of byte; + t[0:] = strbuf; + strbuf = t; +} + +YYLEX.eatstring(l: self ref YYLEX) +{ + esc := 0; +Scan: + for(cnt := 0;;) { + c := Bgetc(bin); + case c { + Eof => + fatal(sys->sprint("%d: <eof> in string constant", line)); + + '\n' => + line++; + diag("newline in string constant"); + break Scan; + + '\\' => + if(esc) { + if(cnt >= len strbuf) + resizebuf(); + strbuf[cnt++] = byte c; + esc = 0; + break; + } + esc = 1; + + '"' => + if(esc == 0) + break Scan; + c = escchar(c); + esc = 0; + if(cnt >= len strbuf) + resizebuf(); + strbuf[cnt++] = byte c; + + * => + if(esc) { + c = escchar(c); + esc = 0; + } + if(cnt >= len strbuf) + resizebuf(); + strbuf[cnt++] = byte c; + } + } + l.lval.str = string strbuf[0: cnt]; +} + +eatnl() +{ + line++; + for(;;) { + c := Bgetc(bin); + if(c == Eof) + diag("eof in comment"); + if(c == '\n') + return; + } +} + +YYLEX.lex(l: self ref YYLEX): int +{ + for(;;){ + c := Bgetc(bin); + case c { + Eof => + return Eof; + '"' => + l.eatstring(); + return TSTRING; + ' ' or + '\t' or + '\r' => + continue; + '\n' => + line++; + '.' => + c = Bgetc(bin); + Bungetc(bin); + if(isdigit(c)) + return l.numsym('.'); + return '.'; + '#' => + eatnl(); + '(' or + ')' or + ';' or + ',' or + '~' or + '$' or + '+' or + '/' or + '%' or + '^' or + '*' or + '&' or + '=' or + '|' or + '<' or + '>' or + '-' or + ':' => + return c; + '\'' => + c = Bgetrune(bin); + if(c == '\\') + l.lval.ival = big escchar(Bgetc(bin)); + else + l.lval.ival = big c; + c = Bgetc(bin); + if(c != '\'') { + diag("missing '"); + Bungetc(bin); + } + return TCONST; + + * => + return l.numsym(c); + } + } +} + +isdigit(c: int): int +{ + return c >= '0' && c <= '9'; +} + +isxdigit(c: int): int +{ + return c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F'; +} + +isalnum(c: int): int +{ + return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || isdigit(c); +} + +YYLEX.numsym(l: self ref YYLEX, first: int): int +{ + Int, Hex, Frac, Expsign, Exp: con iota; + state: int; + + symbol[0] = byte first; + p := 0; + + if(first == '.') + state = Frac; + else + state = Int; + + c: int; + if(isdigit(int symbol[p++]) || state == Frac) { + Collect: + for(;;) { + c = Bgetc(bin); + if(c < 0) + fatal(sys->sprint("%d: <eof> eating numeric", line)); + + case state { + Int => + if(isdigit(c)) + break; + case c { + 'x' or + 'X' => + c = 'x'; + state = Hex; + '.' => + state = Frac; + 'e' or + 'E' => + c = 'e'; + state = Expsign; + * => + break Collect; + } + Hex => + if(!isxdigit(c)) + break Collect; + Frac => + if(isdigit(c)) + break; + if(c != 'e' && c != 'E') + break Collect; + c = 'e'; + state = Expsign; + Expsign => + state = Exp; + if(c == '-' || c == '+') + break; + if(!isdigit(c)) + break Collect; + Exp => + if(!isdigit(c)) + break Collect; + } + symbol[p++] = byte c; + } + + # break Collect + lastsym = string symbol[0:p]; + Bungetc(bin); + case state { + Frac or + Expsign or + Exp => + l.lval.fval = real lastsym; + return TFCONST; + * => + if(len lastsym >= 3 && lastsym[0:2] == "0x") + (l.lval.ival, nil) = str->tobig(lastsym[2:], 16); + else + (l.lval.ival, nil) = str->tobig(lastsym, 10); + return TCONST; + } + } + + for(;;) { + c = Bgetc(bin); + if(c < 0) + fatal(sys->sprint("%d <eof> eating symbols", line)); + # '$' and '/' can occur in fully-qualified Java class names + if(c != '_' && c != '.' && c != '/' && c != '$' && !isalnum(c)) { + Bungetc(bin); + break; + } + symbol[p++] = byte c; + } + + lastsym = string symbol[0:p]; + s := enter(lastsym,TID); + case s.lexval { + TOKI0 or + TOKI1 or + TOKI2 or + TOKI3 => + l.lval.op = s.value; + * => + l.lval.sym = s; + } + return s.lexval; +} + +hash := array[Hashsize] of list of ref Sym; + +enter(name: string, stype: int): ref Sym +{ + s := lookup(name); + if(s != nil) + return s; + + h := 0; + for(p := 0; p < len name; p++) + h = h*3 + name[p]; + if(h < 0) + h = ~h; + h %= Hashsize; + + s = ref Sym(name, stype, 0, 0); + hash[h] = s :: hash[h]; + return s; +} + +lookup(name: string): ref Sym +{ + h := 0; + for(p := 0; p < len name; p++) + h = h*3 + name[p]; + if(h < 0) + h = ~h; + h %= Hashsize; + + for(l := hash[h]; l != nil; l = tl l) + if((s := hd l).name == name) + return s; + return nil; +} + +YYLEX.error(l: self ref YYLEX, s: string) +{ + if(s == "syntax error") { + l.error(sys->sprint("syntax error, near symbol '%s'", lastsym)); + return; + } + sys->print("%s %d: %s\n", file, line, s); + if(nerr++ > 10) { + sys->fprint(sys->fildes(2), "%s:%d: too many errors, giving up\n", file, line); + sys->remove(ofile); + raise "fail: yyerror"; + } +} + +fatal(s: string) +{ + sys->fprint(sys->fildes(2), "asm: %d (fatal compiler problem) %s\n", line, s); + raise "fail:"+s; +} + +diag(s: string) +{ + srcline := line; + sys->fprint(sys->fildes(2), "%s:%d: %s\n", file, srcline, s); + if(nerr++ > 10) { + sys->fprint(sys->fildes(2), "%s:%d: too many errors, giving up\n", file, line); + sys->remove(ofile); + raise "fail: error"; + } +} + +zinst: Inst; + +ai(op: int): ref Inst +{ + i := ref zinst; + i.op = op; + + return i; +} + +aa(val: big): ref Addr +{ + if(val <= big -1073741824 && val > big 1073741823) + diag("offset out of range"); + return ref Addr(0, 0, int val, nil); +} + +isoff2big(o: int): int +{ + return o < 0 || o > 16rFFFF; +} + +inldt := 0; +nldts := 0; +aldts: list of ref Ldts; +curl: ref Ldts; +nexcs := 0; +aexcs: list of ref Exc; +cure: ref Exc; +srcpath: string; + +bin: ref Iobuf; +bout: ref Iobuf; + +line := 0; +heapid := 0; +symbol := array[1024] of byte; +lastsym: string; +nerr := 0; +cmap := array[256] of int; +file: string; + +dlist: ref Desc; +dcout := 0; +dseg := 0; +dcount := 0; + +mdata: ref List; +amodule: ref Sym; +links: ref Link; +linkt: ref Link; +nlink := 0; +listing := 0; +mustcompile := 0; +dontcompile := 0; +ofile: string; +dentry := 0; +pcentry := 0; + +init(nil: ref Draw->Context, args: list of string) +{ + sys = load Sys Sys->PATH; + math = load Math Math->PATH; + bufio = load Bufio Bufio->PATH; + str = load String String->PATH; + + arg := load Arg Arg->PATH; + arg->setusage("asm [-l] file.s"); + arg->init(args); + while((c := arg->opt()) != 0){ + case c { + 'C' => dontcompile++; + 'c' => mustcompile++; + 'l' => listing++; + * => arg->usage(); + } + } + args = arg->argv(); + if(len args != 1) + arg->usage(); + arg = nil; + + kinit(); + pcentry = -1; + dentry = -1; + + file = hd args; + bin = bufio->open(file, Bufio->OREAD); + if(bin == nil) { + sys->fprint(sys->fildes(2), "asm: can't open %s: %r\n", file); + raise "fail: errors"; + } + p := strrchr(file, '/'); + if(p == nil) + p = file; + else + p = p[1:]; + ofile = mkfile(p, ".s", ".dis"); + bout = bufio->create(ofile, Bufio->OWRITE, 8r666); + if(bout == nil){ + sys->fprint(sys->fildes(2), "asm: can't create: %s: %r\n", ofile); + raise "fail: errors"; + } + line = 1; + yyparse(ref YYLEX); + bout.close(); + + if(nerr != 0){ + sys->remove(ofile); + raise "fail: errors"; + } +} + +strrchr(s: string, c: int): string +{ + for(i := len s; --i >= 0;) + if(s[i] == c) + return s[i:]; + return nil; +} + +mkfile(file: string, oldext: string, ext: string): string +{ + n := len file; + n2 := len oldext; + if(n >= n2 && file[n-n2:] == oldext) + n -= n2; + return file[0:n] + ext; +} + +opcode(i: ref Inst): int +{ + if(i.op < 0 || i.op >= len keywds) + fatal(sys->sprint("internal error: invalid op %d (%#x)", i.op, i.op)); + return keywds[i.op].op; +} + +Inst.text(i: self ref Inst): string +{ + if(i == nil) + return "IZ"; + + case keywds[i.op].terminal { + TOKI0 => + return sys->sprint("%s", keywds[i.op].name); + TOKI1 => + return sys->sprint("%s\t%s", keywds[i.op].name, i.dst.text()); + TOKI3 => + if(i.reg != nil) { + pre := ""; + post := ""; + case i.reg.mode { + AXIMM => + pre = "$"; + break; + AXINF => + post = "(fp)"; + break; + AXINM => + post = "(mp)"; + break; + } + return sys->sprint("%s\t%s, %s%d%s, %s", keywds[i.op].name, i.src.text(), pre, i.reg.val, post, i.dst.text()); + } + return sys->sprint("%s\t%s, %s", keywds[i.op].name, i.src.text(), i.dst.text()); + TOKI2 => + return sys->sprint("%s\t%s, %s", keywds[i.op].name, i.src.text(), i.dst.text()); + * => + return "IGOK"; + } +} + +Addr.text(a: self ref Addr): string +{ + if(a == nil) + return "AZ"; + + if(a.mode & AIND) { + case a.mode & ~AIND { + AFP => + return sys->sprint("%d(%d(fp))", a.val, a.off); + AMP => + return sys->sprint("%d(%d(mp))", a.val, a.off); + } + } + else { + case a.mode { + AFP => + return sys->sprint("%d(fp)", a.val); + AMP => + return sys->sprint("%d(mp)", a.val); + AIMM => + return sys->sprint("$%d", a.val); + } + } + + return "AGOK"; +} + +append[T](l: list of T, v: T): list of T +{ + if(l == nil) + return v :: nil; + return hd l :: append(tl l, v); +} + +newa(i: int, size: int): ref List +{ + a := ref Array(i, size); + l := ref List.Array(nil, -1, 0, a); + return l; +} + +# does order matter? +newi(v: big, l: ref List): ref List +{ + n := ref List.Int(nil, -1, 0, v); + if(l == nil) + return n; + + for(t := l; t.link != nil; t = t.link) + ; + t.link = n; + + return l; +} + +news(s: string, l: ref List): ref List +{ + return ref List.Bytes(l, -1, 0, array of byte s); +} + +newb(a: array of byte, l: ref List): ref List +{ + return ref List.Bytes(l, -1, 0, a); +} + +digit(x: int): int +{ + if(x >= 'A' && x <= 'F') + return x - 'A' + 10; + if(x >= 'a' && x <= 'f') + return x - 'a' + 10; + if(x >= '0' && x <= '9') + return x - '0'; + diag("bad hex value in pointers"); + return 0; +} + +heap(id: int, size: int, ptr: string) +{ + d := ref Desc; + d.id = id; + d.size = size; + size /= IBY2WD; + d.map = array[size] of {* => byte 0}; + d.np = 0; + if(dlist == nil) + dlist = d; + else { + f: ref Desc; + for(f = dlist; f.link != nil; f = f.link) + ; + f.link = d; + } + d.link = nil; + dcount++; + + if(ptr == nil) + return; + if(len ptr & 1) { + diag("pointer descriptor has odd length"); + return; + } + + k := 0; + l := len ptr; + for(i := 0; i < l; i += 2) { + d.map[k++] = byte ((digit(ptr[i])<<4)|digit(ptr[i+1])); + if(k > size) { + diag("pointer descriptor too long"); + break; + } + } + d.np = k; +} + +conout(val: int) +{ + if(val >= -64 && val <= 63) { + Bputc(bout, val & ~16r80); + return; + } + if(val >= -8192 && val <= 8191) { + Bputc(bout, ((val>>8) & ~16rC0) | 16r80); + Bputc(bout, val); + return; + } + if(val < 0 && ((val >> 29) & 7) != 7 + || val > 0 && (val >> 29) != 0) + diag(sys->sprint("overflow in constant 0x%ux\n", val)); + Bputc(bout, (val>>24) | 16rC0); + Bputc(bout, val>>16); + Bputc(bout, val>>8); + Bputc(bout, val); +} + +aout(a: ref Addr) +{ + if(a == nil) + return; + if(a.mode & AIND) + conout(a.off); + conout(a.val); +} + +Bputs(b: ref Iobuf, s: string) +{ + for(i := 0; i < len s; i++) + Bputc(b, s[i]); + Bputc(b, '\0'); +} + +lout() +{ + if(amodule == nil) + amodule = enter("main", 0); + + Bputs(bout, amodule.name); + + for(l := links; l != nil; l = l.link) { + conout(l.addr); + conout(l.desc); + Bputc(bout, l.typ>>24); + Bputc(bout, l.typ>>16); + Bputc(bout, l.typ>>8); + Bputc(bout, l.typ); + Bputs(bout, l.name); + } +} + +ldtout() +{ + conout(nldts); + for(la := aldts; la != nil; la = tl la){ + ls := hd la; + conout(ls.n); + for(l := ls.ldt; l != nil; l = tl l){ + t := hd l; + Bputc(bout, t.sign>>24); + Bputc(bout, t.sign>>16); + Bputc(bout, t.sign>>8); + Bputc(bout, t.sign); + Bputs(bout, t.name); + } + } + conout(0); +} + +excout() +{ + if(nexcs == 0) + return; + conout(nexcs); + for(es := aexcs; es != nil; es = tl es){ + e := hd es; + conout(e.n3); + conout(e.n1); + conout(e.n2); + conout(e.n4); + conout(e.n5|(e.n6<<16)); + for(ets := e.etab; ets != nil; ets = tl ets){ + et := hd ets; + if(et.name != nil) + Bputs(bout, et.name); + conout(et.n); + } + } + conout(0); +} + +srcout() +{ + if(srcpath == nil) + return; + Bputs(bout, srcpath); +} + +assem(i: ref Inst) +{ + f: ref Inst; + while(i != nil){ + link := i.link; + i.link = f; + f = i; + i = link; + } + i = f; + + pc := 0; + for(f = i; f != nil; f = f.link) { + f.pc = pc++; + if(f.sym != nil) + f.sym.value = f.pc; + } + + if(pcentry >= pc) + diag("entry pc out of range"); + if(dentry >= dcount) + diag("entry descriptor out of range"); + + conout(XMAGIC); + hints := 0; + if(mustcompile) + hints |= MUSTCOMPILE; + if(dontcompile) + hints |= DONTCOMPILE; + hints |= HASLDT; + if(nexcs > 0) + hints |= HASEXCEPT; + conout(hints); # Runtime flags + conout(1024); # default stack size + conout(pc); + conout(dseg); + conout(dcount); + conout(nlink); + conout(pcentry); + conout(dentry); + + for(f = i; f != nil; f = f.link) { + if(f.dst != nil && f.dst.sym != nil) { + f.dst.mode = AIMM; + f.dst.val = f.dst.sym.value; + } + o := opcode(f); + if(o == IRAISE){ + f.src = f.dst; + f.dst = nil; + } + Bputc(bout, o); + n := 0; + if(f.src != nil) + n |= src(f.src.mode); + else + n |= src(AXXX); + if(f.dst != nil) + n |= dst(f.dst.mode); + else + n |= dst(AXXX); + if(f.reg != nil) + n |= f.reg.mode; + else + n |= AXNON; + Bputc(bout, n); + aout(f.reg); + aout(f.src); + aout(f.dst); + + if(listing) + sys->print("%4d %s\n", f.pc, f.text()); + } + + for(d := dlist; d != nil; d = d.link) { + conout(d.id); + conout(d.size); + conout(d.np); + for(n := 0; n < d.np; n++) + Bputc(bout, int d.map[n]); + } + + dout(); + lout(); + ldtout(); + excout(); + srcout(); +} + +data(typ: int, addr: big, l: ref List) +{ + if(inldt){ + ldtw(int intof(l)); + return; + } + + l.typ = typ; + l.addr = int addr; + + if(mdata == nil) + mdata = l; + else { + for(f := mdata; f.link != nil; f = f.link) + ; + f.link = l; + } +} + +ext(addr: int, typ: int, s: string) +{ + if(inldt){ + ldte(typ, s); + return; + } + + data(DEFW, big addr, newi(big typ, nil)); + + n: ref List; + for(i := 0; i < len s; i++) + n = newi(big s[i], n); + data(DEFB, big(addr+IBY2WD), n); + + if(addr+len s > dseg) + diag("ext beyond mp"); +} + +mklink(desc: int, addr: int, typ: int, s: string) +{ + for(ls := links; ls != nil; ls = ls.link) + if(ls.name == s) + diag(sys->sprint("%s already defined", s)); + + nlink++; + l := ref Link; + l.desc = desc; + l.addr = addr; + l.typ = typ; + l.name = s; + l.link = nil; + + if(links == nil) + links = l; + else + linkt.link = l; + linkt = l; +} + +intof(l: ref List): big +{ + pick rl := l { + Int => + return rl.ival; + * => + raise "list botch"; + } +} + +arrayof(l: ref List): ref Array +{ + pick rl := l { + Array => + return rl.a; + * => + raise "list botch"; + } +} + +bytesof(l: ref List): array of byte +{ + pick rl := l { + Bytes => + return rl.b; + * => + raise "list botch"; + } +} + +nel(l: ref List): (int, ref List) +{ + n := 1; + for(e := l.link; e != nil && e.addr == -1; e = e.link) + n++; + return (n, e); +} + +dout() +{ + e: ref List; + n: int; + for(l := mdata; l != nil; l = e) { + case l.typ { + DEFB => + (n, e) = nel(l); + if(n < DMAX) + Bputc(bout, dbyte(DEFB, n)); + else { + Bputc(bout, dbyte(DEFB, 0)); + conout(n); + } + conout(l.addr); + while(l != e) { + Bputc(bout, int intof(l)); + l = l.link; + } + break; + DEFW => + (n, e) = nel(l); + if(n < DMAX) + Bputc(bout, dbyte(DEFW, n)); + else { + Bputc(bout, dbyte(DEFW, 0)); + conout(n); + } + conout(l.addr); + while(l != e) { + n = int intof(l); + Bputc(bout, n>>24); + Bputc(bout, n>>16); + Bputc(bout, n>>8); + Bputc(bout, n); + l = l.link; + } + break; + DEFL => + (n, e) = nel(l); + if(n < DMAX) + Bputc(bout, dbyte(DEFL, n)); + else { + Bputc(bout, dbyte(DEFL, 0)); + conout(n); + } + conout(l.addr); + while(l != e) { + b := intof(l); + Bputc(bout, int (b>>56)); + Bputc(bout, int (b>>48)); + Bputc(bout, int (b>>40)); + Bputc(bout, int (b>>32)); + Bputc(bout, int (b>>24)); + Bputc(bout, int (b>>16)); + Bputc(bout, int (b>>8)); + Bputc(bout, int b); + l = l.link; + } + break; + DEFF => + (n, e) = nel(l); + if(n < DMAX) + Bputc(bout, dbyte(DEFF, n)); + else { + Bputc(bout, dbyte(DEFF, 0)); + conout(n); + } + conout(l.addr); + while(l != e) { + b := bytesof(l); + Bputc(bout, int b[0]); + Bputc(bout, int b[1]); + Bputc(bout, int b[2]); + Bputc(bout, int b[3]); + Bputc(bout, int b[4]); + Bputc(bout, int b[5]); + Bputc(bout, int b[6]); + Bputc(bout, int b[7]); + l = l.link; + } + break; + DEFS => + a := bytesof(l); + n = len a; + if(n < DMAX && n != 0) + Bputc(bout, dbyte(DEFS, n)); + else { + Bputc(bout, dbyte(DEFS, 0)); + conout(n); + } + conout(l.addr); + for(i := 0; i < n; i++) + Bputc(bout, int a[i]); + + e = l.link; + break; + DEFA => + Bputc(bout, dbyte(DEFA, 1)); + conout(l.addr); + ar := arrayof(l); + Bputc(bout, ar.i>>24); + Bputc(bout, ar.i>>16); + Bputc(bout, ar.i>>8); + Bputc(bout, ar.i); + Bputc(bout, ar.size>>24); + Bputc(bout, ar.size>>16); + Bputc(bout, ar.size>>8); + Bputc(bout, ar.size); + e = l.link; + break; + DIND => + Bputc(bout, dbyte(DIND, 1)); + conout(l.addr); + Bputc(bout, 0); + Bputc(bout, 0); + Bputc(bout, 0); + Bputc(bout, 0); + e = l.link; + break; + DAPOP => + Bputc(bout, dbyte(DAPOP, 1)); + conout(0); + e = l.link; + break; + } + } + + Bputc(bout, dbyte(DEFZ, 0)); +} + +ldts(n: int) +{ + nldts = n; + inldt = 1; +} + +ldtw(n: int) +{ + ls := ref Ldts(n, nil); + aldts = append(aldts, ls); + curl = ls; +} + +ldte(n: int, s: string) +{ + l := ref Ldt(n, s); + curl.ldt = append(curl.ldt, l); +} + +excs(n: int) +{ + nexcs = n; +} + +exc(n1: int, n2: int, n3: int, n4: int, n5: int, n6: int) +{ + e := ref Exc; + e.n1 = n1; + e.n2 = n2; + e.n3 = n3; + e.n4 = n4; + e.n5 = n5; + e.n6 = n6; + e.etab = nil; + aexcs = append(aexcs, e); + cure = e; +} + +etab(s: string, n: int) +{ + et := ref Etab; + et.n = n; + et.name = s; + cure.etab = append(cure.etab, et); +} + +source(s: string) +{ + srcpath = s; +} + +dtype(x: int): int +{ + return (x>>4)&16rF; +} + +dbyte(x: int, l: int): int +{ + return (x<<4) | l; +} + +dlen(x: int): int +{ + return x & (DMAX-1); +} + +src(x: int): int +{ + return x<<3; +} + +dst(x: int): int +{ + return x<<0; +} + +dtocanon(d: real): array of byte +{ + b := array[8] of byte; + export_real(b, array[] of {d}); + return b; +} + +keywds: array of Keywd = array[] of +{ + ("nop", INOP, TOKI0), + ("alt", IALT, TOKI3), + ("nbalt", INBALT, TOKI3), + ("goto", IGOTO, TOKI2), + ("call", ICALL, TOKI2), + ("frame", IFRAME, TOKI2), + ("spawn", ISPAWN, TOKI2), + ("runt", IRUNT, TOKI2), + ("load", ILOAD, TOKI3), + ("mcall", IMCALL, TOKI3), + ("mspawn", IMSPAWN, TOKI3), + ("mframe", IMFRAME, TOKI3), + ("ret", IRET, TOKI0), + ("jmp", IJMP, TOKI1), + ("case", ICASE, TOKI2), + ("exit", IEXIT, TOKI0), + ("new", INEW, TOKI2), + ("newa", INEWA, TOKI3), + ("newcb", INEWCB, TOKI1), + ("newcw", INEWCW, TOKI1), + ("newcf", INEWCF, TOKI1), + ("newcp", INEWCP, TOKI1), + ("newcm", INEWCM, TOKI2), + ("newcmp", INEWCMP, TOKI2), + ("send", ISEND, TOKI2), + ("recv", IRECV, TOKI2), + ("consb", ICONSB, TOKI2), + ("consw", ICONSW, TOKI2), + ("consp", ICONSP, TOKI2), + ("consf", ICONSF, TOKI2), + ("consm", ICONSM, TOKI3), + ("consmp", ICONSMP, TOKI3), + ("headb", IHEADB, TOKI2), + ("headw", IHEADW, TOKI2), + ("headp", IHEADP, TOKI2), + ("headf", IHEADF, TOKI2), + ("headm", IHEADM, TOKI3), + ("headmp", IHEADMP, TOKI3), + ("tail", ITAIL, TOKI2), + ("lea", ILEA, TOKI2), + ("indx", IINDX, TOKI3), + ("movp", IMOVP, TOKI2), + ("movm", IMOVM, TOKI3), + ("movmp", IMOVMP, TOKI3), + ("movb", IMOVB, TOKI2), + ("movw", IMOVW, TOKI2), + ("movf", IMOVF, TOKI2), + ("cvtbw", ICVTBW, TOKI2), + ("cvtwb", ICVTWB, TOKI2), + ("cvtfw", ICVTFW, TOKI2), + ("cvtwf", ICVTWF, TOKI2), + ("cvtca", ICVTCA, TOKI2), + ("cvtac", ICVTAC, TOKI2), + ("cvtwc", ICVTWC, TOKI2), + ("cvtcw", ICVTCW, TOKI2), + ("cvtfc", ICVTFC, TOKI2), + ("cvtcf", ICVTCF, TOKI2), + ("addb", IADDB, TOKI3), + ("addw", IADDW, TOKI3), + ("addf", IADDF, TOKI3), + ("subb", ISUBB, TOKI3), + ("subw", ISUBW, TOKI3), + ("subf", ISUBF, TOKI3), + ("mulb", IMULB, TOKI3), + ("mulw", IMULW, TOKI3), + ("mulf", IMULF, TOKI3), + ("divb", IDIVB, TOKI3), + ("divw", IDIVW, TOKI3), + ("divf", IDIVF, TOKI3), + ("modw", IMODW, TOKI3), + ("modb", IMODB, TOKI3), + ("andb", IANDB, TOKI3), + ("andw", IANDW, TOKI3), + ("orb", IORB, TOKI3), + ("orw", IORW, TOKI3), + ("xorb", IXORB, TOKI3), + ("xorw", IXORW, TOKI3), + ("shlb", ISHLB, TOKI3), + ("shlw", ISHLW, TOKI3), + ("shrb", ISHRB, TOKI3), + ("shrw", ISHRW, TOKI3), + ("insc", IINSC, TOKI3), + ("indc", IINDC, TOKI3), + ("addc", IADDC, TOKI3), + ("lenc", ILENC, TOKI2), + ("lena", ILENA, TOKI2), + ("lenl", ILENL, TOKI2), + ("beqb", IBEQB, TOKI3), + ("bneb", IBNEB, TOKI3), + ("bltb", IBLTB, TOKI3), + ("bleb", IBLEB, TOKI3), + ("bgtb", IBGTB, TOKI3), + ("bgeb", IBGEB, TOKI3), + ("beqw", IBEQW, TOKI3), + ("bnew", IBNEW, TOKI3), + ("bltw", IBLTW, TOKI3), + ("blew", IBLEW, TOKI3), + ("bgtw", IBGTW, TOKI3), + ("bgew", IBGEW, TOKI3), + ("beqf", IBEQF, TOKI3), + ("bnef", IBNEF, TOKI3), + ("bltf", IBLTF, TOKI3), + ("blef", IBLEF, TOKI3), + ("bgtf", IBGTF, TOKI3), + ("bgef", IBGEF, TOKI3), + ("beqc", IBEQC, TOKI3), + ("bnec", IBNEC, TOKI3), + ("bltc", IBLTC, TOKI3), + ("blec", IBLEC, TOKI3), + ("bgtc", IBGTC, TOKI3), + ("bgec", IBGEC, TOKI3), + ("slicea", ISLICEA, TOKI3), + ("slicela", ISLICELA, TOKI3), + ("slicec", ISLICEC, TOKI3), + ("indw", IINDW, TOKI3), + ("indf", IINDF, TOKI3), + ("indb", IINDB, TOKI3), + ("negf", INEGF, TOKI2), + ("movl", IMOVL, TOKI2), + ("addl", IADDL, TOKI3), + ("subl", ISUBL, TOKI3), + ("divl", IDIVL, TOKI3), + ("modl", IMODL, TOKI3), + ("mull", IMULL, TOKI3), + ("andl", IANDL, TOKI3), + ("orl", IORL, TOKI3), + ("xorl", IXORL, TOKI3), + ("shll", ISHLL, TOKI3), + ("shrl", ISHRL, TOKI3), + ("bnel", IBNEL, TOKI3), + ("bltl", IBLTL, TOKI3), + ("blel", IBLEL, TOKI3), + ("bgtl", IBGTL, TOKI3), + ("bgel", IBGEL, TOKI3), + ("beql", IBEQL, TOKI3), + ("cvtlf", ICVTLF, TOKI2), + ("cvtfl", ICVTFL, TOKI2), + ("cvtlw", ICVTLW, TOKI2), + ("cvtwl", ICVTWL, TOKI2), + ("cvtlc", ICVTLC, TOKI2), + ("cvtcl", ICVTCL, TOKI2), + ("headl", IHEADL, TOKI2), + ("consl", ICONSL, TOKI2), + ("newcl", INEWCL, TOKI1), + ("casec", ICASEC, TOKI2), + ("indl", IINDL, TOKI3), + ("movpc", IMOVPC, TOKI2), + ("tcmp", ITCMP, TOKI2), + ("mnewz", IMNEWZ, TOKI3), + ("cvtrf", ICVTRF, TOKI2), + ("cvtfr", ICVTFR, TOKI2), + ("cvtws", ICVTWS, TOKI2), + ("cvtsw", ICVTSW, TOKI2), + ("lsrw", ILSRW, TOKI3), + ("lsrl", ILSRL, TOKI3), + ("eclr", IECLR, TOKI0), + ("newz", INEWZ, TOKI2), + ("newaz", INEWAZ, TOKI3), + ("raise", IRAISE, TOKI1), + ("casel", ICASEL, TOKI2), + ("mulx", IMULX, TOKI3), + ("divx", IDIVX, TOKI3), + ("cvtxx", ICVTXX, TOKI3), + ("mulx0", IMULX0, TOKI3), + ("divx0", IDIVX0, TOKI3), + ("cvtxx0", ICVTXX0, TOKI3), + ("mulx1", IMULX1, TOKI3), + ("divx1", IDIVX1, TOKI3), + ("cvtxx1", ICVTXX1, TOKI3), + ("cvtfx", ICVTFX, TOKI3), + ("cvtxf", ICVTXF, TOKI3), + ("expw", IEXPW, TOKI3), + ("expl", IEXPL, TOKI3), + ("expf", IEXPF, TOKI3), + ("self", ISELF, TOKI1), + (nil, 0, 0), +}; |
