2011-01-02 5 views
2

Ich versuche, einen Parser für eine einfache Auszeichnungssprache mit Happy zu schreiben. Momentan habe ich Probleme mit infinit Loops und verschachtelten Elementen.Verschachtelte Parser in Happy/Endlosschleife?

Meine Markup-Sprache besteht im Wesentlichen aus zwei Elementen, einem für "normalen" Text und einem für fett/hervorgehobenen Text.

data Markup 
    = MarkupText String 
    | MarkupEmph [Markup] 

Zum Beispiel kann ein Text wie Foo *bar* sollte als [MarkupText "Foo ", MarkupEmph [MarkupText "bar"]] analysiert bekommen.

Lexing dieses Beispiels funktioniert gut, aber die Analyse führt zu einer Endlosschleife - und ich kann nicht sehen, warum. Dies ist mein derzeitiger Ansatz:

-- The main parser: Parsing a list of "Markup" 
Markups  :: { [Markup] } 
      : Markups Markup     { $1 ++ [$2] } 
      | Markup       { [$1]  } 

-- One single markup element 
Markup  :: { Markup } 
      : '*' Markups1 '*'     { MarkupEmph $2 } 
      | Markup1       { $1   } 

-- The nested list inside *..* 
Markups1 :: { [Markup] } 
      : Markups1 Markup1     { $1 ++ [$2] } 
      | Markup1       { [$1]  } 

-- Markup which is always available: 
Markup1  :: { Markup } 
      : String       { MarkupText $1 } 

Was ist falsch an diesem Ansatz? Wie könnte das gelöst werden?

Aktualisierung: Entschuldigung. Lexing funktionierte nicht wie erwartet. Die Unendlichkeitsschleife war im Lexer. Es tut uns leid. :)

Update 2: Auf Wunsch Ich verwende dies als Lexer:

lexer :: String -> [Token] 
lexer [] = [] 
lexer [email protected](c:cs) 

    | c == '*'    = TokenSymbol "*" : lexer cs 
    -- ...more rules... 
    | otherwise    = TokenString val : lexer rest 

    where (val, rest) = span isValidChar str 
     isValidChar = (/= '*') 

Die infinit Rekursion aufgetreten, weil ich lexer str hatte statt lexer cs in dieser ersten Regel für '*'. Habe es nicht gesehen, weil mein tatsächlicher Code etwas komplexer war. :)

+0

Um die Vollständigkeit dieser Frage zu gewährleisten, können Sie das Vorher und Nachher Ihres Lexers posten. So können andere sehen, was schief gelaufen ist. Vielen Dank. –

Antwort

1

Nur eine Warnung, es ist eine Weile her, seit ich Parser-Generatoren behandelt habe.

Es scheint, dass Sie einen LR (1) Parser brauchen, der nicht sicher ist, glücklich ist. Ich bin positiv, sobald ich das schreibe, wird jemand in der Lage sein, mich zu korrigieren.

Wenn Ihr Parser nicht nach vorne schauen kann es auf dieser Aussage stecken für immer

Markups1 :: { [Markup] } 
     : Markups1 Markup1 
     | Markup1 

Es wird für einen Markups1 suchen, was wiederum für eine Markups1 aussieht. Das Beste, was ich erraten kann, ist, dass ich nicht nach Markup1 schaue, um zu sehen, ob es eine Zeichenkette ist.

Probieren Sie es wie diese

Markups1 :: { [Markup] } 
     : Markup1 Markups1 
     | 

Umschreiben Im Wesentlichen Sie es wollen zuerst die Zeichenfolge zu finden, dann versuchen, für eine andere Zeichenfolge zu suchen, wenn es einen nicht findet es braucht, um diese Aussage zu beenden.

+0

Ich stimme zu, die Listen sind verdächtig - ich schreibe es normalerweise ': x xs {$ 1: $ 2} | {[]} '. –

+0

Oh, und zum Thema LR Parsing, [siehe diese Handbuchseite] (http://www.haskell.org/happy/doc/html/sec-glr.html) –

+0

"Classic" Happy ist LALR (1) . @TomMD - Ich bin mir nicht sicher, der Status der GLR-Erweiterung - obwohl es in der Code-Basis, das letzte Mal, als ich es versuchte ich war nicht sicher, es funktioniert. Außerdem glaube ich, dass die GLR-Erweiterung eher für das Parsen natürlicher Sprache als für das Parsen von (mehrdeutigen) Programmiersprachen geschrieben wurde. –