Parsing 解析可选递归解析器在无限递归中运行
我目前正在为ECMAScript 5编写一个解析器(作为玩具)。该标准规定了应如何解析逻辑或表达式:Parsing 解析可选递归解析器在无限递归中运行,parsing,haskell,megaparsec,Parsing,Haskell,Megaparsec,我目前正在为ECMAScript 5编写一个解析器(作为玩具)。该标准规定了应如何解析逻辑或表达式: <LogicalORExpression> : <LogicalANDExpression> <LogicalORExpression> || <LogicalANDExpression> : || 基本上这相当于 =[||] 但是我应该如何解析它而不陷入一个infite循环呢?我当前的解析器显然做到了: logicalOrE
<LogicalORExpression> :
<LogicalANDExpression>
<LogicalORExpression> || <LogicalANDExpression>
:
||
基本上这相当于
=[||]
但是我应该如何解析它而不陷入一个infite循环呢?我当前的解析器显然做到了:
logicalOrExpression :: Parser LogicalOrExpression
logicalOrExpression = do
orExpr <- optional $ do
e <- logicalOrExpression
_ <- symbol "||"
return e
andExpr <- logicalAndExpression
case orExpr of
Just e -> return $ LogicalOrExpression (e, andExpr)
Nothing -> return $ AndExpression andExpr
logicalOrExpression::解析器logicalOrExpression
logicalOrExpression=do
orExpr空字符串与这个解析器匹配,我相信它会导致Magaparsec中的无限递归。我认为你的函数中缺少了一个“术语”或“布尔值”。如果我写True | | False
什么会捕获第一个“True”空字符串与这个解析器匹配,我相信它会导致Magaparsec中的无限递归。我认为你的函数中缺少了一个“术语”或“布尔值”。如果我写的是True | | False
语法中第一个与之等价的“True”
<LogicalORExpression> :
<LogicalANDExpression>
<LogicalANDExpression> || <LogicalORExpression>
:
||
变成
<LogicalORExpression> :
<LogicalANDExpression> [|| <LogicalORExpression>]
:
[|| ]
一般来说,如果可能的话,你需要以LL(1)的形式重写语法 那个语法看起来相当于
<LogicalORExpression> :
<LogicalANDExpression>
<LogicalANDExpression> || <LogicalORExpression>
:
||
变成
<LogicalORExpression> :
<LogicalANDExpression> [|| <LogicalORExpression>]
:
[|| ]
一般来说,如果可能的话,你需要以LL(1)的形式重写语法 如果需要解析具有优先级和关联性的运算符语法,那么它最容易使用
expr = makeExprParser term table
where
term = literal <|> parenthesised expr
table = [[InfixL (string "&&" $> And)], [InfixL (string "||" $> Or)]]
expr=makeExprParser术语表
哪里
术语=带括号的文字表达式
表=[[InfixL(字符串“&&“$>和)],[InfixL(字符串“| |“$>或)]]
对于literal
和带括号的的合适定义,这将解析由左关联中缀&
和|
运算符组成的literal表达式语法,其中&
具有比|
更高的优先级。Megaparsec负责生成LL(k)解析器的繁琐工作,并生成正确(本例中为左关联)的解析树
当然,JavaScript的表达式语法要比两个运算符大得多。这个例子可以直接扩展到包含(例如)一元前缀操作符,比如代码>、后缀函数调用等。请参阅。如果需要解析具有优先级和关联性的运算符语法,则最容易使用
expr = makeExprParser term table
where
term = literal <|> parenthesised expr
table = [[InfixL (string "&&" $> And)], [InfixL (string "||" $> Or)]]
expr=makeExprParser术语表
哪里
术语=带括号的文字表达式
表=[[InfixL(字符串“&&“$>和)],[InfixL(字符串“| |“$>或)]]
对于literal
和带括号的的合适定义,这将解析由左关联中缀&
和|
运算符组成的literal表达式语法,其中&
具有比|
更高的优先级。Megaparsec负责生成LL(k)解析器的繁琐工作,并生成正确(本例中为左关联)的解析树
当然,JavaScript的表达式语法要比两个运算符大得多。这个例子可以直接扩展到包含(例如)一元前缀操作符,比如代码>、后缀函数调用等。请参阅。由于我希望在生成的AST方面遵守规范,我决定切换到基于Earley的解析器,而不是解析器组合器,因为Earley的算法可以处理左递归
如果我可以将语法扁平化,我会使用Benjamin Hodgson的答案,因为我想在生成的AST方面忠实于规范,所以我决定切换到基于Earley的解析器,而不是解析器组合器,因为Earley的算法可以处理左递归
如果我可以将语法展平,我会使用Benjamin Hodgson的答案No这两个词是不等价的,因为这会改变操作符的关联性AFAICT@SuperManitu没错。如果您需要原始的,我想您必须对AST进行后处理。左递归在LL(1)解析器中不可行。您也可以尝试sepBy1
,它会给您一个列表,然后您可以在生成AST之前根据自己的意愿进行关联。是的,我认为您是对的,将语法转换为正确的递归语法,然后调整AST。不,这两者是不等价的,因为这会改变操作符的关联性AFAICT@SuperManitu没错。如果您需要原始的,我想您必须对AST进行后处理。左递归在LL(1)解析器中不可行。您也可以尝试sepBy1
,它会给您一个列表,然后您可以在生成AST之前根据自己的意愿进行关联。是的,我认为您是对的,将语法转换为正确的递归语法,然后调整AST。这个可选部分的全部要点是最终不解析任何东西。如果我在修复递归的同时添加任何消耗字符,它也不会再接受所有有效字符串,但必须先获取一些内容,否则将永远成功,而不会取得进展。你所拥有的是,“一个logicalOrExpression是一个logicalOrExpression,它是一个logicalOrExpression,它是一个logicalOrExpression,它是一个logicalOrExpression…”可选部分的全部要点是最终不解析任何东西。如果我在修复递归的同时添加任何消耗字符,它也不会再接受所有有效字符串,但必须先获取一些内容,否则将永远成功,而不会取得进展。你有的是,“一个logicalOrExpression是一个logicalOrExpression,它是一个logicalOrExpression,它是一个logicalOrExpression,它是一个logicalOrExpression…”logicalOrExpression=sepBy1(symbol“| |”)logicalOrExpression
?logicalOrExpression=sepBy1(symbol“| | |”)logicalOrExpression
,但问题是,这将把语法简化为一个单一的语法