2016-11-28 9 views
3

連鎖比較の構文パーズツリーの外観を教えてください。どのように3つのオペランドの比較は、フードの中でPythonで動作しますか?

ほとんどの言語で理解できる限り、演算子の結合性に基づいてノードを構成します。したがって、a < b < cでは、左または右のオペランドのいずれかとしてブール値があります。

しかし、このような表現はa < b and b < cとほぼ同等です(bは1回のみ評価されます)。

このような変換の生成文法ルールとは何ですか?基本的に、Pythonインタプリタはこのような場合に構文解析ツリーを構築するために何をしますか?

+0

文法規則は'比較簡単です。 –

+0

"のような表現は' a

+0

@ PM2Ringはい、そういうわけで、コンピューティングに副作用がなければ、私は「ほとんど」と同等です。 –

答えて

6

comparison grammarが、それは単にあなたがオペレータに複数の比較器を追加することができます、ここでその興味深いものではありません。

comparison ::= or_expr (comp_operator or_expr)* 
comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!=" 
        | "is" ["not"] | ["not"] "in" 

だから、単にPythonのコンパイラ自体を尋ねた(ast moduleを使用することにより、直接Pythonのパーサを頼むことができますのみ)抽象構文木を返す:

>>> import ast 
>>> ast.dump(ast.parse('a > b > c', mode='eval')) 
"Expression(body=Compare(left=Name(id='a', ctx=Load()), ops=[Gt(), Gt()], comparators=[Name(id='b', ctx=Load()), Name(id='c', ctx=Load())]))" 

をだから単一Compareのノードが存在し、複数の事業者やコンパレータでS:

Compare(
    left=Name(id='a'), 
    ops=[Gt(), Gt()], 
    comparators=[Name(id='b'), Name(id='c')]) 

(私はExpressionctx部品を省略しました)。

これにより、インタプリタは必要に応じてコンパレータを評価できます(たとえば、a < bがfalseの場合、残りのコンパレータは考慮する必要はありません)。

得られたバイトコードは、残りの比較をスキップする条件ジャンプを使用:式expr(comp_opのexpr)は* `:

>>> import dis 
>>> dis.dis(compile('a > b > c', '', 'eval')) 
    1   0 LOAD_NAME    0 (a) 
       2 LOAD_NAME    1 (b) 
       4 DUP_TOP 
       6 ROT_THREE 
       8 COMPARE_OP    4 (>) 
      10 JUMP_IF_FALSE_OR_POP 18 
      12 LOAD_NAME    2 (c) 
      14 COMPARE_OP    4 (>) 
      16 RETURN_VALUE 
     >> 18 ROT_TWO 
      20 POP_TOP 
      22 RETURN_VALUE 
関連する問題