在你的詞法分析器中,你可能想要維護一些狀態。這可能包括模式設置,符號表和其他細節。例如,假設你想要跟蹤`NUMBER`標記的出現個數。
一種方法是維護一個全局變量:
~~~
num_count = 0
def t_NUMBER(t):
r'\d+'
global num_count
num_count += 1
t.value = int(t.value)
return t
~~~
如果你不喜歡全局變量,另一個記錄信息的地方是lexer對象內部。可以通過當前標記的lexer屬性訪問:
~~~
def t_NUMBER(t):
r'\d+'
t.lexer.num_count += 1 # Note use of lexer attribute
t.value = int(t.value)
return t
lexer = lex.lex()
lexer.num_count = 0 # Set the initial count
~~~
上面這樣做的優點是當同時存在多個lexer實例的情況下,簡單易行。不過這看上去似乎是嚴重違反了面向對象的封裝原則。lexer的內部屬性(除了lineno)都是以lex開頭命名的(lexdata、lexpos)。因此,只要不以lex開頭來命名屬性就很安全的。
如果你不喜歡給lexer對象賦值,你可以自定義你的lexer類型,就像前面看到的那樣:
~~~
class MyLexer:
...
def t_NUMBER(self,t):
r'\d+'
self.num_count += 1
t.value = int(t.value)
return t
def build(self, **kwargs):
self.lexer = lex.lex(object=self,**kwargs)
def __init__(self):
self.num_count = 0
~~~
如果你的應用會創建很多lexer的實例,并且需要維護很多狀態,上面的類可能是最容易管理的。
狀態也可以用閉包來管理,比如,在Python3中:
~~~
def MyLexer():
num_count = 0
...
def t_NUMBER(t):
r'\d+'
nonlocal num_count
num_count += 1
t.value = int(t.value)
return t
...
~~~
- 0 一些翻譯約定
- 1 前言和預備
- 2 介紹
- 3 PLY概要
- 4 Lex
- 4.1 Lex的例子
- 4.2 標記列表
- 4.3 標記的規則
- 4.4 標記的值
- 4.5 丟棄標記
- 4.6 行號和位置信息
- 4.7 忽略字符
- 4.8 字面字符
- 4.9 錯誤處理
- 4.10 構建和使用lexer
- 4.11 @TOKEN裝飾器
- 4.12 優化模式
- 4.13 調試
- 4.14 其他方式定義詞法規則
- 4.15 額外狀態維護
- 4.16 Lexer克隆
- 4.17 Lexer的內部狀態
- 4.18 基于條件的掃描和啟動條件
- 4.19 其他問題
- 5 語法分析基礎
- 6 Yacc
- 6.1 一個例子
- 6.2 將語法規則合并
- 6.3 字面字符
- 6.4 空產生式
- 6.5 改變起始符號
- 6.6 處理二義文法
- 6.7 parser.out調試文件
- 6.8 處理語法錯誤
- 6.9 行號和位置的跟蹤
- 6.10 構造抽象語法樹
- 6.11 嵌入式動作
- 6.12 Yacc的其他
- 7 多個語法和詞法分析器
- 8 使用Python的優化模式
- 9 高級調試
- 9.1 調試lex()和yacc()命令
- 9.2 運行時調試
- 10 如何繼續