Почему этот код компилируется при вставке, но не работает иначе?
Друг заставил меня взглянуть на эту страницу и заметил странный фрагмент кода в сигнатуре одного из пользователей форума.
Код является однострочным, который выглядит следующим образом:
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" ( "Истина для False" ). "Валюта": "Петля": "Else Debug.Assert CCur" (CLng (CINt ( "Ключ" (False Imp True Xor False Eq True) )))): Stop: On Local Error GoTo 0
Весьма разумно, что этот код компилируется (я не пытался его запустить, но это неуместно), если вы просто вставляете его как есть (и затем не трогайте его снова!) в действительный уровень процедуры сфера.
Некоторые наблюдения:
- Если разделители команд/двоеточия заменены новыми строками, они больше не компилируются
-
On Local Error
можно упростить до On Error
- Вложенные конверсии не представляют особого интереса с первого взгляда, но оказывается, что замена этой серии преобразований и сравнение с простым
Debug.Assert True
заставляет код последовательно компилироваться, поэтому что-то в нем запутывает компилятор.
- Если код вставлен, он компилируется; если он каким-либо образом изменил (даже просто удалив
Local
) после того, как VBE проверил строку, он прекратит компиляцию, и ничто не заставит VBA больше его понять, если строка не удалена и не вставлена повторно.
- Последний rubberduck грамматика/парсер будучи тщательно смоделированным по фактическим спецификациям VBA, он анализирует и решает просто отлично (что, честно говоря, дует мой разум)
- Если строка, как известно, не компилируется, а затем вырезает/повторно вставлена, она не компилируется... но повторно вставляя ее снова извне VBE, она неожиданно компилируется.
Вопрос, как этот код удается скомпилировать против спецификаций языка VB? Это ошибка в реализации VB [6 | A | E]? Другими словами, почему/как это работает?
Я думаю, что это имеет какое-то отношение к разделителю команд (:
) и синтаксису inline-if - если нет инструкции End If
, вещь - это одна строка, а не блок.
Но тогда, что делает этот конкретный код кодом Шредингера? Что делает его одновременно законным и незаконным?
Если код правильно обрабатывается парсером, сгенерированным с использованием формального определения грамматики (ANTLR), то это должна быть законная конструкция? Тогда почему это перестает быть законным, когда вы просто возвращаетесь к этой строке и нажимаете ENTER?
Ответы
Ответ 1
С такой длинной строкой кода трудно определить, где возникает ошибка компиляции, но есть тонкая разница, которая, как представляется, является VBE, применяющей автокоррекцию к строке, или, более вероятно, после нее, она анализируется.
Это строка original - как вставлена из буфера обмена
Строка выглядит как , пока не переместит курсор на другую строку.
Обратите внимание на двоеточие, выделенное жирным шрифтом, между оператором Loop
и Else
keywords:
В поле "Локальная ошибка" Далее: если "Пустое" ничего не делает, тогда делать "Нуль": "ReDim i" ( "Истина до ложного" ). Валюта: Loop: Else
Debug.Assert CCur (CLng (CInt (CBool ( False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Это строка после, вы перемещаете курсор в другую строку:
Обратите внимание, что двоеточие было автоматически удалено VBE. Похоже, что парсер VBE распознает выражение, а затем "оптимизирует" "избыточную" двоеточие.
В поле "Локальная ошибка": "Нет", "Пустое", "Ничего не делает", пока "Null: ReDim я (True To False)). Валюта: Loop Else
Debug.Assert CCur (CLng (CInt (CBool ( False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Если вы добавите двоеточие в строку, которая находится в состоянии недействительного синтаксиса, то автокоррекция снова начнется, но ваша строка вернется к действию, но хрупкий код.
Итак, кажется, что VBE анализирует строку, идентифицирует оптимизацию (избыточный двоеточие), а затем применяет исправление, но VBE не понимает, что оптимизированная строка имеет проблемы с синтаксисом.
Но почему линия заканчивается хрупкой? В строке есть много отвлекающих и нерелевантных ключевых слов, поэтому давайте резко уменьшим их:
Do While..Loop
Если мы минимизируем сложность линии, чтобы изолировать проблему, мы можем упростить ее:
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
While..Wend
Повторяя строку, но заменяя 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
.
Ответ 2
Я бы посоветовал ответить, что здесь Resume Next
является ключевой инструкцией, так как все остальное недействительно пропустит следующую команду.
Колонны разделяют команды так, как если бы они были новыми строками.
В противном случае это действительно очень интригует.