为什么这段代码在粘贴时可以编译,否则会失败?

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

令人惊叹的是,如果您按原样粘贴代码(然后不要再碰它!)进入有效的过程级范围。

一些观察:

问题是,此代码如何针对VB 语言规范进行编译?它是 VB[6|A|E] 实现中的错误吗?也就是说,why/how行得通吗?

认为 它与指令分隔符 (:) 和 inline-if 语法有关 - 假设没有 End If 语句, 单行而不是块。

但是,是什么让 那个特定代码 成为薛定谔的代码?是什么让它既合法又非法?

如果代码被使用形式语法定义 (ANTLR) 生成的解析器正确解析,那么它一定是一个合法的构造?那为什么当你回到那一行并按 ENTER 时它就不再合法了?

我敢冒昧地回答 Resume Next 是这里的关键指令,因为任何其他无效指令都会跳到下一条指令。

冒号分隔命令,就好像它们是新行一样。

否则确实很有趣。

对于这么长的代码行,很难发现编译错误出现的位置,但有一个细微的差别,似乎是 VBE 对该行应用了自动更正,或者更可能是在它之后已解析。

这是原始行 - 从剪贴板粘贴

该行显示为这样直到您将光标移动到另一行。 注意 LoopElse 关键字之间的粗体冒号 语句:

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