Skip to content

Instantly share code, notes, and snippets.

@jrialland
Created April 28, 2017 12:56
Show Gist options
  • Save jrialland/e0d370034da9c7b1b76a8afccbea7424 to your computer and use it in GitHub Desktop.
Save jrialland/e0d370034da9c7b1b76a8afccbea7424 to your computer and use it in GitHub Desktop.
Whitespace assembler in python
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