Why does this code compile when pasted in but fail otherwise?

南楼画角 提交于 2019-12-18 19:09:06

问题


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

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?


回答1:


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.




回答2:


I would adventure to answer that the Resume Next is a key instruction here, since anything else invalid would skip to the next instruction.

Colons separate the commands as if they were new lines.

It is otherwise very inriguing indeed.



来源:https://stackoverflow.com/questions/37147979/why-does-this-code-compile-when-pasted-in-but-fail-otherwise

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!