;---------------------------------------------------------------------------
; Brainf*** Interpreter.ahk
; by wolf_II
;---------------------------------------------------------------------------
; interpreter for Brainf*** code
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
Code = ; Goodbye, World!
;---------------------------------------------------------------------------
(LTrim
Example taken from RosettaCode:org
++++++++++[>+>+++>++++>+++++++>++++++++>+++++++++>++++++++++
>+++++++++++>++++++++++++<<<<<<<<<-]>>>>+.>>>>+..<.<++++++++
.>>>+.<<+.<<<<++++.<++.>>>+++++++.>>>.+++.<+++++++.--------.
<<<<<+.<+++.---.
)
;---------------------------------------------------------------------------
AutoExecute: ; auto-execute section of the script
;---------------------------------------------------------------------------
#SingleInstance, Force ; only one instance allowed
#NoEnv ; don't check empty variables
;-----------------------------------------------------------------------
AppName := "Brainf***"
Gosub, GuiCreate
Gui, Show,, %AppName%
Return
;---------------------------------------------------------------------------
GuiCreate: ; create the main window
;---------------------------------------------------------------------------
; GUI options
Gui, Margin,, 10
Gui, Add, Edit, y0 h0 ; catch the focus
; Brainf*** Code
Gui, Add, GroupBox, w462 h248, Brainf*** Code
Gui, Font, s8, Courier New
Gui, Add, Edit, xp+10 yp+20 w442 r15 vCode, %Code%
Gui, Font ; normal
; buttons
Gui, Add, Button, xm w101 h30, &Load Code
Gui, Add, Button, x+19 wp hp, &Save Code As
Gui, Add, Button, x+19 wp hp Default, &Run Code
Gui, Add, Button, x+19 wp hp, E&xit
; Output
Gui, Add, GroupBox, xm w462 h248, Output
Gui, Font, s8, Courier New
Gui, Add, Edit, xp+10 yp+20 w442 r15 ReadOnly vOutput HwndhOut
Gui, Font ; normal
Return
;---------------------------------------------------------------------------
ButtonLoadCode: ; load code from file
;---------------------------------------------------------------------------
Gui, +OwnDialogs
FileSelectFile, CodeFile,,, Load Brain*** Code, *.bf
If (ErrorLevel = 1) {
; user dismissed the dialog
Gui, Show
Return
}
If Not SubStr(CodeFile, -2) = ".bf"
CodeFile .= ".bf"
If FileExist(CodeFile) {
FileRead, Code, %CodeFile%
GuiControl,, Code, %Code%
} Else
MsgBox, 16, Error - %AppName%, File not found:`n`n"%CodeFile%"
GuiControl,, Output ; clear all output
Gui, Show
Return
;---------------------------------------------------------------------------
ButtonSaveCodeAs: ; save code to file
;---------------------------------------------------------------------------
Gui, +OwnDialogs
Gui, Submit, NoHide
FileSelectFile, CodeFile, S16,, Brain*** Code, *.bf
If (ErrorLevel = 1) {
; user dismissed the dialog
Gui, Show
Return
}
If Not SubStr(CodeFile, -2) = ".bf"
CodeFile .= ".bf"
FileDelete, %CodeFile%
FileAppend, %Code%, %CodeFile%
Gui, Show
Return
;---------------------------------------------------------------------------
GuiClose: ; {Alt-F4} pressed, [X] clicked
;---------------------------------------------------------------------------
ButtonExit: ; Exit button clicked
;---------------------------------------------------------------------------
ExitApp
Return
;---------------------------------------------------------------------------
ButtonRunCode: ; run the code from the edit field
;---------------------------------------------------------------------------
Gui, Submit, NoHide ; get code from GUI
Gosub, set_JumpPointers ; set jump pointers
GuiControl, Disable, Output
GuiControl, Disable, &Load
GuiControl, Disable, &Save
GuiControl, Disable, &Run
Gosub, Interpreter ; do your stuff, kid
GuiControl, Enable, Output
GuiControl, Enable, &Load
GuiControl, Enable, &Save
GuiControl, Enable, &Run
Return
;---------------------------------------------------------------------------
Interpreter: ; This is the Brainf*** Interpreter
;---------------------------------------------------------------------------
; setup BF environment
VarSetCapacity(BF_MEM, 4096, 0)
DataPtr := InstrPtr := 0
Loop {
; read next instruction
CMD := SubStr(Code, ++InstrPtr, 1)
Data@Ptr := NumGet(BF_MEM, DataPtr, "Char")
If (CMD = "+") ; increment the data at DataPointer
NumPut(Data@Ptr + 1, BF_MEM, DataPtr, "Char")
Else If (CMD = "-") ; decrement the data at DataPointer
NumPut(Data@Ptr - 1, BF_MEM, DataPtr, "Char")
Else If (CMD = ">") ; increment the DataPointer
DataPtr++
Else If (CMD = "<") ; decrement the DataPointer
DataPtr--
Else If (CMD = ".") ; print the char at DataPointer
Output(Chr(Data@Ptr))
Else If (CMD = ",") ; get a char from stdin (keyboard)
NumPut(GetChar(), BF_MEM, DataPtr, "Char")
Else If (CMD = "[") { ; conditional jump
If (Data@Ptr = 0)
; continue after the corresponding "]"
InstrPtr := Jump[%InstrPtr%]
} Else If (CMD = "]") { ; conditional jump
If (Data@Ptr != 0)
; continue after the corresponding "["
InstrPtr := Jump[%InstrPtr%]
} Else If (CMD = "") ; this is the end of code
Break
}
Return
;---------------------------------------------------------------------------
set_JumpPointers: ; setup all the jump pointers in two passes
;---------------------------------------------------------------------------
Loop, % Len := StrLen(Code) ; first pass
If (CMD := SubStr(Code, A_Index, 1)) = "["
Push("Stack", A_Index)
Else If (CMD = "]")
Jump[%A_Index%] := Pop("Stack")
Loop, % Len ; second pass goes backwards
If (CMD := SubStr(Code, Index:=Len-A_Index, 1)) = "]"
Push("Stack", Index)
Else If (CMD = "[")
Jump[%Index%] := Pop("Stack")
Return
;---------------------------------------------------------------------------
GetChar() { ; retrieve a single char from StdIn (keyboard)
;---------------------------------------------------------------------------
Progress, b2 w150 zh0 fs9, Brainf*** Interpreter waits for input ...
Input, InKey$, L1
Progress, Off
Return, Asc(InKey$)
}
;---------------------------------------------------------------------------
Push(Stack, x) { ; push x onto stack named "Stack"
;---------------------------------------------------------------------------
local pos
%Stack%_0 := pos := %Stack%_0 ? %Stack%_0 + 1 : 1
%Stack%_%pos% := x
}
;---------------------------------------------------------------------------
Pop(Stack) { ; pop value from stack named "Stack"
;---------------------------------------------------------------------------
local pos
If (pos := %Stack%_0) < 1 ; already empty
Return,, ErrorLevel := -1
Return, %Stack%_%pos%, %Stack%_0--
}
;---------------------------------------------------------------------------
Output(Text) { ; append text to output
;---------------------------------------------------------------------------
; for non-interruptable output
;-----------------------------------------------------------------------
global hOut
SendMessage, 0xC2,, &Text,, ahk_id %hOut% ; EM_REPLACESEL
}
;---------- end of file ----------------------------------------------------