brainfuck esoteric-languages

brainfuck - lolcode



¿Cómo funciona Brainfuck Hello World? (5)

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

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

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

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


1. Conceptos básicos

Para entender Brainfuck debe imaginar un conjunto infinito de celdas inicializadas por 0 cada 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 a la derecha > está moviendo el puntero desde la celda X a la celda X + 1

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

Si aumenta el valor de celda + obtiene:

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

Si aumenta el valor de celda nuevamente, obtiene:

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

Si reduces el valor de la celda - obtienes:

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

Si mueve el puntero a la izquierda < está moviendo el puntero desde la celda X a la celda X-1

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

2. Entrada

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

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

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

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

Asumiendo que la entrada estándar representa a operador, si usa coma, lo que BF hace es leer a código ASCII decimal 97 en la memoria:

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

Por lo general, quiere pensar de esa manera, sin embargo, la verdad es un poco más compleja. La verdad es que BF no lee a un personaje sino a un byte (sea lo que sea ese byte). Déjame mostrarte un ejemplo:

En linux

$ printf ł

huellas dactilares:

ł

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

$ printf ł | hd

el cual muestra:

00000000 c5 82 |..|

Los ceros son compensados. 82 es el primero y c5 es el segundo byte que representa ł (para que podamos leerlos). |..| es una representación gráfica que no es posible en este caso.

Bueno, si ł 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, 197 decimal es c5 hexadecimal. Parece familiar? Por supuesto. ¡Es el primer byte de ł !

3. Salida

Para imprimir el personaje, usa punto . Lo que hace es: Suponiendo que tratemos el valor real de la celda como el código ASCII decimal, imprima el carácter correspondiente a la salida estándar.

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

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

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

un

Porque a 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 e imprimirá 2 veces.

Automóvil club británico

4. Bucles

En BF, el bucle consiste en el inicio del bucle [ y el final del bucle ] . Puedes 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) {} , por lo que es un ciclo infinito.

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

++[-]

Por lo tanto, cada vez que un bucle realiza un bucle, disminuye el valor real de la celda. Una vez que el valor real de la celda es 0 termina 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 más de bucle finito:

++[>]

Este ejemplo muestra, no tenemos que terminar el bucle en la celda en 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 ciclo finaliza otra célula que comenzó, no podemos suponer dónde estará el puntero de la celda. Para ser honesto, esta práctica hace que brainfuck menos brainfuck.


Para responder a la pregunta de cómo sabe qué imprimir, he agregado 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)


Todas las respuestas son exhaustivas, pero carecen de un pequeño detalle: impresión. Al construir tu traductor de brainfuck, también consideras al personaje . , esto es realmente lo que parece una sentencia de impresión en brainfuck. Entonces, ¿qué debe hacer su traductor brainfuck es cada vez que encuentra un . personaje imprime el byte actualmente apuntado.

Ejemplo:

supongamos que tiene -> char *ptr = [0] [0] [0] [97] [0] ... si esta es una afirmación de brainfuck: >>>. su puntero debe moverse 3 espacios hasta el aterrizaje derecho en: [97] , entonces ahora *ptr = 97 , luego de hacer eso su traductor encuentra a . , entonces debería llamar

write(1, ptr, 1)

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


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 . los caracteres se usan para E / S. El texto es ASCII

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

La primera línea inicializa a[0] = 10 simplemente incrementando diez veces desde 0. El bucle de la línea 2 establece efectivamente los valores iniciales para el conjunto: 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 de espacio) y a[4] = 10 (nueva línea). El ciclo funciona sumando 7, 10, 3 y 1 a las celdas a[1] , a[2] , a[3] y a[4] respectivamente, cada vez que pasa el ciclo: 10 adiciones para cada celda en total ( dando a[1]=70 etc.). Una vez finalizado el ciclo, a[0] es cero. >++. luego mueve el puntero a a[1] , que contiene 70, le agrega dos (produce 72, que es el código de carácter ASCII de una H mayúscula), y lo emite.

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

Como ''l'' pasa a ser la séptima letra después de ''e'', ​​para dar salida ''ll'' se agregarán otros siete ( +++++++ ) a a[2] y el resultado se emitirá dos veces.

''o'' es la tercera letra después de ''l'', por lo que a[2] se incrementa tres veces más y muestra 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 incrementan o reducen según sea necesario.


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

Almacena valores en array: [72] [101] [108] [111]

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

  1. > mover el puntero a la derecha por 1

  2. < mover el puntero a la izquierda por 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. , toma entrada a la celda actual.

  7. [ ] loop, +++ [-] contador de 3 conteos bcz tiene 3 ''+'' antes, y - los decrementos cuentan la variable en 1 valor.

los valores almacenados en las celdas son valores ascii:

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

Felicidades! has aprendido la sintaxis de BF

--- Algo más ---

hagamos nuestro primer programa, es decir, Hello World , después de lo cual podrá escribir su nombre en este idioma.

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

rompiendo en pedazos:

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

Hace un conjunto de 4 celdas (número de>) y establece un contador de 10 algo así como: - código de código -

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 en +7> mueve a la celda 2 incrementa 10 a su valor anterior y así sucesivamente ....

<<< regresa 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''

>+.

mueve al segundo incremento de 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 valor presente del último elemento y solo incrementarlo

+++++ ++..

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

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

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

Es solo un lenguaje de broma hecho para desafiar a los programadores y no se usa prácticamente en ninguna parte.