Чи є компілятори, які намагаються самостійно виправити помилки синтаксису? [зачинено]


15

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

Чи існує такий компілятор насправді? Очевидно, що це мало практичне значення, але було б дуже цікаво грати і вчитися.


3
Чи належить IntelliSense до цієї категорії? У багатьох компіляторах помилки, схожі на очікувані крапкою з комою.
Роберт Харві

1
@Robert: Ні, але це хороший момент.
Натан Осман

1
Мій друг зробив досить багато злому на препроцесорі C, наприклад, "inlcude -> include", і дещо працював над тим, щоб розібратися, де відкриті умови повинні бути закриті. Це була його магістерська робота, яку він швидко відмовився від чогось легшого. Все-таки досить цікаве запитання!
Tim Post

3
AC # компілятор не працює з ДУЖЕ корисними повідомленнями про помилки. Це в поєднанні з хорошою документацією, доступною в Інтернеті, для кожного коду помилки працює досить добре. Автоматично виправити синтаксис - це погана ідея, хоча інтерпретатори HTML (наприклад, браузери) часто це роблять.
Робота

1
Компілятор, на який ви посилаєтесь, був оригінальним PL / I. Він припускав, що все, що написав програміст, щось мало означало, і намагався вгадати, що це може бути. З мого досвіду, це дуже погано здогадалося!
david.pfx

Відповіді:


28

У певному сенсі акт складання визначає, що призначений для виконання певного синтаксису, а отже, синтаксична помилка - це коли компілятор не зможе це зрозуміти. Ви можете додати більше "здогадувань", щоб компілятор міг зробити висновки щодо подальших речей і бути більш гнучким із синтаксисом, але він повинен робити це висновок за певним набором правил. І ці правила потім стають частиною мови, і це вже не помилки.

Отже, ні, таких компіляторів немає, адже це питання не має сенсу. Здогадування, які синтаксичні помилки мають бути зроблені згідно з деяким набором правил, просто стає частиною синтаксису.

У цьому сенсі є хороший приклад компілятора, який робить це: Будь-який компілятор C. Вони часто просто роздруковують попередження про щось, що не так, як має бути, а потім припускають, що ви мали на увазі X, і продовжуйте. Це насправді "відгадування" незрозумілого коду (хоча це, здебільшого, не синтаксис), щось таке, що так само могло б зупинити компіляцію з помилкою, і тому кваліфікується як помилка.


4
Це правильна відповідь. Після того, як компілятор може відновити помилку, це вже насправді не помилка. Perl відомий цією поведінкою "Робити що я маю на увазі", вибираючи те, що програміст, швидше за все, мав на увазі неоднозначне джерело.
Джон Перді

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

@ Джордж Едісон: Це або тавтологія, або суперечність.
Джон Перді

Або глибоке розуміння. :)
Леннарт Регебро

23

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

Такий компілятор, мабуть, щось, що навмисно НЕ було створено.


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

2
майже весь останній IDE пропонує пропозиції для синтаксису, і це дуже корисно. а в частині решти частини погоджуються з нугами
Joshi

Я б не користувався таким компілятором. Це під заголовком «чорна магія».
Майкл К

Гммм, де ви б оцінили висновок типу Scala за цією шкалою? Спробувавши це, він би сказав, що це головний внесок у стислий код. З іншого боку, він час від часу стріляв мені в ногу (наприклад, тому, що я думав, що маю справу зі списками, але насправді все ще мав справу з наборами).
тайм

У нас є такі речі, як автоскоп в OMP, тому трохи його можна виконати. Звичайно, код, над яким я працюю, відключив автоматичне копіювання, тому що ми йому не довіряємо. Я міг бачити наявність інтерактивного компілятора, який запитував "ти мав на увазі XXX?". Ось наскільки я б хотів піти. І навіть це, мабуть, занадто небезпечно.
Омега Кентаврі

12

У IDE для мови програмування зазвичай у цей час є компілятор, який працює якось у фоновому режимі, так що він може надавати послуги аналізу, такі як забарвлення синтаксису, IntelliSense, помилки тощо. Очевидно, що такий компілятор повинен вміти розуміти глибоко зламаний код; більшість часу під час редагування код невірний. Але ми все одно мусимо це зрозуміти.

Однак зазвичай функція відновлення помилок використовується лише під час редагування; це не має великого сенсу, щоб дозволити це для фактичної компіляції у сценаріях "основної лінії".

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

Це кумедна демонстрація, але вона виявляється не дуже хорошою особливістю для сценаріїв "основної лінії" з багатьох причин. Повне пояснення було б досить тривалим; коротке пояснення полягає в тому, що це робить для програм, які працюють непередбачувано і випадково , і важко запускати один і той же код через кілька компіляторів або декілька версій одного компілятора. Великі витрати, які додає функція, не виправдані малими перевагами.

Пітер Торр, який презентував цю функцію, коротко обговорює це в публікації в блозі з 2003 року .

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


Я б хотів, щоб мій роботодавець мав ресурси для експерименту; ми навіть не запускаємо одиничні тести вночі, оскільки є так багато можливостей, які можна додати та помилки :(
робота

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 (так, є й інші причини, але це було однією з перших кількох років тому, перш ніж деякі правила нещільності стали конвенцією ).

Як вважає Ерік Ліпперт, багато з цих речей найкраще справляє IDE, а не компілятор. Щоб ми побачили, що автоматичні біти намагаються накрутити для вас.

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

Безпосереднім прикладом, який спадає на думку, є автоматичні властивості в C # (не єдиній мові, яка має щось подібне). Враховуючи, що більшість гетерів / сеттерів у будь-якій програмі насправді є просто обгортками навколо поля, просто дозвольте розробнику вказати їх наміру і нехай компілятор вводить решту.

Що потім змушує мене задуматися: Більшість мов стилю C вже роблять це певною мірою. Для речей, які можна зрозуміти автоматично, просто вдосконаліть синтаксис:

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

Можна зменшити до:

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

Зрештою, я думаю, що це зводиться до цього: Тенденція полягає в тому, що ви не робите компілятора "розумнішим" або "розпущеним". Це мова, яка робиться розумнішою чи розгубленішою.

Крім того, занадто велика "допомога" може бути небезпечною, наприклад, класична помилка "якщо":

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;

Якщо компілятор додати неявний typecast для призначення, це 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.