/brainfuck/lib/brainfuck_ast.rb

https://github.com/vybirjan/MI-RUB-ukoly · Ruby · 243 lines · 197 code · 46 blank · 0 comment · 22 complexity · afe7566a28e6e24d5300368ea2d58aba MD5 · raw file

  1. class BrainfuckContext
  2. def initialize()
  3. @pointer = 0
  4. @memory = Array.new(30000, 0)
  5. end
  6. def inc_pointer
  7. if(@pointer == 30000)
  8. raise RangeError, "Pointer must not exceed 30000"
  9. else
  10. @pointer = @pointer + 1
  11. end
  12. end
  13. def dec_pointer
  14. if(@pointer == 0)
  15. raise RangeError, "Pointer must not be less than zero"
  16. else
  17. @pointer = @pointer - 1
  18. end
  19. end
  20. def inc_value
  21. @memory[@pointer] = (@memory[@pointer] + 1) % 256
  22. end
  23. def dec_value
  24. if(@memory[@pointer] == 0)
  25. @memory[@pointer] = 255
  26. else
  27. @memory[@pointer] = @memory[@pointer] - 1
  28. end
  29. end
  30. def get_value
  31. return @memory[@pointer]
  32. end
  33. def set_value(value)
  34. if(value < 0 or value > 255)
  35. raise ArgumentError, "Value must be between 0 and 255"
  36. else
  37. @memory[@pointer] = value
  38. end
  39. end
  40. def reset
  41. @pointer = 0
  42. 0.upto(30000) {|i|
  43. @memory[i] = 0
  44. }
  45. end
  46. def print_memory(index = @pointer)
  47. if(index < 0)
  48. index = 0
  49. end
  50. if(index > 30000)
  51. index = 30000
  52. end
  53. real_index = [0, index - 4].max
  54. if(real_index + 9 > 30000)
  55. real_index = 30000 - 10
  56. end
  57. top = ""
  58. middle = ""
  59. bottom = ""
  60. if(real_index == 0)
  61. top = "|"
  62. middle = "|"
  63. bottom = " "
  64. else
  65. top << "..."
  66. middle << "..."
  67. bottom << " "
  68. end
  69. real_index.upto(real_index + 9) {|i|
  70. print_memory_internal(i, top, middle, bottom)
  71. }
  72. top << "|"
  73. middle << "|"
  74. if(real_index == 30000 - 10)
  75. top << "|"
  76. middle << "|"
  77. else
  78. top << "..."
  79. middle << "..."
  80. end
  81. puts top
  82. puts middle
  83. puts bottom
  84. end
  85. private
  86. def print_memory_internal(index, top, middle, bottom)
  87. top << "| "
  88. middle << "| "
  89. bottom << " "
  90. value = byte_to_s(@memory[index])
  91. size = [value.length, index.to_s.length].max
  92. ptr = ""
  93. if(index == @pointer)
  94. ptr = "^"
  95. end
  96. top << pad_to_width(index.to_s, size)
  97. middle << pad_to_width(value, size)
  98. bottom << pad_to_width(ptr, size)
  99. top << " "
  100. middle << " "
  101. bottom << " "
  102. end
  103. def byte_to_s(value)
  104. if(value > 31 and value < 127)
  105. return "'" << value.chr << "'"
  106. else
  107. val = value.to_s(16)
  108. ret = "0x"
  109. if(val.length < 2)
  110. ret << "0"
  111. end
  112. ret << val
  113. return ret
  114. end
  115. end
  116. def pad_to_width(text, width)
  117. remaining = width - text.length
  118. remaining = [0, remaining].max
  119. result = ""
  120. half = remaining / 2
  121. rest = remaining % 2
  122. 1.upto(half + rest) {
  123. result << " "
  124. }
  125. result << text
  126. 1.upto(half) {
  127. result << " "
  128. }
  129. return result
  130. end
  131. end
  132. class AstElement
  133. attr_accessor :next
  134. attr_reader :line
  135. attr_reader :column
  136. def initialize(line, column)
  137. @line = line
  138. @column = column
  139. end
  140. end
  141. class IncrementPointer < AstElement
  142. def eval(context)
  143. context.inc_pointer
  144. return @next
  145. end
  146. end
  147. class DecrementPointer < AstElement
  148. def eval(context)
  149. context.dec_pointer
  150. return @next
  151. end
  152. end
  153. class IncrementValue < AstElement
  154. def eval(context)
  155. context.inc_value
  156. return @next
  157. end
  158. end
  159. class DecrementValue < AstElement
  160. def eval(context)
  161. context.dec_value
  162. return @next
  163. end
  164. end
  165. class ReadInput < AstElement
  166. def eval(context)
  167. context.set_value(STDIN.getc.bytes.to_a[0])
  168. return @next
  169. end
  170. end
  171. class PrintValue < AstElement
  172. def eval(context)
  173. print(context.get_value.chr)
  174. return @next
  175. end
  176. end
  177. class LoopStart < AstElement
  178. attr_reader :next
  179. attr_accessor :loopEnd
  180. def eval(context)
  181. if(context.get_value == 0)
  182. return @loopEnd
  183. else
  184. return @next
  185. end
  186. end
  187. end
  188. class LoopEnd < AstElement
  189. attr_accessor :loopHead
  190. def eval(context)
  191. if(context.get_value != 0)
  192. return @loopHead
  193. else
  194. return @next
  195. end
  196. end
  197. end