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

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

问题描述

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

代码是单行的,如下所示:

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 替换这一系列转换和比较可以使代码始终如一地编译,所以 里面的东西弄乱了编译器.
  • 如果粘贴代码,则编译;如果在 VBE 验证该行之后以任何方式对其进行了修改(甚至只是删除 Local),它会停止编译,并且似乎没有任何东西可以让 VBA 再理解它,除非该行被删除并重新粘贴.
  • 最新的 语法/解析器正在密切以实际的 VBA 规范为蓝本,它可以很好地解析和解析(这真的让我大吃一惊)
  • 如果已知该行无法编译,然后剪切/重新粘贴,则无法编译...但从 VBE 外部再次重新粘贴,它会突然编译.

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

认为它与指令分隔符 (:) 和 inline-if 语法有关 - 假设没有 End If声明,事情单行而不是块.

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

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

解决方案

这么长的代码行,很难发现编译错误在哪里蔓延,但似乎是 VBE 应用了一个细微的差别在解析时或更有可能在解析后自动更正.

这是 original 行 - 从剪贴板粘贴

该行看起来像这样直到您将光标移动到另一行.注意 LoopElse 关键字 语句之间的冒号,以粗体表示:

<块引用>

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 解析器识别出该语句,然后优化"掉冗余"冒号.

<块引用>

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 没有意识到优化的行存在语法问题.

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

执行While..循环

<块引用>

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

其中,VBE 再次自动更正为 fragile 行:
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 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 构造存在冲突.

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

A friend made me look at this page, and noticed a strange piece of code in the signature of one of the forum users.

The code is a one-liner that goes as follows:

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

Scrolling removed:

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.

Some observations:

  • 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 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.

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?

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.

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?

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?

解决方案

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.

This is the original line - As pasted from the clipboard

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:

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

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.

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.

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:

Do While..Loop

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

While..Wend

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!

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.

Key point: Don't use Do..Loop in Single-Line If statements that include an Else statement.

这篇关于为什么粘贴时此代码会编译但否则会失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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