11

一位朋友让我看这个页面,并注意到一个论坛用户的签名中有一段奇怪的代码。

该代码是一个单行代码,如下所示:

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会使代码始终编译,因此其中的某些东西会弄乱编译器。
  • 如果粘贴代码,则编译;如果Local在 VBE 验证该行之后以任何方式对其进行了修改(甚至只是删除),它会停止编译,并且似乎没有任何东西可以让 VBA 再理解它,除非该行被删除并重新粘贴。
  • 最新的语法/解析器密切模仿实际的 VBA 规范,它解析和解析得很好(老实说,这让我大吃一惊)
  • 如果已知该行无法编译,然后剪切/重新粘贴,它不会编译......但从 VBE 外部再次重新粘贴它,它会突然编译。

问题是,这段代码如何根据 VB 语言规范进行编译?它是 VB[6|A|E] 实现中的错误吗?换句话说,它为什么/如何工作

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

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

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

4

2 回答 2

12

有了这么长的代码行,很难发现编译错误的来源,但是有一个细微的区别,似乎是 VBE 在解析该行时或更可能在解析该行之后对其应用了自动更正。

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

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

On Local Error Resume Next: If Not Empty is nothing then Do While Null: ReDim i(True To False) As Currency: Loop: ElseDebug.Assert CCur(CLng(CInt(CBool​​(False Imp True Xor False Eqv True)))): Stop : 在本地错误转到 0

这是您将光标移动到另一行后的行:

请注意,冒号已被 VBE 自动删除。看起来 VBE 解析器识别出该语句,然后“优化”掉“冗余”冒号。

On Local Error Resume Next: If Not Empty is nothing then Do While Null: ReDim i(True To False) As Currency: Loop ElseDebug.Assert CCur(CLng(CInt(CBool​​(False Imp True Xor False Eqv True)))): Stop : 在本地错误转到 0

如果您将冒号添加回处于无效语法状态的行,则自动更正将再次启动,但您的行将恢复为有效但脆弱的代码。

因此,VBE 似乎解析了该行,识别了一个优化(冗余冒号),然后应用了修复,但 VBE 没有意识到优化的行存在语法问题。

但是为什么这条线最终会变得脆弱?该行中有很多令人分心且不相关的关键字,因此让我们大幅减少它:

做While..循环

如果我们将线的复杂性最小化,以隔离问题,我们可以将线简化为:
If True Then Do While True: Beep: Loop: Else

VBE 再次自动更正为脆弱的线:
If True Then Do While True: Beep: Loop Else

但我们可以更进一步,将线简化为不合逻辑的短线:
If True Then Do: Loop: Else

和 VBE ,再一次,尽职尽责地删除冒号以生成此行:(不要执行此行,否则您将挂起 EXCEL)
If True Then Do: Loop Else

虽然..文德

重复该行,但将 , 换成Do While LoopWhile Wend语法:
If True Then While True: Beep: Wend: Else

同样,VBE 优化掉冒号,给出:
If True Then While True: Beep: Wend Else

但是现在该行不再脆弱了!

因此,While..Wend 是较旧的构造,而 Do..Loop 构造是较新的(且更灵活),但 VBE 解析器(和语法优化器)似乎与 Do..Loop 构造有冲突。

关键点:不要在包含语句Do..Loop的单行语句中使用。IfElse

于 2016-05-11T13:02:03.810 回答
0

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

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

否则确实非常有趣。

于 2016-05-11T08:06:36.510 回答