Guest User

TPTASM.py

a guest
Aug 2nd, 2013
27
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.16 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. """tptasm.py
  4.  
  5. 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.
  6.  
  7. Here is an overview of its syntax:
  8.  
  9. * Comments start with semicolons (";") e.g. "; This is a comment"
  10. * RAM addresses are represented with square brackets e.g.
  11.  "[6]" = RAM SLOT 6.
  12. * To set A, B, C, RAM addresses or STDOUT to something
  13.  use "SET" e.g. "SET A, [6]" (sets A to the value at RAM
  14.  SLOT 7) or "SET [15], 5" (sets RAM SLOT 15 to 5) or "SET
  15.  OUT, [54]" (outputs RAM SLOT 54 to STDOUT)
  16. * To utilise the ALU use "ADD", "AND" etc. e.g. "ADD [4]"
  17.  (adds A + B and puts the result in RAM SLOT 4) or
  18.  "OR C" (puts A OR B in C)
  19. * To jump to a line use "JMP" e.g. "JMP 3" (jump to ROM SLOT 3)
  20. * To conditionally jump to a line use "IFE" e.g. "IFE 5" (if
  21.  A doesn't equal B, jump to line 5)
  22. * To quit use END by itself on a line.
  23. """
  24.  
  25. import re
  26. import sys
  27.  
  28. # The regex for a TPTASM number
  29. number_re = r"(?:[0-9]+|0[xX][0-9a-fA-F]+|0[bB][0-1]+)"
  30.  
  31. # The regex for a line of TPTASM code
  32. line_re = re.compile(r"""
  33.    ^
  34.    \s*
  35.    (?P<line>
  36.        (?P<name>SET|ADD|AND|OR|IFE|JMP|END)
  37.        (   (?<=SET)\s+(?P<set1>A|B|C|OUT|\[{number}\])\s*,\s*(?P<set2>A|B|C|\[{number}\]|{number})
  38.          | (?<=ADD)\s+(?P<add1>\[{number}\]|C)
  39.          | (?<=AND)\s+(?P<and1>\[{number}\]|C)
  40.          | (?<= OR)\s+(?P<or1>\[{number}\]|C)
  41.          | (?<=IFE)\s+(?P<ife1>{number})
  42.          | (?<=JMP)\s+(?P<jmp1>{number})
  43.          | (?<=END)
  44.        )
  45.    )?
  46.    \s*
  47.    (?P<comment>;.*)? # comment
  48.    $
  49.    """.format(number=number_re), re.X)
  50.  
  51. def isaddr(s):
  52.     """Check if a string is a PTASM memory address."""
  53.     return s.startswith('[')
  54.  
  55. def isnum(s):
  56.     """Check if a string is a valid Python integer."""
  57.     try:
  58.         int(s, 0)
  59.     except:
  60.         return False
  61.     return True
  62.  
  63. def num(s):
  64.     """Turn a number string or RAM address into a Python integer."""
  65.     if s.startswith('['):
  66.         return int(s[1:-1], 0)
  67.     return int(s, 0)
  68.  
  69. def binary(s, width):
  70.     """Make a number binary. Also restrict it to a certain width by adding
  71.    preceding zeros (when necessary)."""
  72.     return ("{:>0%s}" % width).format(bin(num(s))[2:])
  73.  
  74. def parse(text):
  75.     """Parse multiple lines of code and output the compiled program in
  76.    a list of binary strings."""
  77.     lines = text.upper().split('\n')
  78.     out = []
  79.     for lineno, line in enumerate(lines):
  80.         line2 = line_re.match(line)
  81.         if line2 is None:
  82.             raise BaseException("syntax error on line {}".format(lineno + 1))
  83.         gd = line2.groupdict()
  84.         if gd['line'] is None:
  85.             continue
  86.         if gd['name'] == 'SET':
  87.             set1 = gd['set1']
  88.             set2 = gd['set2']
  89.             if set1 == 'A' and isnum(set2):
  90.                 out.append("{}0000000000000001".format(binary(set2, 8)))
  91.             elif set1 == 'B' and isnum(set2):
  92.                 out.append("{}0000000000000010".format(binary(set2, 8)))
  93.             elif set1 == 'C' and isnum(set2):
  94.                 out.append("{}0000000000000011".format(binary(set2, 8)))
  95.             elif isaddr(set1) and isnum(set2):
  96.                 out.append("{}0{}0000100".format(binary(set1, 7), binary(set2, 8)))
  97.             elif set1 == 'A' and isaddr(set2):
  98.                 out.append("111111110{}00000101".format(binary(set2, 7)))
  99.             elif set1 == 'B' and isaddr(set2):
  100.                 out.append("111111110{}00000110".format(binary(set2, 7)))
  101.             elif set1 == 'C' and isaddr(set2):
  102.                 out.append("111111110{}00000111".format(binary(set2, 7)))
  103.             elif set1 == 'A' and set2 == 'C':
  104.                 out.append("000000000000000000001000")
  105.             elif set1 == 'B' and set2 == 'C':
  106.                 out.append("000000000000000000001001")
  107.             elif isaddr(set1) and set2 == 'C':
  108.                 out.append("000000000{}00001010".format(binary(set1, 7)))
  109.             elif set1 == 'OUT' and isaddr(set2):
  110.                 out.append("111111110{}00001101".format(binary(set2, 7)))
  111.             else:
  112.                 raise Exception("unsupported SET operation")
  113.         elif gd['name'] == 'ADD':
  114.             if gd['add1'] == 'C':  # register C
  115.                 out.append("000000000000000000011011")
  116.             else:  # RAM value
  117.                 number = bin(int(gd['add1'][1:-1], 0))[2:]  # convert to binary
  118.                 out.append("000000000{:>07}00011100".format(number))
  119.         elif gd['name'] == 'AND':
  120.             if gd['and1'] == 'C':  # register C
  121.                 out.append("000000000000000000101011")
  122.             else:  # RAM value
  123.                 number = bin(int(gd['and1'][1:-1], 0))[2:]  # convert to binary
  124.                 out.append("000000000{:>07}00101100".format(number))
  125.         elif gd['name'] == 'OR':
  126.             if gd['or1'] == 'C':  # register C
  127.                 out.append("000000000000000000111011")
  128.             else:  # RAM value
  129.                 number = bin(int(gd['or1'][1:-1], 0))[2:]  # convert to binary
  130.                 out.append("000000000{:>07}00111100".format(number))
  131.         elif gd['name'] == 'IFE':
  132.             number = bin(int(gd['ife1'], 0))[2:]  # convert to binary
  133.             out.append("000000000{:>07}01000000".format(number))
  134.         elif gd['name'] == 'JMP':
  135.             number = bin(int(gd['jmp1'], 0))[2:]  # convert to binary
  136.             out.append("000000000{:>07}01010000".format(number))
  137.         elif gd['name'] == 'END':
  138.             out.append("000000001000000000000000")
  139.         else:
  140.             raise Exception("something strange happened! Please report this bug!")
  141.  
  142.  
  143.     return out
  144.  
  145. if __name__ == "__main__":
  146.     print(
  147. """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.
  148.  
  149. Here is an overview of its syntax:
  150.  
  151. * Comments start with semicolons (";") e.g. "; This is a comment"
  152. * RAM addresses are represented with square brackets e.g.
  153.  "[6]" = RAM SLOT 6.
  154. * To set A, B, C, RAM addresses or STDOUT to something
  155.  use "SET" e.g. "SET A, [6]" (sets A to the value at RAM
  156.  SLOT 7) or "SET [15], 5" (sets RAM SLOT 15 to 5) or "SET
  157.  OUT, [54]" (outputs RAM SLOT 54 to STDOUT)
  158. * To utilise the ALU use "ADD", "AND" etc. e.g. "ADD [4]"
  159.  (adds A + B and puts the result in RAM SLOT 4) or
  160.  "OR C" (puts A OR B in C)
  161. * To jump to a line use "JMP" e.g. "JMP 3" (jump to ROM SLOT 3)
  162. * To conditionally jump to a line use "IFE" e.g. "IFE 5" (if
  163.  A doesn't equal B, jump to line 5)
  164. * To quit use END by itself on a line.
  165. """)
  166.     print("Enter code (press {} to finish):".format(("Ctrl-D", "Ctrl-Z")[sys.platform == "win32"]))
  167.     program = sys.stdin.read()
  168.     result = parse(program)
  169.     print("Here is your program! Enjoy!")
  170.     for i in result:
  171.         print(i)
Advertisement
Add Comment
Please, Sign In to add comment