Який взаємозв'язок між мовами програмування, регулярними виразами та формальними мовами


25

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

Моє запитання: як саме мови програмування пов'язані з формальними мовами? Скрізь, де я читав, щось уздовж рядків "формальні мови використовуються для визначення граматики мов програмування".

Тепер, з того, що мені вдалося зібрати, формальна мова - це низка правил виробництва, що застосовуються до певного набору символів (алфавіту мови). Ці правила виробництва визначають набір перетворень, таких як:

b -> a

aaa->c

Це можна застосувати так, щоб:

abab->aaaa aaaa-> ca

Як бічна примітка, якщо ми визначимо, що алфавіт нашої формальної мови як {a, b, c}, то a і b є не терміналами, а c - терміналом, оскільки він не може бути перетворений (будь ласка, виправте мене, якщо я помиляюся про що).

Отже, враховуючи все це, як же це стосується мов програмування? Часто також зазначається, що регулярний вираз використовується для розбору мови в його текстовій формі для забезпечення правильності граматики. Це має сенс. Потім заявляється, що регулярні вирази визначаються формальними мовами. Повернення Regex є істинним або хибним (на мій досвід, принаймні) залежно від того, чи досягнуть кінцеві автомати автомати, що представляють регулярний вираз, до мети. Наскільки я бачу, це не має нічого спільного з перетвореннями *.

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

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


* Якщо ви не вважаєте щось на зразок (a|b)*b*c->trueвиробничого правила, то в цьому випадку правило вимагає автоматизованих автоматів з обмеженим станом (тобто: регулярний вираз). Це не має сенсу, як ми щойно це говорили


2
Ви плутаєте формальні граматики з формальними мовами . Граматика являє собою набір правил перезапису , який описує мову. Мова - це набір рядків, описаних граматикою. Тож граматика є альтернативою регулярному вислову: це спосіб описати мову.
reinierpost

@reinierpost Ви абсолютно праві, переглянувши конспекти лекцій університету, я отримав частину цієї інформації, я бачу свою помилку.
Zwander

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

Відповіді:


24

Хто б вам не сказав, що регулярні вирази використовуються для розбору коду, поширював дезінформацію. Класично (я не знаю, наскільки це справедливо в сучасних компіляторах), аналіз коду - перетворення коду з тексту в дерево синтаксису - складається з двох етапів:

  1. Лексичний аналіз: переробляє необроблений текст у шматки, такі як ключові слова , числові константи , рядки , ідентифікатори тощо. Це класично реалізується за допомогою якоїсь машини кінцевого стану, схожої за духом з детермінованим кінцевим автоматом (DFA).

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

Граматики для мов програмування записуються як безконтекстні граматики, і це подання використовується генераторами аналізаторів для побудови для них швидких аналізаторів. Простим прикладом можуть бути деякі нетермінальні ЗВІТЛЕННЯ, а потім правила форми ЗАЯВЛЕННЯ IF-МІСЛЕННЯ, де IF-ЗАЯВКА якщо КОНДИЦІЯ, то БЛОК-ендіф або подібне (де, наприклад, БЛОК ЗВІТ | БЛОК; ЗАЯВКА). Зазвичай ці граматики конкретизуються у формі Backus-Naur (BNF).

Фактичні специфікації мов програмування не є контекстними. Наприклад, змінна не може з'являтися, якщо вона не була оголошена багатьма мовами, а мови з чітким набором тексту не дозволяють призначити ціле число рядкової змінної. Завдання аналізатора полягає лише у перетворенні необробленого коду у форму, яку простіше обробити.

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


Дякую за вашу відповідь, це, безумовно, очистило кілька речей. Це також викликало набагато більше питань. Чи повинен я додати їх до свого запитання чи задати їх тут?
Zwander

5
@Zwander - насправді жоден. На цьому веб-сайті ми хочемо, щоб ви писали одне питання за кожне питання. Це не дискусійний форум: це сайт із запитаннями та відповідями, і ми хочемо, щоб кожне запитання було окремо. Якщо ця відповідь викликає нове запитання, то приділіть деякий час дослідженню цього подальшого питання, і якщо ви не можете знайти відповідь у жодному зі стандартних джерел, опублікуйте нове запитання. (Але переконайтеся, що спочатку подивіться на стандартні ресурси.)
DW

1
@DW Gotcha, ура.
Zwander

3
Перший із двох етапів, які ви згадуєте, зазвичай виконується за допомогою регулярних виразів. Формат кожного маркера зазвичай задається регулярним виразом. Ці регулярні вирази складаються в єдину DFA, потім DFA застосовується до фактичного коду.
kasperd

2
@Zwander Рекурсивний синтаксичний аналіз - це лише одна техніка розбору. Він може або не може генерувати дерево розбору. Взагалі алгоритм розбору означає розробку обчислювальної стратегії дослідження синтаксичного дерева, що міститься в тексті програми. Це дерево синтаксису / синтаксичного розбору може або не може бути виражене в процесі, залежно від стратегії компіляції (кількість етапів). Однак необхідно, що в кінцевому рахунку є хоча б одне дослідження дерева розбору знизу вгору, чи то експлікаційне, так і ліве неявне в структурі обчислень.
бабу

12

Це кілька важких речей для завдання середньої школи.

Відповідь Юваля Філімуса справді хороша, тому це скоріше додаткова відповідь, щоб уточнити деякі моменти, які він висловив.

Формальна мова - це математична конструкція. Їх використання для мов програмування - лише одне з багатьох можливих застосувань; насправді мовознавець Ноам Хомський зробив вагомий внесок у ранню теорію формальних мов. Він винайшов ієрархію Хомського, яка класифікує формальні мови на регулярні, без контексту тощо. Формальні мови також застосовуються в лінгвістиці для опису синтаксису природних мов, таких як англійська. Подумайте про це як про реальні числа: ми можемо використовувати реальні числа для опису як конкретних речей, як відстань від Лос-Анджелеса до Нью-Йорка, так і абстрактних речей, як відношення окружності кола до його діаметра. Хоча обидва ці речі існують незалежно від реальних чисел, реальні числа є корисною системою для їх опису. Формальні мови є корисною системою для опису як англійської, так і Python, оскільки обидві мають подібний структурований формат.

а+б+c=га+б=г-cабc як розмір долара, наприклад, і тоді рівняння має значення.

Класично мова програмування матиме дві граматики: лексичну граматику та синтаксичну граматику. Лексична граматика стосується таких символів, як букви, крапки з комою, дужки та дужки. Зазвичай це звичайна граматика, тому її можна виразити регулярними виразами або DFA або NFA. (Існують докази в формальній теорії мови, які показують, що три еквівалентні по силі - це означає, що вони приймають однаковий набір мов.) Фаза лексингу укладача чи перекладача є своєрідним міні-перекладачем для звичайної граматики мови. Він читає правила граматики і, дотримуючись цих правил, згрупує окремі символи в лексеми. Наприклад, якщо мова має ifвислів, схожий на більше, ніж C, лексема може зібрати символів iі fв один маркерIF, потім знайдіть дужки, що відкриваються, і виведіть маркер OPEN_PAREN, потім обробіть все, що є між дужками, а потім знайдіть дужки, що закриваються, і виведіть a CLOSE_PAREN. Коли лексеми зроблено лексеми, він передає їм аналізатор, який визначає, чи маркери насправді формують дійсні заяви мови програмування. Отже, якщо ви пишете ip a == bна Python, лексер просто робить все можливе, щоб здогадатися, який маркер ip(мабуть, більшість лексемів буде прийнятий за ідентифікатор), і передає його в аналізатор, який скаржиться, тому що ви не можете мати ідентифікатор у цій позиції.

аб

Давайте розглянемо граматичні правила для ifвисловлювання Python . Це правило:

if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]

Це правило говорить нам про те, як буде ifрозбиратися аналізатор, якщо рядок лексем, надісланий із лексеру, є анотацією. Будь-яке слово в одинарних лапках повинно з’являтися саме так у вихідному коді, тож аналізатор буде шукати звичайне слово if. Потім аналізатор спробує співставити деякі лексеми з правилом для test:

test: or_test ['if' or_test 'else' test] | lambdef

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

Якщо аналізатору вдасться відповідати деяким лексемам test, він спробує відповідати двокрапці. Якщо це вдасться, він спробує співставити ще кілька маркерів, використовуючи правило для suite. Розділ ('elif' test ':' suite)*означає, що ми можемо мати будь-яку кількість повторень буквального тексту elif, за яким слід щось, що збігається test, а потім двокрапка, а потім щось, що відповідає suite. Ми також можемо мати нульові повтори; зірочка в кінці означає "нуль або стільки, скільки ми хочемо".

В самому кінці є ['else' ':' suite]. Ця частина укладена у квадратні дужки; це означає, що ми можемо мати нуль або один, але не більше. Для того, щоб відповідати цьому, парсеру потрібно відповідати буквальному тексту else, двокрапці, а потім a suite. Ось правило для suite:

suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT

Це в основному блок на мовах подібних С. Оскільки Python використовує нові рядки та відступи для позначення речей, лексери виводять NEWLINE, INDENTі DEDENTлексеми, щоб повідомити аналізатору, звідки починався новий рядок, де починався відступ коду та де він повертався до зовнішнього рівня відступу.

Якщо будь-яка з цих спроб збігу не вдалася, аналізатор позначає помилку та зупиняється. Якщо розбір всієї програми буде успішним, аналізатор, як правило, будує дерево розбору, як Юваль висвітлював у своїй відповіді, і, можливо, таблицю символів та інші структури даних, що зберігають семантичну інформацію. Якщо мова набрана статично, компілятор буде обходити дерево розбору та шукати помилки типу. Він також ходить по дереву розбору, щоб генерувати код низького рівня (мова збірки, байт-код Java, .Net Intermediate Language або щось подібне), який саме працює.

Як вправу я рекомендую взяти граматику деякої мови програмування, з якою ви знайомі (знову ж таки, Python , Java , і ось C # , Javascript , C ) і спробувати проаналізувати щось просте, як, можливо, x = a + b;або if (True): print("Yay!"). Якщо ви шукаєте щось простіше, є також приємна граматика для JSON , яка в основному охоплює лише синтаксис об'єктних літералів у Javascript (як {'a': 1, 'b': 2}). Удачі, це згинання мозку, але це виявляється дуже цікаво, коли ви не в якийсь божевільний термін.


Я знаю, що я не повинен публікувати тут "спасибі", але ура, що знайшов час, щоб пояснити все це. "Це важкі речі для завдання в середній школі". Намір завдання - перекинутися на вершину та поговорити про регулярні вирази, але, як завзятий студент з інформатики, я хотів отримати всю картину. Вся тема захоплююча.
Zwander

1
@Zwander Я щойно закінчив коледж, і більшість моїх факультативів були такі речі. Я пам’ятаю, що був повністю розгублений і все-таки повністю поглинений Можливо, вам також сподобаються статті про дизайн компілятора, згадані в цьому блозі , або книги « Вступ до теорії обчислень» Майкла Сіпсера та Джона К. Мартіна, « Вступ до мов та теорія обчислень» . Ви можете знайти дешеві використані копії на Amazon. Вони роблять формальну теорію мови приблизно такою ж простою, як це буде.
цлейсон

10

Коротко

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

Формальні мови - це синтаксис без значення. Він має на меті вивчити структуру наборів рядків, визначених формально, не надаючи значення цим рядкам.

Регулярне вираження та інші формалізми (наприклад, граматики без контексту) використовуються для визначення формальних мов, використовуваних як синтаксичний компонент програмування та природних мов, тобто для подання речень структурованим чином. Інші механізми використовуються для зв'язку цієї структури з семантикою мов програмування.

Тут багато чого спрощено, особливо щодо природної мови.

З набагато більше деталей

Щоб відповісти на ваше запитання, ми повинні почати спочатку. Мова у звичному розумінні - це неофіційно засіб передачі інформації чи ідей. У мові зазвичай розрізняють синтаксис і семантику. Семантика - це те, про що ти хочеш поговорити / написати. інформацію, яку ви хочете передати. Синтаксис - це засіб, який ви використовуєте для його передачі, тобто звичайне представлення, яке можна обмінюватися між людьми, а тепер також між людьми та пристроями, або між пристроями (комп'ютерами).

Як правило, ви будете використовувати слово, dogщоб передати ідею собаки. Слово dogскладається з трьох букв, або якогось еквівалентного звучання, і покликане представляти якусь тварину. Ключова ідея полягає в тому, що спілкування здійснюється через представлення того, що має бути передано. Структури представлення зазвичай називають синтаксисом, тоді як те, що представлено, називається семантикою. Це більше або менше стосується як природної мови, так і мови мов програмування.

Слова - це синтаксичні утворення, які представляють більш-менш елементарні смислові поняття. Але ці елементарні поняття мають бути складені різними способами, щоб надати більш складного значення. Ми пишемо, the dogщоб передати, що ми маємо на увазі конкретну собаку, і the dog bites the catпередати більш складну ідею. Але спосіб організації слів має бути зафіксований правилами, щоб ми могли сказати, хто з собаки та кота насправді кусає іншого.

Тож у нас є такі правила, як такі sentence -> subject verb complement, які повинні відповідати реченням і розповідати, як ідеї, пов'язані з кожною частиною, артикулюються. Ці правила є синтаксичними правилами, оскільки вони говорять нам про те, як слід організувати представлення нашого повідомлення. Сам subjectкан може бути визначений правилом subject -> article nounтощо.

2х+1=23х123

equation -> expression "=" expression  
expression -> expression "+" expression 
expression -> number

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

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

Тож те, що ми бачимо в мові, - це переважно синтаксис та його структура. Наведений вище приклад - лише один із найпоширеніших способів визначення синтаксичних рядків та їх структурної організації. Є й інші. Для даної мови деяким рядкам може бути призначена структура, і, як кажуть, належать до мови, а інші - ні.

Те саме стосується слів. Деякі послідовності літер (або звукових) є законними словами, а інші - ні.

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

На практиці мова структурована на два рівні. Лексичний рівень визначає слова, побудовані з алфавіту символів. Синтаксичний рівень визначає речення, або програми, побудовані з алфавіту слів (а точніше із сімей слів, щоб він залишався скінченним алфавітом). Це обов'язково дещо спрощується.

Структура слів досить проста у більшості мов (програмова або природна), так що їх зазвичай визначають тим, що зазвичай вважається найпростішим видом формальної мови: звичайними мовами. Їх можна визначити за допомогою регулярних виразів (regexp) і досить легко ототожнювати з запрограмованими пристроями, які називаються автоматизаторами кінцевого стану. У випадках мов програмування приклади слова - це ідентифікатор, ціле число, рядок, дійсне число, зарезервоване слово, таке як if або repeat, розділовий символ або відкрита дужка. Прикладами сімей слів є ідентифікатор, рядок, ціле число.

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

statement -> assignment
statement -> loop
loop ->  "while" expression "do" statement
assignment -> "identifier" "=" expression
expression -> "identifier"
expression -> "integer"
expression -> expression "operator" expression

За допомогою таких правил ви можете писати:

while aaa /= bbb do aaa = aaa + bbb / 6 що є твердженням.

А спосіб її отримання може бути представлений структурою дерева, що називається деревом розбору або деревом синтаксису (тут не повне):

                          statement
                              |
            _______________  loop _______________
           /      /                 \            \
      "while" expression           "do"       statement
       __________|_________                       |
      /          |         \                  assignment
 expression "operator" expression          _______|_______
     |           |          |             /       |       \
"identifier"   "/="   "identifier" "identifier"  "="   expression
     |                      |            |                 |
    aaa                    bbb          aaa             ... ...

Імена, що з’являються зліва від правила, називаються нетермінальними, тоді як слова називаються також термінальними, оскільки вони є в алфавіті для мови (вище лексичного рівня). Нетермінальні представляють різні синтаксичні структури, які можна використовувати для складання програми.

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

Насправді існують обмеження щодо цього, коли ідентифікатори потрібно спочатку оголосити, або коли вираз повинен відповідати обмеженням типу. Але таке обмеження може розглядатися як семантичне, а не синтаксичне. Насправді деякі фахівці розміщують їх у тому, що вони називають статичною семантикою .

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

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

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

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

Наприклад, речення the dog bites the catможна проаналізувати за допомогою правила sentence -> subject verb complement. Знаючи зміст 3 Поддер subject, verbі complement, зазвичай , яке складових їх говорять нам про те , що суб'єкт робить дію, і що кішка є той , хто кусає.

Це лише інтуїтивне пояснення, але його можна формалізувати. Семантика побудована вгору від складових. Але це приховує чимало складностей.

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


Дивовижно, дуже корисно. Я розумію, що регекс використовується в процесі токенізації (наприклад, рядковий літерал можна визначити за "[^"]*"його найпростішою формою, ігноруючи символи евакуації тощо), але чи він також використовується при створенні дерева синтаксису (Розмова з точки зору мов програмування)? Я припускаю, що це не так, як автомати з кінцевим станом, за визначенням кінцеві. Синтаксичне дерево, навіть для одного ifтвердження, може бути теоретично нескінченним через введення. Таким чином, регулярний вираз, будучи автоматизованим кінцевим станом, не може використовуватися з метою генерування синтаксичного дерева.
Zwander

@Zwander thx 4 редагування - Ваш приклад регулярного вираження правильний (я мав би навести кілька прикладів). До речі, Regex також є мовою, має власну семантику у світі безлічі рядків та з синтаксисом без контексту ( CF ). Він використовується лише для токенізації мовного рядка, принаймні для мов програмування, як правило, для визначення більшого синтаксису, який використовується для дерев синтаксису, за винятком короткої руки в розширеному BNF (EBNF). Додавання Регексу в якійсь формі до складніших формалізмів не змінює їх виражальну силу в більшості випадків. Ваші зауваження щодо нескінченності не зовсім правильні. Дивіться наступний коментар.
бабу

@Zwander Всі формалізми (формальні мови) описані остаточно. Це фундаментальна гіпотеза. Навіть якщо вас цікавить, скажімо, граматика CF з нескінченною кількістю правил, ви повинні дати кінцевий опис цієї нескінченності правил. Також нескінченність грає на вас трюки (для цього немає місця). ifЗатвердження необмеженої (як завгодно великий) , але завжди звичайно. Кінцево визначеним нескінченним ifє a while. Різниця між CF та регулярною полягає в тому, що CF контролює / дозволяє вкладати (тобто круглість), а звичайний - не. Але обидва докладно описані і дозволяють не обмежувати рядки.
babou

1
@Zwander Формалізм повинен вміти представляти будь-яке добре сформоване речення (програму), але лише добре сформоване речення. Простіше кажучи, FSA не може рахувати без обмежень. Тож вони не можуть знати, скільки дужок було відкрито, які слід закрити, або належним чином вкласти два різних дужки. Багато мовних структур мають «приховані» дужки. Це не просто питання перевірки синтаксису, а головним чином означає, що відповідна структура дерева не може бути виражена і побудована, з чого вивести семантику. Відновлення адекватної структури дерева вимагає проведення підрахунку.
babou

1
(((А-Б)+3)×С)

2

Є суттєві відмінності. Головне серед них, я б сказав, полягає в тому, що для розбору справжніх мов програмування йдеться про обробку синтаксичних помилок. З формальною мовою ви просто скажете "ну це не в мові", але компілятор, який каже, що це не дуже корисно - він повинен сказати вам, що не так, і якщо це була невелика помилка, в ідеалі продовжуйте розбиратися, щоб вона могла повідомляти про більше помилок. Багато досліджень (і впровадження зусиль) йде в цьому. Тож насправді ви навіть не так переймаєтесь справжнім / хибним результатом, просто хочете проаналізувати структуру вхідних даних. Формальні мови використовуються як інструмент, і там багато перекривань, але ви справді вирішуєте іншу проблему.

Крім того, у більшості мов було вибрано не застосовувати певні речі в граматиці , наприклад, згаданий вами приклад, "змінна не може з'являтися, якщо вона не була оголошена". Це, як правило, річ, яку парсер буде повністю ігнорувати, а потім потрапляє в окремий аналіз (семантичний аналіз), який дивиться на таку річ і не впливає на такі міркування, як контекстність. Але не завжди - наприклад, для розбору C часто використовується хакерська лексема , а C ++ - відомий приклад мови, який неможливо розібрати без одночасного аналізу серйозного семантичного аналізу (насправді розбір C ++ не можна визначити, оскільки шаблони Turing завершені ). На більш простих мовах вона, як правило, розділяється, але так простіше.


1

Формальна мова - це набір слів - де слово - це рядок символів з якогось алфавіту.

Це означає, що ваше поєднання виробничих правил і формальної мови занадто сильне. Неправильно, що формальною мовою є правила виробництва. Скоріше правила виробництва визначають формальну мову. Формальна мова - це слова, які можуть бути вироблені виробничим правилом. (Це вимагає, щоб формальна мова була такою, яку можна визначити виробничими правилами, наприклад, звичайні мови можуть бути визначені контекстною вільною граматикою)

Так звичайна мова, що відповідає виразу (a|b)*c*d, визначається виробничими правилами;

S->ACd
A->
A->aA
A->bA
C->
C->cC

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


0

Існує ще одна залежність між регулярними виразами та мовами програмування, що стосується семантики. Основними керуючими конструкціями імперативної мови є послідовний склад (зробіть А, а потім В), вибір (зробіть А чи В) та повторення (зробіть А знову і знову).

Ці ж три способи поєднання поведінки знаходять у регулярних виразах. Увімкніть виклики підпрограми, і у вас є аналогія з EBNF.

Тож існує велика схожість між алгеброю регулярних виразів та алгеброю команд. Це детально досліджує Дайкстра у "Об'єднанні трьох калькуляцій". Це також основа CCS Мілнера, яка дає відповідь на питання: що робити, якщо додати паралелізм?

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