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