txlyre 1 рік тому
батько
коміт
ef1b1f8798
4 змінених файлів з 129 додано та 26 видалено
  1. 19 0
      langs/wmc/wclib/stdio.wc
  2. 1 0
      langs/wmc/wclib/stdlib.wc
  3. 2 0
      langs/wmc/wma.py
  4. 107 26
      langs/wmc/wmc.py

+ 19 - 0
langs/wmc/wclib/stdio.wc

@@ -1,3 +1,22 @@
+gets(s, z) {
+  i;
+
+  while(1) {
+    if (i >= z-1)
+      break;
+
+    c = getc();
+    if (c < 0 || c == '\n')
+      break;
+
+    s[i++] = c;
+  }
+
+  s[i] = 0;
+
+  return s;
+}
+
 getc() {
   c;
 

+ 1 - 0
langs/wmc/wclib/stdlib.wc

@@ -0,0 +1 @@
+NULL=&-15;

+ 2 - 0
langs/wmc/wma.py

@@ -465,6 +465,8 @@ class WMA:
         self.add_label(reg)
         self.buffer.append(0)
 
+    self.add_label("END")
+
     self.compile_labels()
 
     return self.encode()

+ 107 - 26
langs/wmc/wmc.py

@@ -10,6 +10,7 @@ import lark
 GRAMMAR = r"""
 start: toplevel+
 ?toplevel: include
+         | define
          | funcdef
          | arrdec ";"
          | vardec ";"
@@ -17,7 +18,8 @@ start: toplevel+
          | arrinit ";"
          | asm ";"
 
-include: "#" "include" FILENAME 
+include: "#" "include" FILENAME
+define: "#" "define" NAME atom3
 FILENAME: "<" /.+/ ">"
 funcdef: NAME "(" params ")" block
 varinit: NAME
@@ -73,31 +75,41 @@ args:
     | [expr ("," expr)*]
 
 ?expr: op1
-     | op1 "?" op1 ":" expr -> ifexpr
+     | vardec
+     | arrdec
 ?op1: op2
-    | vardec
-    | arrdec
-    | op1 "==" op1 -> equals
-    | op1 "!=" op1 -> not_equals
-    | op1 "+" op2 -> plus
-    | op1 "-" op2 -> minus
+    | op2 "?" expr ":" op1 -> ifexpr
 ?op2: op3
-    | op2 "*" op2 -> times
-    | op2 "/" op3 -> divide
-    | op2 "%" op3 -> modulo
-    | op2 "<" op3 -> less
-    | op2 ">" op3 -> greater
-    | op2 "<=" op3 -> less_or_equals
-    | op2 ">=" op3 -> greater_or_equals
+    | op2 "||" op3 -> or
 ?op3: op4
-    | op3 "**" op4 -> raise
+    | op3 "&&" op4 -> and
 ?op4: op5
-    | op4 "||" op4 -> or
-    | op4 "&&" op4 -> and
-    | "!" atom -> not
-    | "*" atom -> deref
-?op5: atom
-    | op5 "[" op1 "]" -> index
+    | op4 "==" op5 -> equals
+    | op4 "!=" op5 -> not_equals
+?op5: op6
+    | op5 "<" op6 -> less
+    | op5 ">" op6 -> greater
+    | op5 "<=" op6 -> less_or_equals
+    | op5 ">=" op6 -> greater_or_equals
+?op6: op7
+    | op6 "+" op7 -> plus
+    | op6 "-" op7 -> minus
+?op7: op8
+    | op7 "*" op8 -> times
+    | op7 "/" op8 -> divide
+    | op7 "modulo" op8 -> divide
+?op8: op9
+    | op8 "**" op9 -> raise
+?op9: op10
+    | "*" op9 -> deref
+    | "&" op9 -> ref
+?op10: op11
+     | "!" op10 -> not 
+?op11: op12
+     | "-" op11 -> negate
+?op12: atom
+     | op12 "[" expr "]" -> index
+
 ?atom: "(" op1 ")"
      | atom2
      | funcall
@@ -112,6 +124,12 @@ args:
       | STRING
       | "-" atom -> negate
       | array
+?atom3: NAME
+      | INTEGER
+      | FLOAT
+      | CHAR
+      | STRING
+      | "-" (INTEGER|FLOAT) -> negate
 array: "{" atom ("," atom)* "}"
 
 NAME: /[A-Za-z_][a-zA-Z0-9_]*/
@@ -171,6 +189,12 @@ class ASMWalker:
       if self.match(1, *map(lambda s: s.format(m=m[1]), rule2)):
         self.skip(skip)
 
+  def rule3(self, rule1, rule2, rule3, skip=3):
+    m = self.match(0, *rule1)
+    if m:
+      if self.match(1, *map(lambda s: s.format(m=m[1]), rule2)) and self.match(2, *map(lambda s: s.format(m=m[1]), rule2)):
+        self.skip(skip)
+
   def get(self):   
     return self.asm[self.pos]
 
@@ -204,6 +228,12 @@ class Buffer:
         ("push", "(.+)"),
         ("pop {m}",)
       )
+      walker.rule3(
+        ("jmp", "(.+)"),
+        (".*:",),
+        ("{m}:",),
+        skip=1
+      )
 
       if walker.end:
         break
@@ -305,6 +335,8 @@ class WMC:
     self.scope = Scope()
     self.scope.new()
 
+    self.defined = {}
+
     self.compiled_funcs = {}
 
     self.arrays_buffer = Buffer()
@@ -366,10 +398,18 @@ class WMC:
 
     return name
 
-  def compile_literal(self, node):
+  def compile_literal(self, node, soft=False):
     if type(node) is lark.Token:
-      if node.type == "NAME":        
-        value = self.scope.find(node.value)
+      if node.type == "NAME":
+        name = node.value  
+
+        if name in self.defined:
+          return self.defined[name]
+
+        if soft:
+          return name
+
+        value = self.scope.find(name)
 
         self.record_usage(value)
 
@@ -759,6 +799,37 @@ class WMC:
           "la Y Y"
         )
       )
+    elif node.data == "ref":
+      value = node.children[0]
+
+      if type(value) is lark.Token and value.type == "NAME":
+        value = self.compile_literal(
+          value
+        )
+      else:
+        label = self.make_label()
+
+        self.arrays_buffer.emit(
+          "{}:0",
+          label
+        )
+
+        buffer.emit(
+          self.compile_expr(
+            node.children[0]
+          )
+        )
+        buffer.emit(
+          "mov Y {}",
+          label
+        )
+
+        value = label
+
+      buffer.emit(
+        "ld {} Y",
+        value
+      )
     elif node.data == "index":
       buffer.emit(
         self.compile_binary_expr(
@@ -1407,7 +1478,7 @@ class WMC:
           self.compile_program(f.read())
 
         self.included_files.add(filename)
-    elif node.data == "varinit":
+    elif node.data in ("varinit", "define"):
       pass
     else:
       raise Exception(f"Not implemented: {node}")
@@ -1433,6 +1504,16 @@ class WMC:
           raise Exception(f"Duplicated top-level variable declaration: '{name}`.")
 
         self.scope.insert(name) # Because we're at the top-level rn.
+      elif node.data == "define":
+        name = node.children[0].value
+        value = node.children[1]
+
+        if type(value) is lark.Tree and value.data == "negate":
+          value = "-" + self.compile_literal(value.children[0])
+        else:
+          value = self.compile_literal(value, soft=True)
+
+        self.defined[name] = value
 
   def compile_program(self, text):
     ast = self.parser.parse(text)