Da bisher niemand auf deinen Thread geantwortet hat, will ich mich mal an einem Lösungsansatz versuchen. Wie ich sehe, arbeitest du mit Verbs und Parametern die du dynamisch (wahrscheinlich für jede Befehlszeile) parst. Da ich jetzt davon ausgehe, dass du auch mehr wie 2 Verben haben kannst, würde ich die Sache folgendermaßen angehen.
1. Du hast eine Funktion die die Verben und Parameter aus einem Kommando deiner zu parsenden Codedatei einliest.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| var Line : Integer; CommandRecord : TCommandRecord; ResultText : String; begin Line := 0; while ParseNextCommand(Line, CommandRecord) do begin ExecuteCommand(CommandRecord, ResultText); if Trim(ResultText) <> '' then ShowMessage(ResultText); end; end; |
Erklärungen:
ParseNextCommand: Diese Routine liefert dir einen Record zurück, indem das aktuell ausgelesene Kommando und die Parameter deklariert sind.
Übergeben tust du die aktuell zu lesende Zeile (Line), und zwar als var Parameter. Intern erhöht die Parsingfunktion zum Auslesen der Kommandoparameter die Zeile um 1.
Als zweiten Paramter übergibst du den Kommandorecord ebenfalls als var Parameter.
Hat die Funktion ParseNextCommand ein Kommando gefunden, gibt sie True zurück. Findet sie beispielsweise nur eine Leerzeile, erhöht sie intern so lange die Zeile, bis das nächste Kommando gefunden wird.
Prototyp der Funktion ParseNextCommand;
Delphi-Quelltext
1:
| function ParseNextCommand(var Line : Integer; out CommandRecord : TCommandRecord) : Boolean; |
CommandRecord:
CommandRecord ist hier ein selbst definierter Record, der beispielsweise so aussehen könnte.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| type TVerbType = (vtTab, vtGet, vtSet, vtNone);
type TParamType = (ptIndex, ptCount, ptContent, ptNone);
type TVerbParam = record VP_ParamType : TParamType; VP_ValueStr : string; VP_ValueInt : Integer; end;
type TCommandRecord = record CR_Verb : array of TVerbType; CR_Params : array[0..10] of TVerbParam; |
WICHTIG: Ich habe hier mit Enumerationen gearbeitet. Die Funktion ParseCommands muss natürlich mit einer Stringpass-Routine die entsprechenden Schlüsselstrings wie "tab", "get", "index", etc. auslesen und dann den Kommandorecord entsprechend initialisieren.
Beispiel:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| CommandRecord.CR_Verb := vtSet; SetLength(CommandRecord.CR_Params, 1); with CommandRecord.CR_Params[0] do begin VP_ParamType := ptCount; VP_ValueStr := ''; VP_ValueInt := 34; end; |
Dieser Kommandorecord wird in der Funktion ExecuteCommand verarbeitet.
ExecuteCommand:
Diese Funktion bzw. Prozedur verarbeitet ein Kommando. Wahlweise kann noch ein Rückgabewert für einen Successstate eingefügt werden.
Prototyp:
Delphi-Quelltext
1:
| procedure ExecuteCommand(var Command : TCommandRecord; out ResultText : string); |
Hinweis: ResultText wird hier einfach in der Funktion ExecuteCommand(Command, ResultText); durchgeschleift.
Das Abarbeiten der Kommandos in der Funktion sieht relativ simple aus. Es wird mit einer Case-Anweisung geprüft, um welches Verb es sich handelt und dann einfach in die entsprechende Funktion zum Ausführen des Kommandos verzweigt.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure ExecuteCommand(var Command : TCommandRecord; out ResultText : string); begin ResultText := ''; case Command.CR_Verb of vtTab : ExecuteTab(Command); vtGet : ResultText := ExecuteGet(Command); vtSet : ExecuteSet(Command); vtNone : exit; else Exit; end; end; |
ExecuteGet
In der Prozedur ExecuteGet wird weiter verzweigt und der ResultString als Funktionsresult zurückgegeben. Die Implementierung sieht beispielsweise so aus:
Implementierung:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| ExecuteGet(var Command : TCommandRecord; out ResultText : string); var i : Integer; begin ResultText := ''; for i := 0 to 9 do begin case Command.CR_Params[i].VP_ParamType of ptIndex : ResultText := IntToStr(Command.CR_Params[i].VP_ValueInt); ptCount : ResultText := IntToStr(Command.CR_Params[i].VP_ValueInt); ptContent : ResultText := Command.CR_Params[i].VP_ValueStr; ptNone : Exit; else Exit; end; end; end; |
[Abschließend]
Das wars soweit vom Prinzip hier. Der Parser muss nurnoch beim Lesen für jedes Kommando die Einzelparameter in den Commandrecord packen und nur auf den Datentyp achten (Integer, String, etc.). Das ganze wird solange eingelesen, bis ein ";" kommt und damit ersichtlich ist, dass die Kommandozeile abgeschlossen ist. Aufgezweigt wird intern.
Viele Grüße
Backslash
PS: Das war soweit mein Lösungsansatz. In der Art würde ich da rangehen.