解析可选的递归解析器以无限递归方式运行

时间:2017-11-16 20:49:46

标签: parsing haskell megaparsec

我正在为ECMAScript 5(作为玩具)编写解析器。标准规定了如何解析逻辑或表达式:

<LogicalORExpression> :
    <LogicalANDExpression>
    <LogicalORExpression> || <LogicalANDExpression>

基本上这相当于

<logicalOrExpression> = [<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

由于

4 个答案:

答案 0 :(得分:2)

如果需要解析具有优先级和关联性的运算符语法,则应该使用megaparsec's built-in tools

expr = makeExprParser term table
    where
        term = literal <|> parenthesised expr
        table = [[InfixL (string "&&" $> And)], [InfixL (string "||" $> Or)]]

对于literalparenthesised的合适定义,这将解析由左关联中缀&&||运算符组成的文字表达式的语法, &&的优先级高于||。 Megaparsec负责生成LL(k)解析器的繁琐工作,并生成正确的(在这种情况下为左关联)解析树。

当然,JavaScript的表达式语法比两个运算符大得多。此示例可以直接扩展为包括(例如)一元前缀运算符,如!,后缀函数调用等。请参阅the module's documentation

答案 1 :(得分:1)

该语法看起来相当于

<LogicalORExpression> :
    <LogicalANDExpression>
    <LogicalANDExpression> || <LogicalORExpression>

成为

<LogicalORExpression> :
    <LogicalANDExpression> [|| <LogicalORExpression>]

通常,如果可能,您需要以(大致)LL(1)形式重写语法。

答案 2 :(得分:0)

空字符串匹配此解析器,我相信它会在Magaparsec中导致无限递归。我想你错过了一个&#34;术语&#34;或&#34;布尔&#34;在你的功能的某个地方。如果我写了True || False什么会捕获第一个&#34; True&#34;

答案 3 :(得分:-1)

由于我希望在生成的AST方面保持真实,我决定切换到基于Earley的解析器而不是解析器组合器,因为Earley的算法可以处理左递归。

如果我可以将语法弄平,我会用Benjamin Hodgson的答案