为什么这段代码在粘贴时编译但是否则失败?

时间:2016-05-10 20:06:55

标签: vba vb6 specifications vbe

一位朋友让我看了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

滚动已删除:

  

关于本地错误恢复下一个:如果不为空则无效则为空:ReDim i(True to False)作为货币:循环:否则Debug.Assert CCur(CLng(CInt)(CBool​​(False Imp True Xor False Eqv True) )))):停止:在本地错误GoTo 0

相当令人兴奋的是,代码编译(我没有尝试运行它,但这是无关紧要的)如果你只是按原样粘贴(然后再不要再触摸它!)到一个有效的程序级别范围。

一些观察结果:

  • 如果指令分隔符/冒号被新行替换,则不再编译
  • On Local Error可简化为On Error
  • 乍一看,嵌套转换没有任何特别的兴趣,但事实证明取代一系列转换并与简单的Debug.Assert True进行比较会使代码一致地编译,因此某些东西在那里弄乱了编译器。
  • 如果代码被粘贴,则编译;如果在VBE验证了该行之后以任何方式对其进行了修改(甚至只是删除Local),它就会停止编译,似乎没有任何东西让VBA理解它,除非该行被删除并重新粘贴。
  • 最新的语法/解析器与实际的VBA规范it parses and resolves just fine密切相关(这真是让我大吃一惊)
  • 如果已知该行未编译,然后剪切/重新粘贴,则无法编译...但是再次从VBE外部重新粘贴它,它会突然编译。

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

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

但是,是什么让特定代码成为Schrödinger的代码?什么使它既合法又非法?

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

2 个答案:

答案 0 :(得分:12)

如此长的代码行,很难找到编译错误所在的位置,但是有一个细微的差别,似乎是VBE对该行应用了自动更正,或者更有可能在解析之后

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

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

  

关于本地错误恢复下一个:如果不为空则无效则为空:ReDim i(True to False)为货币: Loop: Else Debug.Assert CCur(CLng(CInt( CBool​​(False Imp True Xor False Eqv True)))):停止:On Local Error GoTo 0

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

请注意,VBE已自动删除冒号。似乎VBE解析器识别该语句,然后“优化”“冗余”冒号。

  

关于本地错误恢复下一个:如果不为空则无效则为空:ReDim i(True to False)为货币: Loop Else Debug.Assert CCur(CLng(CInt( CBool​​(False Imp True Xor False Eqv True)))):停止:On Local Error GoTo 0

如果你将冒号添加回处于无效语法状态的行,那么自动更正会再次启动,但你的行返回有效,但脆弱代码。

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

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

Do While..Loop

  

如果我们最小化线路的复杂性,为了隔离问题,我们可以将线路简化为:
  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再次尽职地删除了冒号以产生这条线:( 不要执行此线路,否则您将挂起)
  If True Then Do: Loop Else

While..Wend

  

重复该行,但更换Do While Loop,用于较早的While 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语句的单行If语句中使用Else

答案 1 :(得分:0)

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

Colons将命令分开,好像它们是新行一样。

确实非常有意义。