首页 > 解决方案 > Haskell:如何将语义空白集成到解析器中?

问题描述

我目前正在用 Haskell 编写一种语言https://github.com/EdONeill1/HENRYGCL,并且在弄清楚如何允许将程序编写在多行上时遇到了麻烦。采用以下循环,将 1 加到 x 上,直到达到 10。

Henry > x := 1
Henry > if <x<10> [] x := <x+1> [] x := <x+10>

我希望该程序在某种程度上采用以下形式:

Henry > x := 1
Henry > if <x<10>
[] x := <x+1>
[] x := <x+10>

我考虑过使用该功能spacenewline​​从Text.ParserCombinators.Parsec.Char模块。这将使我能够识别(我认为)换行符\n。使用它时,以下解析器功能:

ifStmt :: Parser HenryVal
ifStmt =
  do 
     reserved "if"
     cond  <- bExpression <|>
              do 
                _ <- char '<'
                x <- try parseBinary
                _ <- char '>'
                return x
    some (space <|> newline)
    reserved "[]"
    stmt1 <- statement
    some (space <|> newline)
    reserved " []"
    stmt2 <- statement
    return $ If cond stmt1 stmt2

当我尝试以下操作时收到以下错误:

Henry > x:=1
1
Henry > if <x<10>
Parse error at "Henry" (line 1, column 10):
unexpected end of input
expecting space or lf new-line
Henry > if <x<10>
Parse error at "Henry" (line 1, column 12):
unexpected end of input
expecting space, lf new-line or "[]"
Henry >

第一个错误是在我完成输入时按 Enter 引起>的,第二个错误是按 Space 一次然后按 Enter 引起的。在这两种情况下,都没有更正换行符。我不确定lfinlf new-line实际意味着什么,因为据我了解,不应该按 Enter 给你一个换行符吗?

在我的代码的另一部分中,我有以下内容,whiteSpace = Token.whiteSpace lexer. 当我some (space <|> newline)用 this 替换 并在 之后按 enterif <x<10>时,实际上会创建一个换行符。然而,尽管能够编写一个完整的 if 语句,但没有终止,它只是让我可以无限期地继续写作。

我很困惑如何从这里开始。我认为我的逻辑使用some (space <|> newline)是正确的,就好像程序遇到至少一个空格或换行符,一个空格或换行符,但我知道我的实现是不正确的。我认为这可能whiteSpace会导致某个地方,但似乎这是另一个死胡同。

标签: parsinghaskell

解决方案


解析器看起来不错。这里的问题是main当前一次在一行上运行解析器。您需要在运行解析器之前累积整个输入。


推荐阅读