haskell中的解析器错误

时间:2011-02-27 01:23:54

标签: parsing haskell

我应该为具有以下语法的语言创建解析器:

Program ::= Stmts "return" Expr ";"
Stmts   ::= Stmt Stmts
            |   ε
Stmt    ::= ident "=" Expr ";"
            |   "{" Stmts "}"
            |   "for" ident "=" Expr "to" Expr Stmt
            |   "choice" "{" Choices "}"
Choices  ::=  Choice Choices
         |  Choice
Choice  ::=  integer ":" Stmt
Expr    ::=  Shift
Shift   ::=  Shift "<<" integer
            |   Shift ">>" integer
            |   Term
Term   ::=  Term "+" Prod
       |    Term "-" Prod
       |    Prod
Prod    ::=  Prod "*" Prim
            |   Prim
Prim    ::= ident
            |   integer
            |   "(" Expr ")"

使用Expr的以下数据类型:

data Expr = Var Ident
        | Val Int
        | Lshift Expr Int
        | Rshift Expr Int
        | Plus Expr Expr
        | Minus Expr Expr
        | Mult Expr Expr
        deriving (Eq, Show, Read)

我的问题是实现Shift运算符,因为当遇到左移或右移时我收到以下错误:

意外“&gt;” 期待经营者或“;”

以下是我对Expr的代码:

expr = try (exprOp) 
    <|> exprShift           

exprOp = buildExpressionParser arithmeticalOps prim <?> "arithmetical expression"

prim :: Parser Expr
prim = new_ident <|> new_integer <|> pE <?> "primitive expression"
            where 
                    new_ident = do {i <- ident; return $ Var i }
                    new_integer = do {i <- first_integer; return $ Val i }
                    pE = parens expr

arithmeticalOps = [ [binary "*" Mult AssocLeft],
                    [binary "+" Plus AssocLeft, binary "-" Minus AssocLeft]
                    ]

binary  name fun assoc = Infix (do{ reservedOp name; return fun }) assoc 

exprShift = 
            do
                e <- expr
                a <- aShift
                i <- first_integer
                return  $ a e i

aShift = (reservedOp "<<" >> return Lshift) 
            <|> (reservedOp ">>" >> return Rshift)

我怀疑这个问题涉及前瞻,但我似乎无法弄明白。

2 个答案:

答案 0 :(得分:1)

这是一个删除了左递归的语法(未经测试)。使用Parsec的许多和许多1可以简化Stmts和Choices。其他递归制作必须扩展:

Program ::= Stmts "return" Expr ";"

Stmts   ::= @many@ Stmt

Stmt    ::= ident "=" Expr ";"
            |   "{" Stmts "}"
            |   "for" ident "=" Expr "to" Expr Stmt
            |   "choice" "{" Choices "}"

Choices  ::=  @many1@ Choice

Choice  ::=  integer ":" Stmt

Expr    ::=  Shift

Shift   ::= Term ShiftRest

ShiftRest ::= <empty>
          | "<<" integer
          | ">>" integer


Term ::= Prod TermRest

TermRest ::= <empty> 
         | "+" Term
         | "-" Term

Prod ::= Prim ProdRest

ProdRest ::= <empty> 
         |   "*" Prod

Prim    ::= ident
        |   integer
        |   "(" Expr ")"

编辑 - “第二部分”

“empty”(角度)是空制作,你在原帖中使用了epsilon,但我不知道它的Unicode代码点,也没想过复制粘贴它。

以下是我将如何编写语法的示例。注意 - 与我发布的语法不同,空版本必须始终是让其他作品有机会匹配的最后选择。此外,抽象语法树的数据类型和构造函数可能与我所做的猜测不同,但应该相当清楚发生了什么。代码未经测试 - 希望任何错误都很明显:

shift :: Parser Expr
shift = do 
    t <- term
    leftShift t <|> rightShift <|> emptyShift t

-- Note - this gets an Expr passed in - it is the "prefix"
-- of the shift production.
--
leftShift :: Expr -> Parser Expr
leftShift t = do 
  reservedOp "<<" 
  i <- int
  return (LShift t i)

-- Again this gets an Expr passed in.
--
rightShift :: Expr -> Parser Expr
rightShift t = do 
  reservedOp ">>" 
  i <- int
  return (RShift t i)

-- The empty version does no parsing.
-- Usually I would change the definition of "shift"
-- and not bother defining "emptyShift", the last 
-- line of "shift" would then be:
--
-- > leftShift t <|> rightShift t <|> return t
--
emptyShift :: Expr -> Parser Expr
emptyShift t = return t

答案 1 :(得分:0)

Parsec对我来说仍然是希腊语,但我的模糊猜测是aShift应该使用try

parsec docs on Hackage有一个示例,解释try<|>的使用可能对您有所帮助。