txlyre 1 年間 前
コミット
d1c76bdd76

+ 0 - 0
langs/wm/wclib/time.wc


+ 11 - 0
langs/wma/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/wm.c ./wm.c
+COPY ./wm/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 -lm
+RUN rm wm.c
+RUN chmod +x /usr/bin/wm
+RUN chmod 705 /usr/bin/wm

+ 12 - 0
langs/wma/run.sh

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

+ 0 - 0
langs/wm/.history → langs/wmc/.history


+ 0 - 0
langs/wm/Dockerfile → langs/wmc/Dockerfile


+ 0 - 0
langs/wm/Dockerfile.user → langs/wmc/Dockerfile.user


+ 0 - 0
langs/wm/run.sh → langs/wmc/run.sh


+ 2 - 2
langs/wm/wclib/stdio.wc → langs/wmc/wclib/stdio.wc

@@ -1,13 +1,13 @@
 getc() {
   c;
 
-  asm("mov IO {c}");
+  asm("in {c}");
 
   return c;
 }
 
 putc(c) {
-  asm("mov {c} IO");
+  asm("out {c}");
 }
 
 putd(n) {

+ 5 - 0
langs/wm/wclib/string.wc → langs/wmc/wclib/string.wc

@@ -16,3 +16,8 @@ strcpy(s, d) {
     i++;
   }
 }
+
+memcpy(s, d, n) {
+  for (i=0;i<n;i++)
+    d[i] = s[i];
+}

+ 11 - 0
langs/wmc/wclib/time.wc

@@ -0,0 +1,11 @@
+time() {
+  c;
+
+  asm("mov T {c}");
+
+  return c;
+}
+
+usleep(s) {
+  asm("mov {s} T");
+}

+ 1 - 1
langs/wm/wm.c → langs/wmc/wm.c

@@ -79,7 +79,7 @@ V w(L a,L v){if(a<-1000){a=llabs(a);a-=1000;L i=a/64;L p=a%64;if(i<0||i>=mi||!mm
 #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,STR};
 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);); 
+SW(o)CS(NOP,);OP3(MVJ,if(a!=b||(a==-15&&b==-15)||(a<0||b<0))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););

+ 8 - 2
langs/wm/wma.py → langs/wmc/wma.py

@@ -58,6 +58,7 @@ command: LABEL? operation
           | "in" arg -> h_in
           | "dir" arg -> h_dir
           | "ret" -> h_ret
+          | "peek" arg -> h_peek
 mixed: arg arg+
 ?arg: INTEGER
     | DOUBLE
@@ -388,9 +389,14 @@ class WMA:
       self.emit(-14)
     elif op.data == "h_ret":
       self.emit(1)
-      self.emit(-2)
-      self.emit(-2)
+      self.emit(-15)
+      self.emit(-15)
       self.emit(-5)
+    elif op.data == "h_peek":
+      self.emit(25)
+      self.compile_arg(op.children[0])
+      self.emit(23)
+      self.compile_arg(op.children[0])
 
   def compile_labels(self):
     position = 0

+ 171 - 18
langs/wm/wmc.py → langs/wmc/wmc.py

@@ -2,6 +2,7 @@
 
 import os
 import os.path
+import re
 import sys
 
 import lark
@@ -38,6 +39,7 @@ asm: "asm" "(" STRING+ ")"
    | continue ";"
    | vardec ";"
    | arrdec ";"
+   | return ";"
    | varinit ";"
    | arrinit ";"
    | inc ";"
@@ -46,18 +48,21 @@ asm: "asm" "(" STRING+ ")"
    | rdec ";"
    | asm ";"
    | funcall ";"
+   | switch
    | if
    | while
    | for
-   | return ";"
 label: NAME ":"
 goto: "goto" NAME
 break: "break"
 continue: "continue"
+switch: "switch" "(" expr ")" "{" case+ default? "}"
+case: "case" atom2 ":" op*
+default: "default" ":" op+
 if: "if" "(" expr ")" op ("else" op)?
 while: "while" "(" expr ")" op
 for: "for" "(" vardec ";" expr ";" (inc|dec|rinc|rdec|vardec|funcall) ")" op
-return: "return" expr
+return: "return" expr?
 inc: NAME ("[" expr "]")? "++"
 dec: NAME ("[" expr "]")? "--"
 rinc: "++" NAME ("[" expr "]")?
@@ -94,18 +99,19 @@ args:
 ?op5: atom
     | op5 "[" op1 "]" -> index
 ?atom: "(" op1 ")"
-     | NAME
-     | INTEGER
-     | FLOAT
-     | CHAR
-     | STRING
-     | "-" atom -> negate
-     | array
+     | atom2
      | funcall
      | inc
      | dec
      | rinc
      | rdec
+?atom2: NAME
+      | INTEGER
+      | FLOAT
+      | CHAR
+      | STRING
+      | "-" atom -> negate
+      | array
 array: "{" atom ("," atom)* "}"
 
 NAME: /[A-Za-z_][a-zA-Z0-9_]*/
@@ -125,6 +131,53 @@ COM: /\/\*(.|\!)*\*\//
 def parse_escape(s):
   return bytes(s, "utf-8").decode("unicode_escape")
 
+class ASMWalker:
+  def __init__(self, asm):
+    self.asm = asm
+    self.pos = -1
+    self.size = len(asm)
+
+  def step(self):
+    if self.pos >= self.size:
+      return False
+
+    self.pos += 1
+
+    return True
+
+  def skip(self, offset):
+    for i in range(self.pos, self.pos+offset):
+      if i >= self.size:
+        break
+
+      self.asm[i] = f"#{self.asm[i]}"
+
+    #self.pos += offset
+
+  def match(self, offset, *args):
+    offset = self.pos + offset
+
+    if offset >= self.size:
+      return None
+
+    asm = self.asm[offset]
+    args = " ".join(args) 
+    
+    return re.match(f"^{args}$", asm)
+
+  def rule2(self, rule1, rule2, skip=2):
+    m = self.match(0, *rule1)
+    if m:
+      if self.match(1, *map(lambda s: s.format(m=m[1]), rule2)):
+        self.skip(skip)
+
+  def get(self):   
+    return self.asm[self.pos]
+
+  @property
+  def end(self):
+    return self.pos >= self.size
+
 class Buffer:
   def __init__(self, *init):
     self.buffer = list(init)
@@ -137,6 +190,28 @@ class Buffer:
     else:
       self.buffer.append(asm.format(*args))
 
+  def optimize(self):
+    buffer = Buffer()
+    walker = ASMWalker(self.buffer)
+
+    while walker.step():
+      walker.rule2(
+        ("jmp", "(.+)"),
+        ("{m}:",),
+        skip=1
+      )
+      walker.rule2(
+        ("push", "(.+)"),
+        ("pop {m}",)
+      )
+
+      if walker.end:
+        break
+
+      buffer.emit(walker.get())
+
+    return buffer
+
   def generate(self):
     return "\n".join(self.buffer)
 
@@ -950,14 +1025,16 @@ class WMC:
       )
     elif node.data == "break":
       if len(self.loops) < 1:
-        raise Exception("'break` outside of a loop.")
+        raise Exception("'break` outside of a loop/switch.")
+
+      labels = self.loops[-1]
 
       buffer.emit(
         "jmp {}",
-        self.loops[-1][1]
+        labels[0] if len(labels) == 1 else labels[1]
       )
     elif node.data == "continue":
-      if len(self.loops) < 1:
+      if len(self.loops) < 1 or len(self.loops[-1]) != 2:
         raise Exception("'continue` outside of a loop.")
 
       buffer.emit(
@@ -1016,18 +1093,92 @@ class WMC:
         self.compile_funcall(node, dest='ZZ')
       )
     elif node.data == "return":
-      buffer.emit(
-        self.compile_expr(
-          node.children[0]
+      if len(node.children) == 1:
+        buffer.emit(
+          self.compile_expr(
+            node.children[0]
+          )
         )
-      )
-
-      buffer.emit("push Y")
+        buffer.emit("push Y")
+      else:
+        buffer.emit("push Z")
+      
       buffer.emit("ret")
     elif node.data == "asm":
       buffer.emit(
         self.compile_asm(node)
       )
+    elif node.data == "switch":
+      default_label = self.make_label()
+      exit_label = self.make_label()
+
+      buffer.emit(
+        self.compile_expr(node.children[0])
+      )
+      buffer.emit(
+        "push Y"
+      )
+
+      self.loops.append((exit_label,))
+
+      labels = {}
+      for child in node.children[1:]:
+        if child.data == "default":
+          label = default_label
+
+          ops = child.children
+        else:
+          label = self.make_label()
+
+          buffer.emit(
+            self.compile_expr(child.children[0])
+          )
+          buffer.emit(
+            "peek X"
+          )
+          buffer.emit(
+            "sblez X Y !"
+          )
+          buffer.emit(
+            "nbnz Y {}",
+            label
+          )
+
+          ops = child.children[1:]
+        
+        subbuffer = Buffer()
+
+        for op in ops:
+          subbuffer.emit(
+            self.compile_op(op)
+          )
+
+        labels[label] = subbuffer
+
+      self.loops.pop()
+
+      buffer.emit(
+        "pop ZZ"
+      )
+      buffer.emit(
+        "jmp {}",
+        default_label if default_label in labels else exit_label
+      )
+
+      for name in labels:
+        buffer.emit(
+          "{}:",
+          name
+        )
+
+        buffer.emit(
+          labels[name]
+        )
+
+      buffer.emit(
+        "{}:",
+        exit_label
+      )
     elif node.data == "if":
       else_label = self.make_label()
       exit_label = self.make_label()
@@ -1319,6 +1470,8 @@ class WMC:
     if "main" not in self.funcs:
       raise Exception("Missing 'main` function.")
 
+    self.buffer = self.buffer.optimize()
+
     return self.buffer.generate() + "\n"
 
 wmc = WMC()

+ 14 - 0
langs/wmi/Dockerfile

@@ -0,0 +1,14 @@
+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/wm.c ./wm.c
+COPY ./wm/wma.py /usr/bin/wma
+RUN chmod +x /usr/bin/wma
+RUN chmod 705 /usr/bin/wma
+COPY ./wm/wmc.py /usr/bin/wmc
+RUN chmod +x /usr/bin/wmc
+RUN chmod 705 /usr/bin/wmc
+RUN gcc -Os -ansi wm.c -o /usr/bin/wm -lm
+RUN rm wm.c
+RUN chmod +x /usr/bin/wm
+RUN chmod 705 /usr/bin/wm

+ 2 - 0
langs/wmi/Dockerfile.user

@@ -0,0 +1,2 @@
+RUN mkdir /home/user/.wclib
+ADD wm/wclib /home/user/.wclib

+ 10 - 0
langs/wmi/run.sh

@@ -0,0 +1,10 @@
+IN="$(mktemp --suffix .wc)"
+OUT="$(mktemp --suffix .s)"
+
+cat > "$IN"
+
+WC_I="/home/user/.wclib" wmc "$IN" "$OUT"
+
+if [ $? -eq 0 ]; then
+  cat "$OUT"
+fi