Jestem względnie nowy w Haskell z głównym tłem programowania pochodzącym z języków OO. Próbuję napisać interpreter z parserem dla prostego języka programowania. Do tej pory mam tłumacza w stanie, z którego jestem dość zadowolony, ale walczę trochę z parserem.Parsowanie w Haskell dla prostego interpretatora
Oto fragment kodu, który mam problemy z
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
język jest nieco bardziej skomplikowane, ale to wystarczy, aby pokazać mój problem.
Tak więc w typie IntExp ICon jest stałą, a IVar jest zmienną, ale teraz jest problem. To na przykład działa skutecznie
runP parseAdd "5 + 5"
co daje (ADD (ikona 5) (ikona 5)), który jest oczekiwany wynik. Problem pojawia się w przypadku korzystania Ivars zamiast ikon np
runP parseAdd „N + M”
To powoduje, że program do błędu się mówiąc, nie było nieoczekiwane „n”, gdzie spodziewano się cyfrą. To prowadzi mnie do przekonania, że parseIntExp nie działa tak jak zamierzałem. Moją intencją było to, że spróbuje przeanalizować ICon, jeśli to zawiedzie, spróbuj sparsować IVar i tak dalej.
Tak więc albo uważam, że problem istnieje w parseIntExp, albo że brakuje mi czegoś w parsevar i parsecton.
Mam nadzieję, że podałem wystarczająco dużo informacji na temat mojego problemu i byłem wystarczająco jasny.
Dzięki za pomoc, jaką możesz mi dać!
Odpowiedź camccanna jest bardzo dobra. Kilka dalszych wskazówek ... "Lexing" i obsługa białych znaków zwykle odbywa się za pomocą modułów Parsec.Token i Parsec.Language. Styl tych lexerów jest dość idiomatyczny - jeśli otrzymasz źródła Parsec z http://legacy.cs.uu.nl/daan/parsec.html, są proste przykłady, takie jak jeden dla Henka, gdzie możesz w większości skopiować kod z . Moduł Token zapewnia również lepsze analizatory liczb, dzięki czemu można uniknąć używania wielu cyfr, a następnie przeczytać. Również instancja Applicative dla Parsec, aby uzyskać notację (<$>) i (<*>), jest dostępna tylko w wersjach 3.0 i nowszych. –
Bardzo dziękuję za odpowiedź i radę. Wygląda na to, że rozwiąże mój problem, i powinienem być w stanie poprawić mój styl kodowania. Twoje zdrowie! – Josh
W przykładzie 'parseICon', wolałbym' ICon. read = << multiple digit' choice, ponieważ jest jaśniejszy do czytania. – fuz