复杂秒差距解析器
我不太知道还能怎么问。我想我在这里需要一般指导。我有这样的事情:
expr = buildExpressionParser table term
<?> "expression"
term = choice [
(float >>= return . EDouble)
, try (natural >>= return . EInteger)
, try (stringLiteral >>= return . EString)
, try (reserved "true" >> return (EBool True))
, try (reserved "false" >> return (EBool False))
, try assign
, try ifelse
, try lambda
, try array
, try eseq
, parens expr
]
<?> "simple expression"
但是,当我测试该解析器时,我大多遇到问题...就像当我尝试解析
(a,b) -> "b"
它时,它被 lambda 解析器接受,但是 expr 解析器讨厌它。有时它甚至完全悬置在永恒的规则中。
我已经通读了为自己编写一个Scheme,但它只解析Scheme的同构源。
也许我通常思考的方向是错误的。
编辑:这里是内部解析器:
assign = do
i <- identifier
reservedOp "="
e <- expr
return $ EAssign i e
ifelse = do
reserved "if"
e <- expr
reserved "then"
a <- expr
reserved "else"
b <- expr
return $ EIfElse e a b
lambda = do
ls <- parens $ commaSep identifier
reservedOp "->"
e <- expr
return $ ELambda ls e
array = (squares $ commaSep expr) >>= return . EArray
eseq = do
a <- expr
semi <|> (newline >>= (\x -> return [x]))
b <- expr
return $ ESequence a b
table = [
[binary "*" EMult AssocLeft, binary "/" EDiv AssocLeft, binary "%" EMod AssocLeft ],
[binary "+" EPlus AssocLeft, binary "-" EMinus AssocLeft ],
[binary "~" EConcat AssocLeft],
[prefixF "not" ENot],
[binaryF "and" EAnd AssocLeft, binaryF "or" EAnd AssocLeft]
]
“讨厌它”我的意思是它告诉我它需要一个整数或浮点数。
I don't quite know how else to ask. I think I need general guidance here. I've got something like this:
expr = buildExpressionParser table term
<?> "expression"
term = choice [
(float >>= return . EDouble)
, try (natural >>= return . EInteger)
, try (stringLiteral >>= return . EString)
, try (reserved "true" >> return (EBool True))
, try (reserved "false" >> return (EBool False))
, try assign
, try ifelse
, try lambda
, try array
, try eseq
, parens expr
]
<?> "simple expression"
When I test that parser, though, I mostly get problems... like when I try to parse
(a,b) -> "b"
it is accepted by the lambda
parser, but the expr
parser hates it. And sometimes it even hangs up completely in eternal rules.
I've read through Write Yourself a Scheme, but it only parses the homogeneous source of Scheme.
Maybe I am generally thinking in the wrong direction.
EDIT: Here the internal parsers:
assign = do
i <- identifier
reservedOp "="
e <- expr
return $ EAssign i e
ifelse = do
reserved "if"
e <- expr
reserved "then"
a <- expr
reserved "else"
b <- expr
return $ EIfElse e a b
lambda = do
ls <- parens $ commaSep identifier
reservedOp "->"
e <- expr
return $ ELambda ls e
array = (squares $ commaSep expr) >>= return . EArray
eseq = do
a <- expr
semi <|> (newline >>= (\x -> return [x]))
b <- expr
return $ ESequence a b
table = [
[binary "*" EMult AssocLeft, binary "/" EDiv AssocLeft, binary "%" EMod AssocLeft ],
[binary "+" EPlus AssocLeft, binary "-" EMinus AssocLeft ],
[binary "~" EConcat AssocLeft],
[prefixF "not" ENot],
[binaryF "and" EAnd AssocLeft, binaryF "or" EAnd AssocLeft]
]
And by "hates it" I meant that it tells me it expects an integer or a floating point.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
评论中的爱德华和我都试图做的是在心里运行你的解析器,如果没有更多的解析器继续下去,这有点困难。我将在这里做出一些猜测,也许它们会帮助你完善你的问题。
猜测 1):您已尝试过
GHCI>;解析 expr "(input)" "(a,b) -> \"b\"
并返回Left ...
。了解错误是什么会很有帮助。猜测 2):您还尝试过
GHCI> parse lambda "(input)" "(a,b) -> \"b\"
并且它返回了对…
。基于此爱德华和我都推断出在您的term
解析器或生成的expr
解析器中的某个地方存在冲突,即解析器的某些部分正在成功匹配字符串的开头并返回一个值,但剩下的内容不再有效。如果您尝试GHCI> 将会很有帮助。解析 term "(input)" "(a,b) -> \"b\"
因为这可以让我们知道问题是在term
还是expr< /code>。
猜测 3):字符串
"(a,b)"
本身就是您编写的语法中的有效表达式(尽管可能不是。正如您打算对其进行编程一样;-)。尝试通过 expr 解析器发送它,看看会发生什么猜测 4):您的语法是递归的,这就是原因。 Parsec 是一个 LL(k) 解析器,如果您习惯使用 LR(1) 或 LR(k) 解析器,则递归规则完全相反。不明白最后一句话没关系,但让我们知道
猜测 5):表达式生成器中的代码看起来像是来自函数的文档。我认为您可能已经找到了术语。如果是这样的话,你可以指出它的来源,如果不是,你可以用几句话解释一下你认为
term
应该如何工作。一般建议:大量的
try
语句最终(也就是现在)会给你带来痛苦。它们在某些情况下很有用,但也有点顽皮。如果下一个角色可以决定什么选择应该成功,那么就不需要他们了。如果你只是想让某些东西运行大量的回溯会减少中间形式的数量,但它也会隐藏病态的情况并使错误更加模糊。What Edward in the comments and I are both trying to do is mentally run your parser, and that is a little difficult without more of the parser to go on. I'm going to make some guesses here, and maybe they will help you refine your question.
Guess 1): You have tried
GHCI> parse expr "(input)" "(a,b) -> \"b\"
and it has returnedLeft …
. It would be helpful to know what the error was.Guess 2): You have also tried
GHCI> parse lambda "(input)" "(a,b) -> \"b\"
and it returnedRight …
. based on this Edward an I have both deduced that somewhere in either yourterm
parser or perhaps in the generatedexpr
parser there is a conflict That is some piece of the parser is succeeding in matching the beginning of the string and returning a value, but what remains is no longer valid. It would be helpful if you would tryGHCI> parse term "(input)" "(a,b) -> \"b\"
as this would let us know whether the problem was interm
orexpr
.Guess 3): The string
"(a,b)"
is by itself a valid expression in the grammar as you have programmed it. (Though perhaps not as you intended to program it ;-). Try sending that through the expr parser and see what happens.Guess 4): Your grammar is left recursive. This is what causes it to get stuck and loop forever. Parsec is a LL(k) parser. If you are used to Yacc and family which are LR(1) or LR(k) parsers, the rules for recursion are exactly reversed. If you didn't understand this last sentence thats OK, but let us know.
Guess 5): The code in the expression builder looks like it came from the function's documentation. I think you may have found the
term
expression somewhere as well. If that is the case you you point to where it came from. if not could you explain in a few sentences how you thinkterm
ought to work.General Advice: The large number of
try
statements are eventually (a.k.a. now) going to cause you grief. They are useful in some cases but also a little naughty. If the next character can determine what choice should succeed there is no need for them. If you are just trying to get something running lots of backtracking will reduce the number of intermediate forms, but it also hides pathological cases and makes errors more obscure.似乎存在左递归,如果
term
中的choice
达到eseq
,这将导致解析器挂起:expr< /代码> ->
术语
->eseq
->expr
term
(a,b)
不会解析为lambda
或array< /code>,所以它会陷入
eseq
循环。我不明白为什么
(a,b) -> “b”
不会解析为expr
,因为 term 中的choice
应该命中您所说的lambda
在到达eseq
之前有效。解析错误中报告的位置是什么?There appears to be left recursion, which will cause the parser to hang if the
choice
interm
ever gets toeseq
:expr
->term
->eseq
->expr
The
term
(a,b)
will not parse as alambda
, or anarray
, so it will fall into theeseq
loop.I don't see why
(a,b) -> "b"
doesn't parse as anexpr
, since thechoice
in term should hit upon thelambda
, which you say works, before reaching theeseq
. What is the position reported in the parse error?