Próbuję parsować bardzo prosty język, który składa się tylko z liczb dziesiętnych lub liczb binarnych. Na przykład, oto kilka ważnych Wejścia:Dlaczego wydaje się, że operator parsektora zależy od kolejności analizatorów składni?
#b1
#d1
#b0101
#d1234
Mam problem za pomocą parsec operator wybór: <|>
. Zgodnie z samouczkiem: Write yourself a Scheme in 48 hours:
[Operator wyboru] próbuje pierwszy parser, a jeśli się nie powiedzie, próbuje drugi. Jeśli się to uda, to zwróci wartość zwróconą przez ten analizator składni ..
Jednak z mojego doświadczenia wynika, że kolejność parserów dostarczała spraw. Oto mój program:
import System.Environment
import Text.ParserCombinators.Parsec
main :: IO()
main = do
(x:_) <- getArgs
putStrLn ("Hello, " ++ readExp x)
bin :: Parser String
bin = do string "#b"
x <- many(oneOf "01")
return x
dec :: Parser String
dec = do string "#d"
x <- many(oneOf "")
return x
-- Why does order matter here?
parseExp = (bin <|> dec)
readExp :: String -> String
readExp input = case parse parseExp "test" input of
Left error -> "Error: " ++ show error
Right val -> "Found val" ++ show val
Oto jak używam programu:
Instalowanie zależnościami
$ cabal sandbox init
$ cabal install parsec
Kompilacja
$ cabal exec ghc Main
Run
$ ./Main "#d1"
Hello, Error: "test" (line 1, column 1):
unexpected "d"
expecting "#b"
$ ./Main "#b1"
Hello, Found val"1"
Jeśli zmienić kolejność parserami następująco: są wykrywane
parseExp = (dec <|> bin)
wtedy tylko liczb binarnych, a program nie określa liczby dziesiętne.
Po przeprowadzonych testach widzę, że problem ten występuje tylko wtedy, gdy jeden z parserów rozpoczął analizowanie danych wejściowych, np. jeśli zostanie znaleziony znak skrótu #
, parser bin jest aktywowany kończąc się niepowodzeniem, ponieważ oczekiwany następny znak to b
, a nie . Wygląda na to, że powinno nastąpić coś w rodzaju powrotu, którego nie mam świadomości.
Doceń pomoc!
Ale w moim przypadku pierwszy parser się nie powiódł. Jest aktywowany, ponieważ pierwsza postać pasuje, ale później nie udaje się, ponieważ nie znajduje następnego oczekiwanego znaku. Spodziewam się, że następny parser powinien zostać aktywowany, ale tak się nie dzieje, jak widać na wyjściu, które wkleiłem. – mandark
@mandark Jest tak z powodu działania Parsec. Będę edytować. – chi
Co bardziej zaskakujące, widziałem parsery 'attoparsec', które mogą odnieść sukces lub zakończyć się niepowodzeniem w zależności od kolejności argumentów na' <|> '. Będę musiał zadać własne pytanie na ten temat. – dfeuer