txlyre 1 년 전
부모
커밋
10d85b2d93
4개의 변경된 파일533개의 추가작업 그리고 0개의 파일을 삭제
  1. 11 0
      langs/wm/Dockerfile
  2. 12 0
      langs/wm/run.sh
  3. 89 0
      langs/wm/wm.c
  4. 421 0
      langs/wm/wma.py

+ 11 - 0
langs/wm/Dockerfile

@@ -0,0 +1,11 @@
+RUN apt-get install gcc python3 python3-pip -y
+RUN pip3 install --break-system-packages lark-parser
+RUN ln -s /usr/bin/python3 /usr/bin/python
+COPY ./wm.c ./wm.c
+COPY ./wma.py /usr/bin/wma
+RUN chmod +x /usr/bin/wma
+RUN chmod 705 /usr/bin/wma 
+RUN gcc -Os -ansi wm.c -o /usr/bin/wm
+RUN rm wm.c
+RUN chmod +x /usr/bin/wm
+RUN chmod 705 /usr/bin/wm

+ 12 - 0
langs/wm/run.sh

@@ -0,0 +1,12 @@
+IN="$(mktemp --suffix .s)"
+OUT="$(mktemp)"
+
+cat > "$IN"
+
+wma "$IN" "$OUT"
+
+if [ $? -eq 0 ]; then
+  SIZE="$(wc -c $OUT)"
+
+  wm -d -s "$SIZE" "$OUT"
+fi

+ 89 - 0
langs/wm/wm.c

@@ -0,0 +1,89 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<stdarg.h>
+#include<getopt.h>
+#include<unistd.h>
+#include<limits.h>
+#include<time.h>
+#include<sys/types.h>
+#include<sys/stat.h>
+#include<fcntl.h>
+typedef int I;typedef char C;typedef C*S;typedef size_t Z;typedef signed long long L;typedef void V;typedef V*P;typedef V**PP;typedef unsigned char U;typedef unsigned long long UL;
+#define R return
+#define K 1
+#define Rk return 1
+#define JA (EZ+SZ)
+#define SIZ(x)(sizeof(x))
+#define SW(x)switch(x){
+#define CS(x,a)case x:{a}break;
+#define DF(a)default:{a}}
+#define ELIF else if
+#define LP()while(1)
+I D=0;Z SZ=5120,MZ=65535,EZ=65535,JZ=10;L*m;L sp=-K,jp=-K;U lo=0;L**mm=0;L mi=0;
+V d(){L p=m[0]-K;L o=p>=0&&p<MZ?m[p]:0;fprintf(stderr,"[wm] stopped at address: 0x%llx (value = 0x%llx); last instruction: 0x%x\n",p,o,lo);fprintf(stderr,"[wm] stack pointer: 0x%llx.\n",(UL)(EZ+sp));fputs("[wm] jump frame:\n",stderr);L i;for(i=0;i<JZ;i++){if(i>=10){fputs("...\n",stderr);break;}fprintf(stderr, "    #%-5lld0x%llx%s\n",i,m[JA+i],i==jp?" (here)":"");if(mi){fprintf(stderr,"[wm] memory banks (%lld total):\n",mi);for(i=0;i<mi;i++){fprintf(stderr,"    #%-5lld (%s)",i,mm[i]?"in use":"free");}}}}
+V e(S s,...){fflush(stderr);fprintf(stderr,"[wm] error: ");va_list a;va_start(a,s);vfprintf(stderr,s,a);va_end(a);putchar('\n');d();exit(1);}
+P a(Z z){P r=malloc(z);if(!r)e("out of memory.");R r;}
+P ra(P p,Z z){P r=realloc(p,z);if(!r)e("out of memory.");R r;}
+V l(S s,FILE*f){m[0]=K;if(!f)e("can't open file '%s'.",s);Z i=K;U b[8];LP(){Z z=fread(b,K,8,f);if(!z)break;if(z!=8){I pz=ftell(f);if(pz<0)e("decoding of the image '%s' failed.",s);else e("decoding of the image '%s' failed near byte at #%ld.",s,pz-z);}if(i>=LLONG_MAX)e("image '%s' is too large (max. = %lld).",s,LLONG_MAX);if(i>=EZ)e("image '%s' doesn't fit into the memory (size = %ld).",s,EZ);m[i++]=(((L)b[0])&0xff)|((((L)b[K])&0xff)<<8)|((((L)b[2])&0xff)<<16)|((((L)b[3])&0xff)<<24)|((((L)b[4])&0xff)<<32)|((((L)b[5])&0xff)<<40)|((((L)b[6])&0xff)<<48)|((((L)b[7])&0xff)<<56);if(D){if(m[i-1]<1)fprintf(stderr,"%04lu:%08lld ",i-2,m[i-1]);else fprintf(stderr,"%04lu:%08llx ",i-2,m[i-1]);if((i-1)%4==0)fputs("\n",stderr);}}if(D){fprintf(stderr,"(%lu)\n\n",i-1);}}
+V pj(L a){if(jp>=0&&jp>=JZ)e("jump frame overflow.");m[++jp+JA]=a;}
+L tj(){if(jp<0)e("jump frame underflow.");R m[JA+jp--];}
+L lj(){if(jp<0)e("jump frame underflow.");R m[JA+jp];}
+Z g(){if(m[0]>=MZ)m[0]=K;R m[m[0]++];}
+L iL(){C b[64];if(!fgets(b,SIZ(b),stdin))R 0;R strtoll(b,0,10);}
+V ro(I);L r(L);V w(L,L);V j(I a){if(a==-1){free(m);exit(0);}ELIF(a==-5)a=tj();if(a<0||a>=MZ)e("attempt to jump to an illegal address: 0x%x.",a);m[0]=a;}
+S rS(L e){L i=e;S s=a(K);Z k=0,z=K;LP(){I c=r(i++);if(c<=0)break;if(k==z-K){z++;s=ra(s,z);}s[k++]=c;}s[i]=0;R s;}
+V fo(L a){L re=a++;I m=r(a++);S n=rS(r(a));I mo=m;m=m==0?O_WRONLY:m==K?(O_RDONLY|O_CREAT):m==2?O_RDWR:m==3?O_APPEND:-K;if(m<0)e("illegal mode flag: 0x%x.",mo);I dc=open(n,m);free(n);w(re,dc);}
+V fw(L a){I dc=r(a++);L re=a++;S s=rS(r(a));Z z=strlen(s);L c=write(dc,s,z);free(s);w(re,c);}
+Z wS(L a,S s){Z i=0;while(s[i++])w(a+i,s[i-1]);w(a+i,0);R i;}
+V fr(L e){I dc=r(e++);Z z=r(e++);S s=a(z+1);w(e++,read(dc,s,z));wS(r(e)-K,s);free(s);}
+V fs(L a){I dc=r(a++);I o=r(a++);I w=r(a);I wo=w;w=w==0?SEEK_SET:w==1?SEEK_CUR:w==2?SEEK_END:-K;if(w<0)e("illegal seek mode: 0x%x.",wo);lseek(dc,o,w);}
+L aM(Z z){I i;for(i=0;i<mi;i++){if(!mm[i])mm[i]=a(SIZ(L)*z);R i;}mm=ra(mm,SIZ(P)*++mi);mm[mi-K]=a(SIZ(L)*z);R mi;}
+V aF(L i){free(mm[i]);mm[i]=0;}
+L mR(L v){L i=r(v);L p=r(v+K);if(i<0||i>=mi||!mm[i])e("attempt to write to an illegal memory bank index: 0x%x.",i);if(p<0||p>=64)e("attempt to write to an illegal memory bank pointer: 0x%x (index: 0x%x).",p,i);R mm[i][p];}
+V mW(L v){L i=r(v);L p=r(v+K);L a=r(v+2);if(i<0||i>=mi||!mm[i])e("attempt to write to an illegal memory bank index: 0x%x.",i);if(p<0||p>=64)e("attempt to write to an illegal memory bank pointer: 0x%x (index: 0x%x).",p,i);mm[i][p]=a;}
+V mF(L v){L i=r(v);if(i<0||i>=mi||!mm[i])e("attempt to deallocate an illegal memory bank index: 0x%x.",i);aF(i);}
+L r(L a){if(a==-K)R getchar();ELIF(a==-2)R 0;ELIF(a==-3)Rk;ELIF(a==-4)R-K;ELIF(a==-5)R lj();ELIF(a==-6)R time(0);ELIF(a==-7)R MZ+sp;ELIF(a==-8)R EZ;ELIF(a==-9)R SZ;ELIF(a==-10)R MZ;ELIF(a==-11)R JZ;ELIF(a==-12)R iL();ELIF(a==-13){R aM(64);}if(a<0||a>=MZ)e("attempt to read from an illegal address: 0x%x.",a);R m[a];}
+V w(L a,L v){if(a==-K){putchar(v);R;}ELIF(a==-2){printf("%lld",v);R;}ELIF(a==-5){pj(v);R;}ELIF(a==-6){usleep(v);R;}ELIF(a==-7){sp=v-MZ;R;}ELIF(a==-8){fo(v);R;}ELIF(a==-9){if(v>=0)close(v);R;}ELIF(a==-10){fr(v);R;}ELIF(a==-11){fw(v);R;}ELIF(a==-12){fs(v);R;}ELIF(a==-13)SW(r(v))CS(0,w(v,aM(64));)CS(K,mF(v);)CS(2,mW(v);)CS(3,mR(v);)DF(w(v,-1);)if(a<0||a>=MZ)e("attempt to write (value = 0x%x) to an illegal address: 0x%x.",v,a);m[a]=v;}
+V pu(L v){if(sp>=0&&sp>=SZ)e("stack overflow (size = %d).",SZ);if(sp<0)sp=0;m[MZ+sp++]=v;}
+L po(){if(sp<0)e("stack underflow.");R m[MZ+--sp];}
+#define OP1(x,p)case x:a=g();if(s)break;{p}break
+#define OP2(x,p)case x:a=g();b=g();if(s)break;{p}break
+#define OP3(x,p)case x:a=g();b=g();c=g();if(s)break;{p}break
+enum{NOP,MVJ,SBLEZ,ABLEZ,SBLZ,BLES,NBNZ,DBNZ,SSLEZ,ASLEZ,IBNC,VBLZ,XBLZ,DSLZ,SSGT,MBNZ,MODBZ,AJA,LA,LD,IA,JMC,JW,PSH,PD,POP,SHLBNZ,SHRBNZ,NBZ,ANZ,ABGZ,SWP};
+V ro(I s){L a,b,c,d,t;U o=g();lo=o;
+SW(o)CS(NOP,);OP3(MVJ,if(a!=b)w(b,r(a));j(c);); 
+ OP3(SBLEZ,w(b,r(b)-r(a));if(r(b)<=0)j(c););
+ OP3(ABLEZ,w(b,r(b)+r(a));if(r(b)<=0)j(c););
+ OP3(SBLZ,w(b,r(b)-r(a));if(r(b)<0)j(c););
+ OP3(BLES,if(r(b)<=r(a))j(c);else w(b,r(b)-r(a)););
+ OP2(NBNZ,w(a,!r(a));if(r(a))j(b););
+ OP2(DBNZ,w(a,r(a)-K);if(r(a))j(b););
+ OP2(SSLEZ,w(b,r(b)-r(a));if(r(b)<0)ro(K););
+ OP2(ASLEZ,w(b,r(b)+r(a));if(r(b)<0)ro(K););
+ OP3(IBNC,t=r(b);w(b,r(a)+K);if(r(b)==t)j(c););
+ OP3(VBLZ,t=r(a);if(t==0)e("division by zero.");w(b,r(b)/t);if(r(b)<0)j(c););
+ OP3(XBLZ,w(b,r(b)^r(a));if(r(b)>r(a))j(c););
+ OP1(DSLZ,w(a,r(a)-K);if(r(a)<0)ro(K););
+ OP2(SSGT,t=r(a)>r(b);w(b,r(b)-r(a));w(a,r(b));if(t)ro(K););
+ OP3(MBNZ,if(a!=-3)w(b,r(b)*r(a));if(r(b))j(c););
+ OP3(MODBZ,t=r(a);if(t==0)e("modulo by zero.");w(b,r(b)%t);if(!r(b))j(c););
+ OP2(AJA,w(b,r(b)+r(a));j(r(b)););
+ OP2(LA,w(b,r(r(a))););OP2(LD,w(b,a););OP1(IA,t=r(r(a));w(t,r(t)+K););
+ OP1(JMC,j(m[0]*a););OP1(JW,pj(m[0]);j(a););
+ OP1(PSH,pu(r(a)););OP1(PD,pu(a););OP1(POP,w(a,po()););
+ OP3(SHLBNZ,w(b,r(b)<<r(a));if(r(b))j(c););
+ OP3(SHRBNZ,w(b,r(b)>>r(a));if(r(b))j(c););
+ OP2(NBZ,w(a,~r(a));if(!r(a))j(c););
+ OP3(ANZ,w(b,r(b)&r(a));if(r(b))j(c););
+ OP3(ABGZ,w(b,r(b)+r(a));if(r(b)>0)j(c););
+ OP2(SWP,t=r(a);w(a,r(b));w(b,t););DF(e("unrecognized operation: 0x%x.",o);)}
+V rn(){LP()ro(0);}
+main(I c,S*as){I o;S f=0;
+ while((o=getopt(c,as,"ds:j:z:f:"))!=-K){
+  SW(o)CS('d',D=1;);CS('f',f=optarg;);
+       CS('s',MZ=strtol(optarg,0,10);if(MZ<=0){fputs("bad -s.\n",stderr);Rk;});
+       CS('j',JZ=strtol(optarg,0,10);if(JZ<=0){fputs("bad -j.\n",stderr);Rk;});
+       CS('z',SZ=strtol(optarg,0,10);if(SZ<=0){fputs("bad -z.\n",stderr);Rk;});
+       CS('?',exit(K););}}
+ I i;for(i=optind;i<c;i++)f=as[i];EZ=MZ;MZ+=SZ;MZ+=JZ;
+ m=a(SIZ(L)*MZ);if(!f)l("<stdin>",stdin);else{FILE*fd=fopen(f,"rb");l(f,fd);fclose(fd);}rn();free(m);for(i=0;i<mi;i++)if(mm[i])free(mm[i]);}

+ 421 - 0
langs/wm/wma.py

@@ -0,0 +1,421 @@
+#!/usr/bin/python
+import sys
+import struct
+
+import lark
+
+GRAMMAR = r"""
+start: _NL? command ((_NL+|";") command)* _NL?
+
+command: LABEL? operation
+       | LABEL (arg|mixed)
+       | LABEL
+       | INCLUDE
+?operation: "nop" -> nop
+          | ("mvj"|"mj") arg arg arg -> mj          
+          | "sblez" arg arg arg -> sjlez
+          | "ablez" arg arg arg -> ajlez
+          | "sblz" arg arg arg -> sjlz
+          | "bles" arg arg arg -> jles
+          | ("nbnz"|"tjt") arg arg -> tjt
+          | ("dbnz"|"djt") arg arg -> djt
+          | "sslez" arg arg -> sslez
+          | "aslez" arg arg -> aslez
+          | ("ibnc"|"ije") arg arg arg -> ije
+          | "vblz" arg arg arg -> djlz
+          | "xblz" arg arg arg -> xjlz
+          | "dslz" arg -> dslz
+          | ("ssgt"|"ssl") arg arg -> ssl
+          | "mbnz" arg arg arg -> mbnz
+          | "modbz" arg arg arg -> modbz
+          | ("aja"|"aj") arg arg -> aj
+          | "la" arg arg -> la
+          | "ld" arg arg -> ld
+          | "ia" arg -> ia
+          | "jmc" arg -> jmc
+          | ("jw"|"ja") arg -> ja
+          | ("push"|"psh") arg -> psh
+          | "pd" arg -> pd
+          | "pop" arg -> pop
+          | "shlbnz" arg arg arg -> shlbnz
+          | "shrbnz" arg arg arg -> shrbnz
+          | "nbz" arg arg -> nbz
+          | "anz" arg arg arg -> anz
+          | "abgz" arg arg arg -> abgz
+          | "swp" arg arg -> swp
+          | "add" arg arg -> h_add
+          | "sub" arg arg -> h_sub
+          | "inc" arg -> h_inc
+          | "dec" arg -> h_dec
+          | ("mov"|"mv") arg arg -> h_mov
+          | ("jmp"|"j") arg -> h_jmp
+          | "hlt" -> h_halt
+          | "out" arg -> h_out
+          | "in" arg -> h_in
+mixed: arg arg+
+?arg: INTEGER
+    | CHAR
+    | CHARS
+    | QMARK
+    | LABELOFFSET
+    | OFFSET
+    | NAME
+    | rep
+rep: arg "*" COUNT
+COUNT: /[0-9]+/
+INTEGER: /-?[0-9]+/
+CHAR: "'" /./ "'"
+CHARS: "\"" /[^"]*/ "\""
+QMARK: "?"
+OFFSET: "$" /(-|\+)[0-9]+/
+LABELOFFSET: "$" /(-|\+)[A-Za-z][a-zA-Z0-9_]*/ 
+LABEL: /[A-Za-z][a-zA-Z0-9_]*:/
+NAME: /[A-Za-z][a-zA-Z0-9_]*/
+INCLUDE: "+" /.+/
+_NL: /\n+/
+IG: /[ \t\r]+/
+COM: /#.*[^\n]/
+%ignore IG
+%ignore COM
+"""
+
+class WMA:
+  def __init__(self):
+    self.buffer = []
+    self.size = 0
+    
+    self.parser = lark.Lark(GRAMMAR)
+
+  def emit(self, *ops):
+    self.buffer.extend(ops)
+    if type(ops[0]) is tuple and ops[0][0]:
+      return
+
+    self.size += len(ops)
+
+  def compile_arg(self, arg):
+    if type(arg) is lark.Tree:
+      if arg.data == "mixed":
+        for subnode in arg.children:
+          self.compile_arg(subnode)    
+      elif arg.data == "rep":
+        count = int(arg.children[1].value)
+
+        for _ in range(count):
+          self.compile_arg(arg.children[0])
+    elif arg.type == "INTEGER":
+      self.emit(int(arg.value))
+    elif arg.type == "CHAR":
+      self.emit(ord(arg.value[1]))
+    elif arg.type == "CHARS":
+      for char in arg.value[1:-1]:
+        self.emit(ord(char))
+    elif arg.type == "QMARK":
+      self.emit(self.size+2)
+    elif arg.type == "OFFSET":
+      self.emit(self.size+int(arg.value[1:])+1)
+    elif arg.type == "LABELOFFSET":
+      self.emit((False, arg.value[2:], arg.value[1]))
+    elif arg.type == "NAME":
+      if arg.value == "IO":
+        self.emit(-1)
+      elif arg.value == "Z":
+        self.emit(-2)
+      elif arg.value == "O":
+        self.emit(-3)
+      elif arg.value == "N":
+        self.emit(-4)
+      elif arg.value == "J":
+        self.emit(-5)
+      elif arg.value == "T":
+        self.emit(-6)
+      elif arg.value == "SP":
+        self.emit(-7)
+      elif arg.value == "EZ":
+        self.emit(-8)
+      elif arg.value == "SZ":
+        self.emit(-9)
+      elif arg.value == "MZ":
+        self.emit(-10)
+      elif arg.value == "JZ":
+        self.emit(-11)
+      elif arg.value == "W":
+        self.emit(-12)
+      elif arg.value == "MM":
+        self.emit(-13)
+      else:
+        self.emit((False, arg.value))
+
+  def compile_operation(self, op):
+    if op.data == "nop":
+      self.emit(0)
+    elif op.data == "mj":
+      self.emit(1)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2])
+    elif op.data == "sjlez":
+      self.emit(2)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2])
+    elif op.data == "ajlez":
+      self.emit(3)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2])
+    elif op.data == "sjlz": 
+      self.emit(4)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2])
+    elif op.data == "jles":
+      self.emit(5)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2]) 
+    elif op.data == "tjt":
+      self.emit(6)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+    elif op.data == "djt":
+      self.emit(7)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+    elif op.data == "sslez":
+      self.emit(8)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+    elif op.data == "aslez":
+      self.emit(9)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+    elif op.data == "ije":
+      self.emit(10)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2]) 
+    elif op.data == "djlz":
+      self.emit(11)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2]) 
+    elif op.data == "xjlz":
+      self.emit(12)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2]) 
+    elif op.data == "dslz":
+      self.emit(13)
+      self.compile_arg(op.children[0])
+    elif op.data == "ssl":
+      self.emit(14)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+    elif op.data == "mbnz":
+      self.emit(15)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2])
+    elif op.data == "modbz":
+      self.emit(16)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2])
+    elif op.data == "aj":
+      self.emit(17)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+    elif op.data == "la":
+      self.emit(18)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+    elif op.data == "ld":
+      self.emit(19)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+    elif op.data == "ia":
+      self.emit(20)
+      self.compile_arg(op.children[0])
+    elif op.data == "jmc":
+      self.emit(21)
+      self.compile_arg(op.children[0])
+    elif op.data == "ja":
+      self.emit(22)
+      self.compile_arg(op.children[0])
+    elif op.data == "psh":
+      self.emit(23)
+      self.compile_arg(op.children[0])
+    elif op.data == "pd":
+      self.emit(24)
+      self.compile_arg(op.children[0])
+    elif op.data == "pop":
+      self.emit(25)
+      self.compile_arg(op.children[0])
+    elif op.data == "shlbnz":
+      self.emit(26)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2])
+    elif op.data == "shrbnz":
+      self.emit(27)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2])
+    elif op.data == "nbz":
+      self.emit(28)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+    elif op.data == "anz":
+      self.emit(29)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2])
+    elif op.data == "abgz":
+      self.emit(30)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.compile_arg(op.children[2])
+    elif op.data == "swp":
+      self.emit(31)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+    elif op.data == "h_add":
+      self.emit(3)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.emit(self.size+2)
+    elif op.data == "h_sub":
+      self.emit(2)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.emit(self.size+2)
+    elif op.data == "h_inc":
+      self.emit(3)
+      self.emit(-3)
+      self.compile_arg(op.children[0])
+      self.emit(self.size+2)
+    elif op.data == "h_dec":
+      self.emit(2)
+      self.emit(-3)
+      self.compile_arg(op.children[0])
+      self.emit(self.size+2)
+    elif op.data == "h_mov":
+      self.emit(1)
+      self.compile_arg(op.children[0])
+      self.compile_arg(op.children[1])
+      self.emit(self.size+2)
+    elif op.data == "h_jmp":
+      self.emit(1)
+      self.emit(0)
+      self.emit(0)
+      self.compile_arg(op.children[0])
+    elif op.data == "h_halt":
+      self.emit(1)
+      self.emit(0)
+      self.emit(0)
+      self.emit(-1)
+    elif op.data == "h_out":
+      self.emit(1)
+      self.compile_arg(op.children[0])
+      self.emit(-1)
+      self.emit(self.size+2)
+    elif op.data == "h_in":
+      self.emit(1)
+      self.emit(-1)
+      self.compile_arg(op.children[0])
+      self.emit(self.size+2)
+
+  def compile_labels(self):
+    labels = {}
+
+    position = 0
+    while position < len(self.buffer):
+      this = self.buffer[position]
+
+      if type(this) is tuple and this[0]:
+        label = this[1]
+
+        if label in labels:
+          raise Exception(f"Duplicated label: {label}.")
+        elif label in ("IO", "Z", "O", "N", "J", "T", "SP", "EZ", "SZ", "MZ", "JZ", "W", "MM"):
+          raise Exception(f"Register override: {label}.")
+
+        self.buffer.pop(position)
+      
+        labels[label] = position + 1
+
+      position += 1
+
+    position = 0
+    while position < len(self.buffer):
+      this = self.buffer[position]
+
+      if type(this) is tuple and not this[0]:
+        label = this[1]
+
+        if label not in labels:          
+          raise Exception(f"Undefined label/register: {label}.")
+        
+        if len(this) == 3:
+          self.buffer[position] = 1 + (position + labels[label] if this[2] == '+' else position - labels[label])
+        else:
+          self.buffer[position] = labels[label]
+
+      position += 1
+
+  def encode(self):
+    return struct.pack(f"<{'q'*self.size}", *self.buffer)
+
+  def precompile(self, source):
+    ast = self.parser.parse(source)
+
+    for command in ast.children:
+      if len(command.children) == 2:
+        label = command.children[0].value[:-1]
+        
+        self.emit((True,label))
+
+        if type(command.children[1]) is lark.Tree and command.children[1].data != "mixed":                
+          self.compile_operation(command.children[1])
+        else:
+          self.compile_arg(command.children[1])
+      else: 
+        if type(command.children[0]) is lark.Token:
+          if command.children[0].type == "LABEL":
+            label = command.children[0].value[:-1]
+        
+            self.emit((True,label)) 
+          else:
+            with open(command.children[0].value[1:], "r") as f:
+              self.precompile(f.read())
+        else:
+          self.compile_operation(command.children[0])
+
+  def compile(self, source):
+    source += "\n"
+    for reg in "ABCDEFGHIXYK":
+      source += f"{reg}:0"
+
+      if reg != "K":
+        source += ";"
+
+    self.precompile(source)
+
+    self.compile_labels()
+
+    return self.encode()
+
+wma = WMA()
+
+try:
+  if len(sys.argv) == 3:
+    with open(sys.argv[1], "r") as fin:
+      with open(sys.argv[2], "wb") as fout:
+        fout.write(wma.compile(fin.read()))
+  else:
+    sys.stdout.buffer.write(wma.compile(sys.stdin.read()))
+except Exception as e:
+  print(e)
+
+  sys.exit(1)