Aktuelle Zeit: 16.09.2019 14:28

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]




Ein neues Thema erstellen Auf das Thema antworten  [ 8 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Fragen zur Programmierung eines Interpreters
BeitragVerfasst: 27.04.2019 11:23 
Offline
Benutzeravatar

Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg
Hallo Kollegen,

ich möchte mein Programm mit einer Art kleinen Skriptsprache versehen, so dass der Anwender eigene Skripte erstellen kann, die mein Programm dann verarbeitet bzw. ausführt. Es geht dabei um die Bearbeitung von Texten.

Bei bestimmten Teilen der Umsetzung ist mir noch nicht klar wie ich es am besten realisieren sollte, daher richtet sich meine Frage an Leute die so etwas schon mal programmiert haben.

Aber erst nochmal kurz erklärt was das eigentlich werden soll. Im Prinzip soll diese Skriptsprache wie eine Macrosprache mit den Textdaten in einem Texteditor arbeiten können. Das vom User erstellte Script soll in der Lage sein ein Ergebnis-Array mit Daten zu füllen die aus einer Textdatei extrahiert werden. Ein Script kann dabei immer nur mit einer Textdatei arbeiten.
Denkbare Befehle wären z.B.:
Code:
GotoLine 30 ; Setzt den Lesepointer in der Textdatei auf den Anfang der 30.ten Zeile
GotoOffset 185 ; Setzt den Lesepointer in der Textdatei vor das 185.te Zeichen
GetString(5) ; Gibt ausgehened vom aktuellen Lesepointer die nächsten 5 Zeichen als String zurück
Die komplexeren Dinge wie Variablen und Bedingungen (If, Else, Endif) lasse ich erstmal außen vor.

Ich würde die Behandlung und Ausführung der Sprache in zwei Schritten durchführen.

1) Tokenizen, also die Befehle und deren Parameter und ggf. Operatoren in numerische Tokens wandeln, die ich dann als 2-dimensionales Array im Speicher halte.
2) Das 2D-Array stellt dann quasi das Script-Programm dar und wird von einer "virtuellen CPU" sequentiell abgearbeitet.

Das Array könnte so aussehen:
Code:
Token, StringParameter1, StringParameter2, IntParamerter1, IntParamerter2, Operator

Ich würde in diesem Array Felder für alle möglichen Parametertypen haben, es würden dann aber nur jene ausgefüllt werden, die der entsprechende Token benötigt. Bei dem Token für GotoLine würde also nur IntParamerter1 genutzt werden, weil "GotoLine" nur einen numerischen Parameter hat.

Das ganze geht sicherlich eleganter, mir ist bisher nur noch nichts anderes dafür eingefallen.

Was mir auch noch nicht ganz klar ist:
Wie gestalte ich den Aufruf der zu einem Token gehörenden Prozedur? Ich könnte ein weiteres Array nutzen in dem ich zu jedem Token die Prozedure-Adresse eingetrage (oder der Tokenizer schreibt die entsprechende Prozedur-Adresse bereits in das Token-Array, dann spart man sich das weitere Adressen-Array):
Code:
Token, Prozedure-Adresse
1, @GotoLine() ; Adresse von Prozedure GotoLine() / 1 = GotoLine
2, @GotoOffset() ; Adresse von Prozedure GotoOffset() / 2 = GotoOffset
3, @GetString() ; Adresse von Prozedure GetString .... usw.

So könnte man dann mit einem Prototype arbeiten und die Prozedur ungefähr so aufrufen:
Code:
Prototype.i Command()
Cmd.Command = [Adresse] ; Hier die Prozedur-Adresse aus der o.g. Tokenliste eintragen.
Cmd() ; Und die Prozedur aufrufen

Hier fragt sich wie man es am besten mit den Parametern und den Operatoren macht. Die Parameter kann ich beim Prototype nicht mit angeben, weil sie unter Umständen für jeden Skriptbefehl anders sind. Ich könnte ein globales "Parameter-Übergabearray" bzw. eine Struktur nutzen, welches wieder jeweils ein Feld für alle möglichen Parameter/Operatoren aufnimmt. Die "virtuelle CPU", die den tokenisierten Code abarbeitet, muss dann die entsprechenden Werte des Tokens dort hinein übertragen und die danach aufgerufene Prozedur müsste sich die für sie passenden Werte von dort herausnehmen.

Globales Parameter-Array: Hierrauf greift jede der aufgerufenen "Befehls-Prozeduren" zu.
Code:
StringParameter1, StringParameter2, IntParamerter1, IntParamerter2, Operator

Das würde vermutlich alles irgendwie gehen, aber sicherlich funktioniert es auch eleganter bzw. einfacher, so dass man nicht immer die Felder für alle möglich vorkommenden Parameter in den Arrays/Strukturen bereithalten muss.

Leider ist dies mein allererster Interpreter, den ich schreibe. Habt ihr dazu ein paar Tipps für mich?
Vielen Dank

Kurzer

_________________
"Never run a changing system!"
PB 5.62, OS: Windows 7 Pro x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Ich bin Baujahr 1968, also aktuell 51.


Zuletzt geändert von Kurzer am 27.04.2019 12:56, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Fragen zur Programmierung eines Interpreters
BeitragVerfasst: 27.04.2019 12:32 
Offline
Benutzeravatar

Registriert: 11.08.2005 19:08
Hallo Kurzer,

wenn du nichts gegen die Verwendung meines Lexer-Moduls hast, kann ich dir heute Abend oder morgen ein Grundgerüst basteln.

_________________
Bild
Warum OpenSource eine Lizenz haben sollte
PureBasic-CodeArchiv-Rebirth: Git-Repository / Download -- Jede Hilfe ist willkommen!
Manjaro Xfce x64 (Hauptsystem) :: WindowsXP/Xubuntu x86 (VirtualBox) :: PureBasic (Linux: x86/x64, Windows: x86) :: jeweils neueste Version


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Fragen zur Programmierung eines Interpreters
BeitragVerfasst: 27.04.2019 12:34 
Offline
Benutzeravatar

Registriert: 24.11.2004 13:12
Wohnort: Germany
Wenns nur für Window ist, verwende doch einen fertigen Interpreter...

Link: viewtopic.php?f=8&t=31072

_________________
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul / OPC-Helper DLL
PB v3.30 / v5.4x - OS Mac Mini OSX 10.xx / Window 10 Pro. (X64) /Window 7 Pro. (X64) / Window XP Pro. (X86) / Ubuntu 14.04
Downloads auf Webspace


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Fragen zur Programmierung eines Interpreters
BeitragVerfasst: 27.04.2019 12:55 
Offline
Benutzeravatar

Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg
Vielen Dank euch beiden für die Angebote. :allright:
Ich würde es jedoch gern selbst umsetzen wollen und auch extrem einfach halten. Habe mir zwar mit meiner Erkältung gerade einen ungünstigen Zeitpunkt ausgesucht, aber mal gucken was so geht.

Eure codes schaue ich mir auf jeden Fall an, um zu sehen, ob ich daraus lernen kann.

Mittlerweile bin ich auch auf dieses Tutorial von puretom gestoßen und lese das gerade: viewtopic.php?f=9&t=27329

_________________
"Never run a changing system!"
PB 5.62, OS: Windows 7 Pro x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Ich bin Baujahr 1968, also aktuell 51.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Fragen zur Programmierung eines Interpreters
BeitragVerfasst: 28.04.2019 00:05 
Offline
Benutzeravatar

Registriert: 22.12.2016 12:49
Wohnort: :D_üsseldorf-Wersten
Hallo Kurzer,

Code:
Procedure   PGotoLine(Zeile.i) : MessageRequester("GotoLine",Str(Zeile)) : EndProcedure
Procedure   PGotoOffset(Zeichen.i) : MessageRequester("GotoOffset",Str(Zeichen)) : EndProcedure
Procedure.s PGetString(Zeichen.i) : MessageRequester("GetString",Str(Zeichen)) : ProcedureReturn("ABCDE") : EndProcedure

Read.s Zeile.s
While Zeile<>"End"
  Kommentar=FindString(Zeile,";")
  If Kommentar
    Zeile=Left(Zeile,Kommentar-1)
  EndIf
  ; Debug Zeile+"#"
  Zeile=ReplaceString(Zeile,"("," ")
  Zeile=ReplaceString(Zeile,")"," ")
  Leerzeichen=FindString(Zeile," ")
  If Leerzeichen
    Befehl.s=Left(Zeile,Leerzeichen-1)
    Parameter=Val(Mid(Zeile,Leerzeichen))
    ; Debug Befehl
    ; Debug Str(Parameter)
  Else
    Befehl=Zeile
    Parameter=0
  EndIf
  Select Befehl
    Case "GotoLine": PGotoLine(Parameter)
    Case "GotoOffset": PGotoOffset(Parameter)
    Case "GetString" : Debug PGetString(Parameter)
    Default : Debug "unbekannter Befehl"
  EndSelect ; Könnte Befehle auch in Tokenliste eintragen und später in verschieden Formaten ausführen.
  Read.s Zeile
Wend

DataSection
  KurzerCode:
  Data.s "GotoLine 30 ; Setzt den Lesepointer in der Textdatei auf den Anfang der 30.ten Zeile"
  Data.s "GotoOffset 185 ; Setzt den Lesepointer in der Textdatei vor das 185.te Zeichen"
  Data.s "GetString(5) ; Gibt ausgehened vom aktuellen Lesepointer die nächsten 5 Zeichen als String zurück"
  Data.s "End" ; Brauche eine Abbruchbedingung, sonst [ERROR] Fehler beim Einlesen von Daten: keine weiteren Daten.
EndDataSection


Gruß

_________________
PB Spickzettel

Erkenntnisapparat einschalten entscheidet über das einzig bekannte Leben im sichtbaren Universum.
Bitte Frage fragen.
Jürgen Kulow Wersten :D_üsseldorf NRW D Europa Erde Sonnensystem Lokale_Flocke Lokale_Blase Orion-Arm
Milchstraße Lokale_Gruppe Virgo-Superhaufen Laniakea Sichtbares_Universum


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Fragen zur Programmierung eines Interpreters
BeitragVerfasst: 28.04.2019 09:20 
Offline
Benutzeravatar

Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg
Hallo Jürgen,

danke für deinen Beitrag. :allright: So in dem Bereich sollte sich das bewegen.

Allerdings trenne ich trotzdem die Aufgabe in mehrere Teile.
1) Interpretation und Prüfung des Quellcodes
2) Umwandlung der Befehle in numerische Tokens.
3) Abarbeiten des auf Tokens basierten Programms.

Ich fange die Entwicklung allerdings von hinten an, also zuerst den Teil, der das in Tokens umgewandelte Programm ablaufen lässt. Ich beschränke mich in der Entwicklungsphase erstmal auf ein paar Befehle.

Ein "tokenisierter" Programmcode liegt bei mir in einem Array vor und je ein Commandoeintrag hat folgenden Aufbau (es ist wie gesagt alles noch absoluter Testcode, Änderungen sind jederzeit möglich):
Code:
Structure ProgramRecord
   iToken.i
   sParam1.s
   sParam2.s
   sParam3.s
   sParam4.s
   sParam5.s
   sParam6.s
EndStructure
Die aktuelle Programmzeile, in der sich das Commando/Token befindet, ergibt sich aus dem Index des Arrays. Ich habe mich dazu entschlossen jeden Parameter erstmal als String zu speichern. Eine Prüfung auf Datentyp muss dann im Schritt davor beim Umwandeln von Quellcode in Tokens stattfinden. Der Grund hierfür ist, dass ich die Strukturen in der Entwicklungsphase erstmal relativ "flach" halten kann, um nicht den Überblick zu verlieren. Später kann man sicherlich auch Adress- oder Indexpointer als Params nutzen, die dann auf den jeweiligen Parameter zeigen, der dann im korrekten Datentyp vorliegt.

Jedes eindeutige Token (Commando) hat bei mir noch folgende Information:
Code:
Structure TokenRecord
   sName.s
   iProcedureAddress.i
   iLastResultType.i
   iFunctionResultType.i
EndStructure
Zum einen der Klartextname. Dies wird später der Programmteil nutzen, der den Quellcodes in Tokens umwandeln muss.
Dann die Adresse der Prozedur die die Funktionalität des betreffenden Befehls/Tokens abbildet und dann noch zwei Bedingungen die für die Klassifizierung des Tokens wichtig sind: Typ des Ergebnisses des Tokens davor und der Typ des Ergebnisses des aktuellen Tokens.

Diese beiden Daten sind wichtig, damit der Programmteil, der den Quellcode in Tokens umwandelt anhand der Datentypen das korrekte Token auswählt.
So kann zum Beispiel der Operator "+" für die Addition von zwei Integerzahlen zuständig sein. Er kann aber auch zwei Strings miteinander verketten. Im Quellcode ist das immer ein + Zeichen, aber im "tokenisierten" Programm müssen das zwei separate Tokens sein, die jeweils ihre eigene Prozedur besitzen. Die eine addiert Zahlen, die andere verkettet Strings.

Weiterhin gibt es eine globale "Register-Struktur", die von allen Programmteilen gelesen und beschreiben werden kann:
Code:
Structure Registers
   iProgramPointer.i
   iQuit.i
   iLastResultType.i
   sLastResult.s
   iLastResult.i
EndStructure
Hier ist der aktuelle Programmzeiger abgespeichert. Also quasi die Zeilennummer innerhalb des "tokenisierten" Programms. Dieser würde z.B. bei einem "GotoProgrammzeile" Kommando wichtig sein und entsprechend verändert werden. Dann sind dort der Datentyp und das Ergebnis des letzten Kommandos/Tokens gespeichert, sowie ein "Quit-Flag", welches vom Befehl "End" gesetzt wird und die Bearbeitungsschleife für die Programmausführung beendet.

Mein Testcode befindet sich mitten in der Entwicklung und einige Teile sind nicht ausprogrammiert, aber zumindets ist er compilierbar und gibt ein paar Daten aus. Es arbeitet jedoch noch nicht mit einem Daten(text)block, obwohl ich bereits einen definiert habe.

Das eigentliche "Tokenprogramm" beginnt in Zeile 147 und besteht aus folgenden Befehlen:
Code:
GotoChar 33  ; Gibt die aktuelle (wirklich angesprungene) Position im Datenfile zurück.  In dem Fall Position Nummer 33
+ 12 ; Addiert 12 auf den Wert des letzten Befehls. Also 33 + 12 und gibt demnach 45 zurück
GetString(5) ; Die Funktion gibt derzeit nur den String "Vier" zu rück.
+ " Meter" ; Verkettet den zuletzt zurückgegeben String "Vier" mit dem String " Meter" und gibt demnach "Vier Meter" zurück.

Hier mal mein bisheriger Testcode:
Code:
EnableExplicit

Enumeration ResultTypes
   #ResultType_ANY
   #ResultType_STRING
   #ResultType_INTEGER
EndEnumeration

Structure TokenRecord
   sName.s
   iProcedureAddress.i
   iLastResultType.i
   iFunctionResultType.i
EndStructure

Structure ProgramRecord
   iToken.i
   sParam1.s
   sParam2.s
   sParam3.s
   sParam4.s
   sParam5.s
   sParam6.s
EndStructure

Structure Registers
   iProgramPointer.i
   iQuit.i
   iLastResultType.i
   sLastResult.s
   iLastResult.i
EndStructure

Structure Datafile
   iReadPointer.i
   iSizeInChars.i
   iLastLine.i
   sData.s
EndStructure

Prototype.i RunCmdProto()

Global stRegisters.Registers
Global Dim stTokens.TokenRecord(99)
Global Dim stProgram.ProgramRecord(9)
Global stDatafile.Datafile
Global.s sCode

sCode = "GotoChar 5 : GetStringPart(0, 10) : End"

stDatafile\iLastLine = 17
stDatafile\iReadPointer = 1
stDatafile\sData ="Zeile 1: Der Interpreter beschäftigt sich nicht mit dem Parsen des ursprünglichen Ausdrucks und" + #CR$ + #LF$ +
"Zeile 2: Der Interpreter beschäftigt sich nicht mit dem Parsen des ursprünglichen Ausdrucks und" + #CR$ + #LF$ +
"Zeile 3: Der Interpreter beschäftigt sich nicht mit dem Parsen des ursprünglichen Ausdrucks und" + #CR$ + #LF$ +
"Zeile 4: Der Interpreter beschäftigt sich nicht mit dem Parsen des ursprünglichen Ausdrucks und" + #CR$ + #LF$ +
"Zeile 5: Der Interpreter beschäftigt sich nicht mit dem Parsen des ursprünglichen Ausdrucks und" + #CR$ + #LF$ +
"Zeile 6: Der Interpreter beschäftigt sich nicht mit dem Parsen des ursprünglichen Ausdrucks und" + #CR$ + #LF$ +
"Zeile 7: Der Interpreter beschäftigt sich nicht mit dem Parsen des ursprünglichen Ausdrucks und" + #CR$ + #LF$ +
"Zeile 8: Der Interpreter beschäftigt sich nicht mit dem Parsen des ursprünglichen Ausdrucks und" + #CR$ + #LF$ +
"Zeile 9: Hier befindet sich Position Nummer: 821" + #CR$ + #LF$ +
"Zeile 10: Der Interpreter beschäftigt sich nicht mit dem Parsen des ursprünglichen Ausdrucks."
stDatafile\iSizeInChars = Len(stDatafile\sData)

Procedure InitTokenArray()
   Protected.s sTokenName
   Protected.i i=0
   
   Restore Tokendef
   Read.s sTokenName
   While sTokenName <> "*"
      stTokens(i)\sName = sTokenName
      Read.i stTokens(i)\iProcedureAddress
      Read.i stTokens(i)\iLastResultType
      Read.i stTokens(i)\iFunctionResultType
      i + 1
      Read.s sTokenName
   Wend
   ReDim stTokens(i-1)
EndProcedure
Procedure ShowRegisters()
   Debug "PC: " + Str(stRegisters\iProgramPointer)
   If stRegisters\iLastResultType = #ResultType_STRING
      Debug "LastResult: " + stRegisters\sLastResult
   ElseIf stRegisters\iLastResultType = #ResultType_INTEGER
      Debug "LastResult: " + Str(stRegisters\iLastResult)
   EndIf
   Debug "Data ReadPointer: " + Str(stDatafile\iReadPointer)
EndProcedure

Procedure Cmd_GetStringPart()
   Debug "GetString (" + stProgram(stRegisters\iProgramPointer)\sParam1 + ")"
   stRegisters\iLastResultType = #ResultType_STRING
   stRegisters\sLastResult = "Vier"
EndProcedure
Procedure Cmd_GotoChar()
   Protected.i iNewReadPointer
   
   iNewReadPointer = Val(stProgram(stRegisters\iProgramPointer)\sParam1)
   If iNewReadPointer <= stDatafile\iSizeInChars
      stDatafile\iReadPointer = iNewReadPointer
   Else
      stDatafile\iReadPointer = stDatafile\iSizeInChars
   EndIf
   stRegisters\iLastResultType = #ResultType_INTEGER
   stRegisters\iLastResult = iNewReadPointer
   ShowRegisters()
EndProcedure
Procedure Cmd_PlusInt()
   Debug Str(stRegisters\iLastResult) + " + " + stProgram(stRegisters\iProgramPointer)\sParam1
   stRegisters\iLastResultType = #ResultType_INTEGER
   stRegisters\iLastResult = stRegisters\iLastResult + Val(stProgram(stRegisters\iProgramPointer)\sParam1)
EndProcedure
Procedure Cmd_PlusStr()
   Debug stRegisters\sLastResult + " + " + stProgram(stRegisters\iProgramPointer)\sParam1
   stRegisters\iLastResultType = #ResultType_STRING
   stRegisters\sLastResult = stRegisters\sLastResult + stProgram(stRegisters\iProgramPointer)\sParam1
EndProcedure
Procedure Cmd_End()
   stRegisters\iQuit = #True
EndProcedure

Procedure ProcessProgramArray(Array stProgram.ProgramRecord(1))
   Protected prRunCmd.RunCmdProto
   
   prRunCmd = stTokens(stProgram(stRegisters\iProgramPointer)\iToken)\iProcedureAddress
   prRunCmd()
   
   Select stRegisters\iLastResultType
      Case #ResultType_INTEGER
         Debug stRegisters\iLastResult
      Default
         Debug stRegisters\sLastResult
   EndSelect
   
   stRegisters\iProgramPointer + 1
   If stRegisters\iProgramPointer = ArraySize(stProgram()) + 1
      Cmd_End()
   EndIf
   
EndProcedure

; --------------------------------------------

InitTokenArray()

; GotoChar 33
stProgram(0)\iToken = 2
stProgram(0)\sParam1 = "33"

; PlusInt
stProgram(1)\iToken = 3
stProgram(1)\sParam1 = "12"

; GetString(5)
stProgram(2)\iToken = 1
stProgram(2)\sParam1 = "5"

; PlusStr
stProgram(3)\iToken = 4
stProgram(3)\sParam1 = " Meter"

; End
stProgram(4)\iToken = 0

Repeat
   ProcessProgramArray(stProgram())
Until stRegisters\iQuit = #True

Debug "Quit it"

;  ShowVariableViewer()
;  CallDebugger
; --------------------------------------------

DataSection
   Tokendef:
   ; Commandname, Address of procedure, Type of last result, Type of command/function result
   ; TokenNr = 0
   Data.s "end"
   Data.i   @Cmd_End(), #ResultType_ANY, #ResultType_ANY

   ; TokenNr = 1
   Data.s "getstringpart"
   Data.i   @Cmd_GetStringPart(), #ResultType_ANY, #ResultType_STRING ; Extracted String

   ; TokenNr = 2
   Data.s "gotochar"
   Data.i   @Cmd_GotoChar(), #ResultType_ANY, #ResultType_INTEGER ; New position of the read pointer
   
   ; TokenNr = 3
   Data.s "+"
   Data.i   @Cmd_PlusInt(), #ResultType_INTEGER, #ResultType_INTEGER ; Result of the numerical addition
   
   ; TokenNr = 4
   Data.s "+"
   Data.i   @Cmd_PlusStr(), #ResultType_STRING, #ResultType_STRING ; Result of string concatenation
   
   Data.s "*" ; Ende-Markierung der Datenliste
EndDataSection

Gruß Kurzer

_________________
"Never run a changing system!"
PB 5.62, OS: Windows 7 Pro x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Ich bin Baujahr 1968, also aktuell 51.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Fragen zur Programmierung eines Interpreters
BeitragVerfasst: 28.04.2019 15:37 
Offline
Benutzeravatar

Registriert: 22.12.2016 12:49
Wohnort: :D_üsseldorf-Wersten
Hallo Kurzer,

schlage vor die Entwicklung zu starten mit: MOV rcx,qword ..
Code:
c:pbcompiler interpre.pb /Commented

Code:
; Select Befehl
  PUSH   qword [v_Befehl]
; Case "GotoLine": PGotoLine(Parameter)
  MOV    rdx,_S1
  MOV    rcx,[rsp]
  SUB    rsp,40
  CALL   SYS_StringEqual
  ADD    rsp,40
  OR     rax,rax
  JE    _Case1
  SUB    rsp,8
  MOV    rcx,qword [v_Parameter]
  SUB    rsp,32
  CALL  _Procedure0
  ADD    rsp,40
; Case "GotoOffset": PGotoOffset(Parameter)
  JMP   _EndSelect1
_Case1:
  MOV    rdx,_S2
  MOV    rcx,[rsp]
  SUB    rsp,40
  CALL   SYS_StringEqual
  ADD    rsp,40
  OR     rax,rax
  JE    _Case2
  SUB    rsp,8
  MOV    rcx,qword [v_Parameter]
  SUB    rsp,32
  CALL  _Procedure2
  ADD    rsp,40
; Case "GetString" : s.s=PGetString(Parameter) ; Änderung zum Ursprungsprogramm, da in EXE der Debug-Befehl nicht aufgerufen wird.
  JMP   _EndSelect1
_Case2:
  MOV    rdx,_S3
  MOV    rcx,[rsp]
  SUB    rsp,40
  CALL   SYS_StringEqual
  ADD    rsp,40
  OR     rax,rax
  JE    _Case3
  MOV    rax,[PB_StringBasePosition]
  PUSH   rax
  SUB    rsp,8
  PUSH   rax
  MOV    rcx,qword [v_Parameter]
  SUB    rsp,32
  CALL  _Procedure4
  ADD    rsp,48
  LEA    rcx,[v_s]
  POP    rdx
  SUB    rsp,40
  CALL   SYS_AllocateString4
  ADD    rsp,40
; Default : Debug "unbekannter Befehl"
  JMP   _EndSelect1
_Case3:
; EndSelect
_Case4:
_EndSelect1:


Gruß


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Fragen zur Programmierung eines Interpreters
BeitragVerfasst: 28.04.2019 16:39 
Offline
Benutzeravatar

Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg
juergenkulow hat geschrieben:
schlage vor die Entwicklung zu starten mit: MOV rcx,qword ..

Ähm, warum? :shock: Wie soll mir Assembler hierbei helfen?

Davon ab, komme ich ganz gut voran. Der Tokenizer ist fast fertig, es fehlt noch eine Preprocessing Routine, die mir verschachtelte Kommandos serialisiert. Also sowas hier:
Code:
GotoChar(GetNumber(...))
Wo also eine Funktion wiederum der Parameter eines Befehls/Funktion ist. Das muss in zwei separate Kommandos gesplittet werden bevor es in Tokens umgewandelt wird.

_________________
"Never run a changing system!"
PB 5.62, OS: Windows 7 Pro x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Ich bin Baujahr 1968, also aktuell 51.


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 8 Beiträge ] 

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 6 Gäste


Sie dürfen keine neuen Themen in diesem Forum erstellen.
Sie dürfen keine Antworten zu Themen in diesem Forum erstellen.
Sie dürfen Ihre Beiträge in diesem Forum nicht ändern.
Sie dürfen Ihre Beiträge in diesem Forum nicht löschen.

Suche nach:
Gehe zu:  

 


Powered by phpBB © 2008 phpBB Group | Deutsche Übersetzung durch phpBB.de
subSilver+ theme by Canver Software, sponsor Sanal Modifiye