it-swarm.com.de

Wie funktioniert das Brainfuck Hello World eigentlich?

Jemand hat mir das geschickt und behauptet, es sei eine hallo Welt in Brainfuck (und ich hoffe es ...)

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

Ich kenne die Grundlagen, die es funktioniert, indem man einen Zeiger bewegt und Sachen inkrementiert und dekrementiert ...

Trotzdem möchte ich noch wissen, wie es tatsächlich funktioniert? Wie wird überhaupt etwas auf dem Bildschirm gedruckt? Wie verschlüsselt es den Text? Ich verstehe gar nichts...

110
speeder

1. Grundlagen

Um Brainfuck zu verstehen, müssen Sie sich unendlich viele Zellen vorstellen, die jeweils mit 0 Initialisiert wurden.

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

Wenn das Brainfuck-Programm gestartet wird, zeigt es auf eine beliebige Zelle.

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

Wenn Sie den Zeiger nach rechts bewegen >, Bewegen Sie den Zeiger von Zelle X nach Zelle X + 1

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

Wenn Sie den Zellenwert + Erhöhen, erhalten Sie:

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

Wenn Sie den Zellenwert erneut erhöhen +, Erhalten Sie:

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

Wenn Sie den Zellenwert - Verringern, erhalten Sie:

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

Wenn Sie den Zeiger nach links bewegen <, Bewegen Sie den Zeiger von Zelle X nach Zelle X-1

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

2. Eingabe

Zum Lesen des Zeichens verwenden Sie ein Komma ,. Was es tut, ist: Lese das Zeichen von der Standardeingabe und schreibe den dezimalen ASCII Code in die eigentliche Zelle.

Schauen Sie sich ASCII-Tabelle an. Der Dezimalcode von ! Ist beispielsweise 33, Während a97 Ist.

Stellen wir uns vor, Ihr BF-Programmspeicher sieht folgendermaßen aus:

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

Unter der Annahme, dass die Standardeingabe für a steht, wird bei Verwendung des Komma-Operators ,a decimal ASCII code 97 Ins Gedächtnis:

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

Im Allgemeinen möchten Sie so denken, die Wahrheit ist jedoch etwas komplexer. Die Wahrheit ist, dass BF kein Zeichen, sondern ein Byte liest (was auch immer dieses Byte ist). Lassen Sie mich Ihnen ein Beispiel zeigen:

Unter Linux

$ printf ł

druckt:

ł

das ist spezifischer polnischer Charakter. Dieses Zeichen wird nicht durch ASCII Encoding codiert. In diesem Fall handelt es sich um eine UTF-8-Codierung, sodass im Computerspeicher mehr als ein Byte benötigt wird. Wir können dies beweisen, indem wir einen hexadezimalen Speicherauszug erstellen:

$ printf ł | hd

welche Shows:

00000000  c5 82                                             |..|

Nullen werden ausgeglichen. 82 Ist das erste und c5 Das zweite Byte, das ł Darstellt (damit wir sie lesen können). |..| Ist eine grafische Darstellung, die in diesem Fall nicht möglich ist.

Nun, wenn Sie ł Als Eingabe für Ihr BF-Programm übergeben, das ein einzelnes Byte liest, sieht der Programmspeicher folgendermaßen aus:

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

Warum 197? Nun, die Dezimalzahl 197 Ist die Hexadezimalzahl c5. Scheint vertraut ? Na sicher. Es ist das erste Byte von ł!

3. Ausgabe

Um ein Zeichen auszudrucken, verwenden Sie den Punkt .. Dies geschieht folgendermaßen: Angenommen, wir behandeln den tatsächlichen Zellenwert wie eine Dezimalzahl ASCII Code, drucken Sie das entsprechende Zeichen auf Standardausgabe.

Stellen wir uns vor, Ihr BF-Programmspeicher sieht folgendermaßen aus:

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

Wenn Sie jetzt den Punkt-Operator (.) Verwenden, gibt BF Folgendes aus:

ein

Weil a Dezimalcode in ASCII ist 97.

Also zum Beispiel BF-Programm wie folgt (97 plus 2 Punkte):

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

Erhöht den Wert der Zelle, auf die es zeigt, auf bis zu 97 und druckt sie zweimal aus.

aa

4. Schleifen

In BF besteht die Schleife aus dem Beginn der Schleife [ Und dem Ende der Schleife ]. Sie können sich vorstellen, wie in C/C++, wo die Bedingung der tatsächliche Zellenwert ist.

Werfen Sie einen Blick auf das BF-Programm unten:

++[]

++ Erhöht den tatsächlichen Zellenwert zweimal:

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

Und [] Ist wie while(2) {}, es ist also eine Endlosschleife.

Nehmen wir an, wir möchten nicht, dass diese Schleife unendlich ist. Wir können zum Beispiel tun:

++[-]

Jedes Mal, wenn eine Schleife eine Schleife durchläuft, wird der tatsächliche Zellenwert verringert. Sobald der tatsächliche Zellenwert 0 Ist, endet die Schleife:

...[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)

Betrachten wir noch ein weiteres Beispiel für eine endliche Schleife:

++[>]

Dieses Beispiel zeigt, dass wir die Schleife nicht an der Zelle beenden müssen, an der die Schleife begonnen hat:

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

Es ist jedoch empfehlenswert, dort zu enden, wo wir begonnen haben. Warum ? Weil wenn die Schleife eine andere Zelle beendet, die sie gestartet hat, können wir nicht annehmen, wo sich der Zellenzeiger befinden wird. Um ehrlich zu sein, macht diese Praxis Brainfuck weniger Brainfuck.

233
Scony

Wikipedia hat eine kommentierte Version des Codes.

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

Zur Beantwortung Ihrer Fragen werden die Zeichen , Und . Für die E/A verwendet. Der Text ist ASCII.

Der Wikipedia Artikel geht auch etwas tiefer.

Die erste Zeile initialisiert a[0] = 10 Durch einfaches zehnmaliges Inkrementieren von 0. Die Schleife von Zeile 2 setzt effektiv die Anfangswerte für das Array: a[1] = 70 (Nahe 72, das ASCII Code für das Zeichen 'H'), a[2] = 100 (nahe 101 oder 'e'), a[3] = 30 (nahe 32, der Code für Leerzeichen) und a[4] = 10 (Zeilenvorschub): Die Schleife fügt den Zellen a[1], a[2], a[3] und a[4] jeweils 7, 10, 3 und 1 hinzu jedes Mal durch die Schleife - 10 Additionen für jede Zelle insgesamt (geben Sie a[1]=70 usw.) Nach Beendigung der Schleife ist a[0] Null. >++. bewegt dann den Zeiger zu a[1], das 70 enthält, werden zwei addiert (wobei 72 erzeugt wird, was ASCII Zeichencode eines Großbuchstaben H) ist), und es wird ausgegeben.

Die nächste Zeile bewegt den Array-Zeiger auf a[2] Und fügt eins hinzu, wobei 101 erzeugt wird, ein 'e' in Kleinbuchstaben, das dann ausgegeben wird.

Da 'l' zufällig der siebte Buchstabe nach 'e' ist, werden zur Ausgabe 'll' weitere sieben (+++++++) Zu a[2] Hinzugefügt und das Ergebnis zweimal ausgegeben.

'o' ist der dritte Buchstabe nach 'l', also wird a[2] noch dreimal erhöht und das Ergebnis ausgegeben.

Der Rest des Programms läuft auf die gleiche Weise ab. Für die Leerzeichen und Großbuchstaben werden verschiedene Array-Zellen ausgewählt und nach Bedarf inkrementiert oder dekrementiert.

50
ken

Um die Frage zu beantworten, wie es weiß, was zu drucken ist, habe ich die Berechnung von ASCII Werten rechts neben dem Code, in dem das Drucken erfolgt, hinzugefügt:

> 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)
8
Rehana Mahfuz

Brainfuck wie sein Name. Es werden nur 8 Zeichen verwendet > [ . ] , - + was es zur schnellsten Programmiersprache macht zu lernen aber am schwierigsten zu implementieren und zu verstehen .... und macht Am Ende hast du es geschafft, dein Gehirn zu ficken.

Es speichert Werte in einem Array: [72] [101] [108] [111]

let, anfänglich Zeiger auf Zelle 1 des Arrays:

  1. > Zeiger um 1 nach rechts bewegen

  2. < Zeiger um 1 nach links bewegen

  3. + Erhöhen Sie den Wert der Zelle um 1

  4. - Erhöhe den Wert des Elements um 1

  5. . Druckwert der aktuellen Zelle.

  6. , Eingabe in die aktuelle Zelle übernehmen.

  7. [ ] Schleife, +++ [-] Zähler von 3 Zählern, bcz, 3 '+' vor sich haben, und - Zählervariable um 1 Wert dekrementieren.

die in Zellen gespeicherten Werte sind ASCII-Werte:

bezieht man sich also auf das obige Array: [72] [101] [108] [108] [111] Wenn Sie mit den ASCII-Werten übereinstimmen, werden Sie feststellen, dass es Hallo writtern ist

Glückwunsch! Sie haben die Syntax von BF gelernt

——-Etwas mehr ———

lassen Sie uns unser erstes Programm erstellen, d. h. Hello World. Danach können Sie Ihren Namen in dieser Sprache schreiben.

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

in Stücke brechen:

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

Erzeugt ein Array mit 4 Zellen (Anzahl von>) und setzt einen Zähler von 10 in etwa wie folgt:

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

da der Zählerwert in Zelle 0 gespeichert ist und> zu Zelle 1 wechselt, wird sein Wert um + 7 aktualisiert.> zu Zelle 2 wechselt, erhöht sich der Wert um 10 auf den vorherigen Wert und so weiter.

<<< kehre zu Zelle 0 zurück und dekrementiere ihren Wert um 1

daher haben wir nach Beendigung der Schleife das Array: [70,100,30,10]

>++. 

bewegt sich zum 1. Element und erhöht seinen Wert um 2 (zwei "+") und druckt dann das Zeichen (".") mit diesem ASCII-Wert. zum Beispiel in Python: chr (70 + 2) # gibt 'H' aus

>+.

bewegt sich zu Schritt 1 der 2. Zelle auf seinen Wert 100 + 1 und druckt ('.') seinen Wert, dh chr (101) chr (101) #prints 'e' jetzt gibt es kein> oder <im nächsten Stück, so dass es den gegenwärtigen Wert annimmt des neuesten Elements und inkrementieren nur dazu

+++++ ++..

das letzte Element = 101 ist daher 101 + 7 und druckt es zweimal aus (da es zwei ‘..’ gibt). chr (108) #prints l two kann als

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

———Wo wird es verwendet? ——-

Es ist nur eine Scherzsprache, die gemacht ist, um Programmierer herauszufordern, und wird praktisch nirgendwo verwendet.

7
TheVishal

Alle Antworten sind gründlich, aber es fehlt ein kleines Detail: Drucken. Bei der Erstellung Ihres Brainfuck-Übersetzers berücksichtigen Sie auch das Zeichen .. So sieht eine Druckanweisung in Brainfuck aus. Ihr Brainfuck-Übersetzer sollte also immer dann vorgehen, wenn er auf ein . -Zeichen stößt, das das aktuell angegebene Byte ausgibt.

Beispiel:

angenommen, Sie haben -> char *ptr = [0] [0] [0] [97] [0] ... wenn dies eine Brainfuck-Anweisung ist: >>>. Ihr Zeiger sollte 3 Leerzeichen nach rechts verschoben werden, um zu landen: [97], Nun *ptr = 97, nachdem Ihr Übersetzer auf ein . gestoßen ist, sollte er dann aufrufen

write(1, ptr, 1)

oder eine entsprechende Druckanweisung zum Drucken des aktuell angezeigten Bytes mit dem Wert 97 und dem Buchstaben a wird dann auf dem std_output gedruckt.

4
rapdean

Ich denke, Sie fragen sich, woher Brainfuck weiß, was mit dem ganzen Code zu tun ist. Es gibt einen Parser, der in einer höheren Sprache geschrieben ist, z. B. Python), um zu interpretieren, was ein Punkt oder ein Zusatzzeichen im Code bedeutet.

Der Parser liest also Ihren Code zeilenweise und sagt, ok, es gibt ein> -Symbol, damit ich den Speicherplatz erweitern muss. Der Code lautet einfach, wenn (Inhalt in diesem Speicherplatz) ==>, memlocation = + memlocation geschrieben in einer höheren Sprache, ähnlich wenn (Inhalt im Speicherort) == ".", dann drucken (Inhalt des Speicherorts).

Hoffe das klärt es auf. tc

1
Rahul