0

我一直在尝试使用以下教程中的详细信息创建解析器

大部分代码是直接从教程中复制的,只更改了几个名称。

import qualified Text.ParserCombinators.Parsec.Token as P 

reserved   = P.reserved   lexer  
integer    = P.integer    lexer
whiteSpace = P.whiteSpace lexer
identifier = P.identifier lexer

data Express = Seq [Express]
          | ID String
          | Num Integer
          | BoolConst Bool
          deriving (Show)

whileParser :: Parser Express
whileParser = whiteSpace >> expr7

expr7 = seqOfStmt 
    <|> expr8        

seqOfStmt =         
    do list <- (sepBy1 expr8 whiteSpace)
    return $ if length list == 1 then head list else Seq list

expr8 :: Parser Express
expr8 = name 
    <|> number
    <|> bTerm

name :: Parser Express
name = fmap ID identifier

number :: Parser Express
number = fmap Num integer

bTerm :: Parser Express
bTerm = (reserved "True"  >> return (BoolConst True ))
    <|> (reserved "False" >> return (BoolConst False))

我知道这段代码可能很可笑,但我真的很想了解更多关于我哪里出错的信息。我也认为这应该提供足够的信息,但如果不让我知道。

Error:
parse error on input `return'  

我相信该错误与不同的返回类型有关,这很奇怪,因为我尝试使用文章开头的教程作为我所尝试的所有内容的基础。

提前致谢,

肖恩

4

1 回答 1

3

如果您对布局规则不满意,您也可以使用不同的语法:

seqOfStmt =         
   do { list 
 <- (sepBy1 expr8 whiteSpace);
       return $ if length 
            list == 1 
        then head list else Seq list;}

但是,没有大括号和分号的布局被认为是优越的,原因有两个:

  1. 你不需要输入丑陋的; 和大括号
  2. 它迫使你编写(大部分)可读的代码,不像我上面给出的扭曲的废话。

规则非常简单:

  1. 不要使用制表符,使用空格。总是。(你的编辑可以这样做,如果没有,就把它扔掉,这是垃圾软件。)
  2. 属于一起的事物必须在同一列中对齐。

例如,您有 2 个属于do块的语句,因此它们必须在同一列中对齐。但是您已将 与 对齐returndo因此编译器将其视为:

do { list <- sepBy1 expr8 whiteSpace; };
return $  ....;

但你想要的是这样的:

do {
    list <- sepBy1 ....;
    return $ .....;
}

(请注意,您可以省略大括号和分号,只要您保持缩进完好无损就可以了。

于 2013-02-28T11:19:26.680 回答