ソースを参照

Added BS compiler

Implemented BS compiler. Fixed asm compiler jump references in asm
compiler.
Min 6 年 前
コミット
c49e82bd6d
2 ファイル変更137 行追加8 行削除
  1. 22 8
      tools/asm_compiler.py
  2. 115 0
      tools/bs_compiler.py

+ 22 - 8
tools/asm_compiler.py

@@ -25,7 +25,7 @@ def decode_byte(val: str):
         if i > 127 or i < -128:
             raise ValueError(f"Invalid binary '{val}', signed int out of bounds")
         if i < 0:  # convert to unsigned
-            i += 2**8
+            i += 2 ** 8
         return i
     if len(val) == 3 and ((val[0] == "'" and val[2] == "'") or (val[0] == '"' and val[2] == '"')):
         return ord(val[1])
@@ -74,9 +74,10 @@ def assemble(file):
                 failed = True
                 continue
             if ref in refs:
-                print(f"{file}:{lnum}: Pointer reference '{ref}' is duplicated with {file}:{refs[ref][0]}")
-                failed = True
-                continue
+                if refs[ref][1] is not None:
+                    print(f"{file}:{lnum}: Pointer reference '{ref}' is duplicated with {file}:{refs[ref][0]}")
+                    failed = True
+                    continue
             refs[ref] = [lnum, len(odata)]
             line = rsplit[1]
         line = line.replace('\n', '').replace('\r', '').replace('\t', '')
@@ -225,6 +226,20 @@ def assemble(file):
     return not failed, odata
 
 
+def readable_size(num, disp_bytes=True):
+    num = abs(num)
+    if num < 1024 and disp_bytes:
+        return "[%3.0fB]" % num
+    if num < 1024 and not disp_bytes:
+        return ""
+    num /= 1024.0
+    for unit in ['Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
+        if abs(num) < 1024.0:
+            return "[%3.1f%sB]" % (num, unit)
+        num /= 1024.0
+    return "[%.1f%sB]" % (num, 'Yi')
+
+
 if __name__ == '__main__':
     parser = argparse.ArgumentParser(description='Assembly compiler', add_help=True)
     parser.add_argument('file', help='Files to compile')
@@ -253,19 +268,18 @@ if __name__ == '__main__':
     success, data = assemble(args.file)
     if success:
         print(f"Saving {args.output_type} data to {output}")
+        print(f"Program size: {len(data)}B {readable_size(len(data), False)}")
         with open(output, 'wb') as of:
             if args.output_type == 'binary':
                 a = '\n'.join([format(i, '08b') for i in data])
                 of.write(a.encode())
             elif args.output_type == 'mem':
                 a = [format(i, '02x') for i in data]
-                for i in range(int(len(a)/8)+1):
-                    of.write((' '.join(a[i*8:(i+1)*8]) + '\n').encode())
+                for i in range(int(len(a) / 8) + 1):
+                    of.write((' '.join(a[i * 8:(i + 1) * 8]) + '\n').encode())
             elif args.output_type == 'bin':
                 of.write(bytes(data))
     else:
         print(f'Failed to compile {args.file}!')
         sys.exit(1)
     sys.exit(0)
-
-

+ 115 - 0
tools/bs_compiler.py

@@ -0,0 +1,115 @@
+#!/usr/bin/python3
+
+import argparse
+import sys
+from os import path
+
+
+ch_add      = {'+'}
+ch_sub      = {'-'}
+ch_left     = {'<'}
+ch_right    = {'>'}
+ch_print    = {'.'}
+ch_start    = {'['}
+ch_stop     = {']'}
+
+def compileBF(filename):
+    program = []
+    # Init program
+    # $ra: Current value
+    # $rb: ??
+    # $rc: Memory pointer
+    # $re: The +/- 1 value
+
+    program.append("CPY $rc 0xFF")
+    program.append("CPY $re 1")
+    program.append("memInitStart:")
+    program.append("JEQ $ra $rc memInitFinish")
+    program.append("SW $rb $ra")
+    program.append("ADD $ra $re")
+    program.append("JMP memInitStart")
+    program.append("memInitFinish:")
+    program.append("CPY $rb 0")
+    program.append("CPY $ra $rb")
+    program.append("CPY $rc $rb")
+
+    f = open(filename, 'r')
+    pc = 0
+    nc = 0
+    lc = 0
+    rc = 0
+    nodePrev = []
+    nodeCount = 0
+    while 1:
+        c = f.read(1)
+        if c == '':
+            break
+        if c in ch_add:
+            pc += 1
+        elif pc > 0:
+            program.append(f"CPY $re {pc}")
+            pc = 0
+            program.append("ADD $ra $re")
+
+        if c in ch_sub:
+            nc += 1
+        elif nc > 0:
+            program.append(f"CPY $re {nc}")
+            nc = 0
+            program.append("SUB $ra $re")
+
+        if c in ch_right:
+            rc += 1
+        elif rc > 0:
+            program.append("SW $ra $rc")
+            program.append(f"CPY $re {rc}")
+            program.append("ADD $rc $re")
+            program.append("LW $ra $rc")
+            rc = 0
+
+        if c in ch_left:
+            lc += 1
+        elif lc > 0:
+            program.append("SW $ra $rc")
+            program.append(f"CPY $re {lc}")
+            program.append("SUB $rc $re")
+            program.append("LW $ra $rc")
+            lc = 0
+
+        if c in ch_print:
+            program.append("CPY $re 0xFF")
+            program.append("SW $ra $re")
+
+        if c in ch_start:
+            nodePrev.append(nodeCount)
+            program.append(f"node{nodeCount:04d}s:")
+            program.append(f"JEQ $ra $rb node{nodeCount:04d}e")
+            nodeCount += 1
+
+        if c in ch_stop:
+            node = nodePrev.pop(-1)
+            program.append(f"JMP node{node:04d}s")
+            program.append(f"node{node:04d}e:")
+
+    f.close()
+    return program
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description='Assembly compiler', add_help=True)
+    parser.add_argument('file', help='Files to compile')
+    # parser.add_argument('-t', '--output_type', choices=['asm', 'mem', 'binary'], default='mem', help='Output type')
+    parser.add_argument('-o', '--output', help='Output file')
+    parser.add_argument('-f', '--force', action='store_true', help='Force override output file')
+    args = parser.parse_args(sys.argv[1:])
+    if not path.isfile(args.file):
+        print(f'No file {args.file}!')
+        sys.exit(1)
+    asm = compileBF(args.file)
+    data = '\n'.join(asm)
+    if args.output and (not path.isfile(args.output) or args.force):
+        with open(args.output, 'w') as o:
+            o.write(data)
+    elif args.output is None:
+        print(data)
+