У якому процесі виникає помилка синтаксису? (токенізація чи розбір)


23

Я намагаюся зрозуміти компіляцію та інтерпретацію, крок за кроком з'ясовуючи загальний образ. Тому я підійшов до питання, читаючи http://www.cs.man.ac.uk/~pjj/farrell/comp3.html цю статтю

Він говорить :

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

Але я не міг зрозуміти, як токенізатор може правильно токенізувати даний потік, який має синтаксичну помилку.

Він повинен застрягнути там чи дати неправильну інформацію парцеру. Я маю на увазі, чи не токенізація також є різновидом перекладача?

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

Наведений приклад маркера всередині вище посилання в заголовку The Tokenizer .

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

Не могли б ви пояснити моє непорозуміння?

Відповіді:


32

Токенізатор - це лише оптимізація аналізатора. Цілком можливо реалізувати аналізатор без токенізатора.

Токенізатор (або лексер, або сканер) розбиває дані до списку лексем. Деякі частини рядка (коментарі, пробіли) зазвичай ігноруються. Кожен маркер має тип (значення цього рядка в мові) та значення (рядок, що складає маркер). Наприклад, фрагмент джерела PHP

$a + $b

могли бути представлені лексемами

Variable('$a'),
Plus('+'),
Variable('$b')

Токенізатор не враховує, чи можливий маркер у цьому контексті. Наприклад, вхід

$a $b + +

радісно виробляв би токен потік

Variable('$a'),
Variable('$b'),
Plus('+'),
Plus('+')

Коли потім аналізатор споживає ці лексеми, він помітить, що дві змінні не можуть слідувати одна за одною, а також два оператори інфіксації не можуть. (Зверніть увагу, що в інших мовах є різні синтаксиси, де такий потік токенів може бути законним, але не в PHP).

Аналізатор може все-таки вийти з ладу на етапі токенізатора. Наприклад, може бути незаконний характер:

$a × ½ — 3

Токенізатор PHP не зміг би зіставити цей вхід зі своїми правилами і створить помилку до початку основного розбору.

Більш формально токенізатори використовуються, коли кожен маркер можна описати як звичайну мову . Токени можуть потім бути узгоджені надзвичайно ефективно, можливо, реалізовані як DFA. На відміну від цього, основна граматика, як правило, не є контекстною і вимагає складнішого, менш ефективного алгоритму розбору, такого як LALR.


Таким чином, ми могли б подумати, що токенізатор є частиною аналізатора, і помилка синтаксису може статися або на етапі токенізації, або на етапі розбору відповідно до форми помилки синтаксису. Дякуємо за роз’яснення.
FZE

4
@FZE: Можна так подумати, але це вводить в оману. Лексінг - це не просто оптимізація парсера. Швидше, лексинг відображає фізичне зображення (деяку послідовність символів) у логічне подання (лексеми, представлені цими символами). Це ізолює аналізатор від дрібниць, наприклад, як представлений кінець рядка, чи ви вирішили представляти логічне і як andабо, &&або щось інше. Це (в основному) окремо і відрізняється від розбору. Оптимізація (якщо така є) - майже випадковий побічний ефект.
Джеррі Труну

@JerryCoffin дякую за подальше пояснення, це має більше сенсу зараз.
FZE

2
@JerryCoffin, амон правильний, що різниця не є принциповою. Ви можете створити згуртовану граматику BNF, яка охоплює і "лексеру", і "парсер". Зазвичай ми класифікуємо правила на низький рівень (наприклад, число, оператор додавання) та високий рівень (підсумовування), але сама граматика такого розрізнення не робить.
Пол Дрейпер

1
@PaulDraper Не впевнений, чи правильний вибір відокремлення звичайної мови як першої фази. Наприклад, збігані пари (не регулярні) можуть бути необхідними для опису рядкових літералів на деяких мовах, але все ж є сенс обробляти їх на першій фазі. Уникнення / мінімізація зворотного відстеження здається кращим орієнтиром.
CodesInChaos

16

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

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

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


11

Токенізатор просто розбиває потік символів на лексеми. Для токенізатора POV це повністю дійсно:

1 * * 1

і перекладається на щось на кшталт: ["1", MULTIPLY, MULTIPLY, "1"] Тільки аналізатор може відкинути такі вирази - він знає, що оператор множення не може слідувати за іншим оператором множення. Наприклад, у JavaScript це створює:

Uncaught SyntaxError: Unexpected token *(…)

Є помилки, які може виявити токенізатор. Наприклад незавершені рядкові літерали: "abcабо недійсні номери: 0x0abcdefg. Вони все ще можуть повідомлятися як синтаксичні помилки:

Uncaught SyntaxError: Unexpected token ILLEGAL

Зауважте, однак маркер не розпізнається і повідомляється як ILLEGAL.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.