2

いくつかのコードを解析するものを書こうとしています。foo(spam)andを正常に解析できますspam+eggsが、foo(spam+eggs)(再帰降下? コンパイラーからの私の用語は少し錆びています) 失敗します。

次のコードがあります。

from pyparsing_py3 import *

myVal = Word(alphas+nums+'_')    
myFunction = myVal + '(' + delimitedList( myVal ) + ')'

myExpr = Forward()
mySubExpr = ( \
    myVal \
    | (Suppress('(') + Group(myExpr) + Suppress(')')) \
    | myFunction \
    )
myExpr << Group( mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr ) )


# SHOULD return: [blah, [foo, +, bar]]
# but actually returns: [blah]
print(myExpr.parseString('blah(foo+bar)'))
4

2 に答える 2

4

Forwards で '<<' 演算子を使用するときの良い習慣は、常に RHS を括弧で囲むことです。あれは:

myExpr << mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr )

次のように優れています。

myExpr << ( mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr ) )

これは、Forward に式を挿入するための「挿入」演算子として「<<」を残念ながら選択した結果です。この特定のケースでは括弧は不要ですが、次の場合:

integer = Word(nums)
myExpr << mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr ) | integer

私が「不幸」と言う理由がわかります。これを「A << B | C」と単純化すると、「<<」は「| |」よりも優先順位が高いため、操作の優先順位によって「(A << B) | C」として評価が実行されることが簡単にわかります。 '。その結果、Forward A には式 B のみが挿入されます。"| C" の部分は実行されますが、MatchFirst オブジェクトを作成する "A | C" が取得され、変数名に割り当てられていないため、すぐに破棄されます。解決策は、括弧内のステートメントを「A << (B | C)」としてグループ化することです。「+」操作のみを使用して構成された式では、「+」は「<<」よりも優先順位が高いため、括弧は実際には必要ありません。しかし、これは単なる幸運なコーディングであり、後で誰かが '|' を使用して別の表現を追加すると問題が発生します。優先順位の意味を理解していません。したがって、この混乱を避けるために、「A << (式)」というスタイルを採用することをお勧めします。

(いつの日か、既存のコードとの互換性を破ることができる pyparsing 2.0 を書き、これを '<<=' 演算子を使用するように変更します。これにより、これらの優先順位の問題がすべて修正されます。 pyparsing で使用される他の演算子のいずれか。)

于 2009-09-04T07:29:36.617 に答える
4

いくつかの問題: delimitedList は myVal のカンマ区切りのリスト、つまり識別子を引数リストの唯一の受け入れ可能な形式として探しているため、もちろん 'foo+bar' には一致しません (myVal のカンマ区切りのリストではありません! ); myVal と myFunction は同じように開始されるため、mySubExpr での順序が重要になります。それを修正すると、さらに別のことが明らかになります-1つではなく2つのレベルのネスト。このバージョンは問題ないようです...:

myVal = Word(alphas+nums+'_')    

myExpr = Forward()
mySubExpr = (
    (Suppress('(') + Group(myExpr) + Suppress(')'))
    | myVal + Suppress('(') + Group(delimitedList(myExpr)) + Suppress(')')
    | myVal
    )
myExpr << mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr ) 

print(myExpr.parseString('blah(foo+bar)'))

希望通りに放出['blah', ['foo', '+', 'bar']]します。冗長なバックスラッシュも削除しました。これは、論理行の継続が括弧内で発生するためです。それらは無害でしたが、可読性を妨げました。

于 2009-09-04T01:47:33.427 に答える