Parsing haskell错误中的解析器

Parsing haskell错误中的解析器,parsing,haskell,Parsing,Haskell,我应该为具有以下语法的语言制作一个解析器: Program ::= Stmts "return" Expr ";" Stmts ::= Stmt Stmts | ε Stmt ::= ident "=" Expr ";" | "{" Stmts "}" | "for" ident "=" Expr "to" Expr Stmt | "choice" "{" Choices "

我应该为具有以下语法的语言制作一个解析器:

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代码:

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)
expr=try(exprOp)
exprShift
exprOp=buildExpressionParser arithmeticalOps prim“算术表达式”
prim::Parser Expr
prim=new_ident new_integer pE“基元表达式”
哪里
new_ident=do{i>返回重新换档)

我怀疑问题在于前瞻性,但我似乎无法解决。

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


我有一个例子解释了
try
的用法,这可能会对您有所帮助。

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


下面的示例解释了如何使用
try
,这可能会对您有所帮助。

这里有一个消除了左递归(未经测试)的语法。可以使用Parsec的多个1简化STMT和选项。必须扩展其他递归产品:

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 ")"
程序::=Stmts“return”Expr
Stmts::=@many@Stmt
Stmt::=ident“=”Expr“
|{“Stmts”}
|对于“ident”=“Expr”到“Expr Stmt”
|选项“{”选项“}”
选择::=@many1@Choice
选项::=integer:“Stmt”
Expr::=Shift
移位::=术语移位
轮班教师::=
|“整数
术语::=Prod TermRest
TermRest::=
|“+”项
|“-”术语
Prod::=Prim ProdRest
ProdRest::=
|“*”产品
Prim::=ident
|整数
|“(“Expr”)”

编辑-“第二部分”

“empty”(在angles中)是空的产品,您在原始帖子中使用了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
shift::Parser Expr
shift=do
解析表达式
左移t=do
reservedOp“>”
i左移t右移t返回t
--
Expr->Parser Expr
空换档t=返回t

这是一个消除了左递归(未经测试)的语法。可以使用Parsec的many和many1简化STMT和选项。其他递归产品必须扩展:

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 ")"
程序::=Stmts“return”Expr
Stmts::=@many@Stmt
Stmt::=ident“=”Expr“
|{“Stmts”}
|对于“ident”=“Expr”到“Expr Stmt”
|选项“{”选项“}”
选择::=@many1@Choice
选项::=integer:“Stmt”
Expr::=Shift
移位::=术语移位
轮班教师::=
|“整数
术语::=Prod TermRest
TermRest::=
|“+”项
|“-”术语
Prod::=Prim ProdRest
ProdRest::=
|“*”产品
Prim::=ident
|整数
|“(“Expr”)”

编辑-“第二部分”

“empty”(在angles中)是空的产品,您在原始帖子中使用了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
shift::Parser Expr
shift=do
解析表达式
左移t=do
reservedOp“>”
i左移t右移t返回t
--
Expr->Parser Expr
空换档t=返回t

简而言之,您的语法在移位生成中留下了递归。对于LL解析器(Parsec就是其中之一),您确实需要删除左递归。“尝试”提供了前瞻性,但它并不能真正解决左递归问题,理想情况下,您希望重构语法。作为记录,整个语法是LR形式的-直接适用于像YACC或Haskell's Happy这样的LR解析器,但不立即适用于像Parsec这样的LL解析器。简而言之,您的语法将递归留在了移位生产中。Fo在一个LL解析器(Parsec就是其中之一)中,您确实需要删除左递归提供了前瞻性,但它并不能真正解决左递归问题,理想情况下,您需要重构语法。作为记录,整个语法是LR形式的-直接适用于像YACC或Haskell's Happy这样的LR解析器,但不立即适用于像Parsec这样的LL解析器。我尝试了几种通过使用chainl1和expres删除左递归的方法sion解析器,但都不起作用。你对合适的方法有什么建议吗?@andreas,对不起,没有线索。就像我说的,我在parsec还是很在行的。我只是想我应该在黑暗中尝试一下,以防它有用。应该有一些关于使用Haskell+parsec作为解析器/解释器的好建议。还有一些结果可能是我帮不上忙。谢谢你的建议。我错误地回答了你的答案。对不起,我尝试了几种使用chainl1和表达式解析器删除左递归的方法,但都不起作用。你对正确的方法有什么建议吗?@andreas,对不起,没有线索。就像我说的,我在parsec还是很在行。我只是想我应该在黑暗中捅一刀以防万一。应该有一些使用Haskel的好技巧