为什么以下的Lua代码完全有效?

问题描述 投票:2回答:2

根据我的Lua知识(根据我在Lua手册中读到的内容),我一直认为Lua中的标识符仅限于AZ&az&_&digits(并且不能开始使用数字也不能保留的关键字,即local local = 123)。

现在我遇到了一些(混淆的)Lua程序,该程序使用所有类型的奇怪字符作为标识符:

https://i.imgur.com/HPLKMxp.png

-- Most likely, copy+paste won't work. Download the file from https://tknk.io/7HHZ
print(_VERSION .. " " .. (jit and "JIT" or "non-JIT"))

local T = {}

T.math = T.math or {}
T.math.​â®â€‹âŞâ®â€‹­ď»żâ€Śâ€­âŽ­ = math.sin
T.math.â¬â€‹â­â¬â­â«â®â€­â€¬ = math.cos

for k, v in pairs(T.math) do print(k, v) end

输出:

Lua 5.1 JIT “功能:内置#45 ®®ďďď:::::::::::»功能:内置#44

我不清楚,为什么这组字符允许使用标识符? 换句话说,为什么它是一个完全有效的Lua程序?

lua luajit
2个回答
5
投票

与某些语言不同,Lua并不是真正由正式规范定义的,它涵盖了所有意外情况并完全解释了Lua的所有行为。在Lua的文档中,并没有真正解释像“编码的Lua文件是什么字符集”这样简单的东西。

所有the docs say about identifiers是:

Lua中的名称(也称为标识符)可以是任何字母,数字和下划线字符串,不以数字开头而不是保留字。

但没有人真正说出“信”是什么。 Lua使用的字符集甚至没有定义。因此,它基本上依赖于实现。 “信”是......无论实现是什么样的。

所以,假设您正在编写Lua实现。并且您希望用户能够提供Unicode编码的字符串(即Lua文本中的字符串)。 Lua 5.3需要这个。但是你也不希望他们必须为他们的文件使用UTF-16编码(因为lua_load获取字节序列,而不是短路)。因此,您的Lua实现假设它在lua_load中获得的字节序列以UTF-8编码,因此用户可以编写使用Unicode字符的字符串。

在编写此实现的词法分析器/解析器部分时,您如何处理?处理UTF-8最简单,最简单的方法是......不处理UTF-8。实际上,这就是编码的重点。由于Lua使用特定符号定义的所有内容都以ASCII编码,而ASCII文本也是具有相同含义的UTF-8文本,因此您基本上可以将UTF-8字符串视为ASCII字符串。对于in-Lua字符串,您只需复制字符串的开始和结束字符之间的字节序列。

那么你如何看待lexing标识符呢?好吧,你可以问上面的问题。或者你可以问一个更简单的问题:角色是空格,控制字符,数字还是符号? “信件”仅仅是其中之一。

Lua定义了它认为是“符号”的东西。 ASCII可以告诉你什么是控制字符,空格和数字。在这种实现中,任何值超出ASCII值的UTF-8代码单元都是一个字母。即使从技术上讲,这些代码单元解码成Unicode认为是“符号”的东西,你的词法分析器只会将其作为一个字母进行威胁。

这种简单的UTF-8 lexing形式为您提供了快速的性能和低内存开销。您不必将UTF-8解码为Unicode代码点,并且您不需要巨大的Unicode表来告诉您代码点是“符号”还是“空格”或其他什么。当然,它也是很多基于ASCII的Lua实现的东西。

所以大多数Lua实现都是这样做的,如果只是偶然的话。做更多事情需要刻意努力。

它还允许用户使用Unicode字符序列作为标识符。这意味着有人可以轻松地用他们的母语(在关键字之外)编写代码。

但这也意味着混淆器有很多方法来创建“标识符”,这些标识符只是无意义字节的字符串。实际上,因为Unicode中有多种方法可以“拼写”相同的明显Unicode字符串(除非您直接检查字节),混淆器可以装配在文本编辑器中呈现时出现的标识符都是相同的文本,而实际上是不同的字串。


0
投票

澄清只有一个标识符T

T.mathT["math"]的糖语法,这也延伸到混淆字符串。让key包含任何字符甚至以数字开头都是完全有效的。

现在能够使用.而不是[ ]不能使用不符合标识符限制的字符串。看看Nicol Bolas的答案是为了彻底打破这些限制。

© www.soinside.com 2019 - 2024. All rights reserved.