简体   繁体   English

Haskell错误中的解析器

[英]parser in haskell error

I am supposed to make a parser for a language with the following grammar: 我应该使用以下语法为一种语言创建解析器:

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 ")"

With the following data type for 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)

My problem is implementing the Shift operator, because I get the following error when I encounter a left or right shift: 我的问题是实现Shift运算符,因为遇到左移或右移时出现以下错误:

unexpected ">" expecting operator or ";" 意外的“>”期望运算符或“;”

Here is the code I have for Expr: 这是我为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)

I suspect the problem is concerning lookahead, but I can't seem to figure it out. 我怀疑问题与前瞻有关,但我似乎无法弄清楚。

Here's a grammar with left recursion eliminated (untested). 这是一个消除了左递归(未调试)的语法。 Stmts and Choices can be simplified with Parsec's many and many1. 可以使用Parsec的many1来简化stmts和Choices。 The other recursive productions have to be expanded: 其他递归产品必须扩展:

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 ")"

Edit - "Part Two" 编辑-“第二部分”

"empty" (in angles) is the empty production, you were using epsilon in the original post, but I don't know its Unicode code point and didn't think to copy-paste it. “空”(角度)是空的生产,您在原始文章中使用的是epsilon,但是我不知道它的Unicode代码点,也没有考虑复制粘贴它。

Here's an example of how I would code the grammar. 这是我如何编写语法的示例。 Note - unlike the grammar I posted empty versions must always be the last choice to give the other productions chance to match. 注意-与语法不同,我发布的空白版本必须始终是给予其他作品匹配的最后选择。 Also your datatypes and constructors for the Abstract Syntax Tree probably differ to the the guesses I've made, but it should be fairly clear what's going on. 同样,您抽象语法树的数据类型和构造函数可能与我所做的猜测有所不同,但是应该很清楚发生了什么。 The code is untested - hopefully any errors are obvious: 该代码未经测试-希望所有错误都是显而易见的:

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

Parsec is still Greek to me, but my vague guess is that aShift should use try . 对我来说,Parsec仍然是希腊语,但是我模糊的猜测是aShift应该使用try

The parsec docs on Hackage have an example explaining the use of try with <|> that might help you out. 关于Hackageparsec文档有一个示例,说明了将try<|>结合使用的方法,可能会对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM