Некоторое время назад я слышал, что раньше был компилятор, который пытался исправить синтаксические ошибки, анализируя контекст и выводя то, что предполагалось.
Такой компилятор действительно существует? Очевидно, что это имеет небольшое практическое значение, но было бы очень интересно играть и учиться.
Ответы:
В каком - то смысле, акт компиляции является выводя , что определенный синтаксис хотел сделать, и , следовательно , ошибка синтаксиса, когда компилятор не в состоянии понять это. Вы можете добавить больше «догадок», чтобы компилятор выводил дальнейшие вещи и был более гибок с синтаксисом, но он должен делать это, выводя на себя определенный набор правил. И эти правила затем становятся частью языка и больше не являются ошибками.
Так что нет, на самом деле таких компиляторов нет, потому что вопрос не имеет смысла. Угадайте, что синтаксические ошибки должны делать согласно некоторому набору правил, становится частью синтаксиса.
В этом смысле, есть хороший пример компилятора, который делает это: любой компилятор Си. Они часто просто распечатывают предупреждение о том, что не так, как должно быть, а затем предполагают, что вы имели в виду X, и продолжайте. На самом деле это «угадывание» нечеткого кода (хотя это, по большей части, не синтаксис как таковой), то, что с таким же успехом могло бы остановить компиляцию с ошибкой и, следовательно, квалифицироваться как ошибка.
источник
Звучит действительно опасно. Если компилятор попытается определить ваше намерение, сделает неверный вывод, исправит код, а затем не сообщит вам (или сообщит вам в каком-то предупреждении, что вы, как и все остальные, игнорируете), то вы собираетесь запустить код, который может серьезно причинить ущерб.
Подобный компилятор, вероятно, очень намеренно НЕ создан.
источник
В среде IDE для языка программирования обычно в наши дни есть компилятор, работающий в фоновом режиме, так что он может предоставлять услуги анализа, такие как окрашивание синтаксиса, IntelliSense, ошибки и так далее. Очевидно, что такой компилятор должен уметь понимать глубоко испорченный код; Большую часть времени при редактировании код не является правильным. Но мы все еще должны понять это.
Однако обычно функция восстановления после ошибок используется только во время редактирования; не имеет смысла допускать это для фактической компиляции в сценариях "mainline".
Интересно, что мы встроили эту функцию в компилятор JScript.NET; в основном можно перевести компилятор в режим, в котором мы позволяем компилятору продолжать работу, даже если возникла ошибка, если бы среда IDE восстановилась из нее. Вы можете ввести код Visual Basic , запустить на нем компилятор JScript.NET и получить разумный шанс выхода работающей программы на другом конце!
Это забавная демонстрация, но она оказывается не очень хорошей функцией для сценариев "mainline" по многим причинам. Полное объяснение будет довольно длинным; краткое объяснение состоит в том, что он предназначен для программ, которые работают непредсказуемо и случайно , и затрудняет запуск одного и того же кода через несколько компиляторов или несколько версий одного и того же компилятора. Большие расходы, которые добавляет функция, не оправдываются небольшими преимуществами.
Питер Торр (Peter Torr), который в свое время занимал эту функцию, кратко обсуждает ее в этой публикации в блоге с 2003 года .
Хотя мы предоставляем эту функцию через API-интерфейсы хостинга скриптов движка JScript .NET, я не знаю ни одного реального клиента, который когда-либо использовал его.
источник
Первое, что приходит мне в голову - это автоматическая вставка точек с запятой в Javascript . Ужасная, ужасная особенность, которая никогда не должна была проникнуть в язык.
Нельзя сказать, что это не могло сделать лучшую работу. Если бы он посмотрел вперед на следующую строку, то он мог бы сделать более точное предположение о намерении программиста, но в конце концов, если есть несколько допустимых путей, по которым синтаксис мог бы пойти, тогда действительно нет замены для программиста, являющегося явным.
источник
Мне кажется, что если компилятор может исправить неправильный синтаксис, то этот синтаксис должен быть задокументирован на языке.
Причина синтаксических ошибок заключается в том, что парсер не может создать абстрактное синтаксическое дерево из программы. Это происходит, когда токен не на своем месте. Чтобы угадать, где должен находиться этот токен, должен ли он быть удален или если для исправления ошибки должен быть добавлен какой-либо другой токен, вам понадобится компьютер, который может угадать намерения программиста. Как машина могла догадаться, что:
Должен был быть:
Он может так же легко быть любым из следующих условий :
56
,5 - 6
,5 & 6
. Компилятору нет способа узнать это.Эта технология еще не существует.
источник
Хотя это не совсем то же самое, именно поэтому HTML превратился в катастрофу. Браузеры терпели плохую разметку, и следующее, что вы знали, браузер A не мог отображать так же, как браузер B (да, есть и другие причины, но это была одна из лучших причин, особенно 10 лет назад, до того, как некоторые из правил расшатанности стали общепринятыми ).
Как делает вывод Эрик Липперт, многие из этих вещей лучше всего обрабатываются в IDE, а не в компиляторе. Это позволяет вам увидеть, что автоматические биты пытаются испортить для вас.
Стратегия, которая, на мой взгляд, является преобладающей, заключается в непрерывном уточнении языка вместо ослабления компилятора: если это действительно то, что компилятор может выяснить автоматически, то введите четко определенную языковую конструкцию вокруг него.
Непосредственный пример, который приходит на ум, - это автоматические свойства в C # (не единственный язык, который имеет нечто подобное): учитывая, что большинство методов получения / установки в любом приложении на самом деле являются просто оболочками вокруг поля, просто позвольте разработчику указать их намерение и позволить компилятору ввести остальное.
Что заставляет меня задуматься: большинство языков стилей Си уже делают это до некоторой степени. Для вещей, которые могут быть выяснены автоматически, просто уточните синтаксис:
Может быть уменьшено до:
В конце концов, я думаю, что это сводится к следующему: тенденция в том, что вы не делаете компилятор «умнее» или «слабее». Это язык, который сделан умнее или слабее.
Кроме того, слишком много «помощи» может быть опасно, например, классическая ошибка «if»:
источник
if (x && y) dothis(); else dothat();
будет выглядеть немного лучше.true
илиfalse
.Когда я программировал FORTRAN и PL / I в конце 80-х и начале 90-х годов на миникомпьютерных и мэйнфреймовых системах DEC и IBM, я, похоже, помнил, что компиляторы регулярно выходили из системы, например, "ошибка бла-бла; предполагая бла-бла и продолжая .." ".. Тогда это было наследием (даже раньше, до моего времени) дней пакетной обработки и перфокарт, когда, вероятно, было огромное ожидание между отправкой кода для запуска и получением результатов. Таким образом, для компиляторов имело смысл попытаться угадать программиста и продолжить, а не прерывать первую обнаруженную ошибку. Имейте в виду, я не помню, чтобы "исправления" были особенно сложными. Когда я в итоге перешел на интерактивные рабочие станции Unix (Sun, SGI и т. Д.),
источник
Целью компилятора является создание исполняемых файлов, которые ведут себя как нужно. Если программист пишет что-то, что является недопустимым, даже если компилятор может с 90% вероятностью угадать, что было задумано, обычно лучше, чтобы программист исправил программу, чтобы прояснить намерение, чем чтобы компилятор выполнил и выполнил исполняемый файл который имел бы значительный шанс скрыть ошибку.
Конечно, языки, как правило, должны быть спроектированы таким образом, чтобы код, который четко выражает намерение, был законным, а код, который явно не выражает намерение, должен быть запрещен, но это не значит, что это так. Рассмотрим следующий код [Java или C #]
f1
Было бы полезно, чтобы компилятор добавил неявную тип-трансляцию для присваивания , поскольку программист мог бы захотетьf1
содержать только одну логическую вещь (float
значение, близкое к 1/10). Вместо того, чтобы поощрять компиляторы принимать неподходящие программы, было бы лучше, если бы спецификация допускала неявные двойные преобразования в некоторые контексты. С другой стороны, назначениеd1
может или не может быть тем, что на самом деле имел в виду программист, но нет правила языка, запрещающего это.Наихудшими видами языковых правил являются те, в которых компиляторы будут делать выводы в тех случаях, когда что-то не может законным образом компилироваться иначе, но когда программа может «случайно» быть действительной в том случае, когда предполагался вывод. Многие ситуации, связанные с неявным завершением оператора, попадают в эту категорию. Если программист, который намеревается написать два отдельных оператора, пропускает терминатор оператора, компилятору обычно удается вывести границу оператора, но иногда он может рассматривать как один оператор что-то, что должно было быть обработано как два.
источник
Синтаксические ошибки особенно трудно исправить. Возьмите случай пропущенного права
)
: мы знаем, что мы можем исправить код, вставив его, но обычно есть много мест, где мы могли бы вставить один и получить синтаксически правильную программу.Гораздо проще указать идентификаторы с ошибками (но учтите, что это не синтаксические ошибки). Можно вычислить расстояние редактирования между неразрешимым идентификатором и всеми идентификаторами в области видимости, и, заменив неразрешимое слово тем, которое, скорее всего, имел в виду пользователь, во многих случаях можно было бы найти правильную программу. Однако оказывается, что все же лучше пометить ошибку и позволить IDE предложить допустимые замены.
источник
Такой компилятор был бы просто непринужденной, нестандартной реализацией любого языка, который он компилирует.
источник
Это было опробовано несколько раз, но часто оно не давало желаемого эффекта: например, HAL 9000 или GlaDOS.
источник
В C вы не можете передавать массивы по значению, но компилятор позволяет писать:
который затем молча переписывается как:
Насколько это глупо? Я предпочел бы здесь серьезную ошибку вместо тихого переписывания, потому что это специальное правило заставило многих программистов полагать, что массивы и указатели - это одно и то же. Они не.
источник