PageRenderTime 47ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/PyBrainfuck.py

https://bitbucket.org/lsabiao/pybrainfuck
Python | 224 lines | 192 code | 8 blank | 24 comment | 0 complexity | 167b822a116f1dbd90111a52355f2305 MD5 | raw file
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # interpretador python de Brainfuck
  4. # Implementação da especificação da linguagem
  5. # Os 8 comandos
  6. # comandos = {"+":"mais", incrementa em 1 o valor da célula atual
  7. # "-":"menos", decrementa em 1 o valor da célula atual
  8. # ">":"sobePonteiro", incrementa em 1 a localização da célula atual
  9. # "<":"descePonteiro", decrementa em 1 a localização da célula atual
  10. #
  11. # ".":"printASCII", mostra na tela o valor da celula atual,
  12. # convertido pra ASCII
  13. #
  14. # ",":"recebeASCII", Recebe um valor em ASCII e posiciona o valor
  15. # inteiro na célula atua
  16. #
  17. # "[":"loop", se o valor na célula atual for zero, vai para
  18. # o "]" correspondente, se não faz a próxima
  19. # instrução
  20. #
  21. # "]":"loopEnd" se o valor na célula atual for zero, vai para
  22. # a próxima instrução, se não volta para o "["
  23. # correspondente
  24. # }
  25. import sys
  26. __version__ = "1.0"
  27. __author__ = "lucas.sabiao@hotmail.com"
  28. estrutura = [0] * 30000 # um vetor com 30000 posições,isso deve ser o programa
  29. ponteiro = 0 # um ponteiro indicando qual é a célula atual
  30. programa = "" # o programa deve estar contido nessa string
  31. posicao = 0 # qual instrução está sendo interpretada
  32. def checkLoop():
  33. # procura por uma quantidade par de '[' e ']'
  34. global programa
  35. aberto = programa.count("[")
  36. fechado = programa.count("]")
  37. if (aberto == fechado):
  38. return True
  39. else:
  40. print ("Quantidade estranha de '[]'")
  41. return False
  42. # implementação de cada instrução como uma funcão
  43. # não fiquei feliz com essa quantidade absurda de "global"s, mas não achei
  44. # nenhuma saída bem didática para isso.
  45. def mais():
  46. global estrutura
  47. global ponteiro
  48. estrutura[ponteiro] += 1
  49. def menos():
  50. global estrutura
  51. global ponteiro
  52. estrutura[ponteiro] -= 1
  53. def sobePonteiro():
  54. global estrutura
  55. global ponteiro
  56. ponteiro += 1
  57. def descePonteiro():
  58. global estrutura
  59. global ponteiro
  60. ponteiro -= 1
  61. def printASCII():
  62. global estrutura
  63. global ponteiro
  64. print chr(estrutura[ponteiro]),
  65. sys.stdout.flush()
  66. def recebeASCII():
  67. global estrutura
  68. global ponteiro
  69. aux = raw_input()
  70. try:
  71. estrutura[ponteiro] = ord(aux)
  72. except:
  73. estrutura[ponteiro] = 0
  74. # Fiquei muito em dúvida sobre como fazer os loops.
  75. # uma abordagem de manter na memória os endereços de cada "abrir" e "fechar"
  76. # seria muito mais performática e limpo, mas achei que ficaria mais ilegível.
  77. def loop():
  78. global estrutura
  79. global ponteiro
  80. global posicao
  81. if(estrutura[ponteiro] == 0):
  82. posicao = procurarEnd()
  83. else:
  84. pass
  85. def loopEnd():
  86. global estrutura
  87. global ponteiro
  88. global posicao
  89. if(estrutura[ponteiro] == 0):
  90. pass
  91. else:
  92. posicao = procurarLoop() - 1
  93. def procurarEnd():
  94. global programa
  95. global posicao
  96. aux = 1
  97. posicaoAtual = posicao
  98. for instrucao in programa[posicao:]:
  99. if(aux == 0):
  100. return posicaoAtual
  101. if(instrucao == "["):
  102. aux += 1
  103. elif(instrucao == "]"):
  104. aux -= 1
  105. posicaoAtual += 1
  106. def procurarLoop():
  107. global programa
  108. global posicao
  109. aux = 1
  110. posicaoAtual = posicao
  111. for p in range(len(programa[:posicao])-1, 0, -1):
  112. if(programa[p] == "]"):
  113. aux += 1
  114. elif(programa[p] == "["):
  115. aux -= 1
  116. if(aux == 0):
  117. return posicaoAtual
  118. posicaoAtual -= 1
  119. def validarCelula():
  120. # python não suporta variáveis como byte.
  121. # workaround
  122. global estrutura
  123. global ponteiro
  124. if (estrutura[ponteiro] > 255):
  125. estrutura[ponteiro] = 255
  126. elif (estrutura[ponteiro] < 0):
  127. estrutura[ponteiro] = 0
  128. def runPrograma():
  129. global programa
  130. global estrutura
  131. global ponteiro
  132. global posicao
  133. if(checkLoop()):
  134. while True:
  135. validarCelula()
  136. try:
  137. # não é a saida mais elegante, mas funciona muito bem
  138. instrucao = programa[posicao]
  139. except IndexError:
  140. break
  141. if (instrucao == "+"):
  142. mais()
  143. elif (instrucao == "-"):
  144. menos()
  145. elif (instrucao == ">"):
  146. sobePonteiro()
  147. elif (instrucao == "<"):
  148. descePonteiro()
  149. elif (instrucao == "."):
  150. printASCII()
  151. elif (instrucao == ","):
  152. recebeASCII()
  153. elif (instrucao == "["):
  154. loop()
  155. elif (instrucao == "]"):
  156. loopEnd()
  157. posicao += 1
  158. if __name__ == "__main__":
  159. # Uso:
  160. # sem argumentos: pede para você digitar o programa
  161. # exemplo ou exemplo.bfmostrar na tela o programa "Hello World"
  162. # baseado no artigo en.wikipedia.org/wiki/Brainfuck
  163. # como interpretador, recebe o caminho para o arquivo a ser interpretado
  164. from sys import argv
  165. from os import getcwd
  166. if(len(argv) > 1):
  167. if (argv[1].lower() == "exemplo" or argv[1].lower() == "exemplo.bf"):
  168. # hello world
  169. programa = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>> \
  170. .>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."
  171. else:
  172. # pegar o arquivo para interpretar
  173. path = getcwd()+"/"+argv[1]
  174. try:
  175. programa = open(path, "r").read()
  176. except:
  177. print "Progama não encontrado"
  178. else:
  179. programa = raw_input("Escreva seu programa: ")
  180. runPrograma()