⚠️ Warning: This is a draft ⚠️

This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.

If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.

;---------------------------------------------------------------------------
; SNUSP Interpreter.ahk
; by wolf_II
;---------------------------------------------------------------------------
; interpreter for SNUSP code
;---------------------------------------------------------------------------



;---------------------------------------------------------------------------
Code = ; Goodbye, World!
;---------------------------------------------------------------------------
    (
Example taken from RosettaCode.org

$@\G.@\o.o.@\d.--b.@\y.@\e.>@\comma.@\.<-@\W.+@\o.+++r.------l.@\d.>+.! #
  |   |     \@------|#  |    \@@+@@++|+++#-    \\               -
  |   \@@@@=+++++#  |   \===--------!\===!\-----|-------#-------/
  \@@+@@@+++++#     \!#+++++++++++++++++++++++#!/
    )



;---------------------------------------------------------------------------
AutoExecute: ; auto-execute section of the script
;---------------------------------------------------------------------------
    #SingleInstance, Force          ; only one instance allowed
    #NoEnv                          ; don't check empty variables
    ;-----------------------------------------------------------------------
    AppName := "SNUSP"
    Gosub, GuiCreate
    Gui, Show,, %AppName%

Return



;---------------------------------------------------------------------------
GuiCreate: ; create the main window
;---------------------------------------------------------------------------
    ; GUI options
    Gui, Margin,, 10
    Gui, Add, Edit, y0 h0 ; catch the focus
    Gui, Add, Checkbox, vWatch, Watch

    ; SNUSP Code
    Gui, Add, GroupBox, w554 h265, SNUSP Code
    Gui, Font, s8, Courier New
    Gui, Add, Edit, xp+10 yp+20 w534 r15 -Wrap +HScroll vCode HwndhCode, %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 w554 h248, Output
    Gui, Font, s8, Courier New
    Gui, Add, Edit, xp+10 yp+20 w534 r15 ReadOnly vOutput HwndhOut
    Gui, Font ; normal

Return



;---------------------------------------------------------------------------
ButtonLoadCode: ; load code from file
;---------------------------------------------------------------------------
    Gui, +OwnDialogs
    FileSelectFile, CodeFile,,, Load SNUSP Code, *.snusp
    If (ErrorLevel = 1) {
        ; user dismissed the dialog
        Gui, Show
        Return
    }
    If Not SubStr(CodeFile, -5) = ".snusp"
        CodeFile .= ".snusp"
    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,, SNUSP Code, *.snusp
    If (ErrorLevel = 1) {
        ; user dismissed the dialog
        Gui, Show
        Return
    }
    If Not SubStr(CodeFile, -5) = ".snusp"
        CodeFile .= ".snusp"
    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
    ;~ GuiControl, Disable, Code
    GuiControl, Disable, Output
    GuiControl, Disable, &Load
    GuiControl, Disable, &Save
    GuiControl, Disable, &Run
    Gosub, PadCode
    ;~ GuiControl, Enable, Code
    GuiControl, Enable, Output
    GuiControl, Enable, &Load
    GuiControl, Enable, &Save
    GuiControl, Enable, &Run

Return



;---------------------------------------------------------------------------
PadCode: ; pad code with spaces
;---------------------------------------------------------------------------
    mL := 0 ; max length
    Loop, Parse, Code, `n
        If (Len := StrLen(A_LoopField)) > mL
            mL := Len
    PaddedCode := ""
    Loop, Parse, Code, `n
        PaddedCode .= A_LoopField Repeat(" ", mL - StrLen(A_LoopField)) "`r`n"
    GuiControl,, Code, % Code := PaddedCode
    ml += 2

    ; find code entry point
    InstrPtr := (pos := InStr(Code, "$")) ? pos : 1

;---------------------------------------------------------------------------
Interpreter: ; this is the SNUSP Interpreter
;---------------------------------------------------------------------------
    ; setup SNUSP environment
    VarSetCapacity(SNUSP_MEM, 4096, 0)
    DataPtr := InstrDir := 0
    ControlFocus,, ahk_id %hCode%
    Loop {

        ; read next instruction
        getNext(InstrPtr)
        CMD := SubStr(Code, InstrPtr, 1)
        Data@Ptr := NumGet(SNUSP_MEM, DataPtr, "Char")
        If Watch {
            Highlight(InstrPtr)
            Sleep, 25
            ;~ ListVars
            ;~ Pause
        }

        If (CMD = "+") ; increment the data at DataPointer
            NumPut(Data@Ptr + 1, SNUSP_MEM, DataPtr, "Char")

        Else If (CMD = "-") ; decrement the data at DataPointer
            NumPut(Data@Ptr - 1, SNUSP_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(), SNUSP_MEM, DataPtr, "Char")

        Else If (CMD = "\") ; LURD
            LURD(InstrDir)

        Else If (CMD = "/") ; RULD
            RULD(InstrDir)

        Else If (CMD = "!") ; SKIP
            getNext(InstrPtr)

        Else If (CMD = "?") { ; SKIPZ
            If (Data@Ptr = 0)
                getNext(InstrPtr)

        } Else If (CMD = "@") { ; ENTER
            Push("Stack", InstrPtr)
            Push("Stack", InstrDir)

        } Else If (CMD = "#") { ; LEAVE
            InstrDir := Pop("Stack")
            InstrPtr := Pop("Stack")
            If (ErrorLevel = -1)
                Break
            Else
                getNext(InstrPtr)

        } Else If (CMD = "") ; this is the end of code
            Break
    }

Return



;---------------------------------------------------------------------------
getNext(ByRef InstrPtr) { ; get next instruction pointer
;---------------------------------------------------------------------------
    ;    instruction directions
    ;         Up = 3
    ;     Left = 2   0 = Right
    ;              1 = Down
    ;-----------------------------------------------------------------------
    global InstrDir, mL
    InstrPtr += (InstrDir > 1 ? -1 : 1) * (InstrDir & 1 ? mL : 1)
}



;---------------------------------------------------------------------------
LURD(ByRef InstrDir) { ; reflect the instruction direction "\"
;---------------------------------------------------------------------------
    ;~ case 0 -> 1
    ;~ case 1 -> 0
    ;~ case 2 -> 3
    ;~ case 3 -> 2
    ;-----------------------------------------------------------------------
    InstrDir += (InstrDir & 1 ? -1 : 1)
}



;---------------------------------------------------------------------------
RULD(ByRef InstrDir) { ; reflect the instruction direction "/"
;---------------------------------------------------------------------------
    ;~ case 0 -> 3
    ;~ case 1 -> 2
    ;~ case 2 -> 1
    ;~ case 3 -> 0
    ;-----------------------------------------------------------------------
    InstrDir := 3 - InstrDir
}



;---------------------------------------------------------------------------
Repeat(String,Count) {
;---------------------------------------------------------------------------
    Loop, %Count%
        Result .= String
    Return, Result
}



;---------------------------------------------------------------------------
GetChar() { ; retrieve a single char from StdIn (keyboard)
;---------------------------------------------------------------------------
    Progress, b2 w150 zh0 fs9, SNUSP 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--
}



;---------------------------------------------------------------------------
Highlight(InstrPtr) { ; select current command in code
;---------------------------------------------------------------------------
    global hCode
    SendMessage, 0xB1, InstrPtr-1, InstrPtr,, ahk_id %hCode% ; EM_SETSEL
}



;---------------------------------------------------------------------------
Output(Text) { ; append text to output
;---------------------------------------------------------------------------
    ; for non-interruptable output
    ;-----------------------------------------------------------------------
    global hOut
    SendMessage, 0xC2,, &Text,, ahk_id %hOut% ; EM_REPLACESEL
}



;---------- end of file ----------------------------------------------------