Je suis relativement nouveau à Haskell avec l'arrière-plan principal de programmation venant des langues d'OO. J'essaie d'écrire un interpréteur avec un analyseur pour un langage de programmation simple. Jusqu'à présent, j'ai l'interprète dans un état dont je suis raisonnablement content, mais je me bats un peu avec l'analyseur.Analyser dans Haskell pour un interprète simple
Voici le morceau de code que je rencontre des problèmes avec
data IntExp
= IVar Var
| ICon Int
| Add IntExp IntExp
deriving (Read, Show)
whitespace = many1 (char ' ')
parseICon :: Parser IntExp
parseICon =
do x <- many (digit)
return (ICon (read x :: Int))
parseIVar :: Parser IntExp
parseIVar =
do x <- many (letter)
prime <- string "'" <|> string ""
return (IVar (x ++ prime))
parseIntExp :: Parser IntExp
parseIntExp =
do x <- try(parseICon)<|>try(parseIVar)<|>parseAdd
return x
parseAdd :: Parser IntExp
parseAdd =
do x <- parseIntExp
whitespace
string "+"
whitespace
y <- parseIntExp
return (Add x y)
runP :: Show a => Parser a -> String -> IO()
runP p input
= case parse p "" input of
Left err ->
do putStr "parse error at "
print err
Right x -> print x
La langue est un peu plus complexe, mais cela suffit pour montrer mon problème. Donc dans le type IntExp ICon est une constante et IVar est une variable, mais maintenant sur le problème. Cet exemple fonctionne avec succès
RUNP parseAdd "5 + 5"
qui donne (Ajouter (ICon 5) (5 ICon)), qui est le résultat attendu. Le problème se pose lors de l'utilisation Ivars plutôt que, par exemple ICÔNES
RUNP parseAdd « n + m »
Cela provoque le programme d'erreur en disant qu'il y avait un inattendu « n », où un chiffre était attendu. Cela m'amène à croire que parseIntExp ne fonctionne pas comme prévu. Mon intention était qu'elle essaye d'analyser un ICon, si cela échoue alors essayez d'analyser un IVar et ainsi de suite. Donc, soit je pense que le problème existe dans parseIntExp, ou qu'il me manque quelque chose dans parseIVar et parseICon.
J'espère avoir donné assez d'informations sur mon problème et j'ai été assez clair.
Merci pour toute aide que vous pouvez me donner!
La réponse de camccann est très bonne. Quelques conseils supplémentaires ... "Lexing" et la gestion des espaces sont généralement effectués avec les modules Parsec.Token et Parsec.Language. Le style pour ces lexers est assez idiomatique - si vous obtenez les sources Parsec de http://legacy.cs.uu.nl/daan/parsec.html il y a des exemples simples tels que celui de Henk où vous pouvez copier le code de . Le module Token vous donne également de meilleurs analyseurs pour les nombres, ce qui vous évite d'utiliser plusieurs chiffres, puis de les lire. L'instance Applicative de Parsec pour obtenir la notation (<$>) & (<*>) n'est également disponible qu'avec les versions 3.0 et ultérieures. –
Merci beaucoup pour la réponse et le conseil. On dirait que ça va régler mon problème, et je devrais pouvoir améliorer mon style de codage. À votre santé! – Josh
Dans l'exemple 'parseICon', je préférerais' ICon. read = << many digit' choix, car il est plus clair à lire. – fuz