2017-02-11 1 views
2

Ich versuche, eine einfache Sprache mit Parsec zu analysieren. Es kann entweder Zuweisungen "x = y" oder Präfixe wie "Präfix Test" geben. Die Parsing-Regel für Zuweisungen ist jedoch gierig und schlägt nicht fehl, wenn kein "=" vorhanden ist. Zum BeispielParsing-Operation ohne Präfix in Parsec

parse tp "" "prefix foo" 

führt zu einem Parsing-Fehler. Der entsprechende Code:

module Test where 
import Text.ParserCombinators.Parsec 
import Text.ParserCombinators.Parsec.Language 
import Text.ParserCombinators.Parsec.Expr 
import qualified Text.ParserCombinators.Parsec.Token as P 

lexer = haskell 
reserved = P.reserved lexer 
reservedOp = P.reservedOp lexer 

data Term = Term String 
    deriving (Show) 

term :: Parser Term 
term = do { x <- many alphaNum 
      ; reservedOp "=" 
      ; y <- many alphaNum 
      ; return (Term (x++y)) 
      } 
    <|> do { reserved "prefix" 
      ; x <- many alphaNum 
      ; return (Term x) 
      } 

tp = do { e<-term; return e } 

Was fehlt mir? Ist meine Herangehensweise überhaupt möglich, oder habe ich Parsec falsch verstanden?

+0

Wie wäre es mit 'Leerzeichen' nach' reserviertem "Präfix" '? – jeiea

+0

Wir kommen nie so weit, der Parser sieht nur im ersten aus. Wenn wir die Reihenfolge der Regeln ändern, wird die Anweisung korrekt analysiert. Dies funktioniert jedoch nur in diesem einfachen Fall. Wenn wir mehr Regeln wie die erste haben, funktioniert der Trick nicht mehr. – hexhex

+0

Es funktioniert nicht, weil 'viele alphaNum'" Präfix "verwendet, aber dann fehlschlägt - sobald ein Parser nach der Verwendung von Eingaben fehlgeschlagen ist, wird es keine andere Alternative versuchen (gegeben durch' <|> 'oder' choice' usw.). Sie benötigen einen "try" auf dem ersten Parser. (Ich glaube, Sie haben Parsec falsch verstanden - Sie erwarten automatisches Backtracking, aber Parsec tut das einfach nicht. Es gibt andere Parser-Bibliotheken, die das tun, glaube ich) – user2407038

Antwort

1

Wie von user2407038 in den Kommentaren hervorgehoben, ist das Problem, dass x <- many alphaNumprefix verbraucht und somit die zweite Regel nicht angewendet werden kann. Die Lösung ist, try vor den Block zu setzen, dieser spult verbrauchte Teile des Streams zurück.