Brain-o-Zap
BrainF_ck-interpreter (Win 98)
|
|
Screenshot
Einführung
Download
Tech-defs
Versions/Techinfo(english)
Techdefs
1) Konzeption
IDE und Engine sind separate Einheiten; die Engine ist als
Delphi-6-Unit
ausgelegt, wird aber demnächst auch als Windows/C-dll
verfügbar sein.
2) Technische Daten
der Engine:
2.1) Speicher
- Codebereich : in dieser Implementierung: beliebig (nur durch den
verfügbaren Hauptspeicher begrenzt)
- Datenbereich: hier 65565
Adressen
- Datentyp: hier: Byte;
Überlauf möglich 255+1 = 0
- Klammerverschachtelungstiefe : 1000
2.2) Prozeduren
constructor create;
destructor destroy;
function GetCode(const s:string):integer; // allocates code-array
function
CmpJmp:integer;
// allocates jmp-array
function
exec:integer;
// allocates dataarray
procedure
FreeData;
// allocates dataarray with length 0
function disassemble:string;
procedure DfltPutch(const d:byte);// does nothing
function DfltGetCh:byte; // Gets value 0
procedure DfltDoEvents; // does nothing.
meaningful is: application.processmessages
procedure DfltDebug(const status:integer;
const aCP,aDP:integer;
const ACode:tcodeArr;
const AJmp :tjmpArr;
const AData:tDataArr;
const aQa,qQe:byte;
const aQueue:tqueue_arr);
end;
Die Dflt-Prozeduren stellen leere Behälter dar; sie tun praktisch
nichts.
Eine Applikation implementiert sinnvolle Prozeduren und lenkt nach dem
Erzeugen einer Engine-Instanz (bf:=tbf.create) deren
diesbezügliche
Prozedurvariablen PutCH, GetCH und DoEvents auf ihre Implementierungen.
2.3) Verwendung
Eine minimale Sequenz von Aufrufen zeigt das folgende:
//initalization
------------------------------
bf:=tbf.create;
// assign
communication-channels between engine & application
bf.putch:=myfrm_putchImplementation;
bf.getch:=myfrm_GetchImplementation;
bf.doevents:=myfrm_DoeventsImplementation ;
//only if abort-mechanism is required
// using: compiling some code
-------------------------
//pass your code
to bf to be compiled
bf.Getcode(',++.') ; // interpret BF-code provided by a
long-string
// the string can contain comments
etc.
bf.CmpJmp
;
// comptes jump-table for
block-control by brackets "[]"
// code is in array CODE[]
//running:
---------------------------------------------
//
execute your code, getting eventually errormessages
errcode:=bf.exec;
if errcode<>0 then
application.messagebox('error:',errmsg[errcode]);
//optionally
you can free the data-array after execution
freedata;
//deleting
// if no more
compiles or executes wished, instance must be freed
bf.destroy;
3) Gültige Codes
Die ursprüngliche Sprachdefinition erklärt 8 Codes:
- Eingabe/Ausgabe eines Zeichens (wird intern als Byte behandelt) :
"," =(komma)
1 Zeichen vom Anwender (über Inputkanal) erhalten
"." =(punkt)
1 Zeichen über Outputkanal ausgeben
">" = 1
Adresse hochzählen
"<" = 1
Adresse herunterzählen
"+" = am
Datenpointer 1 hinzuzählen
"-" = am
Datenpointer 1 abziehen
"[" = wenn
am Datenpointer=0, hinter zugehörige
"]" springen
"]" = wenn
am
Datenpointer>0, hinter zugehörige "[" springen
4) IDE
4.1) "Fenster"
Codefenster und Outputfenster sind Richedit-Fenster, die beliebig
große Ausgaben verwalten können, und -außer dem
anwendungsspezifischen
Popup-Menü- die üblichen Tastenkürzel für
Markieren, Copy&Paste verwenden.
4.2) Compile & Run
Bevor ein Code ausgeführt werden kann, muß er compiliert
werden.
Danach kann er beliebig oft (z.B. mit wechselnden Dateneingaben) aus-
geführt werden, ohne ihn neu zu compilieren.
4.3) Dateneingabe
während der Programmausführung:
es wird eine einzelne Tastatureingabe, abgeschlossen mit Eingabetaste
erwartet
oder aber die Eingabe einer Nummer zwischen 0 und 255 in der Form
#nnn z.B. #0 oder #10 oder #255
Der ASCII-code der Tastatureingabe oder aber die durch #nnn angegebene
Zahl
wird an die Engine übergeben, nicht die Zahl 1 bei Tastendruck "1"
!
4.4) Datenausgabe
während der Programmausführung:
Die von der Engine angelieferten Bytes werden als Ansi-Characters
angezeigt.
Dies schließt die Wirkung der Zeilenumbruchssequenzen,
Tabulatoren etc. ein;
dieser Effekt wird nicht kompensiert.
Nur die Ausgabe der Ascii-Null wird übersetzt in Ascii 180
(kleiner mittlerer
Punkt, da die Ansi-Stringoperationen unter Windows die Ascii-Null als
Begrenzer
behandeln.
4.5) Break
Bei fehlerhaften Läufen, im Eingabe-Wartezustand kann der
Programmlauf
abgebrochen werden. Dies wird durch Zuweisung einer Process-Messages-
Prozedur an den DOEVENTS-Channel /Prozedurvariable ermöglicht.
In der IDE erhält man dazu einen Knopf, der nur aufscheint, wenn
das programm
läuft, und den man während der programmausführung
drücken kann.
4.6) Formatter
Code kann im codefenster komprimiert werden indem alle Zeichen
außer den
BrainFuck-tokens entfernt werden und jede Zeile auf 64 Zeichen
umgebrochen
wird. Hierzu dient ein Eintrag im Code-Popup-Menu.
4.7) Quelltextdateien
brainfuck-Quelltext-Dateien können gelesen und geschrieben
werden.
4.8) Disassemblierung
Der Disassembler liefert folgenden Output:
BF-Opcode Assm
+ INC
- DEC
>
FOC +1 // Fokus
ist der Data-Pointer
< FOC -1
. PUT
, GET
[ WHILE [FOC]>0 BEGIN
] END
Die Assembler-Token sind über die BF.INI-Datei
konfigurierbar, s.u. .
Optimierungen:
4.8.1)
Zusammenfassung von Wiederholungen
Folgen mehrere gleichartige Opcodes (außer Klammern)
hintereinander
werden diese zu der geeigneten Mnemo-Codierung plus einer
Zählangabe zusammen-
gefaßt:
++++ INC 4
<<< FOC -3
.. PUT *2
4.8.2) Sequenzen
bestimmte im Code erkannte Sequenzen werden bereits zu
komplexeren
Menmocodes zusammengefaßt:
[-]
CLR
//clears current position
[->>>>+<<<<]
MOV
+4
//moves value to 4 positions right
[->>>>++++<<<<]
MUL *4 TO +4
//multiplication into new position
[-->>>>+++++<<<<] MUL
*5 div 2 TO +4 //rational multiplication into new position
//For MOV and MUL the following rules are in effect:
//* initial position will be cleared
//* all 4 variations of all these themes are detected
// example given: the four variations of MOV +2
// MOV +2 [->>+<<]
//
[>>+<<-]
// MOV -2 [-<<+>>]
//
[<<+>>-]
Etwas präziser ausgedrückt
enthalten MOV/MUL-Instruktionen einen zusätzlichen INC:
wenn auf DATA[DP] ein MOV +4 folgt
so ist das Ergebnis
vor MOV nach MOV
DATA[DP] =
x 0
DATA[DP+4] =
? ?+x
wenn auf DATA[DP] ein MUL
*3 TO +4 folgt so ist das Ergebnis
vor MOV nach MOV
DATA[DP] =
x 0
DATA[DP+4] =
? ?+3*x
5) Beispiel einer INI-Datei:
[Defaults]
;
DON'T CHANGE THE DEFAULTS
ErrMsgCount=3
DefaultProgsCount=0
Language
= "DE"
ownerLabel
="Doros Brain-F*ck"
[Languages]
;if
you localize messages for other countries, add entries here
LANG1
= "DE"
LANG2
= "EN"
[Globals]
;
Start here, if you want change something
;for
example-programs at the end; must correspond to this number
DefaultProgsCount=2
;select
one of the provided languages
Language
= "DE"
[PopupMenuDE]
Code_fileopen="ein&lesen
BF-Programmdatei"
Code_fileSave="&speichern
BF-Programmdatei"
Code_FilterCode="&Filter
Code"
Output_Clear
= "&Lösche Ausgabe"
input_blank
="#32 Leerzeichen"
input_null
= "#0 Null-Zeichen"
input_newline
= "#10 Neue Zeile"
input_255
="#255 maxbyte"
input_tab
="#9 Tabulator"
[PopupMenuEN]
Code_fileopen="&load
code from file"
Code_fileSave="&save
code to file"
Code_FilterCode="&filter
code"
Output_Clear
= "&clear output"
input_blank
="#32 blank"
input_null
= "#0 null-char"
input_newline
= "#10 newline"
input_255
="#255 maxbyte"
input_tab
="#9 tabulator"
[ButtonsDE]
BTN_COMPILE
= "&Brain-O-"
BTN_RUN
= "&ZAP"
[ButtonsEN]
BTN_COMPILE
= "&Brain"
BTN_RUN
= "&F_ck"
[dialogsDE]
filefilter
= "BrainF*ck-Code (*.bf;*.b)|*.bf;*.b|Alle Dateien(*.*)|*.*"
DefaultExt
= 'bf'
InitialDir
= '.\examples'
[dialogsEN]
filefilter
= "BrainF*ck-Code (*.bf;*.b)|*.bf;*.b|all files(*.*)|*.*"
DefaultExt
= 'bf'
InitialDir
= '.\examples'
[HintsDE]
compile="Zum
Kompilieren BRAIN drücken"
run="Zum
Starten F*CK drücken"
input="Taste
oder numerischen Code mit # eingeben (z.B. #19) mögl.
Bereich:0..255"
code="rechte
Maustaste für Code-Beispiele oder Codedatei.Operationen"
adviceButtons="Code
eingeben, zum Kompilieren BRAIN drücken und dann F*CK!"
adviceInput="Taste
oder #ascii-code, Eingabe"
[HintsEN]
compile="click
BRAIN to compile"
run="click
F*CK to run program"
input="input
key or numerical code preceded by # (i.e. #19) range:0..255"
code="right
mouseclick for code-examples or codefile-operations"
adviceButtons="Enter
Code, press BRAIN and then F*CK!"
adviceInput="Input
key or #asci-number, return"
[ErrMsgDE]
;number
cannot be changed!
Errmsg1="Upps.
You tried to access above data-area(too many >>> going above
65000)";
Errmsg2="Snor.
You tried to access below data-area(too many <<< going below
1)";
Errmsg3="Arrg!
You have too many closing brackets";
[ErrMSGEN]
Errmsg1="Upps.
You tried to access above data-area(too many >>> going above
65000)";
Errmsg2="Snor.
You tried to access below data-area(too many <<< going below
1)";
Errmsg3="Arrg!
You have too many closing brackets";
[AssembDE]
Assemb1=
'Raufzählen '
Assemb2=
'Runterzählen '
Assemb3=
'Speicherstelle +'
Assemb4=
'Speicherstelle -'
Assemb5=
'Schreiben '
Assemb6=
'Kriegen '
Assemb7=
'WHILE [SpSt]>0 BEGIN '
Assemb8=
'END'
Assemb9=
'Löschen '
Assemb10='Verschieben
'
Assemb11='Mult
'
Assemb12='
TO '
[AssembEN]
Assemb1=
'INC '
Assemb2=
'DEC '
Assemb3=
'FOC +'
Assemb4=
'FOC -'
Assemb5=
'PUT '
Assemb6=
'GET '
Assemb7=
'WHILE [FOC]>0 BEGIN '
Assemb8=
'END'
Assemb9=
'CLR '
Assemb10='MOV
'
Assemb11='MUL
'
Assemb12='
TO '
[About]
;can
be localized, need not be rtf, should not be more than 22 lines
line1
="{\rtf1\ansi\deff0\deftab720{\fonttbl{\f0\fswiss MS Sans Serif;}"
line2
="{\f1\froman\fcharset2 Symbol;}"
line3
="{\f2\fswiss\fcharset1 Tahoma;}"
line4
="{\f3\fswiss\fcharset1 MS Sans Serif;}"
line5
="{\f4\fswiss\fcharset1 MS Sans Serif;}}"
line6
="{\colortbl\red0\green0\blue0;\red0\green128\blue128;}"
line7
="\deflang1031\pard\qc\plain\f2\fs32\cf1\b BrainF*ck"
line8
="\par - IDE/Interpreter for Win98 - "
line9
="\par \plain\f2\fs32\b "
line10
="\par \plain\f2\fs20 written in Delphi by "
line11
="\par "
line12
="\par Gottfried Helms"
line13
="\par Kassel"
line14
="\par "
line15
="\par for"
line16
="\par "
line17
="\par \plain\f2\fs20\b Doro @ d0r0 de\plain\f2\fs20 "
line18
="\par 5.1.2004/8.1.2004"
line19
="\par \plain\f4\fs16 "
line20
="\par V 1.2 "
line21
="\par }"
; you
can add as may examples as you like, but think of reasonable size
; of
popup-menu!
; two
kind sources for code:
;
http://koeln.ccc.de/prozesse/zombies/brainfuck/index.en.xml
;
http://www.hevanet.com/cristofd/brainfuck/
[Example1]
titleDE
= "Hello World"
titleEN
= "Hello World"
line1
= ";BrainF*ck : Hello World! "
line2
= "; "
line3
=
">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[
"
line4
=
"-]>++++++++[<++++>-]<.>+++++++++++[<++++++++>-]<-.--------.
"
line5
=
"+++.------.--------.[-]>++++++++[<++++>-]<+.[-]++++++++++.
"
line6
= " "
[Example2]
titleDE
= "Hallo Doro"
titleEN
= "Hallo Doro"
line1
= ";BrainF*ck: Hallo doro! "
line2
= "; "
line3
= ";START "
line4
= ">+++++++++[<++++++++>-]<. "
line5
= ">+++++++[<++++>-]<+----. "
line6
= "+++++++++++.. "
line7
= "+++.[-] "
line8
= ">++++++++[<++++>-]<. "
line9
= ">+++++++++[<++++++++>-]<----. +++++++++++. +++. "
line10
= "---.[-] >++++++++[<++++>-]<+. "
line11
= "[-]++++++++++. "
line12
= ";ENDE "
Gottfried
Helms, Uni Kassel
mailto://helms@uni-kassel.de