Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- """tptasm.py
- TPTASM is an assembly language for The Powder Toy's "8-bit processor v1.0" (see http://powdertoy.co.uk/Discussions/Thread/View.html?Thread=17358). Assembly languages make low-level programming a lot easier by getting rid of the bit manipulation and replacing it with friendlier words and numbers that actually show what the code does.
- Here is an overview of its syntax:
- * Comments start with semicolons (";") e.g. "; This is a comment"
- * RAM addresses are represented with square brackets e.g.
- "[6]" = RAM SLOT 6.
- * To set A, B, C, RAM addresses or STDOUT to something
- use "SET" e.g. "SET A, [6]" (sets A to the value at RAM
- SLOT 7) or "SET [15], 5" (sets RAM SLOT 15 to 5) or "SET
- OUT, [54]" (outputs RAM SLOT 54 to STDOUT)
- * To utilise the ALU use "ADD", "AND" etc. e.g. "ADD [4]"
- (adds A + B and puts the result in RAM SLOT 4) or
- "OR C" (puts A OR B in C)
- * To jump to a line use "JMP" e.g. "JMP 3" (jump to ROM SLOT 3)
- * To conditionally jump to a line use "IFE" e.g. "IFE 5" (if
- A doesn't equal B, jump to line 5)
- * To quit use END by itself on a line.
- """
- import re
- import sys
- # The regex for a TPTASM number
- number_re = r"(?:[0-9]+|0[xX][0-9a-fA-F]+|0[bB][0-1]+)"
- # The regex for a line of TPTASM code
- line_re = re.compile(r"""
- ^
- \s*
- (?P<line>
- (?P<name>SET|ADD|AND|OR|IFE|JMP|END)
- ( (?<=SET)\s+(?P<set1>A|B|C|OUT|\[{number}\])\s*,\s*(?P<set2>A|B|C|\[{number}\]|{number})
- | (?<=ADD)\s+(?P<add1>\[{number}\]|C)
- | (?<=AND)\s+(?P<and1>\[{number}\]|C)
- | (?<= OR)\s+(?P<or1>\[{number}\]|C)
- | (?<=IFE)\s+(?P<ife1>{number})
- | (?<=JMP)\s+(?P<jmp1>{number})
- | (?<=END)
- )
- )?
- \s*
- (?P<comment>;.*)? # comment
- $
- """.format(number=number_re), re.X)
- def isaddr(s):
- """Check if a string is a PTASM memory address."""
- return s.startswith('[')
- def isnum(s):
- """Check if a string is a valid Python integer."""
- try:
- int(s, 0)
- except:
- return False
- return True
- def num(s):
- """Turn a number string or RAM address into a Python integer."""
- if s.startswith('['):
- return int(s[1:-1], 0)
- return int(s, 0)
- def binary(s, width):
- """Make a number binary. Also restrict it to a certain width by adding
- preceding zeros (when necessary)."""
- return ("{:>0%s}" % width).format(bin(num(s))[2:])
- def parse(text):
- """Parse multiple lines of code and output the compiled program in
- a list of binary strings."""
- lines = text.upper().split('\n')
- out = []
- for lineno, line in enumerate(lines):
- line2 = line_re.match(line)
- if line2 is None:
- raise BaseException("syntax error on line {}".format(lineno + 1))
- gd = line2.groupdict()
- if gd['line'] is None:
- continue
- if gd['name'] == 'SET':
- set1 = gd['set1']
- set2 = gd['set2']
- if set1 == 'A' and isnum(set2):
- out.append("{}0000000000000001".format(binary(set2, 8)))
- elif set1 == 'B' and isnum(set2):
- out.append("{}0000000000000010".format(binary(set2, 8)))
- elif set1 == 'C' and isnum(set2):
- out.append("{}0000000000000011".format(binary(set2, 8)))
- elif isaddr(set1) and isnum(set2):
- out.append("{}0{}0000100".format(binary(set1, 7), binary(set2, 8)))
- elif set1 == 'A' and isaddr(set2):
- out.append("111111110{}00000101".format(binary(set2, 7)))
- elif set1 == 'B' and isaddr(set2):
- out.append("111111110{}00000110".format(binary(set2, 7)))
- elif set1 == 'C' and isaddr(set2):
- out.append("111111110{}00000111".format(binary(set2, 7)))
- elif set1 == 'A' and set2 == 'C':
- out.append("000000000000000000001000")
- elif set1 == 'B' and set2 == 'C':
- out.append("000000000000000000001001")
- elif isaddr(set1) and set2 == 'C':
- out.append("000000000{}00001010".format(binary(set1, 7)))
- elif set1 == 'OUT' and isaddr(set2):
- out.append("111111110{}00001101".format(binary(set2, 7)))
- else:
- raise Exception("unsupported SET operation")
- elif gd['name'] == 'ADD':
- if gd['add1'] == 'C': # register C
- out.append("000000000000000000011011")
- else: # RAM value
- number = bin(int(gd['add1'][1:-1], 0))[2:] # convert to binary
- out.append("000000000{:>07}00011100".format(number))
- elif gd['name'] == 'AND':
- if gd['and1'] == 'C': # register C
- out.append("000000000000000000101011")
- else: # RAM value
- number = bin(int(gd['and1'][1:-1], 0))[2:] # convert to binary
- out.append("000000000{:>07}00101100".format(number))
- elif gd['name'] == 'OR':
- if gd['or1'] == 'C': # register C
- out.append("000000000000000000111011")
- else: # RAM value
- number = bin(int(gd['or1'][1:-1], 0))[2:] # convert to binary
- out.append("000000000{:>07}00111100".format(number))
- elif gd['name'] == 'IFE':
- number = bin(int(gd['ife1'], 0))[2:] # convert to binary
- out.append("000000000{:>07}01000000".format(number))
- elif gd['name'] == 'JMP':
- number = bin(int(gd['jmp1'], 0))[2:] # convert to binary
- out.append("000000000{:>07}01010000".format(number))
- elif gd['name'] == 'END':
- out.append("000000001000000000000000")
- else:
- raise Exception("something strange happened! Please report this bug!")
- return out
- if __name__ == "__main__":
- print(
- """TPTASM is an assembly language for The Powder Toy's "8-bit processor v1.0" (see http://powdertoy.co.uk/Discussions/Thread/View.html?Thread=17358). Assembly languages make low-level programming a lot easier by getting rid of the bit manipulation and replacing it with friendlier words and numbers that actually show what the code does.
- Here is an overview of its syntax:
- * Comments start with semicolons (";") e.g. "; This is a comment"
- * RAM addresses are represented with square brackets e.g.
- "[6]" = RAM SLOT 6.
- * To set A, B, C, RAM addresses or STDOUT to something
- use "SET" e.g. "SET A, [6]" (sets A to the value at RAM
- SLOT 7) or "SET [15], 5" (sets RAM SLOT 15 to 5) or "SET
- OUT, [54]" (outputs RAM SLOT 54 to STDOUT)
- * To utilise the ALU use "ADD", "AND" etc. e.g. "ADD [4]"
- (adds A + B and puts the result in RAM SLOT 4) or
- "OR C" (puts A OR B in C)
- * To jump to a line use "JMP" e.g. "JMP 3" (jump to ROM SLOT 3)
- * To conditionally jump to a line use "IFE" e.g. "IFE 5" (if
- A doesn't equal B, jump to line 5)
- * To quit use END by itself on a line.
- """)
- print("Enter code (press {} to finish):".format(("Ctrl-D", "Ctrl-Z")[sys.platform == "win32"]))
- program = sys.stdin.read()
- result = parse(program)
- print("Here is your program! Enjoy!")
- for i in result:
- print(i)
Advertisement
Add Comment
Please, Sign In to add comment