使用 Haskell 解析方案 dottedlist/list

标签 parsing haskell scheme parsec

我正在关注this guide关于编写计划解释器。在尝试左因子 DottedList/List 的语法时,我想出了这个:

E -> (H T)
H -> E H'
H' -> <space> H
H' -> <term>
T ->  <term>
T -> <space> . <space> E

--

spaces :: Parser ()
spaces = skipMany1 (space <?> "spaces")

parseExpr :: Parser LispVal
parseExpr = (... omitted ...) <|>
             do char '('
                h <- sepBy parseExpr spaces
                t <- optionMaybe ((spaces' >> char '.' >> spaces' >> parseExpr)  <?> "parseDotExpr failed")
                z <- if isJust t then return $ DottedSuffix $ fromJust t else return Tail
                z' <- case z of Tail           -> return $ List x
                                DottedSuffix s -> return $ DottedList x s
                char ')'
                return z'

不幸的是,这不能处理基本的点列表:

test/Spec.hs:23: 
1) test eval 1 evals DottedList
     expected: "(1 2 . 1)"
      but got: "Parse error at \"lisp\" (line 1, column 7):\nunexpected \".\"\nexpecting spaces' or parseExpr!"

test/Spec.hs:26: 
2) test eval 1 evals DottedList (quoted)
     expected: "((1 2) . 1)"
      but got: "Parse error at \"lisp\" (line 1, column 15):\nunexpected \".\"\nexpecting spaces' or parseExpr!"

test/Spec.hs:29: 
3) test eval 1 evals DottedList (sugared)
     expected: "((1 2) . 1)"
      but got: "Parse error at \"lisp\" (line 1, column 9):\nunexpected \".\"\nexpecting spaces' or parseExpr!"

更新: 从 @pat 的回复中,我使用以下方法通过了测试:

parseExpr :: Parser LispVal
parseExpr = {- omitted -}
         <|> do char '('
                x <- many1 (do e <- parseExpr; spaces'; return e)
               {- omitted -}

最佳答案

sepBy 解析器看到点之前的空格,并 promise 解析另一个表达式,但失败了。

您应该让词素消耗并丢弃尾随空格(请参阅parsec的lexeme)并将sepBy更改为many1optionMaybe 可以在看到点后提交,否则需要 try

关于使用 Haskell 解析方案 dottedlist/list,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47566098/

相关文章:

json - Racket 中的 REST API JSON 解析

parsing - 在Menhir/Ocamlyacc中为运算符(operator)指定动态优先级和优先级

php - 将值传递给隐藏的表单字段/解析数据

monads - 为什么在编写新的 Monad Transformers 时使用样板

haskell - "compose"怎么是iso的?

sql - 如何让 Haskell 在编译时检查 SQL?

installation - 在 Windows 10 上安装 MIT Scheme -- 'Requested Allocation is too large'

scheme - 具有非 Lisp 语法的 CL/Scheme DSEL

algorithm - 如何使用解析树求解表达式?

parsing - Prolog DCG 中的可选或重复项