|
@@ -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()
|