¿Cómo funciona realmente Brainfuck Hello World?


118

Alguien me envió esto y afirmó que es un hola mundo en Brainfuck (y eso espero ...)

++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

Sé lo básico que funciona moviendo un puntero e incrementando y disminuyendo cosas ...

Sin embargo, todavía quiero saber, ¿cómo funciona realmente? ¿Cómo imprime algo en la pantalla en primer lugar? ¿Cómo codifica el texto? No entiendo en absoluto...


31
Debe ser bastante difícil mantener una aplicación escrita en este idioma ..
e2-e4

17
@ ring0: no, ese es un lenguaje de solo escritura.
LetMeSOThat4U

¿cuál es su uso práctico?
Yash Kumar Verma

10
@YashVerma no necesita uno ..
Insane

49
@YashVerma Está claramente especificado en el nombre del idioma.
Mateen Ulhaq

Respuestas:


255

1. Conceptos básicos

Para entender Brainfuck debes imaginar una variedad infinita de celdas inicializadas por 0cada una.

...[0][0][0][0][0]...

Cuando se inicia el programa Brainfuck, apunta a cualquier celda.

...[0][0][*0*][0][0]...

Si mueve el puntero hacia la derecha, >lo está moviendo de la celda X a la celda X + 1

...[0][0][0][*0*][0]...

Si aumenta el valor de la celda +, obtiene:

...[0][0][0][*1*][0]...

Si vuelve a aumentar el valor de la celda +, obtiene:

...[0][0][0][*2*][0]...

Si disminuye el valor de la celda -, obtiene:

...[0][0][0][*1*][0]...

Si mueve el puntero hacia la izquierda <, está moviendo el puntero de la celda X a la celda X-1

...[0][0][*0*][1][0]...

2. Entrada

Para leer el carácter se usa la coma ,. Lo que hace es: lee el carácter de la entrada estándar y escribe su código ASCII decimal en la celda real.

Eche un vistazo a la tabla ASCII . Por ejemplo, el código decimal de !es 33, mientras que aes97 .

Bueno, imaginemos que la memoria de su programa BF se ve así:

...[0][0][*0*][0][0]...

Suponiendo que la entrada estándar significa a, si usa el ,operador de coma , lo que hace BF es leer ael código ASCII decimal 97en la memoria:

...[0][0][*97*][0][0]...

Generalmente quieres pensar de esa manera, sin embargo, la verdad es un poco más compleja. La verdad es que BF no lee un carácter sino un byte (cualquiera que sea ese byte). Déjame mostrarte un ejemplo:

En linux

$ printf ł

huellas dactilares:

ł

que es un carácter polaco específico. Este carácter no está codificado por codificación ASCII. En este caso, es la codificación UTF-8, por lo que solía ocupar más de un byte en la memoria de la computadora. Podemos probarlo haciendo un volcado hexadecimal:

$ printf ł | hd

que muestra:

00000000  c5 82                                             |..|

Los ceros están compensados. 82es el primero y el c5segundo byte que representa ł(en el orden en que los leemos).|..|es una representación gráfica que no es posible en este caso.

Bueno, si pasa łcomo entrada a su programa BF que lee un solo byte, la memoria del programa se verá así:

...[0][0][*197*][0][0]...

¿Por qué 197? Bueno, 197decimal es c5hexadecimal. ¿Te parece familiar? Por supuesto. Es el primer byte de ł!

3. Salida

Para imprimir el carácter se usa el punto. .Lo que hace es: Suponiendo que tratamos el valor real de la celda como un código ASCII decimal, imprime el carácter correspondiente en la salida estándar.

Bueno, imaginemos que la memoria de su programa BF se ve así:

...[0][0][*97*][0][0]...

Si usa el operador de punto (.) Ahora, lo que hace BF es imprimir:

una

Porque ael código decimal en ASCII es 97.

Entonces, por ejemplo, un programa BF como este (97 más 2 puntos):

++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++ ..

Aumentará el valor de la celda a la que apunta hasta 97 y lo imprimirá 2 veces.

Automóvil club británico

4. Bucles

En BF, el bucle consta de un comienzo [y un final de bucle ]. Puede pensar que es como en C / C ++, donde la condición es el valor real de la celda.

Eche un vistazo al programa BF a continuación:

++[]

++ incrementa el valor real de la celda dos veces:

...[0][0][*2*][0][0]...

Y []es como while(2) {}, entonces es un bucle infinito.

Digamos que no queremos que este bucle sea infinito. Podemos hacer por ejemplo:

++[-]

Entonces, cada vez que un bucle se repite, disminuye el valor real de la celda. Una vez que el valor real de la celda 0finaliza el ciclo:

...[0][0][*2*][0][0]...        loop starts
...[0][0][*1*][0][0]...        after first iteration
...[0][0][*0*][0][0]...        after second iteration (loop ends)

Consideremos otro ejemplo de bucle finito:

++[>]

Este ejemplo muestra que no hemos terminado el ciclo en la celda en la que comenzó el ciclo:

...[0][0][*2*][0][0]...        loop starts
...[0][0][2][*0*][0]...        after first iteration (loop ends)

Sin embargo, es una buena práctica terminar donde comenzamos. Por qué ? Porque si el bucle termina otra celda que comenzó, no podemos asumir dónde estará el puntero de la celda. Para ser honesto, esta práctica hace que la cogida de cerebro sea menos cogida de cerebro.


4
Genial, ahora lo entendí :)
speeder

25
Esa fue una solución perfecta para el novato que intenta comprender esta ideología del lenguaje. Felicitaciones y excelente publicación.
Casey

4
La mejor intro de Brainfuck que he visto. Honestamente, deshaces un poco BF por tu publicación
Boyang

3
Supongo que si necesitas un proyecto para tu tiempo libre, siempre puedes agregar soporte Unicode a Brainfuck.
Álvaro González

3
Después de tu publicación, BF es! BF ya!
thanos.a

52

Wikipedia tiene una versión comentada del código.

+++++ +++++             initialize counter (cell #0) to 10
[                       use loop to set the next four cells to 70/100/30/10
    > +++++ ++              add  7 to cell #1
    > +++++ +++++           add 10 to cell #2 
    > +++                   add  3 to cell #3
    > +                     add  1 to cell #4
    <<<< -                  decrement counter (cell #0)
]                   
> ++ .                  print 'H'
> + .                   print 'e'
+++++ ++ .              print 'l'
.                       print 'l'
+++ .                   print 'o'
> ++ .                  print ' '
<< +++++ +++++ +++++ .  print 'W'
> .                     print 'o'
+++ .                   print 'r'
----- - .               print 'l'
----- --- .             print 'd'
> + .                   print '!'
> .                     print '\n'

Para responder a sus preguntas, el ,y. caracteres se utilizan para E / S. El texto es ASCII.

El artículo de Wikipedia también continúa con más profundidad.

La primera línea se inicializa a[0] = 10simplemente aumentando diez veces desde 0. El ciclo de la línea 2 establece efectivamente los valores iniciales para la matriz: a[1] = 70(cerca de 72, el código ASCII para el carácter 'H'), a[2] = 100(cerca de 101 o 'e' ), a[3] = 30(cerca de 32, el código del espacio) y a[4] = 10(nueva línea). El bucle funciona mediante la adición de 7, 10, 3 y 1, a las células a[1], a[2], a[3]y a[4]respectivamente cada vez a través del bucle - 10 adiciones para cada celda en total (dando a[1]=70etc.). Una vez finalizado el ciclo, a[0]es cero. >++.luego mueve el puntero a a[1], que contiene 70, le suma dos (produciendo 72, que es el código de caracteres ASCII de una H mayúscula) y lo muestra.

La siguiente línea mueve el puntero de la matriz a[2]y le agrega uno, produciendo 101, una 'e' minúscula, que luego se muestra.

Como 'l' es la séptima letra después de 'e', ​​para generar 'll' se agregan otras siete ( +++++++) a[2]y el resultado se genera dos veces.

'o' es la tercera letra después de 'l', por lo que a[2]se incrementa tres veces más y genera el resultado.

El resto del programa continúa de la misma manera. Para el espacio y las letras mayúsculas, se seleccionan diferentes celdas de matriz y se aumentan o disminuyen según sea necesario.


Pero, ¿POR QUÉ imprime? ¿o como? Los comentarios me están explicando la intención de la línea, ahora lo que hace.
speeder

8
Imprime porque el compilador lo sabe ,y .se usa para E / S, al igual que C imprime usando putchar. Es un detalle de implementación manejado por el compilador.
ken

1
Y también porque está configurando las celdas requeridas a los valores enteros para los caracteres ASCII en "Hola mundo"
slugonamission

Esperaba una explicación más profunda ... pero: /
speeder

1
@speeder: agregué la explicación detallada del código de Wikipedia a la respuesta. Puede ver el artículo vinculado para obtener más información.
ken

9

Para responder a la pregunta de cómo sabe qué imprimir, agregué el cálculo de los valores ASCII a la derecha del código donde ocurre la impresión:

> just means move to the next cell
< just means move to the previous cell
+ and - are used for increment and decrement respectively. The value of the cell is updated when the increment/decrement happens

+++++ +++++             initialize counter (cell #0) to 10

[                       use loop to set the next four cells to 70/100/30/10

> +++++ ++              add  7 to cell #1

> +++++ +++++           add 10 to cell #2 

> +++                   add  3 to cell #3

> +                     add  1 to cell #4

<<<< -                  decrement counter (cell #0)

]            

> ++ .                  print 'H' (ascii: 70+2 = 72) //70 is value in current cell. The two +s increment the value of the current cell by 2

> + .                   print 'e' (ascii: 100+1 = 101)

+++++ ++ .              print 'l' (ascii: 101+7 = 108)

.                       print 'l' dot prints same thing again

+++ .                   print 'o' (ascii: 108+3 = 111)

> ++ .                  print ' ' (ascii: 30+2 = 32)

<< +++++ +++++ +++++ .  print 'W' (ascii: 72+15 = 87)

> .                     print 'o' (ascii: 111)

+++ .                   print 'r' (ascii: 111+3 = 114)

----- - .               print 'l' (ascii: 114-6 = 108)

----- --- .             print 'd' (ascii: 108-8 = 100)

> + .                   print '!' (ascii: 32+1 = 33)

> .                     print '\n'(ascii: 10)

9

Brainfuck igual que su nombre. Utiliza solo 8 caracteres, > [ . ] , - +lo que lo convierte en el lenguaje de programación más rápido de aprender, pero el más difícil de implementar y comprender. … .Y hace que finalmente termines jodiendo tu cerebro.

Almacena valores en una matriz: [72] [101] [108] [111]

let, inicialmente puntero apuntando a la celda 1 de la matriz:

  1. > mover el puntero a la derecha en 1

  2. < mover el puntero a la izquierda en 1

  3. + incrementar el valor de la celda en 1

  4. - incrementar el valor del elemento en 1

  5. . imprimir el valor de la celda actual.

  6. , llevar entrada a la celda actual.

  7. [ ] bucle, +++ [-] contador de 3 cuentas porque tiene 3 ′ + 'antes, y - disminuye la variable de cuenta en 1 valor.

los valores almacenados en las celdas son valores ascii:

así que refiriéndose a la matriz anterior: [72] [101] [108] [108] [111] si coincide con los valores ascii, encontrará que es Hello Writtern

¡Felicidades! has aprendido la sintaxis de BF

——- Algo más ———

permítanos crear nuestro primer programa, es decir, Hello World , después del cual podrá escribir su nombre en este idioma.

+++++ +++++[> +++++ ++ >+++++ +++++ >+++ >+ <<<-]>++.>+.+++++ ++..+++.++.+++++ +++++ +++++.>.+++.----- -.----- ---.>+.>.

rompiendo en pedazos:

+++++ +++++[> +++++ ++ 
                  >+++++ +++++ 
                  >+++ 
                  >+ 
                  <<<-]

Hace una matriz de 4 celdas (número de>) y establece un contador de 10 algo como: —- código de psuedo—-

array =[7,10,3,1]
i=10
while i>0:
 element +=element
 i-=1

porque el valor del contador se almacena en la celda 0 y> se mueve a la celda 1 actualiza su valor por + 7> se mueve a la celda 2 incrementa 10 a su valor anterior y así sucesivamente….

<<< vuelve a la celda 0 y disminuye su valor en 1

por lo tanto, después de completar el ciclo, tenemos una matriz: [70,100,30,10]

>++. 

se mueve al primer elemento e incrementa su valor en 2 (dos '+') y luego imprime el carácter ('.') con ese valor ascii. es decir, por ejemplo en python: chr (70 + 2) # imprime 'H'

>+.

se mueve al incremento de la 2da celda 1 a su valor 100 + 1 e imprime ('.') su valor es decir, chr (101) chr (101) # imprime 'e' ahora no hay> o <en la siguiente pieza, por lo que toma el valor actual del último elemento e incrementarlo solo

+++++ ++..

último elemento = 101 por lo tanto, 101 + 7 y lo imprime dos veces (ya que hay dos '..') chr (108) #prints l dos veces se puede usar como

for i in array:
    for j in range(i.count(‘.’)):
           print_value

——— ¿Dónde se usa? ——-

Es solo un lenguaje de broma creado para desafiar a los programadores y no se usa prácticamente en ningún lado.


4

Todas las respuestas son completas, pero les falta un pequeño detalle: la impresión. Al construir tu traductor de brainfuck, también consideras el personaje ., así es como se ve una declaración impresa en Brainfuck. Entonces, lo que debe hacer su traductor de mierda de cerebro es, cada vez que encuentra un .carácter, imprime el byte apuntado actualmente.

Ejemplo:

suponga que tiene -> char *ptr = [0] [0] [0] [97] [0]... si esta es una declaración de mierda: >>>.su puntero debe moverse 3 espacios hacia el aterrizaje derecho en:, [97]así que ahora *ptr = 97, después de hacer eso, su traductor encuentra a ., debe llamar

write(1, ptr, 1)

o cualquier declaración de impresión equivalente para imprimir el byte apuntado actualmente, que tiene el valor 97 y la letra ase imprimirá en el std_output.


1

Creo que lo que estás preguntando es cómo sabe Brainfuck qué hacer con todo el código. Hay un analizador escrito en un lenguaje de nivel superior como Python para interpretar lo que significa un punto, o lo que significa un signo de suma en el código.

Entonces, el analizador leerá su código línea por línea y dirá que está bien, hay un símbolo>, así que tengo que avanzar la ubicación de la memoria, el código es simplemente, if (contenido en esa ubicación de memoria) ==>, memlocation = + memlocation que es escrito en un lenguaje de nivel superior, de manera similar si (contenido en la ubicación de la memoria) == ".", luego imprime (contenido de la ubicación de la memoria).

Espero que esto lo aclare. tc

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.