mirror of https://git.cro.wtf/kip.git
70 lines
3.0 KiB
C
70 lines
3.0 KiB
C
#include"u.h"
|
|
|
|
#define MEMSZ 0x40000
|
|
_ B*inb,meb[MEMSZ];
|
|
_ W inl,mel;
|
|
V mb(W i,B b){Q(i>=MEMSZ||i<0x100,die("memory overflow, or tried to write to IVT {ip=%x}",i))meb[i]=b;}
|
|
V mh(W i,H h){mb(i,h>>8),mb(i+1,h);}
|
|
V mw(W i,W w){mh(i,w>>16),mh(i+2,w);}
|
|
V mcpy(W dst,B*src,W l){for(W i=0;i<l;++i)mb(dst+i,src[i]);}
|
|
|
|
#define OPSZ 38
|
|
_ B ops[OPSZ*2]="npexpbphpwfbfhfwmbmhmwioiimdmrdddrduswovadsumudianorxrslsrsaeqltgtnojujccacc";
|
|
_ B op(B x[2]){W i;for(i=0;i++<OPSZ;)Q(ops[i*2]==x[0]&&ops[1+i*2]==x[1],R i);R OPSZ;}
|
|
_ B htob(B h){R h>='a'&&h<='f'?h-'a'+10:h>='A'&&h<='F'?h-'F'+10:h>='0'&&h<='9'?h-'0':16;}
|
|
_ B ws(B x){R' '==x||'\t'==x||'\r'==x||'\n'==x;}
|
|
|
|
_ V tw(S t){fprintf(stderr,"`%.*s`",t.l,t.p);}
|
|
_ V tasrt(S t,C c){Q(c!=*t.p,tw(t),die(" expected %c",c))}
|
|
_ B tz(S t){R t.l<4?1:t.l<6?2:t.l<10?4:(tw(t),die(" >=32 bits"),0);}
|
|
_ V tto4b(S w,B*bs){W b;++w.p,--w.l;Sfor(w,a,i,Q(16>(b=htob(a)),bs[i/2]=(i%2?bs[i/2]:0)<<4|b)OR tw(w),die(" unknown char `%c`\n",a))}
|
|
_ W tton(S w){W b;W r;r=0,++w.p,--w.l;Sfor(w,a,i,Q(16>(b=htob(a)),r<<=4,r|=b)OR tw(w),die(" unknown char `%c`\n",a));R r;}
|
|
|
|
_ S next(S*t){B c,**p;W*l;l=&t->l,p=&t->p;*p+=*l,*l=0;WH(ws(**p),++*p);c=**p,++*l;
|
|
Q(0==c,R*t)OR
|
|
Q('"'==c,WH('"'!=(*p)[(*l)++],))OR
|
|
Q('{'==c,WH('}'!=(*p)[(*l)++],))OR WH(!ws((*p)[*l]),++*l);
|
|
R*t;}
|
|
|
|
typedef struct{W a;}Label;
|
|
typedef struct{Vec ws;}Macro;
|
|
typedef struct{S n;W a;}Ref;
|
|
Ht labels;
|
|
Ht macros;
|
|
Vec refs;
|
|
|
|
#define BE(y,...)Q(seql(Sl(y),x),__VA_ARGS__)OR
|
|
_ V builtin(S*t){FILE*f;S y,x=*t;++x.p,--x.l;
|
|
BE("org",tasrt(next(t),'#'),mel=tton(*t))
|
|
BE("res",tasrt(next(t),'#'),mel+=tton(*t))
|
|
BE("emb",tasrt(y=next(t),'"'),y.p[y.l-1]=0;WIF(f,(C*)y.p+1,"rb",mel+=fread(meb+mel,1,(W)0-1,f)))
|
|
tw(x),die(" unknown builtin");}
|
|
|
|
_ V pass1(S*t){S x=*t;B c,o;c=*x.p;
|
|
Q('{'==c,/*discard*/)OR
|
|
Q('"'==c,mcpy(mel,x.p+1,x.l-=2),mel+=x.l)OR
|
|
Q('#'==c,B bs[tz(x)];tto4b(x,bs),mcpy(mel,bs,SZ(bs)),mel+=SZ(bs))OR
|
|
Q(':'==c,++x.p,--x.l,hput(&labels,x,&(Label){mel}))OR
|
|
Q('@'==c,++x.p,--x.l,vput(&refs,&(Ref){x,mel}),mel+=4)OR
|
|
Q('!'==c,Macro m={0};++x.p,--x.l,vini(&m.ws,8,SZ(S));WH(';'!=*next(t).p,vput(&m.ws,t));hput(¯os,x,&m);)OR
|
|
Q('`'==c,Macro*m;++x.p,--x.l;Q(m=Hget(Macro,macros,x),Vfor(S,m->ws,y,i,pass1(&y)))OR tw(x),die(" unknown macro"))OR
|
|
Q('-'==c,builtin(t))OR
|
|
Q(2!=x.l||OPSZ==(o=op(x.p)),tw(x),die(" unknown inst"))OR
|
|
mb(mel++,o);}
|
|
|
|
_ V pass2(V){Label*l;
|
|
Vfor(Ref,refs,r,i,Q(l=Hget(Label,labels,r.n),mw(r.a,l->a))OR tw(r.n),die(" unknown ref"))}
|
|
|
|
_ V run(V){S t={0,inb};
|
|
hini(&labels,64,SZ(Label)),hini(¯os,64,SZ(Macro)),vini(&refs,64,SZ(Ref));
|
|
WH(0!=*next(&t).p,pass1(&t));
|
|
pass2();}
|
|
|
|
I main(I ac,C**av){FILE *f;
|
|
Q(3!=ac,die("usage: as INPUT.ASM OUTPUT.ROM"))
|
|
/*todo:this is undefined behaviour for binary streams (SEEK_END)*/
|
|
WIF(f,av[1],"rb",fseek(f,0,SEEK_END),inl=ftell(f),fseek(f,0,SEEK_SET),inb=mk(inl+1),fread(inb,1,inl,f))
|
|
WIF(f,av[2],"wb",Q(chdir(dirname(av[1])),die("?"))inb[inl]=0,run(),del(inb),fwrite(meb+0x100,1,mel-0x100,f))
|
|
printf("done: %d bytes wrote\n",mel-0x100);
|
|
R 0;}
|