lex を試す。Lexer の複製

マニュアルによると、こういうこと?


クラスで定義していないときは、以下のようにやれば良い。
これは、lex() を呼んで再度ルールなどを構築し直すよりも速い。

lexer = lex.lex()
...
newlexer = lexer.clone()


一方、クラス定義した場合は、ちょっと考えどころ。
同じように以下のようにすると、オブジェクト m が同じだから、
インスタンス変数が同じものになりまずい。

m = MyLexer()
a = lex.lex(object=m)      # Create a lexer

b = a.clone()              # Clone the lexer

ということらしいのだが、どんな感じでダメになるのか確認するコードが書けなかった。
そもそも、a や b から m にアクセスする方法が分からなかった。


ちょっと調べたら、lexmodule というのがそれらしい。
でも、Lexer を作っているくせに、lex.lex() に Lexer を渡して良く分からない a とか b とかいうものを作ること自体どうなんだろうか?

#!/usr/bin/env python

import ply.lex as lex

def lex_data(lexer, data):
    lexer.input(data)
    
    while 1:
        tok = lexer.token()
        if not tok: break      # No more input
        print tok

class MyLexer:
    tokens = (
        'A',
        'PLUS',
    )
    
    t_A    = r'a'
    t_PLUS = r'\+'
    
    def t_error(self, t):
        print "Illegal character '%s'" % t.value[0]
        t.lexer.skip(1)
    
    def __init__(self, name):
        self.name = name

m = MyLexer("my lexer")
lexer1 = lex.lex(object=m)
lexer2 = lexer1.clone()

print lexer1.lexmodule.name
print lexer2.lexmodule.name

lex_data(lexer1, "a+a")
print

lex_data(lexer2, "a+a+a")

で、

my lexer
my lexer
LexToken(A,'a',1,0)
LexToken(PLUS,'+',1,1)
LexToken(A,'a',1,2)

LexToken(A,'a',1,0)
LexToken(PLUS,'+',1,1)
LexToken(A,'a',1,2)
LexToken(PLUS,'+',1,3)
LexToken(A,'a',1,4)


別のオブジェクトを使うコード

#!/usr/bin/env python

import ply.lex as lex

class MyLexer:
    tokens = (
        'A',
        'PLUS',
    )
    
    t_A    = r'a'
    t_PLUS = r'\+'
    
    def t_error(self, t):
        print "Illegal character '%s'" % t.value[0]
        t.lexer.skip(1)
    
    def __init__(self, name):
        self.name = name
    
    def lexer(self, lexer):
        self.lexer = lexer
    
    def clone(self, name):
         c = MyLexer(name)        # Create a new instance of myself
         # Copy attributes from self to c as appropriate
         
         # Clone the lexer
         c.lexer = self.lexer.clone(c)
         return c
    
    def lex_data(self, data):
        self.lexer.input(data)
        
        while 1:
            tok = self.lexer.token()
            if not tok: break      # No more input
            print tok

m = MyLexer("my lexer1")
m.lexer(lex.lex(object=m))

lexer1 = m
lexer2 = m.clone("my lexer2")

print lexer1.name
print lexer2.name

lexer1.lex_data("a+a")
print

lexer2.lex_data("a+a+a")

で、

my lexer1
my lexer2
LexToken(A,'a',1,0)
LexToken(PLUS,'+',1,1)
LexToken(A,'a',1,2)

LexToken(A,'a',1,0)
LexToken(PLUS,'+',1,1)
LexToken(A,'a',1,2)
LexToken(PLUS,'+',1,3)
LexToken(A,'a',1,4)
  • そもそも lex() の呼び出しコストなんて気にする必要があるのだろうか?
  • 同じ lex を同時に二つ持つ場面って?