Het boek "The Pragmatic Programmer" (als je het nog niet gelezen hebt, stop dan met het lezen van dit artikel en doe het nu!) zegt dat we elk jaar één nieuwe programmeertaal moeten leren.
Hoewel sommigen misschien beweren dat het te veel moeite is, kunnen we het er allemaal over eens zijn dat het een goed idee kan zijn. Het kiezen van een nieuwe taal om te leren is niet zo eenvoudig. We willen onze tijd toch niet besteden aan iets dat we in de praktijk misschien nooit zullen gebruiken? Maar misschien moeten we soms een uitzondering maken en iets leren voor de lol? Ik stel jullie graag de Brainfuck-taal voor. Het is een taal die je in een paar minuten kunt leren, dus er is geen probleem om te veel van je tijd voor niets te investeren. Ik kan je ook beloven dat het oplossen van problemen met Brainfuck je hersenen zal stimuleren (alle f*cks zijn slechts een bonus ;)). Laten we beginnen! Volgens Wikipedia:
Brainfuck is een esoterische programmeertaal gemaakt in 1993 door Urban Müller. De taal bestaat uit slechts acht eenvoudige commando's en een instructie-aanwijzer. Hoewel het volledig Turing-compleet is, is het niet bedoeld voor praktisch gebruik, maar om programmeurs uit te dagen en te amuseren.
Overzicht taal
Stel je een oneindig lang lint (of tape) voor dat bestaat uit cellen, elk geïnitialiseerd op 0. Er is ook een beweegbare datapointer die aanvankelijk naar de eerste cel wijst. Er zijn ook twee stromen bytes voor invoer en uitvoer. Instructies worden één voor één uitgevoerd. De machine stopt na het uitvoeren van de laatste instructie.
Opdracht
Wat doet het?
>
gegevensaanwijzer naar de volgende cel rechts verplaatsen
<
gegevensaanwijzer naar de volgende cel aan de linkerkant verplaatsen
+
waarde van huidige cel verhogen
–
waarde van huidige cel verlagen
.
uitvoer van de byte van een cel met de huidige punt in ASCII code
,
lees een byte van stdin en sla de waarde op in de huidige cel
[
als de huidige cel 0 is, spring dan naar de overeenkomende ]
]
naar de overeenkomende [ springen
Alle tekens behalve ><+-.,[] worden genegeerd.
Laten we eens kijken naar een eenvoudig voorbeeld:
,+.
Het wordt als volgt geïnterpreteerd:
lees een byte en sla deze op in de huidige cel (cel0)
waarde van huidige cel verhogen (cell0 = cell0 + 1)
schrijf inhoud van huidige cel naar uitvoer
Het resultaat is dat een karakter van de invoer wordt gelezen en het volgende karakter uit de ASCII-tabel wordt afgedrukt.
Interpreter / Compiler
Voordat we nuttige (?) programma's in Brainfuck kunnen schrijven, hebben we een interpreter of een compiler nodig. AFAIK, er is geen officiële, maar dat is geen probleem. Er zijn tientallen onofficiële op het Internet te vinden. Ik kan deze twee aanbevelen:
"Hello World!" zou het eerste programma moeten zijn dat we schrijven als we een nieuwe taal leren. Maar het schrijven ervan in Brainfuck is iets moeilijker dan in andere talen. We moeten beginnen met iets eenvoudigers... Laten we een programma schrijven dat een enkele letter "H" op het scherm afdrukt (zo spannend :D):
Hoe werkt het? Het stelt de waarde van de huidige cel in op 72 (met stappen van 72) en drukt het af op het scherm met "." (H heeft code 72 in ASCII). Nu weet je wat we moeten doen om "Hello World!" op het scherm af te drukken, maar eerst gaan we een kleine refactoring uitvoeren. Het schrijven van al die '+' vereist te veel typen en tellen. We kunnen het korter maken door [ en ] om een lus te maken. Om de waarde op 72 te zetten, kunnen we bijvoorbeeld een lus maken die de waarde 7 keer met 10 verhoogt. Op deze manier krijgen we 70. Door 2 toe te voegen wordt het 72. Het ziet er als volgt uit:
++++++++++ # zet cel0 op 10
[# lus tot cel0 is 0
- # verlaag cel0
> # verplaats data pointer naar rechts (cell1)
+++++++ # cel1 met 7 verhogen
# gegevensaanwijzer naar rechts verplaatsen (cell1)
++ # verhogen met 2
. # het resultaat afdrukken
Ik heb commentaar toegevoegd om duidelijk te maken hoe alles werkt. Hetzelfde programma zonder commentaar:
++++++++++[->+++++++++.
Is het niet prachtig? 🙂
Hallo Wereld!
We gaan terug naar ons programma "Hello World! We kunnen de waarde van de eerste cel instellen op 72 (H) en deze afdrukken, de waarde van de 2e cel instellen op 101 (e) en deze afdrukken, de waarde van de 3e cel instellen op 108 en deze afdrukken, enzovoort. Hier is de implementatie van dit algoritme:
Ja, slechts 1120 bytes om "Hello World!" af te drukken... Maar we kunnen beter! In plaats van voor elk teken een nieuwe cel te gebruiken, gebruiken we er maar één. Om de letter "e" (101) af te drukken, kunnen we de waarde in cel0 (72) opnieuw gebruiken. We kunnen de waarde 29 keer met één verhogen (101 - 72). En het resultaat is als volgt:
Het is slechts 106 bytes en het print een nieuwe regel aan het einde! Verbazingwekkend.
Een string omkeren
Nu zijn we klaar om iets uitdagenders te schrijven. Laten we een programma schrijven dat een regel van de invoer leest en in omgekeerde volgorde afdrukt. Het eerste probleem is om karakters te lezen en te stoppen op het karakter van de nieuwe regel. Onthoud dat er geen break, als of andere soortgelijke verklaringen. We moeten [ en ]. Laten we beginnen met een programma dat alle tekens uit de invoer leest en ze in opeenvolgende cellen plaatst:
,[>,]
Het begint met het lezen van het eerste teken en gaat door tot het laatste , operatie retourneert 0. Het zal echter eeuwig blijven lussen in een implementatie die iets anders teruggeeft dan O voor EOF (de taal specificeert dit gedrag niet). Dus hoe kunnen we stoppen op het nieuwe regelkarakter? Hier is de truc:
+[++++++++++>,----------]
We beginnen met cel0 ingesteld op 1 om ervoor te zorgen dat onze lus minstens één keer wordt uitgevoerd. In een lus verhogen we de waarde van de huidige cel met 10, verplaatsen we de datapointer naar de volgende cel, lezen we een teken en verlagen we de waarde met 10. Op deze manier stopt het programma in een volgende iteratie als er een nieuw lijnteken (10 in ASCII) wordt gelezen. Op deze manier als er een nieuw regelkarakter (10 in ASCII) wordt gelezen, stopt het programma in een volgende iteratie, anders wordt de waarde hersteld door 10 toe te voegen.
Na deze stap zien onze cellen er als volgt uit:
11 C1 C2 C3 0* 0 0
Cn het n-de teken van invoer is, en * is de huidige positie van de gegevensaanwijzer. Nu moeten we beginnen de gegevensaanwijzer naar links te verplaatsen en alle cellen afdrukken tot we waarde 11 bereiken. Hier is mijn kijk op de taak:
Toen ik op Brainfuck stuitte, een esoterische programmeertaal, deed ik het in eerste instantie af als niets meer dan een gimmick of een grap. Deze eigenaardige, en zoals velen zullen beweren, verbijsterend moeilijke taal, kwam op mij over als iets dat alleen bedoeld was voor amusement. Maar na verloop van tijd veranderde mijn kijk op Brainfuck dramatisch.
Het raadselachtige karakter van Brainfuck daagt je uit en dwingt je om je kijk op het leven te verbreden. programmeertalen. Deze esoterische taal laat je de schoonheid en noodzaak inzien van de high-level talen die we gewend zijn. Het brengt het belang van abstracties, de juiste naamgevingsconventies en een georganiseerde geheugenindeling in het domein van programmeertalen onder de aandacht. Dit is iets wat Brainfuck, met zijn minimalistische ontwerp bestaande uit slechts acht eenvoudige commando's, niet biedt.
Brainfuck is een complete Turing-taal die het belang van een duidelijke, coherente broncode nog eens benadrukt. Ondanks dat het erkend wordt als een van de meest uitdagende esoterische talen om programma's in te schrijven, schittert het ironisch genoeg als beginnersfavoriet voor iedereen die zelf een Brainfuck compiler of een Brainfuck interpreter wil maken. De reden hiervoor is de eenvoud van de commandoset en het feit dat het geen complexe parsing vereist.
Het maken van een Brainfuck-programma is op twee manieren uniek. Ten eerste moet je je aanpassen aan het gebruik van een enkele geheugenpointer, wat je dwingt om anders over je broncode na te denken. En ten tweede heb je de 'nul-optie', wat de mogelijkheid is om de geheugencel op nul te zetten, een functie die niet gebruikelijk is in andere formele programmeertalen.
Op het gebied van leren is er meer dan Brainfuck op het eerste gezicht lijkt. Met genoeg tijd en de juiste instelling is het mogelijk om hetzelfde programma op veel verschillende manieren te schrijven met verschillende Brainfuck-codes. De laatste helft van deze reis draait om inventiviteit en het vinden van nieuwe, creatieve manieren om de zes symbolen te gebruiken.
Hoewel de Brainfuck interpreters minimalistisch zijn, geven ze je een diepgaand begrip van hoe code draait, wat het programma afdrukt en de onderliggende mechanica van een Turing-taal. Uiteindelijk is Brainfuck niet zomaar een esoterische programmeertaal. Het is een geheel nieuwe dimensie, een andere kijk op hoe we programma's zien, begrijpen en schrijven.