PageRenderTime 67ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/bfinterpreter.py

https://github.com/TinnedTuna/gbf
Python | 158 lines | 81 code | 17 blank | 60 comment | 13 complexity | 65058da06cc09dd82c525e23e0b04b69 MD5 | raw file
  1. import sys
  2. import stack
  3. import tape
  4. """
  5. Brainfuck interpreter
  6. Uses a bre-built map of where to jump as an optimization. Code must be
  7. preprocessed, this is not a repl.
  8. """
  9. class BFInterpreter():
  10. def __init__(self, tape_size=None):
  11. if (tape_size==None):
  12. self.tape = tape.Tape() # default tape
  13. else:
  14. self.tape = tape.Tape(tape_size)
  15. #self.stack = stack.Stack() # Stack for loops
  16. self.instruction_pointer = 0 # Current instruction
  17. self.program = [] # The program
  18. self.instructions = { ">":self.tape.move_forwards, \
  19. "<":self.tape.move_backwards, \
  20. "+":self.tape.increment, \
  21. "-":self.tape.decrement, \
  22. "[":self.enter_loop, \
  23. "]":self.end_loop, \
  24. ".":self.output, \
  25. ",":self.input, \
  26. "#":self.debug \
  27. }
  28. self.jump_map = {} # A place to look for corresponding braces
  29. def preprocess_program(self, input_code=None):
  30. """
  31. Preprocess the brainfuck
  32. Remove comments, split each individual instruction into the
  33. program tape. Clear the memory tape for the next execution.
  34. """
  35. if (input_code == None):
  36. return;
  37. map(self.program.append, filter((lambda (char): char in self.instructions), input_code))
  38. #self.program.append(False) # Causes interpretation to stop after the program has finished.
  39. self.build_jump_map(self.program)
  40. def build_jump_map(self, input_program):
  41. """
  42. Build a map of where each "]" has an opening "[".
  43. input_program must be a list of bf commands.
  44. """
  45. open_bracket_stack = stack.Stack()
  46. for inst, command in enumerate(input_program):
  47. if command in (">","<","+","-",".",",","#",):
  48. # Ignore all normal brainfuck characters.
  49. pass
  50. elif (command=="["):
  51. # We've found one, push it's location onto the stack.
  52. open_bracket_stack.push(inst)
  53. elif (command=="]"):
  54. # We've found a closing one. Map this location to the location
  55. # on the top of the stack
  56. try:
  57. previous_bracket = open_bracket_stack.pop()
  58. self.jump_map[previous_bracket]=inst
  59. self.jump_map[inst] = previous_bracket
  60. except:
  61. #print "Missing open bracket."
  62. raise
  63. #print self.jump_map
  64. def output(self):
  65. """
  66. Outputs the value of the current cell.
  67. """
  68. try:
  69. sys.stdout.write(chr(self.tape.current_cell()%256)) # Wrapping fits it into ascii codes
  70. except:
  71. print "Error -001"
  72. def input(self):
  73. """
  74. Set the current cell to a new value
  75. """
  76. try:
  77. temp = ord(raw_input())
  78. self.tape.replace(temp)
  79. except:
  80. print "Error -002"
  81. raise
  82. def enter_loop(self):
  83. """
  84. Do the code goodness for entering a loop.
  85. """
  86. if (self.tape.current_cell()==0):
  87. # Jump past the end.
  88. self.instruction_pointer = (self.jump_map[self.instruction_pointer])
  89. else:
  90. pass
  91. def end_loop(self):
  92. """
  93. Jump to the start of the loop if the current cell is not 0.
  94. """
  95. # if (not self.tape.current_cell()):
  96. # Jump to the start of the loop
  97. self.instruction_pointer = (self.jump_map[self.instruction_pointer]-1)
  98. #else:
  99. # pass
  100. def execute(self):
  101. """
  102. Execute the cleaned brainfuck program
  103. Will only correctly run after preprocess_program() has been run.
  104. """
  105. while len(self.program)>(self.instruction_pointer):
  106. self.step()
  107. #self.tape = tape.Tape() # Clear for next time.
  108. def step(self):
  109. """
  110. Do a single step in a brainfuck program
  111. """
  112. try:
  113. self.instructions[self.program[self.instruction_pointer]]()
  114. self.instruction_pointer+=1
  115. except tape.TapeError:
  116. #print "Tape underflow, instruction number: "+str(self.instruction_pointer)
  117. raise
  118. def debug(self):
  119. """
  120. Print debugging information.
  121. """
  122. print "Tape: "+str(self.tape.tape[:10])+" Current Pointer: "+str(self.tape.pointer)+" Instruction Pointer: "+str(self.instruction_pointer)
  123. def clear_tape(self):
  124. """
  125. Clear the tape for next round.
  126. """
  127. self.tape = tape.Tape()
  128. def __str__(self):
  129. """
  130. A string representation of the interpreter
  131. """
  132. return str((self.instruction_pointer, self.program,))
  133. def __len__(self):
  134. """
  135. The length of this brainfuck interpreter
  136. """
  137. return len(self.tape)