1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279 |
- import os
- import os.path
- import sys
- import lark
- GRAMMAR = r"""
- start: toplevel+
- ?toplevel: include
- | funcdef
- | arrdec ";"
- | vardec ";"
- | varinit ";"
- | arrinit ";"
- | asm ";"
- include: "#" "include" FILENAME
- FILENAME: "<" /.+/ ">"
- funcdef: NAME "(" params ")" block
- varinit: NAME
- arrinit: NAME "[" INTEGER "]"
- vardec: NAME "=" expr
- arrdec: NAME "[" expr "]" ("=" expr)?
- params:
- | NAME ("," NAME)*
- block: "{" op* "}"
- asm: "asm" "(" STRING+ ")"
- ?op: block
- | label
- | goto ";"
- | vardec ";"
- | arrdec ";"
- | varinit ";"
- | arrinit ";"
- | inc ";"
- | dec ";"
- | rinc ";"
- | rdec ";"
- | asm ";"
- | funcall ";"
- | if
- | while
- | for
- | return ";"
- label: NAME ":"
- goto: "goto" NAME
- if: "if" "(" expr ")" op ("else" op)?
- while: "while" "(" expr ")" op
- for: "for" "(" vardec ";" expr ";" (inc|dec|vardec|funcall) ")" op
- return: "return" expr
- inc: NAME "++"
- dec: NAME "--"
- rinc: "++" NAME
- rdec: "--" NAME
- funcall: NAME "(" args ")"
- args:
- | [expr ("," expr)*]
- ?expr: op1
- | op1 "?" op1 ":" expr -> ifexpr
- ?op1: op2
- | vardec
- | op1 "==" op1 -> equals
- | op1 "!=" op1 -> not_equals
- | op1 "+" op2 -> plus
- | op1 "-" op2 -> minus
- ?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
- ?op3: op4
- | op3 "**" op4 -> raise
- ?op4: op5
- | op4 "||" op4 -> or
- | op4 "&&" op4 -> and
- | "!" atom -> not
- | "*" atom -> deref
- ?op5: atom
- | op5 "[" op1 "]" -> index
- ?atom: "(" op1 ")"
- | NAME
- | INTEGER
- | FLOAT
- | CHAR
- | STRING
- | "-" atom -> negate
- | array
- | funcall
- | inc
- | dec
- | rinc
- | rdec
- array: "{" atom ("," atom)* "}"
- NAME: /[A-Za-z_][a-zA-Z0-9_]*/
- INTEGER: /[0-9]+/
- FLOAT: /[0-9]+\.[0-9]+/
- CHAR: /'(.|(\\.))'/
- _STRING_INNER: /(.|\n)*?/
- _STRING_ESC_INNER: _STRING_INNER /(?<!\\)(\\\\)*?/
- STRING: "\"" _STRING_ESC_INNER "\""
- IG: /[ \t\r\n]+/
- COM: /\/\*(.|\!)*\*\//
- %ignore IG
- %ignore COM
- """
- def parse_escape(s):
- return bytes(s, "utf-8").decode("unicode_escape")
- class Buffer:
- def __init__(self, *init):
- self.buffer = list(init)
- def emit(self, asm, *args):
- if type(asm) is list:
- self.buffer.extend(asm)
- elif type(asm) is Buffer:
- self.buffer.extend(asm.buffer)
- else:
- self.buffer.append(asm.format(*args))
- def generate(self):
- return "\n".join(self.buffer)
- def __add__(self, other):
- if type(other) is Buffer:
- return Buffer(
- *self.buffer + other.buffer
- )
- raise TypeError
- class Scope:
- def __init__(self):
- self.scopes = []
- self.ndx = 0
- self.names = set()
- def new(self):
- self.scopes.append((self.ndx, {}, {}))
- self.ndx += 1
- def leave(self):
- self.scopes.pop()
- def add_label(self, name):
- renamed = f"__{self.scopes[-1][0]}l_{name}"
- self.scopes[-1][2][name] = renamed
- return renamed
- def get_label(self, name):
- if name not in self.scopes[-1][2]:
- raise Exception(f"Undeclared label: '{name}`.")
- return self.scopes[-1][2][name]
- def is_local(self, name):
- return name in self.scopes[-1][1]
- def insert(self, name):
- renamed = f"__{self.scopes[-1][0]}_{name}"
- self.scopes[-1][1][name] = renamed
- self.names.add(renamed)
- return renamed
- def find(self, name):
- for _, scope, _ in self.scopes[::-1]:
- if name in scope:
- return scope[name]
- raise Exception(f"Undeclared identifier: '{name}`.")
- def __contains__(self, name):
- for _, scope, _ in self.scopes[::-1]:
- if name in scope:
- return True
- return False
- def __getitem__(self, name):
- if name in self:
- return self.find(name)
- return self.insert(name)
- def __iter__(self):
- for _, scope, _ in self.scopes[::-1]:
- for name in scope:
- yield (name, scope[name])
- @property
- def is_toplevel(self):
- return self.scopes[-1][0] == 0
- class Func:
- def __init__(self, argc, params):
- self.argc = argc
- self.params = params
- class WMC:
- def __init__(self):
- self.funcs = {}
- self.used_symbols = {}
- self.where = "toplevel"
- self.scope = Scope()
- self.scope.new()
- self.compiled_funcs = {}
- self.arrays_buffer = Buffer()
- self.init_buffer = Buffer()
- self.buffer = Buffer(
- "jw __main",
- "pop Y",
- "mov 80 _dirBuf",
- "mov Y _dirBuf+1",
- "dir _dirBuf",
- "hlt",
- "_dirBuf:0*4",
- )
- self.label_ndx = 0
- self.included_files = set()
- self.parser = lark.Lark(GRAMMAR)
- def record_usage(self, name):
- if name in self.used_symbols:
- self.used_symbols[name].add(self.where)
- else:
- self.used_symbols[name] = set([self.where])
- def is_used(self, name):
- if name in ("main", "toplevel"):
- return True
- if name not in self.used_symbols:
- return False
- for other in self.used_symbols[name]:
- if other == name:
- continue
- if self.is_used(other):
- return True
- return False
- def make_label(self):
- name = f"__{self.label_ndx}l"
- self.label_ndx += 1
- return name
- def make_array(self, value):
- name = self.make_label()
- self.arrays_buffer.emit(
- "{}:{}",
- name, value
- )
- return name
- def compile_literal(self, node):
- if type(node) is lark.Token:
- if node.type == "NAME":
- value = self.scope.find(node.value)
- self.record_usage(value)
- return value
- elif node.type in ("INTEGER", "FLOAT"):
- return node.value
- elif node.type == "CHAR":
- return str(ord(parse_escape(node.value[1:-1])))
- elif node.type == "STRING":
- value = parse_escape(node.value[1:-1])
- value = map(ord, value)
- value = map(str, value)
- value = " ".join(value)
- value += " 0"
- return value
- elif node.data == "array":
- value = []
- for child in node.children:
- value.append(
- self.compile_literal(child)
- )
- return " ".join(value)
- raise Exception(f"Not implemented: {node}")
- def compile_unary_expr(self, node, *ops):
- buffer = Buffer()
- buffer.emit(
- self.compile_expr(
- node.children[0]
- )
- )
- for op in ops:
- buffer.emit(op)
- return buffer
- def compile_binary_expr(self, node):
- buffer = Buffer()
- buffer.emit(
- self.compile_expr(
- node.children[0]
- )
- )
- buffer.emit('push Y')
- buffer.emit(
- self.compile_expr(
- node.children[1]
- )
- )
- buffer.emit('push Y')
- buffer.emit('pop X')
- buffer.emit('pop Y')
- return buffer
- def compile_compare_expr(self, node, *ops, true='1', false='0'):
- buffer = Buffer()
- ret_label = self.make_label()
- exit_label = self.make_label()
- buffer.emit(
- self.compile_binary_expr(
- node
- )
- )
- for op in ops:
- buffer.emit(
- op,
- ret_label
- )
- buffer.emit(
- "mov {} Y",
- false
- )
- buffer.emit(
- "jmp {}",
- exit_label
- )
- buffer.emit(
- "{}:",
- ret_label
- )
- buffer.emit(
- "mov {} Y",
- true
- )
- buffer.emit(
- "{}:",
- exit_label
- )
- return buffer
- def compile_expr(self, node):
- buffer = Buffer()
- if type(node) is lark.Token:
- if node.type == "NAME":
- buffer.emit(
- "mov {} Y",
- self.compile_literal(node)
- )
- elif node.type in ("INTEGER", "FLOAT"):
- buffer.emit(
- "mov {} Y",
- self.compile_literal(node)
- )
- elif node.type == "CHAR":
- buffer.emit(
- "mov {} Y",
- self.compile_literal(node)
- )
- elif node.type == "STRING":
- buffer.emit(
- "ld {} Y",
- self.make_array(
- self.compile_literal(node)
- )
- )
- else:
- raise Exception(f"Not implemented: {node}")
- elif node.data == "ifexpr":
- else_label = self.make_label()
- exit_label = self.make_label()
- buffer.emit(
- self.compile_expr(
- node.children[0]
- )
- )
- buffer.emit(
- "nbnz Y {}",
- else_label
- )
- buffer.emit(
- self.compile_expr(
- node.children[1]
- )
- )
- buffer.emit(
- "jmp {}",
- exit_label
- )
- buffer.emit(
- "{}:",
- else_label
- )
- buffer.emit(
- self.compile_expr(
- node.children[2]
- )
- )
- buffer.emit(
- "{}:",
- exit_label
- )
- elif node.data == "equals":
- buffer.emit(
- self.compile_compare_expr(
- node,
- "sblez X Y !",
- "nbnz Y {}",
- true='1',
- false='0'
- )
- )
- elif node.data == "not_equals":
- buffer.emit(
- self.compile_compare_expr(
- node,
- "sblez X Y !",
- "nbnz Y {}",
- true='0',
- false='1'
- )
- )
- elif node.data == "plus":
- buffer.emit(
- self.compile_binary_expr(
- node
- )
- )
- buffer.emit(
- "ablez X Y !"
- )
- elif node.data == "minus":
- buffer.emit(
- self.compile_binary_expr(
- node
- )
- )
- buffer.emit(
- "sblez X Y !"
- )
- elif node.data == "times":
- buffer.emit(
- self.compile_binary_expr(
- node
- )
- )
- buffer.emit(
- "mbnz X Y !"
- )
- elif node.data == "divide":
- buffer.emit(
- self.compile_binary_expr(
- node
- )
- )
- buffer.emit(
- "vblz X Y !"
- )
- elif node.data == "modulo":
- buffer.emit(
- self.compile_binary_expr(
- node
- )
- )
- buffer.emit(
- "modbz X Y !"
- )
- elif node.data == "raise":
- buffer.emit(
- self.compile_binary_expr(
- node
- )
- )
- buffer.emit(
- "mov 12 _dirBuf"
- )
- buffer.emit(
- "mov X _dirBuf+1"
- )
- buffer.emit(
- "mov Y _dirBuf+2"
- )
- buffer.emit(
- "dir _dirBuf"
- )
- buffer.emit(
- "mov _dirBuf+2 Y"
- )
- elif node.data == "or":
- true_label = self.make_label()
- exit_label = self.make_label()
- buffer.emit(
- self.compile_expr(
- node.children[0]
- )
- )
- buffer.emit(
- "nbnz Y !"
- )
- buffer.emit(
- "nbnz Y {}",
- true_label
- )
- buffer.emit(
- self.compile_expr(
- node.children[1]
- )
- )
- buffer.emit(
- "jmp {}",
- exit_label
- )
- buffer.emit(
- "{}:",
- true_label
- )
- buffer.emit(
- "mov 1 Y"
- )
- buffer.emit(
- "{}:",
- exit_label
- )
- elif node.data == "and":
- false_label = self.make_label()
- exit_label = self.make_label()
- buffer.emit(
- self.compile_expr(
- node.children[0]
- )
- )
- buffer.emit(
- "nbnz Y {}",
- false_label
- )
- buffer.emit(
- self.compile_expr(
- node.children[1]
- )
- )
- buffer.emit(
- "jmp {}",
- exit_label
- )
- buffer.emit(
- "{}:",
- false_label
- )
- buffer.emit(
- "mov 0 Y"
- )
- buffer.emit(
- "{}:",
- exit_label
- )
- elif node.data == "less":
- buffer.emit(
- self.compile_compare_expr(
- node,
- "inc Y",
- "sblez X Y {}"
- )
- )
- elif node.data == "greater":
- buffer.emit(
- self.compile_compare_expr(
- node,
- "dec Y",
- "sblez X Y {}",
- true='0',
- false='1'
- )
- )
- elif node.data == "less_or_equals":
- buffer.emit(
- self.compile_compare_expr(
- node,
- "sblez X Y {}"
- )
- )
- elif node.data == "greater_or_equals":
- buffer.emit(
- self.compile_compare_expr(
- node,
- "inc Y",
- "sblez X Y {}",
- true='0',
- false='1'
- )
- )
- elif node.data == "not":
- buffer.emit(
- self.compile_unary_expr(
- node,
- "nbnz Y !"
- )
- )
- elif node.data == "deref":
- buffer.emit(
- self.compile_unary_expr(
- node,
- "la Y Y"
- )
- )
- elif node.data == "index":
- buffer.emit(
- self.compile_binary_expr(
- node
- )
- )
- buffer.emit(
- "ablez X Y !"
- )
- buffer.emit(
- "la Y Y"
- )
- elif node.data == "negate":
- buffer.emit(
- self.compile_unary_expr(
- node,
- "mov Y X",
- "sblez X Y !",
- "sblez X Y !",
- )
- )
- elif node.data == "array":
- buffer.emit(
- "ld {} Y",
- self.make_array(
- self.compile_literal(node)
- )
- )
- elif node.data == "inc":
- name = self.scope[node.children[0].value]
- self.record_usage(name)
- buffer.emit(
- "mov {} Y",
- name
- )
- buffer.emit(
- "inc {}",
- name
- )
- elif node.data == "dec":
- name = self.scope[node.children[0].value]
- self.record_usage(name)
- buffer.emit(
- "mov {} Y"
- )
- buffer.emit(
- "dec {}",
- name
- )
- elif node.data == "rinc":
- name = self.scope[node.children[0].value]
- self.record_usage(name)
- buffer.emit(
- "inc {}",
- name
- )
- buffer.emit(
- "mov {} Y",
- name
- )
- elif node.data == "rdec":
- name = self.scope[node.children[0].value]
- self.record_usage(name)
- buffer.emit(
- "dec {}",
- name
- )
- buffer.emit(
- "mov {} Y"
- )
- elif node.data == "funcall":
- buffer.emit(
- self.compile_funcall(node, dest='Y')
- )
- else:
- raise Exception(f"Not implemented: {node}")
- return buffer
- def compile_funcall(self, node, dest='Y'):
- buffer = Buffer()
- name = node.children[0].value
- if name not in self.funcs:
- raise Exception(f"Call to an undeclared function: '{name}`.")
- if self.funcs[name].argc != len(node.children[1].children):
- raise Exception(f"Function '{name}` expects {self.funcs[name].argc} arguments, but got {node.children[1].children}.")
- for arg in node.children[1].children[::-1]:
- buffer.emit(
- self.compile_expr(arg)
- )
- buffer.emit(
- "push Y"
- )
- buffer.emit(
- "jw __{}",
- name
- )
- buffer.emit(
- "pop {}",
- dest
- )
- self.record_usage(name)
- return buffer
- def compile_asm(self, node):
- buffer = Buffer()
- table = {}
- for name, renamed in self.scope:
- table[name] = renamed
- for child in node.children:
- value = parse_escape(child.value[1:-1])
- for name in table:
- if f"{{{name}}}" in value:
- self.record_usage(table[name])
- try:
- value = value.format(
- **table
- )
- except:
- raise Exception("Malformed asm directive.")
- buffer.emit(value)
- return buffer
- def compile_arrdec(self, node):
- buffer = Buffer()
- name = node.children[0].value
- if name in self.scope and len(node.children) == 3: # Index assignment.
- name = self.scope.find(name)
- self.record_usage(name)
- buffer.emit(
- self.compile_expr(
- node.children[1]
- )
- )
- buffer.emit(
- "mov {} X",
- name
- )
- buffer.emit(
- "ablez X Y !"
- )
- buffer.emit(
- "push Y"
- )
- buffer.emit(
- self.compile_expr(
- node.children[2]
- )
- )
- buffer.emit(
- "pop X"
- )
- buffer.emit(
- "str Y X"
- )
- return buffer
- if not self.scope.is_toplevel and self.scope.is_local(name):
- raise Exception(f"Duplicated declaration of a local variable: '{node.children[0].value}`.")
- name = self.scope[name]
- self.record_usage(name)
- count = int(node.children[1].value)
- if count <= 0:
- raise Exception(f"Illegal array declaration '{node.children[0].value}`: array size should be >0, but it is {count}.")
- if len(node.children) == 3:
- value = self.compile_literal(node.children[2])
- size = len(value.split(" ")) # Dirty.
- if size < count:
- value += f" 0*{count-size}"
- elif size != count:
- raise Exception(f"Illegal array declaration '{node.children[0].value}`: value size is {size}, but expected {count}.")
- buffer.emit(
- "ld {} Y",
- self.make_array(value)
- )
- else:
- buffer.emit(
- "ld {} Y",
- self.make_array(f"0*{count}")
- )
- buffer.emit(
- "mov Y {}",
- name
- )
- return buffer
- def compile_op(self, node):
- buffer = Buffer()
- if node.data == "block":
- buffer.emit(
- self.compile_block(
- node
- )
- )
- elif node.data == "label":
- buffer.emit(
- "{}:",
- self.scope.get_label(node.children[0].value)
- )
- elif node.data == "goto":
- buffer.emit(
- "jmp {}",
- self.scope.get_label(node.children[0].value)
- )
- elif node.data == "varinit":
- name = node.children[0].value
- if self.scope.is_local(name):
- raise Exception(f"Duplicated declaration of a local variable: '{name}`.")
-
- self.scope.insert(name)
- elif node.data == "vardec":
- name = self.scope[node.children[0].value]
- self.record_usage(name)
- buffer.emit(
- self.compile_expr(node.children[1])
- )
- buffer.emit(
- "mov Y {}",
- name
- )
- elif node.data in ("arrdec", "arrinit"):
- buffer.emit(
- self.compile_arrdec(node)
- )
- elif node.data in ("inc", "rinc"):
- name = self.scope[node.children[0].value]
- self.record_usage(name)
- buffer.emit(
- "inc {}",
- name
- )
- elif node.data == ("dec", "rdec"):
- name = self.scope[node.children[0].value]
- self.record_usage(name)
- buffer.emit(
- "dec {}",
- name
- )
- elif node.data == "funcall":
- buffer.emit(
- self.compile_funcall(node, dest='ZZ')
- )
- elif node.data == "return":
- buffer.emit(
- self.compile_expr(
- node.children[0]
- )
- )
- buffer.emit("push Y")
- buffer.emit("ret")
- elif node.data == "asm":
- buffer.emit(
- self.compile_asm(node)
- )
- elif node.data == "if":
- else_label = self.make_label()
- exit_label = self.make_label()
- buffer.emit(
- self.compile_expr(
- node.children[0]
- )
- )
- buffer.emit(
- "nbnz Y {}",
- else_label
- )
- buffer.emit(
- self.compile_op(
- node.children[1]
- )
- )
- buffer.emit(
- "jmp {}",
- exit_label
- )
- buffer.emit(
- "{}:",
- else_label
- )
- if len(node.children) == 3:
- buffer.emit(
- self.compile_op(
- node.children[2]
- )
- )
- buffer.emit(
- "{}:",
- exit_label
- )
- elif node.data == "while":
- loop_label = self.make_label()
- exit_label = self.make_label()
- buffer.emit(
- "{}:",
- loop_label
- )
- buffer.emit(
- self.compile_expr(
- node.children[0]
- )
- )
- buffer.emit(
- "nbnz Y {}",
- exit_label
- )
- buffer.emit(
- self.compile_op(
- node.children[1]
- )
- )
- buffer.emit(
- "jmp {}",
- loop_label
- )
- buffer.emit(
- "{}:",
- exit_label
- )
- elif node.data == "for":
- loop_label = self.make_label()
- exit_label = self.make_label()
- self.scope.new()
- buffer.emit(
- self.compile_op(
- node.children[0]
- )
- )
- buffer.emit(
- "{}:",
- loop_label
- )
- buffer.emit(
- self.compile_expr(
- node.children[1]
- )
- )
- buffer.emit(
- "nbnz Y {}",
- exit_label
- )
- buffer.emit(
- self.compile_op(
- node.children[3]
- )
- )
- buffer.emit(
- self.compile_op(
- node.children[2]
- )
- )
- self.scope.leave()
- buffer.emit(
- "jmp {}",
- loop_label
- )
- buffer.emit(
- "{}:",
- exit_label
- )
- else:
- raise Exception(f"Not implemented: {node}")
- return buffer
- def collect_labels(self, node):
- for child in node.children:
- if child.data == "label":
- self.scope.add_label(child.children[0].value)
- def compile_block(self, node, *prepend_names, scope=True):
- if scope:
- self.scope.new()
- for name in prepend_names:
- self.scope.insert(name)
- buffer = Buffer()
- self.collect_labels(node)
- for child in node.children:
- buffer.emit(
- self.compile_op(child)
- )
- if scope:
- self.scope.leave()
- return buffer
- def compile_toplevel(self, node):
- buffer = Buffer()
- if node.data == "funcdef":
- name = node.children[0].value
- params = self.funcs[name].params
- buffer.emit("__{}:", name)
- for param in params:
- buffer.emit(
- "pop __{}_{}",
- self.scope.ndx, param
- )
- self.where = name
- buffer.emit(
- self.compile_block(
- node.children[2],
- *params
- )
- )
- buffer.emit(
- "push Z"
- )
- buffer.emit(
- "ret"
- )
- elif node.data == "vardec":
- name = node.children[0].value
- self.init_buffer.emit(
- self.compile_expr(node.children[1])
- )
- self.init_buffer.emit(
- "mov Y __0_{}",
- name
- )
- self.record_usage(f"__0__{name}")
- elif node.data in ("arrdec", "arrinit"):
- self.init_buffer.emit(
- self.compile_arrdec(node)
- )
- elif node.data == "asm":
- buffer.emit(
- self.compile_asm(node)
- )
- elif node.data == "include":
- filename = node.children[0].value[1:-1]
- if not os.path.isfile(filename):
- filename = os.path.join(os.getenv("WC_I"), filename)
- if not os.path.isfile(filename):
- raise Exception(f"No such file: '{os.path.basename(filename)}`.")
- if filename not in self.included_files:
- with open(filename, "r") as f:
- self.compile_program(f.read())
- self.included_files.add(filename)
- elif node.data == "varinit":
- pass
- else:
- raise Exception(f"Not implemented: {node}")
- return buffer
- def collect_toplevel(self, ast):
- for node in ast.children:
- if node.data == "funcdef":
- name = node.children[0].value
- if name in self.funcs:
- raise Exception(f"Duplicated function declaration: '{name}`.")
- self.funcs[name] = Func(
- len(node.children[1].children),
- tuple(map(lambda t: t.value, node.children[1].children))
- )
- elif node.data in ("varinit", "vardec", "arrinit", "arrdec"):
- name = node.children[0].value
- if name in self.scope:
- raise Exception(f"Duplicated top-level variable declaration: '{name}`.")
- self.scope.insert(name) # Because we're at the top-level rn.
- def compile_program(self, text):
- ast = self.parser.parse(text)
- #print(ast.pretty())
- self.collect_toplevel(ast)
- for node in ast.children:
- buffer = self.compile_toplevel(node)
- if node.data == "funcdef":
- self.compiled_funcs[node.children[0].value] = buffer
- else:
- self.buffer.emit(buffer)
- def compile(self, text):
- self.compile_program(text)
- for name in self.compiled_funcs:
- if self.is_used(name):
- self.buffer.emit(self.compiled_funcs[name])
- for param in self.funcs[name].params:
- self.record_usage(param)
- self.buffer = self.init_buffer + self.buffer + self.arrays_buffer
- for name in self.scope.names:
- if self.is_used(name):
- self.buffer.emit(
- "{}:0", name
- )
- if "main" not in self.funcs:
- raise Exception("Missing 'main` function.")
- return self.buffer.generate() + "\n"
- wmc = WMC()
- try:
- if len(sys.argv) == 3:
- with open(sys.argv[1], "r") as fin:
- with open(sys.argv[2], "w") as fout:
- fout.write(wmc.compile(fin.read()))
- else:
- sys.stdout.write(wmc.compile(sys.stdin.read()))
- except Exception as e:
- #__import__('traceback').print_exc()
- print(e)
- sys.exit(1)
|