Существуют ли какие-либо компиляторы, которые пытаются исправить синтаксические ошибки самостоятельно? [закрыто]


15

Некоторое время назад я слышал, что раньше был компилятор, который пытался исправить синтаксические ошибки, анализируя контекст и выводя то, что предполагалось.

Такой компилятор действительно существует? Очевидно, что это имеет небольшое практическое значение, но было бы очень интересно играть и учиться.


3
Входит ли IntelliSense в эту категорию? Многие компиляторы имеют ошибки, подобные ожидаемым [точка с запятой].
Роберт Харви

1
@ Роберт: Нет, но это хороший момент.
Натан Осман

1
Мой друг довольно много взломал препроцессор C, например, «inlcude -> include», а также попытался выяснить, где должны быть закрыты открытые условия. Это была его магистерская работа, которую он быстро отбросил для чего-то более легкого. Все-таки довольно интересный вопрос!
Тим Пост

3
Компилятор AC # терпит неудачу с ОЧЕНЬ полезными сообщениями об ошибках. Это в сочетании с хорошей документацией, доступной онлайн для каждого кода ошибки, работает довольно хорошо. Это плохая идея автоматически исправлять синтаксис, хотя интерпретаторы HTML (например, браузеры) часто делают это в любом случае.
Работа

1
Компилятор, на который вы ссылаетесь, был оригинальным PL / I. Предполагалось, что то, что написал программист, должно что-то значить, и пыталось угадать, что это может быть. По моему опыту, он очень плохо угадал!
david.pfx

Ответы:


28

В каком - то смысле, акт компиляции является выводя , что определенный синтаксис хотел сделать, и , следовательно , ошибка синтаксиса, когда компилятор не в состоянии понять это. Вы можете добавить больше «догадок», чтобы компилятор выводил дальнейшие вещи и был более гибок с синтаксисом, но он должен делать это, выводя на себя определенный набор правил. И эти правила затем становятся частью языка и больше не являются ошибками.

Так что нет, на самом деле таких компиляторов нет, потому что вопрос не имеет смысла. Угадайте, что синтаксические ошибки должны делать согласно некоторому набору правил, становится частью синтаксиса.

В этом смысле, есть хороший пример компилятора, который делает это: любой компилятор Си. Они часто просто распечатывают предупреждение о том, что не так, как должно быть, а затем предполагают, что вы имели в виду X, и продолжайте. На самом деле это «угадывание» нечеткого кода (хотя это, по большей части, не синтаксис как таковой), то, что с таким же успехом могло бы остановить компиляцию с ошибкой и, следовательно, квалифицироваться как ошибка.


4
Это правильный ответ. Как только компилятор может восстановиться после ошибки, это больше не является ошибкой. Perl (в?) Известен своим поведением «делай, что я имею в виду», выбирая то, что программист, скорее всего, имел в виду, учитывая неоднозначный источник.
Джон Перди

Perl жертвует многословием для размера исходного кода.
Натан Осман

@ Джордж Эдисон: Это либо тавтология, либо противоречие.
Джон Перди

Или глубокое понимание. :)
Леннарт Регебро

23

Звучит действительно опасно. Если компилятор попытается определить ваше намерение, сделает неверный вывод, исправит код, а затем не сообщит вам (или сообщит вам в каком-то предупреждении, что вы, как и все остальные, игнорируете), то вы собираетесь запустить код, который может серьезно причинить ущерб.

Подобный компилятор, вероятно, очень намеренно НЕ создан.


5
Я знаю это. Такой компилятор не использовался бы для компиляции, но концепция довольно интересна и обладает потенциалом обучения.
Натан Осман

2
почти все последние версии IDE содержат предложения по синтаксису, и это действительно полезно. а в остальной части согласен с нганью
Джигар Джоши

Я бы не использовал такой компилятор. Это относится к «черной магии».
Майкл К

Хм, где бы вы оценили вывод типа Scala по этой шкале? Попробовав, можно сказать, что это важный вклад в сжатый код. С другой стороны, он иногда выстрелил мне в ногу (например, потому что я думал, что имею дело со списками, но на самом деле все еще имел дело с сетами).
Timday

У нас есть такие вещи, как автоскоп в OMP, так что немного это выполнимо. Конечно, код, над которым я работаю, отключил автоскопинг, потому что мы ему не доверяем. Я мог видеть наличие интерактивного компилятора, который спрашивает: «Вы имели в виду XXX?». Насколько я был бы готов пойти. И даже это, вероятно, слишком опасно.
Омега Центавра

12

В среде IDE для языка программирования обычно в наши дни есть компилятор, работающий в фоновом режиме, так что он может предоставлять услуги анализа, такие как окрашивание синтаксиса, IntelliSense, ошибки и так далее. Очевидно, что такой компилятор должен уметь понимать глубоко испорченный код; Большую часть времени при редактировании код не является правильным. Но мы все еще должны понять это.

Однако обычно функция восстановления после ошибок используется только во время редактирования; не имеет смысла допускать это для фактической компиляции в сценариях "mainline".

Интересно, что мы встроили эту функцию в компилятор JScript.NET; в основном можно перевести компилятор в режим, в котором мы позволяем компилятору продолжать работу, даже если возникла ошибка, если бы среда IDE восстановилась из нее. Вы можете ввести код Visual Basic , запустить на нем компилятор JScript.NET и получить разумный шанс выхода работающей программы на другом конце!

Это забавная демонстрация, но она оказывается не очень хорошей функцией для сценариев "mainline" по многим причинам. Полное объяснение будет довольно длинным; краткое объяснение состоит в том, что он предназначен для программ, которые работают непредсказуемо и случайно , и затрудняет запуск одного и того же кода через несколько компиляторов или несколько версий одного и того же компилятора. Большие расходы, которые добавляет функция, не оправдываются небольшими преимуществами.

Питер Торр (Peter Torr), который в свое время занимал эту функцию, кратко обсуждает ее в этой публикации в блоге с 2003 года .

Хотя мы предоставляем эту функцию через API-интерфейсы хостинга скриптов движка JScript .NET, я не знаю ни одного реального клиента, который когда-либо использовал его.


Я бы хотел, чтобы у моего работодателя были ресурсы для таких экспериментов; мы даже не запускаем модульные тесты ночью, потому что есть так много функций, которые нужно добавить, и исправить ошибки :(
Job

1
Это тот ответ, на который я надеялся ... как я упоминал ранее - очевидно, что такая функция имеет мало практического применения, но предоставит отличный способ изучить некоторые методы, которые могут быть применены к другим вещам. (Разбор языка и т. Д.)
Натан Осман

1
@Job: Общая мудрость заключается в том, что если вы не будете регулярно запускать юнит-тесты, у вас будет гораздо больше ошибок, которые нужно исправить .
Эрик Липперт

Я уже знаю, что мне нужно делать с моей работой, а не скулить здесь. В некоторых компаниях, занимающихся разработкой программного обеспечения, руководители не совсем понимают разницу между прототипом и готовым продуктом. В конце концов, с пиксельной разницей часто нет большой разницы. Не стоит начинать с прототипа, чтобы не тратить время впустую. Но ужасный ответ «выглядит хорошо, сколько дней, чтобы перенести это в производство?». Это те же люди, которые будут подозрительны, если инженеры скажут им, что им нужно тратить время на инфраструктуру или рефакторинг. Я слышал, даже Спольскому это не нравится.
Работа

10

Первое, что приходит мне в голову - это автоматическая вставка точек с запятой в Javascript . Ужасная, ужасная особенность, которая никогда не должна была проникнуть в язык.

Нельзя сказать, что это не могло сделать лучшую работу. Если бы он посмотрел вперед на следующую строку, то он мог бы сделать более точное предположение о намерении программиста, но в конце концов, если есть несколько допустимых путей, по которым синтаксис мог бы пойти, тогда действительно нет замены для программиста, являющегося явным.


1
Я искренне согласен с функцией вставки точек с запятой в JavaScript - совершенно бесполезной.
Натан Осман

7

Мне кажется, что если компилятор может исправить неправильный синтаксис, то этот синтаксис должен быть задокументирован на языке.

Причина синтаксических ошибок заключается в том, что парсер не может создать абстрактное синтаксическое дерево из программы. Это происходит, когда токен не на своем месте. Чтобы угадать, где должен находиться этот токен, должен ли он быть удален или если для исправления ошибки должен быть добавлен какой-либо другой токен, вам понадобится компьютер, который может угадать намерения программиста. Как машина могла догадаться, что:

int x = 5 6;

Должен был быть:

int x = 5 + 6;

Он может так же легко быть любым из следующих условий : 56, 5 - 6, 5 & 6. Компилятору нет способа узнать это.

Эта технология еще не существует.


1
Такая технология не может существовать. Чтение мыслей не допускается; все инструкции должны однозначно исходить из кода.
Работа

Верно, но то, что я действительно имел в виду, было: «Есть ли какие-либо компиляторы, которые пытаются исправить неправильный синтаксис, делая предположения на основе контекста». Тот факт, что компилятор исправляет неверный синтаксис, не делает синтаксис действительным. Кроме того, я понимаю, что такой инструмент был бы бесполезен для разработки кода.
Натан Осман

6

Хотя это не совсем то же самое, именно поэтому HTML превратился в катастрофу. Браузеры терпели плохую разметку, и следующее, что вы знали, браузер A не мог отображать так же, как браузер B (да, есть и другие причины, но это была одна из лучших причин, особенно 10 лет назад, до того, как некоторые из правил расшатанности стали общепринятыми ).

Как делает вывод Эрик Липперт, многие из этих вещей лучше всего обрабатываются в IDE, а не в компиляторе. Это позволяет вам увидеть, что автоматические биты пытаются испортить для вас.

Стратегия, которая, на мой взгляд, является преобладающей, заключается в непрерывном уточнении языка вместо ослабления компилятора: если это действительно то, что компилятор может выяснить автоматически, то введите четко определенную языковую конструкцию вокруг него.

Непосредственный пример, который приходит на ум, - это автоматические свойства в C # (не единственный язык, который имеет нечто подобное): учитывая, что большинство методов получения / установки в любом приложении на самом деле являются просто оболочками вокруг поля, просто позвольте разработчику указать их намерение и позволить компилятору ввести остальное.

Что заставляет меня задуматься: большинство языков стилей Си уже делают это до некоторой степени. Для вещей, которые могут быть выяснены автоматически, просто уточните синтаксис:

 if (true == x)
 {
    dothis();
 }
 else
 {
    dothat();
 }

Может быть уменьшено до:

if (true == x)
    dothis();
else
    dothat();

В конце концов, я думаю, что это сводится к следующему: тенденция в том, что вы не делаете компилятор «умнее» или «слабее». Это язык, который сделан умнее или слабее.

Кроме того, слишком много «помощи» может быть опасно, например, классическая ошибка «if»:

if (true == x)
    if (true == y)
       dothis();
else
    dothat();

Следует отметить, что XHTML предоставил решение проблемы, которую создали плохие спецификации HTML.
Натан Осман

2
if (x && y) dothis(); else dothat();будет выглядеть немного лучше.
Работа

1
Кошка умирает каждый раз, когда кто-то сравнивает с trueили false.
JensG

2

Когда я программировал FORTRAN и PL / I в конце 80-х и начале 90-х годов на миникомпьютерных и мэйнфреймовых системах DEC и IBM, я, похоже, помнил, что компиляторы регулярно выходили из системы, например, "ошибка бла-бла; предполагая бла-бла и продолжая .." ".. Тогда это было наследием (даже раньше, до моего времени) дней пакетной обработки и перфокарт, когда, вероятно, было огромное ожидание между отправкой кода для запуска и получением результатов. Таким образом, для компиляторов имело смысл попытаться угадать программиста и продолжить, а не прерывать первую обнаруженную ошибку. Имейте в виду, я не помню, чтобы "исправления" были особенно сложными. Когда я в итоге перешел на интерактивные рабочие станции Unix (Sun, SGI и т. Д.),


2
Эти компиляторы продолжат работу, но они продолжат работать ТОЛЬКО с целью поиска дальнейших ошибок, чтобы вы могли (потенциально) исправить некоторые вещи перед повторной отправкой. Современные ПК достаточно быстры, чтобы «интерактивный» компилятор вполне мог остановиться на первой синтаксической ошибке и отправить вас в редактор. (И, фактически, оригинальный Turbo Pascal, в начале 1980-х, работал именно так. Это было здорово.)
Джон Р. Штром

1
Да, я помню, что оптимизирующий компилятор IBM PL / I иногда выдавал пропущенные операторы BEGIN и END, а ISTR - пропущенные точки с запятой.
TMN

1

Целью компилятора является создание исполняемых файлов, которые ведут себя как нужно. Если программист пишет что-то, что является недопустимым, даже если компилятор может с 90% вероятностью угадать, что было задумано, обычно лучше, чтобы программист исправил программу, чтобы прояснить намерение, чем чтобы компилятор выполнил и выполнил исполняемый файл который имел бы значительный шанс скрыть ошибку.

Конечно, языки, как правило, должны быть спроектированы таким образом, чтобы код, который четко выражает намерение, был законным, а код, который явно не выражает намерение, должен быть запрещен, но это не значит, что это так. Рассмотрим следующий код [Java или C #]

const double oneTenth = 0.1;
const float  oneTenthF = 0.1f;
...
float f1 = oneTenth;
double d1 = oneTenthF;

f1Было бы полезно, чтобы компилятор добавил неявную тип-трансляцию для присваивания , поскольку программист мог бы захотеть f1содержать только одну логическую вещь ( floatзначение, близкое к 1/10). Вместо того, чтобы поощрять компиляторы принимать неподходящие программы, было бы лучше, если бы спецификация допускала неявные двойные преобразования в некоторые контексты. С другой стороны, назначение d1может или не может быть тем, что на самом деле имел в виду программист, но нет правила языка, запрещающего это.

Наихудшими видами языковых правил являются те, в которых компиляторы будут делать выводы в тех случаях, когда что-то не может законным образом компилироваться иначе, но когда программа может «случайно» быть действительной в том случае, когда предполагался вывод. Многие ситуации, связанные с неявным завершением оператора, попадают в эту категорию. Если программист, который намеревается написать два отдельных оператора, пропускает терминатор оператора, компилятору обычно удается вывести границу оператора, но иногда он может рассматривать как один оператор что-то, что должно было быть обработано как два.


0

Синтаксические ошибки особенно трудно исправить. Возьмите случай пропущенного права) : мы знаем, что мы можем исправить код, вставив его, но обычно есть много мест, где мы могли бы вставить один и получить синтаксически правильную программу.

Гораздо проще указать идентификаторы с ошибками (но учтите, что это не синтаксические ошибки). Можно вычислить расстояние редактирования между неразрешимым идентификатором и всеми идентификаторами в области видимости, и, заменив неразрешимое слово тем, которое, скорее всего, имел в виду пользователь, во многих случаях можно было бы найти правильную программу. Однако оказывается, что все же лучше пометить ошибку и позволить IDE предложить допустимые замены.


-1

Такой компилятор был бы просто непринужденной, нестандартной реализацией любого языка, который он компилирует.


-2

Это было опробовано несколько раз, но часто оно не давало желаемого эффекта: например, HAL 9000 или GlaDOS.


-3

В C вы не можете передавать массивы по значению, но компилятор позволяет писать:

void foo(int array[10]);

который затем молча переписывается как:

void foo(int* array);

Насколько это глупо? Я предпочел бы здесь серьезную ошибку вместо тихого переписывания, потому что это специальное правило заставило многих программистов полагать, что массивы и указатели - это одно и то же. Они не.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.