为什么粘贴时会编译此代码,否则会失败? [英] Why does this code compile when pasted in but fail otherwise?

查看:222
本文介绍了为什么粘贴时会编译此代码,否则会失败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一个朋友让我看看此页面,并注意到其中一位论坛用户的签名中出现了一段奇怪的代码.

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理解它的方法,除非删除并重新粘贴了该行.
  • 最新的语法/解析器紧密相关的问题以实际的VBA规范为模型,它解析并解决得很好(说实在让我震惊)
  • 如果已知该行无法编译,然后剪切/重新粘贴,则不会编译...而是从VBE外部再次将其重新粘贴,则它会突然编译.
  • If instruction separators / colons are replaced with new lines, it no longer compiles
  • On Local Error can be simplified to On 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.

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

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 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构造作斗争.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆