J'essaye d'analyser un fragment du langage Abap avec Parsec en haskell. Les instructions dans Abap sont délimitées par des points. La syntaxe pour la définition de la fonction est:Comportement étrange analysant un langage impératif en utilisant Parsec
FORM <name> <arguments>.
<statements>.
ENDFORM.
Je vais l'utiliser comme un exemple minimal. Voici ma tentative d'écrire le type correspondant dans haskell et l'analyseur. Le GenStatement
-Constructeur est pour toutes les autres instructions sauf la définition de fonction comme décrit ci-dessus. Tester l'analyseur avec l'entrée suivante entraîne un comportement étrange.
module Main where
import Control.Applicative
import Data.Functor.Identity
import qualified Text.Parsec as P
import qualified Text.Parsec.String as S
import Text.Parsec.Language
import qualified Text.Parsec.Token as T
type Args = String
type Name = String
data AbapExpr -- ABAP Program
= Form Name Args [AbapExpr]
| GenStatement String [AbapExpr]
deriving (Show, Read)
lexer :: T.TokenParser()
lexer = T.makeTokenParser style
where
caseSensitive = False
keys = ["form", "endform"]
style = emptyDef
{ T.reservedNames = keys
, T.identStart = P.alphaNum <|> P.char '_'
, T.identLetter = P.alphaNum <|> P.char '_'
}
dot :: S.Parser String
dot = T.dot lexer
reserved :: String -> S.Parser()
reserved = T.reserved lexer
identifier :: S.Parser String
identifier = T.identifier lexer
argsP :: S.Parser String
argsP = P.manyTill P.anyChar (P.try (P.lookAhead dot))
genericStatementP :: S.Parser String
genericStatementP = P.manyTill P.anyChar (P.try dot)
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
-- 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."
résultats dans
Right (GenStatement "form foo arg1 arg2 arg2" [GenStatement "form bar arg1" [GenStatement "endform" [GenStatement "endform" []]]])
il semble donc la première Brach échoue toujours et seulement la deuxième branche générique est réussie. Toutefois, si la deuxième branche (analyse des déclarations génériques) est commenté les formes d'analyse syntaxique réussit tout à coup:
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
Maintenant, nous obtenons
Right (Form "foo" "arg1 arg2 arg2" [Form "bar" "arg1" []])
Comment est-ce possible? Il semble que la première branche réussisse alors pourquoi ne fonctionne-t-elle pas dans le premier exemple - qu'est-ce qui me manque?
Un grand merci à l'avance!
fonctionne comme un charme! Merci beaucoup! – jules