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的好技巧