2017-10-14 2 views
3

Ich versuche, ein Fragment der Abap-Sprache mit Parsec in Haskell zu analysieren. Die Anweisungen in Abap sind durch Punkte begrenzt. Die Syntax für die Funktionsdefinition lautet:Seltsames Verhalten Parsing einer imperativen Sprache mit Parsec

FORM <name> <arguments>. 
    <statements>. 
ENDFORM. 

Ich werde es als ein minimales Beispiel verwenden. Hier ist mein Versuch, den entsprechenden Typ in Haskell und dem Parser zu schreiben. Der GenStatement -Constructor ist für alle anderen Anweisungen außer der Funktionsdefinition wie oben beschrieben.

Das Testen des Parsers mit der folgenden Eingabe führt zu einem seltsamen Verhalten.

-- a wrapper for convenience 
parse :: S.Parser a -> String -> Either P.ParseError a 
parse = flip P.parse "Test" 

testParse1 = parse abapExprP "form foo arg1 arg2 arg2. form bar arg1. endform. endform." 

Ergebnisse in

Right (GenStatement "form foo arg1 arg2 arg2" [GenStatement "form bar arg1" [GenStatement "endform" [GenStatement "endform" []]]]) 

so scheint es das erste Brach nicht immer und nur die zweite allgemeine Zweig erfolgreich ist. Allerdings, wenn der zweite Zweig (allgemeine Aussagen Parsen) Parsing Formen kommentiert plötzlich gelingt:

abapExprP = P.try (P.between (reserved "form") 
          (reserved "endform" >> dot) 
          abapFormP) 
    -- <|> abapStmtP 
    where 
    abapFormP = Form <$> identifier <*> argsP <* dot <*> many abapExprP 
    -- abapStmtP = GenStatement <$> genericStatementP <*> many abapExprP 

Jetzt bekommen wir

Right (Form "foo" "arg1 arg2 arg2" [Form "bar" "arg1" []]) 

Wie ist das möglich? Es scheint, dass der erste Zweig erfolgreich ist. Warum funktioniert das nicht im ersten Beispiel? Was fehlt mir?

Vielen Dank im Voraus!

Antwort

2

Sieht für mich, dass Ihr Parser genericStatementP parst jeden Charakter, bis ein Punkt erscheint (Sie P.anyChar verwenden). Daher erkennt es die reservierten Schlüsselwörter für Ihren Lexer nicht.

Ich glaube, Sie definieren müssen:

type Args = [String] 

und:

argsP :: S.Parser [String] 
argsP = P.manyTill identifier (P.try (P.lookAhead dot)) 

genericStatementP :: S.Parser String 
genericStatementP = identifier 

Mit diesen Änderungen, die ich folgendes Ergebnis:

Right (Form "foo" ["arg1","arg2","arg2"] [Form "bar" ["arg1"] []]) 
+0

wirkt wie ein Zauber! Danke vielmals! – jules