Created
April 28, 2017 12:56
-
-
Save jrialland/e0d370034da9c7b1b76a8afccbea7424 to your computer and use it in GitHub Desktop.
Whitespace assembler in python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys,re | |
""" | |
+--+-----------+------------------+-------------------------------------------------------------+ | |
| | OPCODE | OPERAND | DESCRIPTION | | |
+--+-----------+------------------+-------------------------------------------------------------+ | |
| | push | signed-number | Push a number onto the stack | | |
| | dup | | Push top of stack into the stack again | | |
| | swap | | Swap two topmost numbers on stack | | |
| | pop | | Pop & discard number on top of stack | | |
| | add | | Pop two numbers,add,push result | | |
| | sub | | Pop two numbers,subtract,push result | | |
| | mul | | Pop two numbers,multiply,push result | | |
| | div | | Pop two numbers,integer divide,push result | | |
| | mod | | Pop two numbers,modulo,push result | | |
| | store | | Pop value and address; store value on heap at that address | | |
| | load | | Pop address; push onto stack the heap value at that address | | |
| | label | unsigned-number | Target for other flow-control ops | | |
| | call | unsigned-number | Call subroutine | | |
| | jump | unsigned-number | Unconditional jump | | |
| | jz | unsigned-number | Pop top of stack; jump if it's zero | | |
| | jn | unsigned-number | Pop top of stack; jump if it's negative | | |
| | ret | | Return from subroutine | | |
| | exit | | Exit interpreter | | |
| | outchar | | Pop top of stack; print it as ascii character | | |
| | outnum | | Pop top of stack; print it as decimal number | | |
| | readchar | | Read character from stdin & push it onto stack | | |
| | readnum | | Read integer from stdin & push it onto stack | | |
+--+-----------+------------------+-------------------------------------------------------------+ | |
""" | |
ops={'push':' ','pop':' \n\n','dup':' \n ','copy':' \t ','swap':' \n\t','add':'\t ','sub':'\t \t','mul':'\t \n','div':'\t \t ','mod':'\t \t\t','store':'\t\t ','load':'\t\t\t','label':'\n ','call':'\n \t','jump':'\n \n','jz':'\n\t ','jn':'\n\t\t','ret':'\n\t\n','exit':'\n\n\n','readchar':'\t\n\t ','readnum':'\t\n\t\t','outchar':'\t\n ','outnum':'\t\n \t'} | |
def encode(num): | |
return '' if num is None else [' ','\t'][num < 0]+ ''.join(map(lambda c:{'0':' ','1':'\t'}[c],bin(abs(num))[2:])) + '\n' | |
def scan(s): | |
for l in s.split('\n'): | |
l = l.strip() | |
if l and l[0] != '#': | |
if ':' in l: | |
yield 'label',int(l.replace(':','')) | |
else: | |
parts = l.split() | |
yield parts[0],None if len(parts)<2 else int(parts[1]) | |
def asm(src): | |
return ''.join(ops[op]+encode(arg) for op,arg in scan(src)) | |
if __name__ == '__main__': | |
if len(sys.argv)>1: | |
source = ''.join([file(f).read() for f in sys.argv[1:]]) | |
with file(re.sub('\\.wsa$','.ws',sys.argv[-1]),'w') as f : f.write(asm(source)) | |
else: | |
print 'usage : ' + sys.argv[0] + ' <files>' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment