多行PLY解析器

时间:2015-11-29 05:16:44

标签: python parsing ply

我使用PLY来解析跨越多行的算术表达式(或通过&#34 ;;"分开)。我不确定是否要忽略换行令牌,因为我并不真正需要它们。如果忽略它们(在t_NEWLINE中返回无),是否有必要在作品中对它们进行说明?

def t_NEWLINE(self, t):
    r"""\n+|;+"""
    t.lexer.lineno += t.value.count("\n") + t.value.count(";")
    return t # or not

def p_expression(self, t):
    """ expression : ..."""

def p_expressions(self, t):
    """ expressions : expression
                    | expressions NEWLINE expression
    """
    # Do I need NEWLINE at all? How does the production figure out where expression ends without NEWLINE?

1 个答案:

答案 0 :(得分:1)

这似乎更像是语言设计而不是实现的问题,尽管当然,即使完全指定了设计,实现也可能并不明显。

有几种可能的语言方法允许多个多行表达式,我对你有兴趣实现哪一个并不清楚:

  1. Python风格。表达式由;或换行符终止,但在括号表达式((...)[...]{...})内忽略换行符。

  2. ECMAscript风格。表达式必须由;终止,但如果下一个标记无法扩展表达式,则会在行尾自动插入;

  3. 最大-蒙克。表达式是可以解析为表达式的最长的令牌流,但如果需要,;可用于分隔表达式。

    我实际上并不知道实现此选项的通用语言。但它(或某些变体)可以编写,例如,

    a = 3    b = 7    c = a + b
    

    这似乎应该是明确的。

  4. 实施策略。

    1。括号隐藏换行符。

    在语言变得复杂之前,这是非常简单的实现。对于简单表达式,您只需要保留一个全局括号深度计数,该计数通过(任何类型的)左括号递增并随关闭递减;如果括号深度为0,则\n规则返回;,否则吞下换行符。

    我个人觉得这种线条延续的风格令人恼火,虽然我每次回到Python编程时都会很快习惯它。尽管如此,它仍然有点让你无法写出来:

    x = some * long * sub-expression       +
        another * long * sub-expression    +
        magical-constant
    

    在ECMAscript中可以正常工作。

    2。自动分号

    事实证明,你可以在词法分析器的ECMAscript中处理这个问题,方法是在一行上查找第一个标记,在合法标记对的字典中查找前一个标记。如果令牌对不在字典中,则返回分号标记而不是行上的第一个标记;记住该令牌,以便下一次对词法分析器的调用将返回它。构建合法令牌对的字典是非常重要的,并且验证它是正确的甚至更难,但只需要在每次更改语法时完成:)

    ECMAscript实际上对规则有一些例外,因此在换行符分隔时,某些本来合法的表达式会被视为非法。通过从法律对的字典中删除一些令牌对,可以实现这些异常(当它发生时)。例如,++后增量运算符不能通过换行符与其操作数分隔,因此在下面插入一个分号:

    a
    ++b
    

    否则会出现语法错误。 (前两个令牌将被解析为a++,然后无法解析b。)

    另一个有趣的案例是:

    a + b
    (c + d).format("x")
    

    这可以解析为函数调用:

    a + b(c + d).format("x")
    

    所以最好在b(之间进行自动分号插入。

    3。最大咀嚼

    这实际上只是自动分号插入的变体,即使两个令牌之间没有换行符,也可以插入分号。由于上面提到的例外情况,您可能希望拥有两组不同的合法令牌对,或者将某些令牌对标记为仅在未换行时才有效。