是Python的语法LL(1)吗?

时间:2018-12-03 15:14:55

标签: python parsing compiler-construction grammar

this question的可能重复项,但是对我来说不够具体。

python语法为claimed to be LL(1),但是我注意到Python grammar中的某些表达式确实使我感到困惑,例如,以下函数调用中的参数:

foo(a)
foo(a=a)

对应于以下语法:

argument: ( test [comp_for] |
            test '=' test |
            '**' test |
            '*' test )

test在语法的第一位置出现两次。这意味着仅查看test的Python就无法确定它是test [comp_for]还是test '=' test

更多示例:

comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'

请注意'is''is' 'not'

subscript: test | [test] ':' [test] [sliceop]

test也出现两次。

我对LL(1)的理解是否错误? Python在词法分析或语法分析期间是否对语法做一些变通办法,以使其LL(1)可处理?谢谢大家。

2 个答案:

答案 0 :(得分:2)

您是正确的,像'is' | 'is' 'not'这样的结构不是LL(1)。通过将其更改为'is' notOpt,其中notOpt: 'not' | ϵ,或者如果您允许EBNF语法,只需将'is' 'not'?(或'is' ['not'] EBNF的味道。

因此,语言为LL(1),但语法在技术上并非如此。我认为Python设计人员认为这是可以的,因为在没有太多好处的情况下,左侧分解版本将更难以阅读,并且当前版本仍然可以毫无困难地用作LL(1)解析器的基础。

答案 1 :(得分:2)

grammar presented in the Python documentation(用于生成Python解析器)以扩展BNF的形式编写,其中包括“操作符”,例如可选性([a])和Kleene闭包((a b c)* )。但是,LL(1)是仅适用于不具有此类运算符的简单无上下文语法的类别。因此,询问该特定语法是否为LL(1)是一个类别错误。

为了使问题有意义,必须将语法转换为简单的无上下文语法。当然,这是可能的,但是没有规范的转换,Python文档也没有解释所使用的精确转换。某些转换可能会产生LL(1)语法,而其他转换可能不会。 (实际上,对Kleene星的幼稚翻译很容易导致模棱两可,根据定义,这对任何k都不是LL(k)。)

在实践中,Python解析设备将语法转换为可执行的解析器,而不是上下文无关的语法。出于Python的务实目的,仅需提前一个令牌即可构建预测分析器就足够了。由于预测解析器可以使用条件语句和循环之类的控制结构,因此无需完全转换为无上下文语法。因此,可以使用未完全左分解的EBNF生成物(如已记录的语法),甚至可以使用向LL(1)转换不平凡的EBNF生成物:

simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE

在上面的生产中,(';' small_stmt)*的重复后面可能是';',这意味着简单的while循环将无法正确表示生产。我不知道Python解析器生成器如何处理此生成,但是可以在扩展重复之后通过左分解将其转换为CFG:

simple_stmt: small_stmt rest_A
rest_A     : ';' ret_B
           | NEWLINE
rest_B     : small_stmt rest_A
           | NEWLINE

类似地,可以将整个EBNF转换为LL(1)语法。之所以没有这样做,是因为该练习对于解析或解释语法都没有用。它将很难阅读,并且EBNF可以直接转换为解析器。

这一点与Python是否为LL(1)的问题无关,因为如果该语言存在LL(1)语法,则该语言就是LL(1)。语言的语法永远都是无限的,包括对于任何k都不是LL(k)的语法,甚至不是上下文无关的语法,但这与 language < / em>为LL(1):即使存在一个LL(1)语法,语言也为LL(1)。 (我知道这不是最初的问题,因此我将不再进一步探讨这个问题。)