一位朋友让我看了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
进行比较会使代码一致地编译,因此某些东西在那里弄乱了编译器。Local
),它就会停止编译,似乎没有任何东西让VBA理解它,除非该行被删除并重新粘贴。问题是,这段代码如何根据VB语言规范进行编译?这是VB [6 | A | E]实现中的错误吗?换句话说,为什么/如何运作?
我认为它与指令分隔符(:
)和内联if语法有关 - 假设没有End If
语句,那么是单行而不是块。
但是,是什么让特定代码成为Schrödinger的代码?什么使它既合法又非法?
如果使用正式语法定义(ANTLR)生成的解析器正确解析了代码,那么它必须是一个合法的构造吗?那么为什么当你回到那条线并点击ENTER时它就不再合法了?
答案 0 :(得分:12)
如此长的代码行,很难找到编译错误所在的位置,但是有一个细微的差别,似乎是VBE对该行应用了自动更正,或者更有可能在解析之后
该行显示为直到,您将光标移动到另一行。
请注意Loop
和Else
关键字语句之间的粗体冒号:
关于本地错误恢复下一个:如果不为空则无效则为空: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没有意识到优化的行有语法问题。
但为什么这条线最终会变得脆弱?该行中有许多令人分心和不相关的关键字,所以让我们大幅减少它:
如果我们最小化线路的复杂性,为了隔离问题,我们可以将线路简化为:
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
重复该行,但更换
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将命令分开,好像它们是新行一样。
确实非常有意义。