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