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