解析方案 dottedlist/list 与 Haskell
Parsing scheme dottedlist/list with Haskell
我正在关注 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
解析器看到点之前的 space,并承诺解析另一个失败的表达式。
你应该让 lexemes 消耗和丢弃尾随的 spaces(参见 parsec 的 lexeme
)并将 sepBy
更改为 many1
。 optionMaybe
可以在看到一个点后提交,否则需要 try
.
我正在关注 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
解析器看到点之前的 space,并承诺解析另一个失败的表达式。
你应该让 lexemes 消耗和丢弃尾随的 spaces(参见 parsec 的 lexeme
)并将 sepBy
更改为 many1
。 optionMaybe
可以在看到一个点后提交,否则需要 try
.