0

Python でのパーサーの実装について説明している記事を読んだところです: http://effbot.org/zone/simple-top-down-parsing.htm

コードの背後にある一般的な考え方は、この論文で説明されています: http://mauke.hopto.org/stuff/papers/p41-pratt.pdf

Pythonでパーサーを書くのはかなり新しいので、学習演習として似たようなものを書こうとしています。しかし、記事で見つかったものと同様のコードを作成しようとすると、TypeError: unbound method TypeError. このようなエラーに遭遇したのはこれが初めてで、これを理解しようと一日中費やしましたが、問題は解決していません。この問題がある最小限のコード例 (全体) を次に示します。

import re

class Symbol_base(object):
    """ A base class for all symbols"""
    id = None # node/token type name
    value = None #used by literals
    first = second = third = None #used by tree nodes

    def nud(self):
        """ A default implementation for nud """
        raise SyntaxError("Syntax error (%r)." % self.id)

    def led(self,left):
        """ A default implementation for led """
        raise SyntaxError("Unknown operator (%r)." % self.id)

    def __repr__(self):
        if self.id == "(name)" or self.id == "(literal)":
            return "(%s %s)" % (self.id[1:-1], self.value)
        out = [self.id, self.first, self.second, self.third]
        out = map(str, filter(None,out))
        return "(" + " ".join(out) + ")"


symbol_table = {}
def symbol(id, bindingpower=0):
    """ If a given symbol is found in the symbol_table return it.
        If the symblo cannot be found theni create the appropriate class
        and add that to the symbol_table."""
    try:
        s = symbol_table[id]
    except KeyError:
        class s(Symbol_base):
            pass
        s.__name__ = "symbol:" + id #for debugging purposes
        s.id = id
        s.lbp = bindingpower
        symbol_table[id] = s
    else:
        s.lbp = max(bindingpower,s.lbp)
    return s

def infix(id, bp):
    """ Helper function for defining the symbols for infix operations """
    def infix_led(self, left):
        self.first = left
        self.second = expression(bp)
        return self
    symbol(id, bp).led = infix_led

#define all the symbols
infix("+", 10)
symbol("(literal)").nud = lambda self: self #literal values must return the symbol itself
symbol("(end)")

token_pat = re.compile("\s*(?:(\d+)|(.))")

def tokenize(program):
    for number, operator in token_pat.findall(program):
        if number:
            symbol = symbol_table["(literal)"]
            s = symbol()
            s.value = number
            yield s
        else:
            symbol = symbol_table.get(operator)
            if not symbol:
                raise SyntaxError("Unknown operator")
            yield symbol
    symbol = symbol_table["(end)"]
    yield symbol()

def expression(rbp = 0):
    global token
    t = token
    token = next()
    left = t.nud()
    while rbp < token.lbp:
        t = token
        token = next()
        left = t.led(left)
    return left

def parse(program):
    global token, next
    next = tokenize(program).next
    token = next()
    return expression()

def __main__():
    print parse("1 + 2")

if __name__ == "__main__":
    __main__()

これをpypyで実行しようとすると:

Traceback (most recent call last):
  File "app_main.py", line 72, in run_toplevel
  File "parser_code_issue.py", line 93, in <module>
    __main__()
  File "parser_code_issue.py", line 90, in __main__
    print parse("1 + 2")
  File "parser_code_issue.py", line 87, in parse
    return expression()
  File "parser_code_issue.py", line 81, in expression
    left = t.led(left)
TypeError: unbound method infix_led() must be called with symbol:+ instance as first argument (got symbol:(literal) instance instead)

操作用のインスタンスを作成していないため、これが発生すると推測していinfixますが、その時点でインスタンスを作成したくありません。インスタンスを作成せずにこれらのメソッドを変更する方法はありますか?

なぜこれが起こっているのか、コードを修正するために何ができるのかを説明する助けがあれば大歓迎です!

また、この動作は python 3 で変更されますか?

4

2 に答える 2

3

tokenize()関数でシンボルのインスタンスを作成するのを忘れました。数値でない場合、 yield symbol()、 not symbol:

else:
    symbol = symbol_table.get(operator)
    if not symbol:
        raise SyntaxError("Unknown operator")
    yield symbol()

その 1 つの変更により、コードは次のように出力されます。

(+ (literal 1) (literal 2))
于 2013-09-20T08:02:12.647 に答える
1

新しい関数をオブジェクトのインスタンスにバインドしていません。

import types

obj = symbol(id, bp)
obj.led = types.MethodType(infix_led, obj)

別のSOの質問に対する受け入れられた回答を参照してください

于 2013-09-20T08:08:23.157 に答える