FABSIL Array Based Stupid Interpreter Language (Neue Version 2)

  • Jaja, das ist dumm, ich weiß.
    Trotzdem hier: v2.1 des FABSIL Interpreters. :D

    Den Programmcode schreibt man in das Array $MEM eine Datei, die Daten mit Zeilenumbruch getrennt. Die möglichen Befehle stehen in dem längeren Kommentar.

    Spoiler anzeigen

    [autoit;FABSIL AutoIt based stupid interpreter Language
    #include <Array.au3>
    #include <File.au3>
    Global $V=False, $MEM, $POINTER=0, $DIR=1
    If $CMDLINE[0] Then
    For $i = 1 To $CMDLINE[0]
    Switch $CMDLINE[$i]
    Case '-?','--help'
    MsgBox(0x40000, 'FABSIL Commandline Options', _
    'The only possible switch oder than -? / --help is -v / --versatile before the filename to output everything that''s happening')
    Exit
    Case '-v','--versatile'
    $V = True
    Case Else
    If not FileExists($CMDLINE[$i]) Then Exit MsgBox(16,"FABSIL Error","File doesn't exist")
    $FILE=$CMDLINE[$i]
    EndSwitch
    Next
    Else
    $FILE=FileOpenDialog("FABSIL Interpreter",@WorkingDir,"FABSIL File (*.fabsil)|All files (*.*)",1)
    If not FileExists($FILE) Then Exit
    EndIf

    _FileReadToArray($FILE,$MEM)
    If $MEM[0] = 0 Then Exit MsgBox(16,"FABSIL Error","The file is empty")
    _ArrayDelete($MEM,0)

    Func w($data)
    ;Write Data to the current pointer position
    guarantee($POINTER)
    $MEM[$POINTER] = $data
    EndFunc
    Func r()
    ;Read Data from the current pointer position
    If UBound($MEM) > $POINTER Then Return $MEM[$POINTER]
    Return 0
    EndFunc
    Func i()
    $POINTER += $DIR
    EndFunc
    Func d()
    $POINTER -= $DIR
    EndFunc

    #cs commands
    NET = NextElement'sTarget
    0 do nothing
    1 put the element from the next in the element of the following element (1,2,3: put content from 2 in 3)
    2 change the direction
    3 quit
    4 output the data of the next element ( 4,2: output $MEM[2]
    5 input data into next element ( 5,2: input into $MEM[2]
    6 jump to position of the next element
    7 relative jump of the number of the next element
    8 increment the element of the next element
    9 decrement the element of the next element
    10 if next elements target is zero, jump to the next but one. otherwise jump to next but second one.
    #ce

    ;Interpreter:
    ConsoleWrite(@CRLF & @CRLF)
    While 1
    Switch r()
    Case 0;do nothing
    V("Doing nothing" & @CRLF)
    Case 1;put
    i()
    $from=r()
    guarantee($from)
    V("Copying from " & $POINTER & " (" & r() & ") to")
    i()
    guarantee(r())
    $MEM[r()]=$MEM[$from]
    V(r() & @CRLF)
    Case 2;decrease
    $DIR *= -1
    V("Changing direction (now " & $DIR & ")" & @CRLF)
    Case 3;quit
    V("Exiting")
    ConsoleWrite(@CRLF & @CRLF)
    ExitLoop
    Case 4;output
    i()
    V("Outputting the data from " & r() & ":" & @CRLF)
    $oldP = $POINTER
    guarantee($POINTER)
    $POINTER = r()
    ConsoleWrite(StringReplace(r(),"@CRLF",@CRLF))
    $POINTER = $oldP
    Case 5;input
    i()
    $oldP=$POINTER
    $POINTER=r()
    guarantee($POINTER)
    V("Demanding input")
    w(InputBox("Machine","Eingabe verlangt:"))
    V(" (" & r() & ")" & @CRLF)
    $POINTER=$oldP
    Case 6;jumpto
    i()
    $POINTER = r()-$DIR
    V("Jumping to " & $POINTER+$DIR & @CRLF)
    If UBound($MEM) <= $POINTER Then
    V("Exiting because of pointer beyond memory")
    Exit
    EndIf
    Case 7;jumprelative
    i()
    V("Jumping " & r() & " steps forward (now ")
    $POINTER += (r()-$DIR)
    If UBound($MEM) <= $POINTER Then
    V(@CRLF & "Exiting because of pointer beyond memory")
    Exit
    EndIf
    V($POINTER+$DIR & ")" & @CRLF)
    Case 8;increment
    i()
    $oldP=$POINTER
    $POINTER=r()
    guarantee($POINTER)
    V("Incrementing " & $POINTER & " (now " & r()+1 & ")" & @CRLF)
    w(r()+1)
    $POINTER=$oldP
    Case 9;decrement
    i()
    $oldP=$POINTER
    $POINTER=r()
    guarantee($POINTER)
    V("Decrementing " & $POINTER & " (now " & r()-1 & ")" & @CRLF)
    w(r()-1)
    $POINTER=$oldP
    Case 10
    i()
    V("If " & $MEM[r()] & "is zero (is")
    If $MEM[r()] = 0 Then
    i()
    $POINTER = r()-$DIR
    V("), thus jumping to " & $POINTER+$DIR & @CRLF)
    If UBound($MEM) <= $POINTER Then
    V(@CRLF & "Exiting because of pointer beyond memory")
    Exit
    EndIf
    Else
    i()
    i()
    $POINTER = r()-$DIR
    V(" not), thus jumping to " & $POINTER+$DIR & @CRLF)
    If UBound($MEM) <= $POINTER Then
    V(@CRLF & "Exiting because of pointer beyond memory")
    Exit
    EndIf
    EndIf
    EndSwitch
    i()
    WEnd

    Func V($data)
    If $V Then ConsoleWrite($data)
    EndFunc
    Func guarantee($num)
    While UBound($MEM) <= $num
    _ArrayAdd($MEM,0)
    WEnd
    EndFunc[/autoit]

    Alter Beispielcode

    Edit: Erklärung des Beispielcodes:
    [4,2,"Wie heißt du?",5,14,4,7,@CRLF & "Hallo, ",4,14,4,13,3,"!",0]
    4,2: Gib den Inhalt von Position 2 aus.
    Danach ist der Pointer auf dem String, aber da der Interpreter keinen Befehl sieht, überspringt er es.
    5,14: Verlange eine Eingabe und speichere sie in Position 14.
    4,7: Gib den Inhalt von Position 7 aus (@CRLF & "Hallo ")
    String wird wieder übersprungen.
    4,14: Gib Position 14 aus (den Namen)
    4,13: Und jetzt das Ausrufezeichen von Position 13.
    3: Skript wird beendet.

    edit: Interpreter verbessert und eine Fehlerquelle behoben. Springt man zu einem noch nicht existierenden Speicherplatz, wird er automatisch erzeugt.
    Man kann nun die Kommandozeilenoption -v mitgeben, dann ist der Interpreter besonders ausführlich. Der Befehl 2 ist komplett neu: Richtungswechsel. Das ermöglicht einen netten Effekt:
    Gibt achtmal "Test" aus:

    Code
    Test,6,3,4,0,4,0,4,0,4,0,2


    "@CRLF" wird beim Ausgeben automatisch zum Zeilenumbruch geändert.
    Die komplette FABSIL-Spezifikation für Leute, die selbst einen Interpreter schreiben wollen, findet sich auf http://www.l3viathan.de/fabsil.


    Ich habe die Bedeutung der Abkürzung außerdem von "AutoIt Based" zu "Array Based" geändert, weil ich als Übung plane, den Interpreter in einer anderen Sprache umzusetzen.

    Twitter: @L3viathan2142
    Benutze AutoIt persönlich nicht mehr, da ich keinen Windows-Rechner mehr besitze.

    5 Mal editiert, zuletzt von L3viathan (21. März 2011 um 09:27)

  • In der Sprache fehlt irgendwie was. Man kann nur Eingaben und Ausgaben machen. Um etwas sinnvolles damit anzufangen, benötigt man zumindest noch Inkrementieren, Dekrementieren und Vergleich auf 0 oder so.

  • Jetzt kann man sicher so was machen: 2 Zahlen eingeben -> jeweils um 1 dekrementieren bis eine Zahl 0 ist. Diese ist dann die kleinere ;)

  • Soeben gemacht:

    Code
    ["Zahl 1 eingeben:","Zahl 2 eingeben:","Die größere Zahl ist ",@CRLF,4,0,5,100,4,3,4,1,5,101,4,3,1,100,120,1,101,121,10,120,36,26,10,121,41,30,9,120,9,121,6,22,4,2,4,101,3,4,2,4,100,3]


    Ich musste allerdings einen kleinen Bug fixen, siehe #1

    Twitter: @L3viathan2142
    Benutze AutoIt persönlich nicht mehr, da ich keinen Windows-Rechner mehr besitze.

  • Ich musste allerdings einen kleinen Bug fixen, siehe #1


    Durch deinen Bugfix ist das aber jetzt verbugt.
    Ich schreibe da grade was interessantes mit, aber wenn ich einen jump (10) mache, wird der Pointer auf 1 Feld zu niedrig gesetzt - zumindest wenn ich rückwärts springe. Springe ich nach [55], lande ich in [54]. Das hat mich grade einige Haare gekostet...

  • Eigentlich dürfte das nicht passieren, weil der Pointer ja am Ende der While-Schleife inkrementiert wird... o_O
    Naja, ich guck es mir mal an..

    edit: Nochmal überprüft: Kann ich nicht reproduzieren. It's not a bug, it's a feature (wegen dem ohnehin folgenden Inkrement).

    Twitter: @L3viathan2142
    Benutze AutoIt persönlich nicht mehr, da ich keinen Windows-Rechner mehr besitze.

    Einmal editiert, zuletzt von L3viathan (17. März 2011 um 11:42)

  • Vielleicht ist es auch ein Fehler meinerseits gewesen (Falsch platziertes ConsoleWrite o.ä.) - kann das leider grade nicht überprüfen, da ich auf der Arbeit bin. Naja heute Abend werd ich daran weiterarbeiten wenn ich zuhause bin, und dann erlebt ihr heute hoffentlich noch den ersten FABSIL-Fakultätsberechner :thumbup:

  • Ich habe es nach langer Fehlersuche geschafft, Ganzzahldivision in FABSIL umzusetzen (sogar mit Überprüfung, ob Divisor 0 ist):

    Code
    ["Fehler: Division durch null","Ergebnis: ",5,100,5,101,1,100,110,1,101,111,0,1,12,102,10,101,41,20,10,110,44,24,1,101,111,10,111,31,35,8,102,6,20,9,110,9,111,6,27,4,0,3,4,1,4,102,3]

    Twitter: @L3viathan2142
    Benutze AutoIt persönlich nicht mehr, da ich keinen Windows-Rechner mehr besitze.

  • Was haltet ihr von einem FABSIL-Compiler? Habs jetzt nicht getestet, aber theoretisch sollte es klappen ;)

    Spoiler anzeigen
    [autoit]

    Func _CreateFABSIL($sCode)
    ; ProgAndy
    Local $oDict = ObjCreate("Scripting.Dictionary"), $temp
    $oDict.CompareMode = 1
    Local $aCode = StringSplit(StringStripCR($sCode), @LF & ",", 2)
    Local $aResolveLabel[UBound($aCode)], $iResolveIndex = 0
    For $i = 0 To UBound($aCode)-1
    If StringIsDigit($aCode[$i]) Or StringIsFloat($aCode[$i]) Then
    $aCode[$i] = Number($aCode[$i])
    ElseIf StringRegExp($aCode[$i], "^#\w+:") Then
    $temp = StringRegExp($aCode[$i], "^(#\w+):(.*)", 1)
    $oDict($temp[0]) = __NumConv($temp[1])
    ElseIf StringRegExp($aCode[$i], "^#\w+$") Then
    $aResolveLabel[$iResolveIndex] = $i
    $iResolveIndex += 1
    ElseIf StringLeft($aCode[$i], "@")
    Switch $aCode[$i]
    Case "@idle"
    $aCode[$i] = 0 ;do nothing
    Case "@put"
    $aCode[$i] = 1 ;put the element from the next in the element of the following element (1,2,3: put content from 2 in 3)
    Case "@back"
    $aCode[$i] = 2 ;decrease POINTER by two (because it will be increased: effectively decreased by 1)
    Case "quit"
    $aCode[$i] = 3 ;quit
    Case "@out"
    $aCode[$i] = 4 ;output the data of the next element ( 4,2: output $MEM[2]
    Case "@in"
    $aCode[$i] = 5 ;input data into next element ( 5,2: input into $MEM[2]
    Case "@jump"
    $aCode[$i] = 6 ;jump to position of the next element
    Case "@reljump"
    $aCode[$i] = 7 ;relative jump of the number of the next element
    Case "@inc"
    $aCode[$i] = 8 ;increment the element of the next element
    Case "@dec"
    $aCode[$i] = 9 ;decrement the element of the next element
    Case "@if"
    $aCode[$i] = 10 ;if next elements target is zero, jump to the next but one. otherwise jump to next but second one.
    EndSwitch
    EndIf
    Next
    For $i = 0 To $iResolveIndex-1
    $temp = $aResolveLabel[$i]
    $aCode[$temp] = $oDict($temp)
    Next
    Return $aCode
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func __NumConv(Const $sString)
    ; ProgAndy
    If StringIsDigit($sString) Or StringIsFloat($sString) Then Return Number($sString)
    Return $sString
    EndFunc

    [/autoit]

    Edit: Hat sogar Labels für den Jump ;) Befehle mit label versehen #label_name:Befehl und Label verwenden: #label_name
    Dafür gibt es 5 Zeichen, die man im Text nicht normal verwenden kann: @LF, Komma, @CR sind Trennzeichen für doe Befehle, @ am Anfang eines Strings nur vorkommen, wenn es keinem Befehl entspricht, # niemals am Stringanfang.

    Einmal editiert, zuletzt von progandy (21. März 2011 um 00:41)

  • Oh, @progandy, hätte ich das früher gesehen, hätte ich die Änderungen an meinem Interpreter vielleicht bleiben lassen.

    Jedenfalls: Neue Version 2 (final?) mit Dateieinlesung und Ausführlichkeitsoption.
    Ich muss mal eine Spezifizierung schreiben, um zwischen Interpreter und Sprache zu trennen.

    edit: Nochmal deinen Code angeguckt: Das kollidiert ja kaum mit meinen Änderungen, leichtes Abwandeln dürfte helfen.

    Twitter: @L3viathan2142
    Benutze AutoIt persönlich nicht mehr, da ich keinen Windows-Rechner mehr besitze.

  • Ich hab den "Compiler" mal aktualisiert und ein simples Beispiel erstellt:

    Spoiler anzeigen
    [autoit]

    ; _CreateFABSIL
    ;
    ; all elements are separated via @CRLF, @LF or comma (,)
    ;
    ; Commands:
    ; @idle - do nothing
    ; @put - put the element from the next in the element of the following element (1,2,3: put content from 2 in 3)
    ; @reverse - reverses moving direction of pointer (increment --> decrement or decrement --> increment)
    ; @quit - quit
    ; @out - output the data of the next element ( 4,2: output $MEM[2]
    ; @in - input data into next element ( 5,2: input into $MEM[2]
    ; @jump - jump to position of the next element
    ; @reljump - relative jump of the number of the next element
    ; @inc - increment the element of the next element
    ; @dec - decrement the element of the next element
    ; @if - if next elements target is zero, jump to the next but one. otherwise jump to next but second one.
    ;
    ; Labels:
    ; #LABEL:command - set label to index
    ; #LABEL - replace with index of label
    ;
    ; Strings:
    ; Encapsulated in "...":
    ; - "" will be replaced with "
    ; - single % will be replaced with ,
    ; - String will be formatted via StringFormat
    ; not encapsulated:
    ; - String will be formatted via StringFormat
    Func _CreateFABSIL($sCode)
    ; ProgAndy
    Local $oDict = ObjCreate("Scripting.Dictionary"), $temp
    $oDict.CompareMode = 1
    Local $aCode = StringSplit(StringStripCR($sCode), @LF & ",", 2)
    Local $aResolveLabel[UBound($aCode)], $iResolveIndex = 0
    For $i = 0 To UBound($aCode) - 1
    $aCode[$i] = __ConvertEntry($aCode[$i], $i, $oDict)
    If @extended Then
    $aResolveLabel[$iResolveIndex] = $i
    $iResolveIndex += 1
    EndIf
    Next
    For $i = 0 To $iResolveIndex - 1
    $temp = $aResolveLabel[$i]
    $aCode[$temp] = $oDict($aCode[$temp])
    Next
    Return $aCode
    EndFunc ;==>_CreateFABSIL

    [/autoit] [autoit][/autoit] [autoit]

    Func __ConvertEntry($sString, $i, ByRef $oLabels)
    ; ProgAndy
    $sString = StringStripWS($sString, 3)
    If StringIsDigit($sString) Or StringIsFloat($sString) Then
    $sString = Number($sString)
    ElseIf StringRegExp($sString, "^#\w+:") Then
    $temp = StringRegExp($sString, "^(#\w+):(.*)", 1)
    $oLabels($temp[0]) = $i
    $sString = __ConvertEntry($temp[1], $i, $oLabels)
    ElseIf StringRegExp($sString, "^#\w+$") Then
    SetExtended(1)
    ElseIf StringLeft($sString, 1) = "@" Then
    Switch $sString
    Case "@idle"
    $sString = 0 ;do nothing
    Case "@put"
    $sString = 1 ;put the element from the next in the element of the following element (1,2,3: put content from 2 in 3)
    Case "@reverse"
    $sString = 2 ;reverses moving direction of pointer (increment --> decrement or decrement --> increment)
    Case "@quit"
    $sString = 3 ;quit
    Case "@out"
    $sString = 4 ;output the data of the next element ( 4,2: output $MEM[2]
    Case "@in"
    $sString = 5 ;input data into next element ( 5,2: input into $MEM[2]
    Case "@jump"
    $sString = 6 ;jump to position of the next element
    Case "@reljump"
    $sString = 7 ;relative jump of the number of the next element
    Case "@inc"
    $sString = 8 ;increment the element of the next element
    Case "@dec"
    $sString = 9 ;decrement the element of the next element
    Case "@if"
    $sString = 10 ;if next elements target is zero, jump to the next but one. otherwise jump to next but second one.
    EndSwitch
    ElseIf StringLeft($sString, 1) = '"' And StringRegExp($sString, '^"([^"]|"")*(?<!")"$') Then
    $sString = StringFormat(StringRegExpReplace(StringReplace(StringMid($sString, 2, StringLen($sString) - 2), '""', '"', 0, 1), '(?<!%)(%%)*%(?!%)', ','))
    Else
    $sString = StringFormat($sString)
    EndIf
    Return $sString
    EndFunc ;==>__ConvertEntry

    [/autoit]


    Beispiel:

    [autoit]

    $MEM = _CreateFABSIL('#msg:"-hi\r\ndu%-", @jump, #out, #quit:@quit, #out:@out, #msg, @jump, #quit, @out, #msg')

    [/autoit]