123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572 |
- #!/usr/bin/python
- import os
- import os.path
- import re
- import sys
- import lark
- GRAMMAR = r"""
- start: toplevel+
- ?toplevel: include
- | define
- | funcdef
- | arrdec ";"
- | vardec ";"
- | varinit ";"
- | arrinit ";"
- | asm ";"
- include: "#" "include" FILENAME
- define: "#" "define" NAME atom3
- 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 ";"
- | break ";"
- | continue ";"
- | vardec ";"
- | arrdec ";"
- | return ";"
- | varinit ";"
- | arrinit ";"
- | inc ";"
- | dec ";"
- | rinc ";"
- | rdec ";"
- | asm ";"
- | funcall ";"
- | switch
- | if
- | while
- | for
- 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?
- inc: NAME ("[" expr "]")? "++"
- dec: NAME ("[" expr "]")? "--"
- rinc: "++" NAME ("[" expr "]")?
- rdec: "--" NAME ("[" expr "]")?
- funcall: NAME "(" args ")"
- args:
- | [expr ("," expr)*]
- ?expr: op1
- | vardec
- | arrdec
- ?op1: op2
- | op2 "?" expr ":" op1 -> ifexpr
- ?op2: op3
- | op2 "||" op3 -> or
- ?op3: op4
- | op3 "&&" op4 -> and
- ?op4: op5
- | 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 "%" op8 -> modulo
- ?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
- | inc
- | dec
- | rinc
- | rdec
- ?atom2: NAME
- | INTEGER
- | FLOAT
- | CHAR
- | STRING
- | "-" atom -> negate
- | array
- ?atom3: NAME
- | INTEGER
- | FLOAT
- | CHAR
- | STRING
- | "-" (INTEGER|FLOAT) -> negate
- 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 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 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]
- @property
- def end(self):
- return self.pos >= self.size
- 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 optimize(self):
- buffer = Buffer()
- walker = ASMWalker(self.buffer)
- while walker.step():
- walker.rule2(
- ("jmp", "(.+)"),
- ("{m}:",),
- skip=1
- )
- walker.rule2(
- ("push", "(.+)"),
- ("pop {m}",)
- )
- walker.rule3(
- ("jmp", "(.+)"),
- (".*:",),
- ("{m}:",),
- skip=1
- )
- if walker.end:
- break
- buffer.emit(walker.get())
- return buffer
- 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.defined = {}
- 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)
- self.loops = []
- 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, soft=False):
- if type(node) is lark.Token:
- 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)
- 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 == "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(
- 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":
- if len(node.children) == 2:
- raise Exception(f"Not implemented: {node}")
- name = self.scope[node.children[0].value]
- self.record_usage(name)
- buffer.emit(
- "mov {} Y",
- name
- )
- buffer.emit(
- "inc {}",
- name
- )
- elif node.data == "dec":
- if len(node.children) == 2:
- raise Exception(f"Not implemented: {node}")
- name = self.scope[node.children[0].value]
- self.record_usage(name)
- buffer.emit(
- "mov {} Y"
- )
- buffer.emit(
- "dec {}",
- name
- )
- elif node.data == "rinc":
- if len(node.children) == 2:
- raise Exception(f"Not implemented: {node}")
- name = self.scope[node.children[0].value]
- self.record_usage(name)
- buffer.emit(
- "inc {}",
- name
- )
- buffer.emit(
- "mov {} Y",
- name
- )
- elif node.data == "rdec":
- if len(node.children) == 2:
- raise Exception(f"Not implemented: {node}")
- 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')
- )
- elif node.data == "vardec":
- buffer.emit(
- self.compile_op(node)
- )
- elif node.data == "arrdec":
- buffer.emit(
- self.compile_arrdec(node)
- )
- 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 == "break":
- if len(self.loops) < 1:
- raise Exception("'break` outside of a loop/switch.")
- labels = self.loops[-1]
- buffer.emit(
- "jmp {}",
- labels[0] if len(labels) == 1 else labels[1]
- )
- elif node.data == "continue":
- if len(self.loops) < 1 or len(self.loops[-1]) != 2:
- raise Exception("'continue` outside of a loop.")
- buffer.emit(
- "jmp {}",
- self.loops[-1][0]
- )
- 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"):
- if len(node.children) == 2:
- raise Exception(f"Not implemented: {node}")
- name = self.scope[node.children[0].value]
- self.record_usage(name)
- buffer.emit(
- "inc {}",
- name
- )
- elif node.data == ("dec", "rdec"):
- if len(node.children) == 2:
- raise Exception(f"Not implemented: {node}")
- 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":
- if len(node.children) == 1:
- buffer.emit(
- self.compile_expr(
- node.children[0]
- )
- )
- 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()
- 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()
- self.loops.append((loop_label, exit_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]
- )
- )
- self.loops.pop()
- buffer.emit(
- "jmp {}",
- loop_label
- )
- buffer.emit(
- "{}:",
- exit_label
- )
- elif node.data == "for":
- loop_label = self.make_label()
- exit_label = self.make_label()
- self.loops.append((loop_label, exit_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()
- self.loops.pop()
- 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 in ("varinit", "define"):
- 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.
- 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)
- #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.")
- self.buffer = self.buffer.optimize()
- 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)
|