![]() |
Parserbau Grundlagen + Verständnisfrage
Hallo,
ich versuche mich grad an einem Parser, der wie folgt aufgebaut ist:
Delphi-Quellcode:
Leider kommt mein Parser aber nicht zu '''if Token='Mein_Nächstes_gesuchtes_wort' then ...
procedure Parse;
begin while LineNum < Stringliste.Count do begin Token := GetToken; //LineNum wird in SkipSpaces erhöht, wenn Zeile zuende SkipSpaces; if Token = 'Mein_gesuchtes_Wort' then begin Token := GetToken; SkipSpaces; if Token = 'Mein_nächstes_gesuchtes_Wort' then begin //entweder nächsten Token holen oder, wenn fertig //Aktion auslösen end; end; end; end; //Hier noch die Prozedur SkipSpaces procedure SkipSpaces; begin while StringListe.Strings[LineNum][StringPosition]=' ' do inc(StringPosition); if StringPosition >= Length(StringListe.Strings[LineNum]) then begin StringPosition := 1; inc(LineNum); end; end; Warum nicht? In meinem Testtext kommen die gesuchten Wörter definitiv mit Sicherheit vor. Warum findet sie der Parser dann nicht? Bisher habe ich rausgefunden, das der Parser scheitert, wenn Leerzeilen dazwischen liegen, denn dann läuft er, findet das nächste gesuchte Wort nicht, die Schlife läuft bis zum Ende und im nächsten Parserdurchlauf ist er nicht mehr in jenem Scope, wo ich das 'mein_nächstes_gesuchtes_wort erwarte. ER ist stattdessen in der Ebene, wo er höchstens 'mein_gesuchtes_wort' finden würde, das aber im Text dann nicht mehr vorkommt. Wie kann ich den Entwurf besser machen, so das Spaces einfach überlesen werden. |
AW: Parserbau Grundlagen + Verständnisfrage
SkipSpaces überspringt das letzte Zeichen in einer Zeile, wenn es kein Space ist. Wenn eine Zeile mit einem Leerzeichen anfängt, hast du auch ein Problem.
|
AW: Parserbau Grundlagen + Verständnisfrage
Du solltest SkipSpaces nochmal überdenken.
Das Problem wird sichtbar, wenn du die Unteraufgaben noch ein wenig auslagerst. Du möchtest es sicherlich etwa so haben:
Delphi-Quellcode:
So, wie du es jetzt geschrieben hast, sieht es aber so aus:
procedure SkipSpaces;
begin while (Look()=' ') or IsLinebreak() do MoveForward(); end;
Delphi-Quellcode:
Siehst du den Unterschied?
procedure SkipSpaces;
begin while Look()=' ' do MoveForward(); if IsLinebreak() then MoveForward(); end; Tipp am Rande: Du solltest dir die wichtigen Subaufgaben sowieso besser auslagern. Ein
Delphi-Quellcode:
/
Look()
Delphi-Quellcode:
und ein
Peek()
Delphi-Quellcode:
wirst du noch an vielen Stellen brauchen. Und noch ein Tipp: Implementier Look()/Peek() so, dass es Zeilenumbrüche selbst behandelt und als #10 oder #13 zurückliefert, das macht vieles einfacher.
MoveForward
|
AW: Parserbau Grundlagen + Verständnisfrage
Ich würde noch den zu parsenden Text nicht als Liste von Zeilen ansehen, sondern als einen einzigen String. Den Zeilenvorschub kannst Du als Leerzeichen behandeln (beim einlesen). Dann ist alles viel transparenter und dein Skipspaces wird zu einem einfachen
Delphi-Quellcode:
Noch viel transparenter wird es so (finde ich)
Procedure SkipSpaces;
Begin While (TextPos<Length(MyText)) and (MyText[TextPos] in WhiteSpaceCharacters) do inc(TextPos); If TextPos>Length(MyTExt) Then TextIsAtEof := True; End;
Delphi-Quellcode:
Das saubere 'Advance' kannst Du auch in deinem 'GetToken' verwenden.
Procedure Advance;
Begin if TextisAtEof Then Raise EParserException.Create('Tried to read past eof'); inc(TextPos); If TextPos>Length(MyTExt) Then TextIsAtEof := True; End; Procedure SkipSpaces; Begin While not TextIsAtEof and (MyText[TextPos] in WhiteSpaceCharacters) do inc(TextPos); End; |
AW: Parserbau Grundlagen + Verständnisfrage
Hey, danke Euch allen für Eure Antworten. Habe jetzt folgende Version für SkipSpaces:
Delphi-Quellcode:
Nun gerät GetToken aber in eine Endlossschleife. Warum das jetzt?
procedure MoveForward;
begin while FLook=' ' do FLook:=GetChar; if IsNewLine(FLook) then FLook:=GetChar; end; //Und nun meine Version für GetToken: function GetToken: String; begin FLineNum := 0; while FLinenum < FParseThis.Count do begin FPos := 1; while FPos<=Length(FParseThis[FLineNum]) do begin MoveForward; FLook := GetChar; //nächstes Zeichen Token := Token + Flook; //Token bauen inc(FPos); //Zeichenposition anpassen end; inc(FLineNum); end; Result := FToken; DoGetToken(FToken); end; |
AW: Parserbau Grundlagen + Verständnisfrage
Ich glaube, Du hast einen Denkfehler.
Verwende drei Operationen: GetChar: Liefert das nächste Zeichen. Bei Zeilenende liefert die Funktion ein ' '. Bei TAB auch. Wenn es den Beginn eines Kommentars sieht (Lookahead!) dann überspringt die Funktion alles bis zum Ende des Kommentars. Anstelle des Kommentars wird ein ' ' geliefert. SkipSpaces: Geht bis zum nächsten Zeichen <> ' '. Verwendet GetChar. GetToken: Liefert einen String bestehen aus den Zeichen bis zum nächsten Terminalsymbol. Danach mit SkipSpaces weiterhüpfen. Das reicht.
Delphi-Quellcode:
Du bist beim Parsen etwas eingeschränkt, weil Du den Parser mit den paar Operationen nicht dazu bringen kannst, nach einem Syntaxfehler wieder so aufzusetzen, das alle Fehler gefunden werden. Aber das ist -soweit ich mich entsinne- eh nicht trivial.
Function TwoWords (ParserTree : TParserTree) : Boolean;
Begin if GetToken.TokenType = tkWord then begin // Remember current word; If GetToken.TokenType = tkWord then begin // Success - we've found two words in a row ... exit; end; Raise ParserError('Expected a word here') end; Raise ParserError('Expected a word here') End; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:30 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz