Parsec:扩展工作解析器会产生奇怪的结果
Parsec: extending a working parser gives odd results
对于一个项目,我们的任务是构建一个 haskell 控制微型 arduino 机器人的解析器/评估器。
首先,我基本上对已经实现的解析器设置做了一些研究,然后发现了这个:https://wiki.haskell.org/Parsing_a_simple_imperative_language。
(诚然)复制粘贴代码后,我开始测试它。它奏效了\o/。
现在是时候扩展它的功能了。
编辑代码:
data Stmt = Seq [Stmt]
| Assign String AExpr
| If BExpr Stmt Stmt
| While BExpr Stmt
| Motor String AExpr
| Skip
deriving (Show)
Token.reservedNames = [ "if"
, "then"
, "else"
, "while"
, "do"
, "skip"
, "true"
, "false"
, "not"
, "and"
, "or", "set" , "to"
]
statement' :: Parser Stmt
statement' = ifStmt
<|> whileStmt
<|> skipStmt
<|> assignStmt
<|> motorStatement
motorStatement :: Parser Stmt
motorStatement =
do reserved "set"
var <- identifier
reserved "to"
expr <- aExpression
return $ Motor var expr
这些是我编辑的仅有的代码片段。
为了测试这一切,我制作了一个小测试文件:
x := 4;
x := 6;
上面的代码在我更改之前解析得很好,但是在我添加更改之后我得到以下错误
< (line 3, column 1):
< unexpected end of input
< expecting "if", "while", "skip", identifier or "set"
由于我对 Haskell 的了解有限,我无法弄清楚为什么会发生这种“unexpected end of input
”。
也许这里的某些 Haskeller 可以指出错误。
我不相信您的输入在您进行更改之前已正确解析。使用 sepBy1
:
解析语句列表
sequenceOfStmt =
do list <- (sepBy1 statement' semi)
-- If there's only one statement return it without using Seq.
return $ if length list == 1 then head list else Seq list
sequenceOfStmt
是贪婪的,因为如果它看到一个分号,它会期望看到另一个 statement'
。所以分号应该被视为语句分隔符而不是语句终止符。
尝试 运行 这些测试以了解 sepBy1
的行为:
import Text.Parsec
import Text.Parsec.Combinator
p1 = sepBy1 (char 'a') (char ';')
test1 = parseTest p1 "a;a" -- OK
test2 = parseTest p1 "a;a;" -- FAILS
为了帮助探索这个问题,我已将 ParseWhile 语言的源代码放在 lpaste.net 上:http://lpaste.net/163332
对于一个项目,我们的任务是构建一个 haskell 控制微型 arduino 机器人的解析器/评估器。
首先,我基本上对已经实现的解析器设置做了一些研究,然后发现了这个:https://wiki.haskell.org/Parsing_a_simple_imperative_language。
(诚然)复制粘贴代码后,我开始测试它。它奏效了\o/。 现在是时候扩展它的功能了。
编辑代码:
data Stmt = Seq [Stmt]
| Assign String AExpr
| If BExpr Stmt Stmt
| While BExpr Stmt
| Motor String AExpr
| Skip
deriving (Show)
Token.reservedNames = [ "if"
, "then"
, "else"
, "while"
, "do"
, "skip"
, "true"
, "false"
, "not"
, "and"
, "or", "set" , "to"
]
statement' :: Parser Stmt
statement' = ifStmt
<|> whileStmt
<|> skipStmt
<|> assignStmt
<|> motorStatement
motorStatement :: Parser Stmt
motorStatement =
do reserved "set"
var <- identifier
reserved "to"
expr <- aExpression
return $ Motor var expr
这些是我编辑的仅有的代码片段。 为了测试这一切,我制作了一个小测试文件:
x := 4;
x := 6;
上面的代码在我更改之前解析得很好,但是在我添加更改之后我得到以下错误
< (line 3, column 1):
< unexpected end of input
< expecting "if", "while", "skip", identifier or "set"
由于我对 Haskell 的了解有限,我无法弄清楚为什么会发生这种“unexpected end of input
”。
也许这里的某些 Haskeller 可以指出错误。
我不相信您的输入在您进行更改之前已正确解析。使用 sepBy1
:
sequenceOfStmt =
do list <- (sepBy1 statement' semi)
-- If there's only one statement return it without using Seq.
return $ if length list == 1 then head list else Seq list
sequenceOfStmt
是贪婪的,因为如果它看到一个分号,它会期望看到另一个 statement'
。所以分号应该被视为语句分隔符而不是语句终止符。
尝试 运行 这些测试以了解 sepBy1
的行为:
import Text.Parsec
import Text.Parsec.Combinator
p1 = sepBy1 (char 'a') (char ';')
test1 = parseTest p1 "a;a" -- OK
test2 = parseTest p1 "a;a;" -- FAILS
为了帮助探索这个问题,我已将 ParseWhile 语言的源代码放在 lpaste.net 上:http://lpaste.net/163332