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