在SLY中有一个编写计算器的例子(转载自calc.py
here):
from sly import Lexer
class CalcLexer(Lexer):
tokens = { NAME, NUMBER }
ignore = ' \t'
literals = { '=', '+', '-', '*', '/', '(', ')' }
# Tokens
NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'
@_(r'\d+')
def NUMBER(self, t):
t.value = int(t.value)
return t
@_(r'\n+')
def newline(self, t):
self.lineno += t.value.count('\n')
def error(self, t):
print("Illegal character '%s'" % t.value[0])
self.index += 1
看起来好像被窃听了,因为NAME
and NUMBER
在定义之前就使用它们。但实际上,并没有NameError
,并且这段代码执行得很好。这是如何运作的?什么时候可以在定义名称之前引用它?
Python 知道四种直接名称查找: 内置/程序全局、模块全局、函数/闭包主体和类主体。这NAME
, NUMBER
在类主体中解决,因此受到此类范围的规则的约束。
类体的评估是元类提供的命名空间,它可以实现名称查找的任意语义。具体来说,狡猾的Lexer
is a LexerMeta
类使用a LexerMetaDict作为命名空间;该命名空间为未定义的名称创建新的标记。
class LexerMetaDict(dict):
...
def __getitem__(self, key):
if key not in self and key.split('ignore_')[-1].isupper() and key[:1] != '_':
return TokenStr(key, key, self.remap)
else:
return super().__getitem__(key)
The LexerMeta
还负责添加_函数到命名空间以便无需进口即可使用。
class LexerMeta(type):
'''
Metaclass for collecting lexing rules
'''
@classmethod
def __prepare__(meta, name, bases):
d = LexerMetaDict()
def _(pattern, *extra):
...
d['_'] = _
d['before'] = _Before
return d
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)