这可能是所使用的解析算法的结果。一个简单的心理模型是令牌生成器尝试匹配 所有 令牌模式,并识别找到的 最长
匹配。在较低的级别上,令牌生成器逐个字符地工作,并且仅基于当前状态和输入字符做出决定-不应回溯或重新读取输入。
将具有公共前缀的模式(在本例中为
int文字模式和文字模式的组成部分)连接起来之后,
float在分词器中发生的事情是:
- 读取
1
,并进入指示 “正在读取afloat
或int
文字”的状态 - 读取
.
,并进入 “读取float
文字”状态 - 读取
_
,不能是float
文字的一部分。解析器发出1.
作为float
文字令牌。 - 从开始进行解析
_
,并最终__class__
作为标识符令牌发出。
另外:
这种标记化方法也是通用语言受到语法限制的原因。例如,标识符包含字母,数字和下划线,但不能以数字开头。如果允许,则123abc可以用作标识符,也可以用作整数,123后跟标识符abc。类似于lex的令牌生成器会将其识别为前者,因为它导致最长的单个令牌,但是没有人喜欢在尝试读取代码时将这样的细节保留在他们的脑海中。或尝试为此编写和调试令牌生成器时。
然后,解析器尝试处理令牌流:
<FloatLiteral: '1.'> <Identifier: '__class__'>
在Python中,直接跟有 标识符 的 文字( 在标记之间没有 运算符)
没有意义,因此解析器无法正常运行。这也意味着Python会抱怨语法无效的原因不是令牌生成器错误“该字符在整数文字中无效”,而是解析器错误“标识符不能直接跟随整数文字”
123abc``a``abc``123
为什么标记生成器无法识别的原因
1作为一个
int字面的是,这使得它的角色 离开 了 _
float
-或者
int_状态决定了它只是阅读。如果是
.,那是
float文字的开始,此后可能会继续。如果还有其他的话,那是一个完整的
int文字令牌。
令牌生成器不可能“返回”并将其他内容重新读取为先前的输入。实际上,令牌生成器的级别太低,不足以关心“属性访问”是什么并且无法处理此类歧义。
现在,您的第二个示例是有效的,因为令牌生成器知道一个
float文字只能包含一个文字
.。更准确地说:第一个
.使它从
float
-或-
int_状态过渡到
float_ 状态。在这种状态下,它只希望数字(或
E科学/工程符号的a
j,复数的a
…)继续原
float义。不是数字等的第一个字符(即
.)绝对不再是
float文字的一部分,并且令牌生成器可以发出完成的令牌。因此,第二个示例的令牌流将是:
<FloatLiteral: '1.'> <Operator: '.'> <Identifier: '__class__'>
当然,解析器随后会将其识别为有效的Python。现在我们也知道为什么建议的解决方法会有所帮助。在Python中,用空格分隔标记是 可选的
–与Lisp不同。相反,空格 会 分隔令牌。(也就是说,除了
string文字外,没有其他标记可以包含空格,只是在标记之间跳过。)因此,代码如下:
1 .__class__
始终标记为
<IntLiteral: '1'> <Operator: '.'> <Identifier: '__class__'>
由于右括号不能出现在
int文字中,因此:
(1).__class__
被读取为:
<Operator: '('> <IntLiteral: '1'> <Operator: ')'> <Operator: '.'> <Identifier: '__class__'>
有趣的是,上述内容暗示以下内容也有效:
1..__class__ # => <type 'float'>
float文字的小数部分是可选的,第二次
.读取将使前面的输入被识别为一个。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)