pathc.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. """
  2. This program compiles Path 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 db 0
  29. SEGMENT .code USE32
  30. ..start
  31. mov EBX, array
  32. push DWORD 0
  33. jmp progstart
  34. """ % (putchar, getchar)
  35. movecharacters = "\\/v^<>"
  36. program = []
  37. hasstart = 0
  38. progwidth = 0
  39. for line in fileinput.input():
  40. n = [c for c in line]
  41. if line.find("$") >= 0:
  42. hasstart = 1
  43. program.append(n)
  44. if progwidth < len(n):
  45. progwidth = len(n)
  46. progheight = len(program)
  47. for line in range(len(program)): #pad the lines out
  48. program[line] += " " * (progwidth - len(program[line]))
  49. if not hasstart:
  50. print "progstart:"
  51. proglocs = {}
  52. jnum = 0
  53. for y, line in enumerate(program):
  54. for x, char in enumerate(line):
  55. if char in movecharacters:
  56. proglocs[(x,y)] = jnum
  57. jnum += 1
  58. skipnum = 0
  59. checkjump = 0
  60. def outputrowdata(y, row, myname, left, right, realx, realy):
  61. """Print out the code for a "row" of data."""
  62. global skipnum, checkjump
  63. amskipping = 0
  64. for x, char in enumerate(row):
  65. # if char not in "$+-}{,.v><^\\\/!#":
  66. # continue
  67. skipinturn = 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 BYTE [EBX]"
  74. if char == "-":
  75. print "dec BYTE [EBX]"
  76. if char == "}":
  77. print "add EBX, 4"
  78. if char == "{":
  79. print "CMP EBX, array"
  80. print "JE chjump_%i" % (checkjump)
  81. print "sub EBX, 4"
  82. print "chjump_%i:" % (checkjump)
  83. checkjump += 1
  84. if char == ",":
  85. print "call %s" % (getchar)
  86. print "mov [EBX], AL"
  87. print "cmp EAX, 3"
  88. print "JE NEAR endprogram"
  89. if char == ".":
  90. print "push DWORD [EBX]"
  91. print "call %s" % (putchar)
  92. print "pop EAX"
  93. if char == ">":
  94. print "CMP DWORD [EBX], 0"
  95. print "JNE NEAR right_%i" % (proglocs[xypos])
  96. if myname == "right":
  97. print "right_%i:" % (proglocs[xypos])
  98. if char == "<":
  99. print "CMP BYTE [EBX], 0"
  100. print "JNE NEAR left_%i" % (proglocs[xypos])
  101. if myname == "left":
  102. print "left_%i:" % (proglocs[xypos])
  103. if char == "^":
  104. print "CMP BYTE [EBX], 0"
  105. print "JNE NEAR up_%i" % (proglocs[xypos])
  106. if myname == "up":
  107. print "up_%i:" % (proglocs[xypos])
  108. if char == "v":
  109. print "CMP BYTE [EBX], 0"
  110. print "JNE NEAR down_%i" % (proglocs[xypos])
  111. if myname == "down":
  112. print "down_%i:" % (proglocs[xypos])
  113. if char == "\\":
  114. print "JMP NEAR %s_%i" % (right, proglocs[xypos])
  115. print "%s_%i:" % (myname, proglocs[xypos])
  116. if char == "/":
  117. print "JMP NEAR %s_%i" % (left, proglocs[xypos])
  118. print "%s_%i:" % (myname, proglocs[xypos])
  119. if char == "!":
  120. print "JMP skip_%i" % (skipnum)
  121. skipnum += 1
  122. skipinturn = 1
  123. if char == "#":
  124. print "JMP NEAR endprogram"
  125. #jump-to points for the instructions that skip over others
  126. #these are annoyingly complicated, to account for the fact
  127. #that there might be two in a row
  128. if amskipping:
  129. print "skip_%i:" % (skipnum - 1 - skipinturn)
  130. amskipping -= 1
  131. if char == "!":
  132. amskipping += 1
  133. #just make sure to clean up - no dangling references
  134. if amskipping:
  135. print "skip_%i:" % (skipnum - 1)
  136. print "JMP endprogram"
  137. #these parts output the rows of code, forwards and backwards, up and down
  138. for y, row in enumerate(program):
  139. if [x for x in movecharacters if x in row] or \
  140. "$" 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 [x for x in movecharacters if x 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 [y for y in movecharacters if y 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 [y for y in movecharacters if y 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]"