为什么这段代码在粘贴时可以编译,否则会失败?
Why does this code compile when pasted in but fail otherwise?
一位朋友让我看 this page,并注意到其中一位论坛用户的签名中有一段奇怪的代码。
代码是一行代码,如下所示:
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
滚动删除:
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
令人惊叹的是,如果您按原样粘贴代码(然后不要再碰它!)进入有效的过程级范围。
一些观察:
- 如果指令分隔符/冒号被换行,它不再编译
On Local Error
可以简化为On Error
- 乍一看,嵌套转换并没有什么特别的意义,但事实证明,用简单的
Debug.Assert True
替换那一系列转换和比较可以使代码始终如一地编译,因此 里面的东西 弄乱了编译器。
- 如果粘贴代码,则编译;如果在 VBE 验证该行后以任何方式修改它(甚至只是删除
Local
),它将停止编译,并且似乎没有任何东西可以使 VBA 理解它,除非行被删除并重新粘贴。
- 最新的rubberduck grammar/parser being closely modeled on the actual VBA specs, it parses and resolves just fine(老实说让我大吃一惊)
- 如果已知该行无法编译,然后 cut/re-pasted,它不会编译...但是从 VBE 外部再次重新粘贴,它突然编译。
问题是,此代码如何针对VB 语言规范进行编译?它是 VB[6|A|E] 实现中的错误吗?也就是说,why/how行得通吗?
我 认为 它与指令分隔符 (:
) 和 inline-if 语法有关 - 假设没有 End If
语句, 是单行而不是块。
但是,是什么让 那个特定代码 成为薛定谔的代码?是什么让它既合法又非法?
如果代码被使用形式语法定义 (ANTLR) 生成的解析器正确解析,那么它一定是一个合法的构造?那为什么当你回到那一行并按 ENTER 时它就不再合法了?
我敢冒昧地回答 Resume Next
是这里的关键指令,因为任何其他无效指令都会跳到下一条指令。
冒号分隔命令,就好像它们是新行一样。
否则确实很有趣。
对于这么长的代码行,很难发现编译错误出现的位置,但有一个细微的差别,似乎是 VBE 对该行应用了自动更正,或者更可能是在它之后已解析。
这是原始行 - 从剪贴板粘贴
该行显示为这样直到您将光标移动到另一行。
注意 Loop
和 Else
关键字之间的粗体冒号 语句:
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else
Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
这是您将光标移动到另一行后的行:
注意冒号已被 VBE 自动删除。看起来 VBE 解析器识别了语句,然后 "optimizes" "redundant" 冒号消失了。
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop Else
Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
如果您 将冒号添加回 到处于无效语法状态的行,则自动更正将再次启动,但您的行 returns 变为有效, 但 脆弱 代码。
因此,VBE 似乎解析了该行,确定了优化(冗余冒号),然后应用了修复,但 VBE 没有意识到优化后的行存在语法问题。
但为什么线最终变得脆弱?该行中有很多分散注意力和不相关的关键字,所以让我们大幅减少它:
执行 While..Loop
If we minimize the complexity of the line, to isolate the problem, we can simplify the line to:
If True Then Do While True: Beep: Loop: Else
Which, again, VBE autocorrects to a fragile line:
If True Then Do While True: Beep: Loop Else
But we can go even further and reduce the line to an illogically short line:
If True Then Do: Loop: Else
And VBE, once again, dutifully removes the colon to produce this line: (DO NOT EXECUTE THIS LINE OR YOU WILL HANG EXCEL)
If True Then Do: Loop Else
同时..Wend
Repeating the line, but swapping out the Do While Loop
, for the older While Wend
syntax:
If True Then While True: Beep: Wend: Else
Again, VBE optimizes away the colon, to give:
If True Then While True: Beep: Wend Else
But now the line is not fragile anymore!
因此,While..Wend 是较旧的构造,而 Do..Loop 构造较新(并且更灵活),但 VBE 解析器(和语法优化器)似乎与 Do..Loop 斗争构建。
要点:不要在包含 Else
语句的单行 If
语句中使用 Do..Loop
。
一位朋友让我看 this page,并注意到其中一位论坛用户的签名中有一段奇怪的代码。
代码是一行代码,如下所示:
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
滚动删除:
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
令人惊叹的是,如果您按原样粘贴代码(然后不要再碰它!)进入有效的过程级范围。
一些观察:
- 如果指令分隔符/冒号被换行,它不再编译
On Local Error
可以简化为On Error
- 乍一看,嵌套转换并没有什么特别的意义,但事实证明,用简单的
Debug.Assert True
替换那一系列转换和比较可以使代码始终如一地编译,因此 里面的东西 弄乱了编译器。 - 如果粘贴代码,则编译;如果在 VBE 验证该行后以任何方式修改它(甚至只是删除
Local
),它将停止编译,并且似乎没有任何东西可以使 VBA 理解它,除非行被删除并重新粘贴。 - 最新的rubberduck grammar/parser being closely modeled on the actual VBA specs, it parses and resolves just fine(老实说让我大吃一惊)
- 如果已知该行无法编译,然后 cut/re-pasted,它不会编译...但是从 VBE 外部再次重新粘贴,它突然编译。
问题是,此代码如何针对VB 语言规范进行编译?它是 VB[6|A|E] 实现中的错误吗?也就是说,why/how行得通吗?
我 认为 它与指令分隔符 (:
) 和 inline-if 语法有关 - 假设没有 End If
语句, 是单行而不是块。
但是,是什么让 那个特定代码 成为薛定谔的代码?是什么让它既合法又非法?
如果代码被使用形式语法定义 (ANTLR) 生成的解析器正确解析,那么它一定是一个合法的构造?那为什么当你回到那一行并按 ENTER 时它就不再合法了?
我敢冒昧地回答 Resume Next
是这里的关键指令,因为任何其他无效指令都会跳到下一条指令。
冒号分隔命令,就好像它们是新行一样。
否则确实很有趣。
对于这么长的代码行,很难发现编译错误出现的位置,但有一个细微的差别,似乎是 VBE 对该行应用了自动更正,或者更可能是在它之后已解析。
这是原始行 - 从剪贴板粘贴
该行显示为这样直到您将光标移动到另一行。
注意 Loop
和 Else
关键字之间的粗体冒号 语句:
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency:
Loop: Else
Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
这是您将光标移动到另一行后的行:
注意冒号已被 VBE 自动删除。看起来 VBE 解析器识别了语句,然后 "optimizes" "redundant" 冒号消失了。
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency:
Loop Else
Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
如果您 将冒号添加回 到处于无效语法状态的行,则自动更正将再次启动,但您的行 returns 变为有效, 但 脆弱 代码。
因此,VBE 似乎解析了该行,确定了优化(冗余冒号),然后应用了修复,但 VBE 没有意识到优化后的行存在语法问题。
但为什么线最终变得脆弱?该行中有很多分散注意力和不相关的关键字,所以让我们大幅减少它:
执行 While..Loop
If we minimize the complexity of the line, to isolate the problem, we can simplify the line to:
If True Then Do While True: Beep: Loop: Else
Which, again, VBE autocorrects to a fragile line:
If True Then Do While True: Beep: Loop Else
But we can go even further and reduce the line to an illogically short line:
If True Then Do: Loop: Else
And VBE, once again, dutifully removes the colon to produce this line: (DO NOT EXECUTE THIS LINE OR YOU WILL HANG EXCEL)
If True Then Do: Loop Else
同时..Wend
Repeating the line, but swapping out the
Do While Loop
, for the olderWhile Wend
syntax:
If True Then While True: Beep: Wend: Else
Again, VBE optimizes away the colon, to give:
If True Then While True: Beep: Wend Else
But now the line is not fragile anymore!
因此,While..Wend 是较旧的构造,而 Do..Loop 构造较新(并且更灵活),但 VBE 解析器(和语法优化器)似乎与 Do..Loop 斗争构建。
要点:不要在包含 Else
语句的单行 If
语句中使用 Do..Loop
。