Створюючи аналізатор на мові програмування, що я заробляю і що втратив, вибравши те чи інше?
Створюючи аналізатор на мові програмування, що я заробляю і що втратив, вибравши те чи інше?
Відповіді:
Я буду протиставляти LL та LR синтаксичний аналіз для кількох критеріїв:
Складність
LL виграє тут, руки вниз. Ви можете легко вручну написати парсер LL. Насправді це зазвичай робиться: компілятор Microsoft C # - це рукописний рекурсивний аналізатор походження (джерело тут , шукайте коментар Патріка Крістіансена - публікація в блозі також дуже цікава).
LR розбір використовує досить протиінтуїтивний метод для розбору тексту. Це працює, але мені знадобилося певний час, щоб обернути голову, як саме це працює. Писати такий аналізатор вручну важко: ви б більш-менш реалізували генератор аналізаторів LR.
Загальність
LR виграє тут: усі мови LL - це мови LR, але є більше мов LR, ніж мови LL (мова - це мова LL, якщо вона може бути розібрана з LL-аналізатором, а мова - це мова LR, якщо її можна розібрати аналізатор LR).
LL має досить багато неприємностей, які будуть турбувати вас при впровадженні майже будь-якої мови програмування. Дивіться тут для огляду.
Є однозначні мови, які не є LR мовами, але вони досить рідкісні. Ви майже ніколи не стикаєтесь з такими мовами. Однак LALR має кілька питань.
LALR - це більш-менш хак для LR-парсерів, щоб зменшити таблиці. Таблиці для аналізатора LR зазвичай можуть стати величезними. LALR-парсери відмовляються від можливості аналізувати всі мови LR в обмін на менші таблиці. Більшість парсерів LR насправді використовують LALR (хоча не секретно, зазвичай ви можете точно знайти те, що він реалізує).
LALR може скаржитися на конфлікти зменшення та зменшення змін. Це спричинене злому таблиці: вона "згортає" подібні записи разом, що працює, оскільки більшість записів порожні, але коли вони не порожні, це створює конфлікт. Такі помилки не є природними, важко зрозуміти, а виправлення, як правило, досить дивні.
Помилки компілятора та відновлення помилок
LL виграє тут. У синтаксичному розборі LL зазвичай легко видавати корисні помилки компілятора, зокрема в рукописних аналізаторах. Ви знаєте, чого очікуєте далі, тому, якщо він не з’явиться, ви зазвичай знаєте, що пішло не так і яка найрозумніша помилка.
Крім того, при розборі LL відновлення помилок набагато простіше. Якщо введення не розбирається правильно, ви можете спробувати трохи пропустити вперед і з’ясувати, чи решта входу правильно аналізує. Якщо, наприклад, деякий оператор програмування неправильно сформований, ви можете пропустити вперед і проаналізувати наступний вислів, щоб ви могли отримати кілька помилок.
Використовувати LR-аналізатор, це набагато складніше. Ви можете спробувати збільшити свою граматику, щоб вона приймала помилкове введення та друкувала помилки в тих областях, де все пішло не так, але це зазвичай зробити досить важко. Шанс, що опинишся в граматиці, що не є LR (або не LALR), також збільшується.
Швидкість
Швидкість насправді не є проблемою з тим, як ти розбираєш свій вхід (LL або LR), а швидше з якістю отриманого коду та використанням таблиць (ти можеш використовувати таблиці як для LL, так і для LR). Тому LL і LR порівнянні в цьому відношенні.
Посилання
Ось посилання на сайт, який також контрастує LL та LR. Шукайте розділ внизу.
Тут ви можете знайти розмову щодо відмінностей. Непогано критично дивитись на думки, озвучені там, хоча там відбувається трохи священної війни .
Для отримання додаткової інформації, тут і тут є два мої власні пости про парсери, хоча вони не суворо стосуються контрасту між LL та LR.