2015-06-02 1 views
2

Я изучаю haskell с Write yourself a scheme.Parsec <|> выбор в синтаксическом анализаторе, ошибка бросает, но не переходит к следующему парсеру

Я в настоящее время пытаюсь реализовать признание в схеме char. A char - #\<character> или #\<character-name>, как #\a или #\ или #\space.

Так я написал следующий код:

-- .. some code .. 
data LispVal = Atom String 
      | List [LispVal] 
      | DottedList [LispVal] LispVal 
      | String String 
      | Number Integer 
      | Bool Bool 
      | Char Char deriving Show 
-- .... More code ... 
parseChar :: Parser LispVal 
parseChar = liftM Char (parseSingleChar <|> parseSpecialCharNotation) 

parseSingleChar :: Parser Char 
parseSingleChar = do string "#\\" 
        x <- letter 
        return x 

parseSpecialCharNotation :: Parser Char 
parseSpecialCharNotation = do string "#\\" 
           x <- (parseSpace <|> parseNewline) 
           return x 

parseSpace :: Parser Char 
parseSpace = do char 's' 
       char 'p' 
       char 'a' 
       char 'c' 
       char 'e' 
       return ' ' 

parseNewline :: Parser Char 
parseNewline = do char 'n' 
        char 'e' 
        char 'w' 
        char 'l' 
        char 'i' 
        char 'n' 
        char 'e' 
        return '\n' 

-- .. some more code... 

readExpr :: String -> String 
readExpr input = case parse parseExpr "lisp" input of 
       Left err -> "Parse Error: " ++ show err 
       Right val -> "Found value: " ++ show val 

В этот момент я не знал о string парсера Parsec.

Проблема в том, что я признаю, #\a, но #\space рассматривается как s.

*Main> readExpr "#\\space" 
"Found value: Char 's'" 

Чтобы решить эту проблему, я изменил parseChar в

parseChar :: Parser LispVal 
parseChar = liftM Char (parseSpecialCharNotation <|> parseSingleChar) 

но ранее проблема решена, но теперь она дает мне ошибки с нормальными персонажами, как -

*Main> readExpr "#\\s" 
"Parse Error: \"lisp\" (line 1, column 4):\nunexpected end of input\nexpecting \"p\"" 

Почему это происходит? Разве он не переместился в parseSingleChar, так как parseSpecialCharNotation не удалось?

Полный код по адресу: Gist

ответ

5

из documentation для <|>:

синтаксический анализатор называется предсказанием, так как д только пытался, когда парсер р не потребляли любой входной сигнал (то есть смотреть вперед. 1).

В вашем случае оба анализа потребляют "#\\" перед сбоем, поэтому другая альтернатива не может быть оценена. Вы можете использовать try для обеспечения отслеживанию работы, как и ожидалось:

Парсер try p ведет себя как синтаксический анализатор p, за исключением того, что он делает вид, что он не употреблял вход, когда возникает ошибка.

Что-то вроде следующего:

try parseSpecialCharNotation <|> parseSingleChar 

Примечание стороны: это лучше, чтобы извлечь "#\\" из парсеров, потому что в противном случае вы делаете ту же работу дважды. Что-то вроде следующего:

do 
    string "#\\" 
    try parseSpecialCharNotation <|> parseSingleChar 

Кроме того, вы можете использовать string комбинатор вместо серии char анализаторов.

Смежные вопросы