1. Nozioni di base
Per capire Brainfuck devi immaginare una serie infinita di celle inizializzate da 0
ciascuna.
...[0][0][0][0][0]...
Quando il programma Brainfuck viene avviato, punta a qualsiasi cella.
...[0][0][*0*][0][0]...
Se sposti il puntatore a destra, >
stai spostando il puntatore dalla cella X alla cella X + 1
...[0][0][0][*0*][0]...
Se aumenti il valore della cella +
ottieni:
...[0][0][0][*1*][0]...
Se aumenti di nuovo il valore della cella, +
ottieni:
...[0][0][0][*2*][0]...
Se diminuisci il valore della cella -
ottieni:
...[0][0][0][*1*][0]...
Se sposti il puntatore a sinistra, <
stai spostando il puntatore dalla cella X alla cella X-1
...[0][0][*0*][1][0]...
2. Ingresso
Per leggere il carattere usi la virgola ,
. Quello che fa è: legge il carattere dallo standard input e scrive il suo codice ASCII decimale nella cella effettiva.
Dai un'occhiata alla tabella ASCII . Ad esempio, il codice decimale di !
è 33
, mentre a
è 97
.
Bene, immaginiamo che la memoria del tuo programma BF sia simile a:
...[0][0][*0*][0][0]...
Supponendo che lo standard input stia per a
, se usi l' ,
operatore virgola , ciò che BF fa è leggere il a
codice ASCII decimale 97
in memoria:
...[0][0][*97*][0][0]...
In genere vuoi pensare in questo modo, tuttavia la verità è un po 'più complessa. La verità è che BF non legge un carattere ma un byte (qualunque sia quel byte). Lascia che ti mostri un esempio:
In linux
$ printf ł
stampe:
ł
che è il carattere polacco specifico. Questo carattere non è codificato dalla codifica ASCII. In questo caso è la codifica UTF-8, quindi richiedeva più di un byte nella memoria del computer. Possiamo dimostrarlo facendo un dump esadecimale:
$ printf ł | hd
che mostra:
00000000 c5 82 |..|
Gli zeri sono compensati. 82
è il primo ec5
è il secondo byte che rappresenta ł
(in ordine li leggeremo). |..|
è una rappresentazione grafica che non è possibile in questo caso.
Bene, se passi ł
come input al tuo programma BF che legge un byte singolo, la memoria del programma sarà simile a:
...[0][0][*197*][0][0]...
Perché 197
? Beh, il 197
decimale èc5
esadecimale. Sembra familiare? Ovviamente. È il primo byte di ł
!
3. Uscita
Per stampare il carattere si utilizza il punto .
Quello che fa è: Supponendo di trattare il valore effettivo della cella come un codice ASCII decimale, stampare il carattere corrispondente sullo standard output.
Bene, immaginiamo che la memoria del tuo programma BF sia simile a:
...[0][0][*97*][0][0]...
Se ora usi l'operatore punto (.), Ciò che BF fa è stampare:
un'
Perché il a
codice decimale in ASCII è 97
.
Quindi, ad esempio, un programma BF come questo (97 più 2 punti):
++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++ ..
Aumenterà il valore della cella che punta fino a 97 e lo stamperà 2 volte.
aa
4. Loop
In BF il ciclo è costituito dall'inizio [
e dalla fine del ciclo ]
. Puoi pensare che sia come in C / C ++ dove la condizione è il valore effettivo della cella.
Dai un'occhiata al programma BF di seguito:
++[]
++
incrementa due volte il valore effettivo della cella:
...[0][0][*2*][0][0]...
Ed []
è come while(2) {}
, quindi è un ciclo infinito.
Diciamo che non vogliamo che questo ciclo sia infinito. Possiamo fare ad esempio:
++[-]
Quindi ogni volta che un ciclo viene ripetuto, il valore effettivo della cella diminuisce. Una volta che il valore effettivo della cella è 0
terminato il 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)
Consideriamo ancora un altro esempio di ciclo finito:
++[>]
Questo esempio mostra che non dobbiamo terminare il ciclo nella cella in cui il ciclo è iniziato:
...[0][0][*2*][0][0]... loop starts
...[0][0][2][*0*][0]... after first iteration (loop ends)
Tuttavia è buona norma finire dove siamo partiti. Perché ? Perché se il ciclo termina un'altra cella è iniziata, non possiamo presumere dove sarà il puntatore della cella. Ad essere onesti, questa pratica rende brainfuck meno brainfuck.