snuspc.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. """
  2. This program compiles SNUSP programs to assembly.
  3. Copyright (C) 2004 John Bauman
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. """
  16. import fileinput
  17. #these can also be changed to "putchar" and "getchar",
  18. #those can work with files, but getchar requires newlines to be input
  19. putchar="_putch"
  20. getchar="_getche"
  21. #preamble
  22. print """
  23. EXTERN ExitProcess
  24. IMPORT ExitProcess kernel32.dll
  25. EXTERN %s
  26. EXTERN %s
  27. SEGMENT .data USE32
  28. array times 30000 dw 0
  29. SEGMENT .code USE32
  30. ..start
  31. mov EBX, array
  32. push DWORD 0
  33. jmp progstart
  34. """ % (putchar, getchar)
  35. program = []
  36. hasstart = 0
  37. progwidth = 0
  38. for line in fileinput.input():
  39. n = [c for c in line]
  40. if line.find("$") >= 0:
  41. hasstart = 1
  42. program.append(n)
  43. if progwidth < len(n):
  44. progwidth = len(n)
  45. progheight = len(program)
  46. for line in range(len(program)): #pad the lines out
  47. program[line] += " " * (progwidth - len(program[line]))
  48. if not hasstart:
  49. print "progstart:"
  50. proglocs = {}
  51. jnum = 0
  52. for y, line in enumerate(program):
  53. for x, char in enumerate(line):
  54. if char == "\\" or char == "/":
  55. proglocs[(x,y)] = jnum
  56. jnum += 1
  57. jumpnum = 0
  58. callnum = 0
  59. skipnum = 0
  60. def outputrowdata(y, row, myname, left, right, realx, realy):
  61. """Print out the code for a "row" of data."""
  62. global skipnum, callnum, jumpnum
  63. amskipping = amcalling = amjumping = 0
  64. for x, char in enumerate(row):
  65. skipinturn = 0
  66. callinturn = 0
  67. jumpinturn = 0
  68. xypos = (realx(x,y), realy(x,y)) #find out the REAL position
  69. #check each character
  70. if myname == "right" and char == "$":
  71. print "progstart:"
  72. if char == "+":
  73. print "inc DWORD [EBX]"
  74. if char == "-":
  75. print "dec DWORD [EBX]"
  76. if char == ">":
  77. print "add EBX, 4"
  78. if char == "<":
  79. print "sub EBX, 4"
  80. if char == ",":
  81. print "call %s" % (getchar)
  82. print "mov [EBX], EAX"
  83. print "cmp EAX, 3"
  84. print "JE NEAR endprogram"
  85. if char == ".":
  86. print "push DWORD [EBX]"
  87. print "call %s" % (putchar)
  88. print "pop EAX"
  89. if char == "\\":
  90. print "JMP NEAR %s_%i" % (right, proglocs[xypos])
  91. print "%s_%i:" % (myname, proglocs[xypos])
  92. if char == "/":
  93. print "JMP NEAR %s_%i" % (left, proglocs[xypos])
  94. print "%s_%i:" % (myname, proglocs[xypos])
  95. if char == "?":
  96. print "CMP DWORD [EBX], 0"
  97. print "JE jump_%i" % (jumpnum)
  98. jumpnum += 1
  99. jumpinturn = 1
  100. if char == "!":
  101. print "JMP skip_%i" % (skipnum)
  102. skipnum += 1
  103. skipinturn = 1
  104. if char == "@":
  105. print "push call_%i" % (callnum)
  106. callnum += 1
  107. callinturn = 1
  108. if char == "#":
  109. print "cmp DWORD [ESP], 0"
  110. print "JE NEAR endprogram"
  111. print "ret"
  112. #jump-to points for the instructions that skip over others
  113. #these are annoyingly complicated, to account for the fact
  114. #that there might be two in a row
  115. if amjumping:
  116. print "jump_%i:" % (jumpnum - 1 - jumpinturn)
  117. amjumping -= 1
  118. if char == "?":
  119. amjumping += 1
  120. if amcalling:
  121. print "call_%i:" % (callnum - 1 - callinturn)
  122. amcalling -= 1
  123. if char == "@":
  124. amcalling += 1
  125. if amskipping:
  126. print "skip_%i:" % (skipnum - 1 - skipinturn)
  127. amskipping -= 1
  128. if char == "!":
  129. amskipping += 1
  130. #just make sure to clean up - no dangling references
  131. if amjumping:
  132. print "jump_%i:" % (jumpnum - 1)
  133. if amcalling:
  134. print "call_%i:" % (callnum - 1)
  135. if amskipping:
  136. print "skip_%i:" % (skipnum - 1)
  137. print "JMP endprogram"
  138. #these parts output the rows of code, forwards and backwards, up and down
  139. for y, row in enumerate(program):
  140. if "/" in row or "\\" in row or "$" in row or (y == 0 and not hasstart):
  141. outputrowdata(y, row, "right", "up", "down",
  142. lambda a,b:a,
  143. lambda a,b:b)
  144. for y, row in enumerate(program):
  145. row = row[:]
  146. row.reverse()
  147. if "/" in row or "\\" in row:
  148. outputrowdata(y, row, "left", "down", "up",
  149. lambda a,b:progwidth - a - 1,
  150. lambda a,b:b)
  151. for x, row in enumerate(zip(*program)):
  152. if "/" in row or "\\" in row:
  153. outputrowdata(x, row, "down", "left", "right",
  154. lambda a,b:b,
  155. lambda a,b:a)
  156. for x, row in enumerate(zip(*program)):
  157. row = list(row)
  158. row.reverse()
  159. if "/" in row or "\\" in row:
  160. outputrowdata(x, row, "up", "right", "left",
  161. lambda a,b:b,
  162. lambda a,b:progheight - a - 1)
  163. print "endprogram:"
  164. print "push DWORD 0"
  165. print "call [ExitProcess]"