为什么粘贴时会编译此代码,否则会失败? [英] Why does this code compile when pasted in but fail otherwise?
问题描述
一个朋友让我看看此页面,并注意到其中一位论坛用户的签名中出现了一段奇怪的代码.
A friend made me look at this page, and noticed a strange piece of code in the signature of one of the forum users.
该代码是一种单行代码,如下所示:
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
滚动删除:
关于本地错误的信息继续下一个:如果不为空,则执行Null:将i(True to False)转换为货币:循环:Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True) )))):停止:出现本地错误时转到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
令人难以置信的是,如果您仅按原样粘贴该代码(然后不要再次对其进行操作!),则该代码可以编译(我没有尝试运行它,但这无关紧要).范围.
Quite mind-blowingly, that code compiles (I didn't try to run it, but that's irrelevant) if you just paste it as-is (and then don't touch it again!) into a valid procedure-level scope.
一些观察结果:
- 如果用新行替换指令分隔符/冒号,它将不再编译
-
On Local Error
可以简化为On Error
- 乍一看,嵌套转换没有什么特别的意义,但是事实证明,用简单的
Debug.Assert True
替换该系列的转换和比较可以使代码一致地进行编译,因此 something 搞砸了编译器. - 如果粘贴了代码,则会编译;如果在VBE验证了该行之后以任何方式对其进行了修改(甚至只是删除了
Local
),它将停止编译,并且似乎没有任何使VBA理解它的方法,除非删除并重新粘贴了该行. - 最新的 rubberduck 语法/解析器紧密相关的问题以实际的VBA规范为模型,它解析并解决得很好(说实在让我震惊)
- 如果已知该行无法编译,然后剪切/重新粘贴,则不会编译...而是从VBE外部再次将其重新粘贴,则它会突然编译.
- If instruction separators / colons are replaced with new lines, it no longer compiles
On Local Error
can be simplified toOn Error
- The nested conversions aren't of any particular interest at first sight, but it turns out replacing that series of conversions and comparisons with a simple
Debug.Assert True
makes the code consistently compile, so something in there is messing up the compiler. - If the code is pasted, it compiles; if it's modified in any way (even merely removing
Local
) after the VBE has validated the line, it stops compiling, and nothing seems to make VBA understand it anymore, unless the line is deleted and re-pasted. - The latest rubberduck grammar/parser being closely modeled on the actual VBA specs, it parses and resolves just fine (which honestly blows my mind)
- If the line is known to not compile, and then cut/re-pasted, it doesn't compile... but re-pasting it again from outside the VBE, it suddenly compiles.
问题是,该代码如何根据VB语言规范进行编译?这是VB [6 | A | E]实现中的错误吗?换句话说,为什么/如何工作?
The question is, how does this code manage to compile against the VB language specs? Is it a bug in the VB[6|A|E] implementation? In other words, why/how does it work?
我认为与指令分隔符(:
)和内联-if语法有关—在没有End If
语句的情况下,是单行而不是块.
I think it has something to do with the instruction separator (:
) and the inline-if syntax - given there's no End If
statement, the thing is a single line and not a block.
但是,什么使该特定代码成为Schrödinger的代码?是什么使它同时合法和非法?
But then, what makes that specific code be Schrödinger's code? What is it that makes it both legal and illegal at the same time?
如果通过使用正式语法定义(ANTLR)生成的解析器正确解析了代码,那么它一定是合法的构造吗?那么为什么当您仅返回到该行并按ENTER键时,它为什么不再合法呢?
If the code gets correctly parsed by a parser generated using a formal grammar definition (ANTLR), then it must be a legal construct? Then why does it stop being legal when you merely go back to that line and hit ENTER?
推荐答案
使用这么长的代码行,很难发现编译错误在哪里蔓延,但是有一个细微的差别,似乎是VBE应用了在解析后或更可能在解析后自动更正该行.
With such a long line of code, it's hard to spot where the compile error creeps in, but there is a subtle difference that appears to be the VBE applying an autocorrect to the line as, or more likely after, it is parsed.
该行将显示为直到,将光标移动到另一行.
请注意Loop
和Else
关键字语句之间以粗体表示的冒号:
The line appears like this until you move the cursor to another line.
Notice the colon, in bold, between the Loop
and Else
keywords statement:
关于本地错误的信息,继续:下一个:如果不为空,则执行Null:将i(True To False)转换为货币:
Loop: Else
Debug.Assert CCur(CLng(CInt(CBool( False Imp True Xor False Eqv True)))))):停止:出现本地错误时转到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
这是在将光标移动到另一行之后的行:
注意,冒号已被VBE自动删除.似乎VBE解析器可以识别该语句,然后优化"冗余"冒号.
This is the line after you move the cursor to another line:
Notice the colon has been auto-removed by VBE. It seems like the VBE parser recognizes the statement, and then "optimizes" the "redundant" colon away.
关于本地错误的信息,继续:下一个:如果不为空,则执行Null:将i(True To False)转换为货币:
Loop Else
Debug.Assert CCur(CLng(CInt(CBool( False Imp True Xor False Eqv True)))))):停止:出现本地错误时转到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
如果您将冒号加回到处于无效语法状态的行,则自动更正会再次启动,但是您的行将恢复为有效,但易碎代码.
If you add back the colon to a line that is in the invalid syntax state, then the autocorrect kicks in again, but your line returns to being valid, but fragile code.
因此,似乎VBE解析了该行,确定了一个优化(冗余冒号),然后应用了此修复程序,但VBE并未意识到优化的行存在语法问题.
So, it seems that VBE parses the line, identifies an optimization (the redundant colon), and then applies the fix, but VBE doesn't realize the optimized line has syntax problems.
但是为什么生产线最终变得脆弱?该行中有许多分散注意力和无关紧要的关键字,因此让我们大幅度地减少它:
But why does the line end up being fragile? There are lots of distracting and irrelevant keywords in the line, so let's reduce it drastically:
如果我们最小化生产线的复杂性以找出问题,我们可以将生产线简化为:
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
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
虽然..结束
重复该行,但换出
Do While Loop
,以使用较旧的While Wend
语法:
If True Then While True: Beep: Wend: Else
再次,VBE优化了结肠,得到:
If True Then While True: Beep: Wend Else
但是现在这条线不再易碎了!
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构造作斗争.
So, the While..Wend is the older construct, and the Do..Loop construct is newer (and more flexible), but it seems the VBE parser (and syntax optimizer) struggle with the Do..Loop construct.
要点:不要在包含Else
语句的单行If
语句中使用Do..Loop
.
Key point: Don't use Do..Loop
in Single-Line If
statements that include an Else
statement.
这篇关于为什么粘贴时会编译此代码,否则会失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!