AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi Parserbau Grundlagen + Verständnisfrage
Thema durchsuchen
Ansicht
Themen-Optionen

Parserbau Grundlagen + Verständnisfrage

Ein Thema von Nintendo · begonnen am 22. Sep 2012 · letzter Beitrag vom 24. Sep 2012
Antwort Antwort
Nintendo

Registriert seit: 16. Feb 2009
82 Beiträge
 
#1

Parserbau Grundlagen + Verständnisfrage

  Alt 22. Sep 2012, 18:41
Hallo,

ich versuche mich grad an einem Parser, der wie folgt aufgebaut ist:

Delphi-Quellcode:
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_Wortthen
    begin
      Token := GetToken;
      SkipSpaces;
      if Token = 'Mein_nächstes_gesuchtes_Wortthen
      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;
Leider kommt mein Parser aber nicht zu '''if Token='Mein_Nächstes_gesuchtes_wort' then ...

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.

Geändert von Nintendo (22. Sep 2012 um 18:43 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#2

AW: Parserbau Grundlagen + Verständnisfrage

  Alt 22. Sep 2012, 18:52
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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von implementation
implementation

Registriert seit: 5. Mai 2008
940 Beiträge
 
FreePascal / Lazarus
 
#3

AW: Parserbau Grundlagen + Verständnisfrage

  Alt 22. Sep 2012, 19:50
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:
procedure SkipSpaces;
begin
  while (Look()=' ') or IsLinebreak() do
    MoveForward();
end;
So, wie du es jetzt geschrieben hast, sieht es aber so aus:
Delphi-Quellcode:
procedure SkipSpaces;
begin
  while Look()=' do
    MoveForward();
  if IsLinebreak() then
    MoveForward();
end;
Siehst du den Unterschied?


Tipp am Rande: Du solltest dir die wichtigen Subaufgaben sowieso besser auslagern. Ein Look() /Peek() und ein MoveForward 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.

Geändert von implementation (22. Sep 2012 um 19:55 Uhr)
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#4

AW: Parserbau Grundlagen + Verständnisfrage

  Alt 23. Sep 2012, 11:22
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:
Procedure SkipSpaces;
Begin
  While (TextPos<Length(MyText)) and (MyText[TextPos] in WhiteSpaceCharacters) do
    inc(TextPos);

  If TextPos>Length(MyTExt) Then
    TextIsAtEof := True;
End;
Noch viel transparenter wird es so (finde ich)
Delphi-Quellcode:
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;
Das saubere 'Advance' kannst Du auch in deinem 'GetToken' verwenden.
  Mit Zitat antworten Zitat
Nintendo

Registriert seit: 16. Feb 2009
82 Beiträge
 
#5

AW: Parserbau Grundlagen + Verständnisfrage

  Alt 24. Sep 2012, 21:16
Hey, danke Euch allen für Eure Antworten. Habe jetzt folgende Version für SkipSpaces:

Delphi-Quellcode:
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;
Nun gerät GetToken aber in eine Endlossschleife. Warum das jetzt?
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#6

AW: Parserbau Grundlagen + Verständnisfrage

  Alt 24. Sep 2012, 21:38
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:
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;
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.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:44 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz