Як створити власну мову програмування та компілятор для неї [закрито]


427

Я ретельно займаюся програмуванням і натрапив на мови, включаючи BASIC, FORTRAN, COBOL, LISP, LOGO, Java, C ++, C, MATLAB, Mathematica, Python, Ruby, Perl, JavaScript, Assembly та ін. Я не можу зрозуміти, як люди створюють мови програмування та розробляють компілятори для цього. Я також не міг зрозуміти, як люди створюють ОС, такі як Windows, Mac, UNIX, DOS тощо. Інше, що для мене загадкове, - це те, як люди створюють бібліотеки, такі як OpenGL, OpenCL, OpenCV, Cocoa, MFC тощо. Останнє, чого я не можу з’ясувати, - це те, як вчені розробляють мову складання та асемблер для мікропроцесора. Я дуже хотів би дізнатися всі ці речі, і мені 15 років. Я завжди хотів бути комп'ютерним співробітником, як-то Беббідж, Тьюрінг, Шеннон чи Денніс Річі.


Я вже читав компіляторну програму Aho та програму концепцій ОС Tanenbaum, і всі вони лише обговорюють поняття та код на високому рівні. Вони не вникають у подробиці та нюанси та як створити компілятор чи операційну систему. Я хочу конкретного розуміння, щоб я міг сам створити його, а не просто розуміти, що таке нитка, семафор, процес чи розбір. Я запитав свого брата про все це. Він є студентом на бакалавраті в ЄЕС на МІТ і не має поняття, як насправді створити всі ці речі в реальному світі. Все, що він знає, - це лише розуміння дизайну компілятора та ОС, наприклад, тих, про які ви згадали, хлопці (наприклад, такі як Нитка, Синхронізація, Паралельність, управління пам’яттю, Лексичний аналіз, Проміжне генерування коду тощо)


Якщо ви на Unix / Linux, ви можете отримати інформацію про спеціальні інструменти: lex, yaccі bison.
mouviciel

Першою моєю пропозицією було б прочитати книгу Дракона Ахо. amazon.com/Compilers-Principles-Techniques-Alfred-Aho/dp/…
Джуліан

1
Можливо, не надто корисно, але я рекомендую перейти через sites.google.com/site/steveyegge2/blog-rants (блог Стіва Йегге) та steve-yegge.blogspot.com/ (інший блог Стіва Йегге).
КК.

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

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

Відповіді:


407

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

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

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

Мене це дивно, але багато людей дивляться на мови програмування як на чарівні. Коли я зустрічаюся з людьми на вечірках чи що завгодно, якщо вони запитують мене, що я роблю, я їм кажу, що я розробляю мови програмування та впроваджую компілятори та інструменти, і це дивно, скільки разів люди - професійні програмісти, зауважте, - скажіть "Ух, я ніколи про це не думав, але так, хтось повинен створити ці речі". Це так, як вони думали, що мови просто зароджуються повністю сформованими за допомогою інфраструктури навколо них.

Вони не просто з'являються. Мови розроблені як і будь-який інший продукт: ретельно здійснюючи серію компромісів серед конкуруючих можливостей. Компілятори та інструменти побудовані як і будь-який інший професійний програмний продукт: розбиваючи проблему, записуючи по одному рядку коду за один раз, а потім випробовуючи чорт із отриманої програми.

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

Крім того, розгляньте домен, який вас цікавить, а потім розробіть доменну мову (DSL), яка визначає рішення проблем у цьому домені. Ви згадали LOGO; це чудовий приклад DSL для домену "малювання ліній". Регулярні вирази - це DSL для домену "знайти шаблон у рядку". LINQ в C # / VB - це DSL для домену "фільтр, об'єднання, сортування та проектування". HTML - це DSL для домену "опишіть макет тексту на сторінці" тощо. Є безліч доменів, які піддаються мовним рішенням. Один з моїх улюблених - Inform7, що є DSL для домену "текстова пригодницька гра"; це, мабуть, серйозна мова програмування найвищого рівня, яку я коли-небудь бачив.

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

  1. лексичні : які правила щодо слів у мові, які символи є законними, як виглядають цифри тощо.
  2. синтаксичний : як слова мови поєднуються у більші одиниці? У більшій одиниці C # знаходяться такі речі, як вирази, висловлювання, методи, класи тощо.
  3. семантично : з урахуванням синтаксично юридичної програми, як ви з'ясуєте, що робить програма ?

Запишіть ці правила якомога точніше . Якщо ви добре працюєте над цим, то можете використовувати це як основу для написання компілятора чи перекладача. Погляньте на специфікацію C # або специфікацію ECMAScript, щоб побачити, що я маю на увазі; вони переповнені дуже точними правилами, які описують, що робить легальна програма і як розібратися, що робити.

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

Я пишу блог про дизайн C #, VB, VBScript, JavaScript та інших мов та інструментів; якщо ця тема вас цікавить, перевірте це. http://blogs.msdn.com/ericlippert (історичний) та http://ericlippert.com (поточний)

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

http://blogs.msdn.com/b/ericlippert/archive/2010/02/04/how-many-passes.aspx

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


Ви писали про те, наскільки оптимізація компілятора вже не проводиться, оскільки CLR може робити їх автоматично?

6
@ Thorbjørn: Давайте будемо зрозумілі щодо термінології. "Компілятор" - це будь-який пристрій, який перекладає з однієї мови програмування на іншу. Однією з приємних речей, що є компілятор C #, який перетворює C # в IL, і компілятор IL ("тремтіння"), який перетворює IL в машинний код, - це те, що ви можете написати компілятор C # в IL (легко!), І помістити оптимізацію процесора в тремтіння. Справа не в тому, що оптимізація компілятора "не робиться", це те, що команда компілятора jit робить їх для нас. Дивіться blogs.msdn.com/b/ericlippert/archive/2009/06/11/…
Ерік Ліпперт

6
@ Cyclotis04: Inform6 компілює Z-код, який є відомим надзвичайно раннім прикладом віртуальної машини на основі байт-коду. Ось як усі ці ігри Infocom у 1980-х роках могли бути як більшими, ніж пам'ять, так і портативними для багатьох архітектур; ігри були складені до z-коду, а потім інтерпретатори z-коду з підказками пам’яті коду були реалізовані для декількох машин. Сьогодні, звичайно, ви можете запустити інтерпретатор zcode на наручних годинниках, якщо вам потрібно, але ще в той день, який був високотехнологічним . Детальніше дивіться на en.wikipedia.org/wiki/Z-machine .
Ерік Ліпперт

@EricLippert Compiler - це не пристрій, пристрій - це щось, що містить апаратне забезпечення. Ми можемо сказати заздалегідь задану програму, яка має набір правил для перетворення вхідних даних у машинний код
dharam

2
@dhams: пристрій - це будь-яка річ, зроблена для певної мети. Кожен компілятор, про який я коли-небудь писав, працював на апаратному забезпеченні, яке було створене для того, щоб дозволити існуванню компіляторів.
Ерік Ліпперт

127

Ви можете знайти Lets Build a Compiler від Jack Crenshaw цікавим вступом до написання компіляторів та мови складання.

Автор тримав це дуже просто та зосереджено на побудові фактичної функціональності.


2
Що цікаво про вступ Креншова, це те, що він закінчується (спойлер: він є неповним) приблизно в той час, коли ви почнете придивлятися до тих питань, які б змусили вас усвідомити. І тоді ви кажете, ей, якщо мені доведеться написати повну специфікацію мови, чому б не зробити це в офіційній нотації, що потім я можу подати в інструмент для створення аналізатора? І тоді ти робиш це, як і всі.
kindall

3
@kindall, вам потрібно зробити це вручну, щоб зрозуміти, що є причина використовувати інструменти.

72

дуже хотів би дізнатися цей матеріал". Якщо ви довгостроково серйозні:

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

  • Дотримуйтесь уроків математики через середню школу та продовжуйте навчання в коледжі всі 4 роки. Зосередьтеся на нестандартній математиці: логіці, теорії груп, метаматематиці. Це змусить вас мислити абстрактно. Це дасть вам змогу прочитати передові статті теорії щодо складання та зрозуміти, чому ці теорії цікаві та корисні. Ви можете ігнорувати ці передові теорії, якщо назавжди хочете відстати від найсучаснішого.

  • Збирайте / читайте стандартні тексти компілятора: Aho / Ullman тощо. Вони містять те, що спільнота, як правило, погоджується - це фундаментальний матеріал. Ви можете не використовувати все з цих книг, але ви повинні знати, що воно існує, і ви повинні знати, чому ви не використовуєте його. Я думав, що Мухнік чудовий, але це для досить просунутих тем.

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

  • Справді гарне місце для початку - дізнатися про BNF (Backus Naur Form), парсери та генератори парсера. BNF ефективно використовується повсюдно в землі компілятора, і ви не можете реально спілкуватися зі своїми колегами-компіляторами, якщо ви цього не знаєте.

Якщо ви хочете чудово ознайомитись зі збиранням та прямим значенням BNF не лише для документації, а як мета -мови, що обробляється інструментом, дивіться цей підручник (не мій) про створення "мета" компіляторів (компіляторів, що створюють компілятори) на основі папір з 1964 р. (так, ви читаєте це право) ["META II - синтаксично орієнтована мова написання компілятора" Валь Шорре. (http://doi.acm.org/10.1145/800257.808896)] Цей ІМХО - одна з найкращих наукових робіт, написаних коли-небудь: вона вчить будувати компілятори-компілятори на 10 сторінках. Я дізнався спочатку з цієї роботи.

Те, про що я писав вище, дуже багато з особистого досвіду, і я думаю, що це мені досить добре послужило. YMMV, але IMHO, не дуже.


54
-1 Нічого з перерахованого вище не потрібно.
Ніл Баттерворт

77
@nbt Нічого з перерахованого вище не потрібно. Але все вищесказане допомагає. Дійсно багато.
Конрад Рудольф

1
Я особливо не погоджуюся з "Навчіться математиці мислити абстрактно!" навіювання. Навіть якщо ви думаєте, що "навчитися мислити абстрактно" особливо корисно для створення власної мови програмування та компілятора (я не знаю - мені здається, що набагато корисніше вчитися на практиці, ніж брати ці кругові, неймовірно непрямі маршрути) , математика - не єдине поле з абстрактною думкою! (Я математик btw, тому я взагалі не заперечую використання математики, просто її застосовність у цьому конкретному випадку ...)
grautur

26
Якщо ви хочете прочитати передові технічні документи з теорії компілятора, вам краще бути математично компетентним. Ви можете вирішити ігнорувати цю літературу, і ваша теорія, а отже, і компілятори будуть для неї біднішими. Тут найменувачі говорять про те, що ви можете створити компілятор без великої кількості формальної освіти, і я згоден. Вони, мабуть, означають, що ви можете створити справді хороші компілятори без цього. Це не ставка, яку я хотів би взяти.
Іра Бакстер

7
CS - це дисципліна, яка справді корисна для розробки та впровадження мови. Звичайно, це не обов'язково, але існували десятиліття досліджень, які можна і потрібно використовувати, і взагалі немає підстав повторювати інші помилки.
Дональні стипендіати

46

Ось онлайн-книга / курс, який ви можете прослідкувати під назвою «Елементи обчислювальних систем: побудова сучасного комп’ютера з перших принципів» .

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

Глави:

  1. Огляд курсу
  2. Булева логіка
  3. Комбінаторні фішки
  4. Послідовні фішки
  5. Мова машини
  6. Комп'ютерна архітектура
  7. Асемблер
  8. Віртуальна машина I: Арифметика
  9. Віртуальна машина II: управління
  10. Мова програмування
  11. Компілятор I: Синтаксичний аналіз
  12. Компілятор II: Генерація коду
  13. Операційна система
  14. Елемент списку

Більше весело їхати


Дякую за правки, невідома людина. Я кілька разів спробував, але не зміг достатньо зосередити свої думки на описі ... але не хотів згадувати про книгу. Книга зараз в Інтернеті за посиланням Плану дослідження: www1.idc.ac.il/tecs/plan.html . Це також дуже доступно в Інтернеті. Радуйте всіх.
Joe Internet

Я збирався запропонувати це сам ... для ледачих, ознайомтеся з 10-хвилинним вступом: від NAND до тетрісу в 12 кроків @ youtube.com/watch?v=JtXvUoPx4Qs
Річард Ентоні Хайн

46

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

Мови не повинні бути мовами програмування. Вони можуть бути будь-якою мовою, правила якої можна записати. Ви напевно бачили Google Translate ; це компілятор, оскільки він може перекласти одну мову (скажімо, німецьку) на іншу (можливо, японську).

Інший приклад компілятора - це механізм візуалізації HTML. Його вхід - це HTML-файл, а вихід - це низка інструкцій для малювання пікселів на екрані.

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

Чи можете ви написати програму, яка перевертає кожне слово в рядку? Наприклад:

When the cat's away, the mice will play.

стає

nehW eht s'tac yawa, eht ecim lliw yalp.

Програму написати не так складно, але потрібно подумати про деякі речі:

  • Що таке "слово"? Чи можете ви визначити, які символи складають слово?
  • Де починаються і закінчуються слова?
  • Чи розділені слова лише одним пробілом, чи їх може бути більше - або менше?
  • Чи потрібно також переставити розділові знаки?
  • Що про розділові знаки всередині слова?
  • Що відбувається з великої літери?

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

Як щодо цього: Чи можете ви написати програму, яка бере низку інструкцій з малювання та виводить файл PNG (або JPEG)? Можливо, щось подібне:

image 100 100
background black
color red
line 20 55 93 105
color green
box 0 0 99 99

Знову ж таки, вам потрібно буде подумати, щоб визначити мову:

  • Які примітивні інструкції?
  • Що відбувається після слова "рядок"? Що настає після "кольору"? Так само для "фону", "коробки" тощо.
  • Що таке число?
  • Чи дозволений пустий вхідний файл?
  • Чи гаразд з великої літери слів?
  • Чи дозволені негативні числа?
  • Що станеться, якщо ви не дасте директиву "зображення"?
  • Чи правильно не вказати колір?

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

Розумієте, написати компілятор не так складно. Компілятори, які ви використовували в Java або C, - це просто більші версії цих двох прикладів. Тож піди на це! Визначте просту мову та напишіть програму, яка змусить цю мову щось робити. Рано чи пізно ви захочете поширити мову. Наприклад, ви можете додати змінні або арифметичні вирази. Ваш компілятор стане складнішим, але ви зрозумієте кожен його фрагмент, тому що ви його написали самостійно. Ось так і з’являються мови та компілятори.


7
myFirstCompiler = (str) -> ("" + (str || "")). split (''). reverse (). join (''); jsfiddle.net/L7qSr
Битва Ларрі

21

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


4
Зауважте, вам може знадобитися трохи більше фактичного досвіду, щоб отримати максимальну користь від цієї книги. Хоча велика довідка.

13
-1 Тільки той, хто її не читав, може подумати, що книжка-дракон корисна. і це особливо не стосується питання.
Ніл Баттерворт

33
Книга Дракона? Для захопленого п’ятнадцятирічного віку? Я вважаю за краще, щоб він довше тримав ентузіазм.
Девід Торнлі

1
Більш доступна альтернатива: «Прагматика мови програмування» 3е .
willjcroz

@DavidThornley Не рахуй його повністю (Так, я розумію, що це дуже стара публікація). Я почав досліджувати, як мови працюють у віці 15 років і зосередився спеціально на віртуальних машинах. Зараз мені 16, і після місяців досліджень, письма та переписування я маю працюючого перекладача та упорядника, яким я задоволений.
Девід

10

"Давайте побудуємо компілятор" вже було запропоновано. Існує "модернізована" версія, що використовує Haskell замість Turbo Pascal: http://alephnullplex.appspot.com/blog/view/2010/01/12/lbach-1-introduction

За допомогою Haskell, є дуже повчальний інтерпретатор схеми, який може дати подальші ідеї: Напишіть собі схему за 48 годин


10

Не вірте, що у компіляторі чи ОС є щось магічне: немає. Пам’ятаєте програми, які ви написали, щоб рахувати всі голосні в рядку або додавати числа в масиві? Компілятор не відрізняється концепцією; це просто набагато більше.

Кожна програма має три етапи:

  1. прочитати деякі речі
  2. обробляти цей матеріал: перевести вхідні дані у вихідні дані
  3. написати інші речі - вихідні дані

Подумайте: що вводиться до компілятора? Рядок символів з вихідного файлу.

Що виводиться з компілятора? Рядок байтів, що представляють машинні інструкції до цільового комп'ютера.

Отже, що таке фаза "процесу" компілятора? Що робить ця фаза?

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


3
Як сказав Ніл, правда, але не корисно. Фундаментальні аспекти компілятора, такі як таблиці рекурсивних граматик та символів, не є очевидними.
Мейсон Уілер

1
@ Mason Wheeler: Я думаю, хто реально прагне написати компілятор (і спроектувати цільову мову?), Швидше за все, вважатиме, що рекурсивні граматичні та символьні таблиці є досить базовими поняттями.
FumbleFingers

8

Я не експерт, але ось мій удар:

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

Викрасти хтось інший відповідь із SO ( https://stackoverflow.com/questions/3826692/how-do-i-translate-assembly-to-binary ), збірка виглядає так:

label:  LDA #$00
        JMP label

Потім ви запускаєте його через асемблер і перетворюєтесь на щось подібне:

$A9 $00
$4C $10 $00

Тільки все це розсипано, ось так:

$A9 $00 $4C $10 $00

Це справді не магія.

Ви не можете записати це в блокнот, оскільки блокнот використовує ASCII (не шістнадцятковий). Ви б скористалися шістнадцятковим редактором або просто записували байти програмно. Ви записуєте цей шістнадцятковий файл у файл, називаєте його "a.exe" або "a.out", а потім повідомляєте ОС запустити його.

Звичайно, сучасні процесори та операційні системи справді досить складні, але це основна ідея.

Якщо ви хочете написати новий компілятор, ось як це робиться:

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

2) Напишіть перекладача. Перекладіть свою мову, скажімо, на Javascript. Тепер ваша мова працюватиме в браузері.

3) Напишіть перекладача на щось нижчий рівень, наприклад, LLVM, C або Assembly.

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

4) (Безглуздо) Напишіть оптимізатор. Над цим працюють десятки років.

4) (Здоров'я) Включіться у існуючу спільноту. GCC, LLVM, PyPy, основна команда, яка працює над будь-яким перекладачем.


8

Кілька інших дали чудові відповіді. Я просто додам ще кілька пропозицій. По-перше, гарною книгою для того, що ви намагаєтеся зробити, є тексти впровадження сучасного компілятора Appel (виберіть C , Java або Standard ML ). Ця книга переносить вас через повну реалізацію компілятора простої мови, Tiger, для складання MIPS, яку можна запустити в емуляторі, а також мінімальну бібліотеку підтримки часу виконання. Для одного проходу все необхідне для складання мовного твору, це досить гарна книга 1 .

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

Нарешті, я згадав, що Appel має свій текст на мовах C, Java та Standard ML - якщо ви серйозно ставитесь до побудови компілятора та мов програмування, рекомендую вивчити ML та використовувати цю версію Appel. Мови сімейства ML мають системи сильного типу, які є переважно функціональними - особливості, які будуть відрізнятися від багатьох інших мов, тому вивчення їх, якщо ви ще не знаєте функціональної мови, відточить ваше мовне ремесло. Крім того, їх відповідність шаблонам та функціональні набори думок надзвичайно добре підходять до тих типів маніпуляцій, які потрібно часто робити в компіляторі, тому компілятори, написані мовами на основі ML, як правило, набагато коротші та простіші для розуміння, ніж компілятори, написані на C, Java або подібні мови. Книга Харперана Standard ML - досить хороший посібник для початку роботи; Проблема цього допоможе вам підготувати вас до впровадження стандартної книги компілятора Appel. Якщо ви вивчите Standard ML, то також буде досить легко підібрати OCaml для подальшої роботи; IMO, він має кращі інструменти для працюючого програміста (більш інтегровано інтегрується з навколишнім середовищем ОС, легко виробляє виконувану програму та має деякі вражаючі інструменти для створення компіляторів, такі як ulex та Menhir).


1 Для довгострокової довідки я віддаю перевагу Книзі Драконів, оскільки в ній є більше деталей щодо речей, які я, швидше за все, посилаюся на такі, як внутрішня робота алгоритмів парсера та ширше висвітлення різних підходів, але книга Аппеля дуже хороша за перший прохід. В основному, Appel вчить вас одним із способів робити все цілком через компілятор і проводити вас через нього. Книга Драконів більш детально висвітлює різні альтернативи дизайну, але надає набагато менше вказівок щодо того, як налагодити щось.


Відредаговано : замініть некоректну посилання Aho на Sethi, згадайте CTMCP.


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

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

6

Мені довелося створити компілятор для класу в коледжі.

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

Після того, як ви закінчите граматику (правила вашої мови), написання компілятора настільки ж просто, як і лише слідування цим правилам. Компілятори зазвичай переводяться в машинний код, але якщо ви не хочете вивчити x86, я пропоную вам поглянути на MIPS або зробити власну віртуальну машину.

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

Удачі!


8
Концептуально простий? Так. Насправді просто? Ні.
Ніл Баттерворт

7
Ум. Після сканування / розбору компілятору необхідно зробити перевірку / висновок, оптимізацію, розподіл реєстру тощо тощо. Ці кроки можуть бути простими. (Використовуючи інтерпретований код, ви просто відкладаєте ці частини до етапу виконання.)
Макке

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

6

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

Тепер, коли я це написав, мені доведеться перечитати його.



5

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

По-перше, питання про те, як працює комп’ютер? Це так: Введення -> Обчислення -> Вихід.

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

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

Щоб відповісти на це, нам потрібно зрозуміти структуру процесора. Далі - досить простий погляд. Процесор по суті складається з двох частин. Один - це набір пам'яті, вбудований всередині процесора, який служить робочою пам'яттю. Вони називаються «регістри». Друга - це купа електронних машин, побудованих для виконання певних операцій з використанням даних у регістрах. Є два спеціальні регістри, що називаються «Програма лічильника» або ПК та «Реєстр інструкцій», або ІР Процесор вважає пам'ять розділеною на три частини. Перша частина - це «пам'ять програми», в якій зберігається виконана комп'ютерна програма. Друга - «пам'ять даних». Третій використовується для якихось спеціальних цілей, про це ми поговоримо пізніше. Лічильник програм містить місце наступної інструкції для читання з пам'яті програми. Лічильник інструкцій містить число, яке посилається на поточну операцію, що виконується. Кожна операція, яку може виконувати процесор, посилається на число, яке називається опкодом операції. Як працює комп'ютер, він читає місце пам'яті, на яке посилається лічильник програм, в Реєстр інструкцій (і збільшує лічильник програм так, щоб він вказував на місце пам'яті наступної інструкції). Далі він зчитує Реєстр інструкцій та виконує бажану операцію. Наприклад, інструкцією може бути зчитування певного місця пам'яті в регістрі, або запис у якийсь реєстр, або виконання певної операції, використовуючи значення двох регістрів, і запис результатів у третій регістр. Лічильник інструкцій містить число, яке посилається на поточну операцію, що виконується. Кожна операція, яку може виконувати процесор, посилається на число, яке називається опкодом операції. Як працює комп'ютер, він читає місце пам'яті, на яке посилається лічильник програм, в Реєстр інструкцій (і збільшує лічильник програм так, щоб він вказував на місце пам'яті наступної інструкції). Далі він зчитує Реєстр інструкцій та виконує бажану операцію. Наприклад, інструкцією може бути зчитування певного місця пам'яті в регістрі, або запис у якийсь реєстр, або виконання певної операції, використовуючи значення двох регістрів, і запис результатів у третій регістр. Лічильник інструкцій містить число, яке посилається на поточну операцію, що виконується. Кожна операція, яку може виконувати процесор, посилається на число, яке називається опкодом операції. Як працює комп'ютер, він читає місце пам'яті, на яке посилається лічильник програм, в Реєстр інструкцій (і збільшує лічильник програм так, щоб він вказував на місце пам'яті наступної інструкції). Далі він зчитує Реєстр інструкцій та виконує бажану операцію. Наприклад, інструкцією може бути зчитування певного місця пам'яті в регістрі, або запис у якийсь реєстр, або виконання певної операції, використовуючи значення двох регістрів, і запис результатів у третій регістр. Кожна операція, яку може виконувати процесор, посилається на число, яке називається опкодом операції. Як працює комп'ютер, він читає місце пам'яті, на яке посилається лічильник програм, в Реєстр інструкцій (і збільшує лічильник програм так, щоб він вказував на місце пам'яті наступної інструкції). Далі він зчитує Реєстр інструкцій та виконує бажану операцію. Наприклад, інструкцією може бути зчитування певного місця пам'яті в регістрі, або запис у якийсь реєстр, або виконання певної операції, використовуючи значення двох регістрів, і запис результатів у третій регістр. Кожна операція, яку може виконувати процесор, посилається на число, яке називається опкодом операції. Як працює комп'ютер, він читає місце пам'яті, на яке посилається лічильник програм, в Реєстр інструкцій (і збільшує лічильник програм так, щоб він вказував на місце пам'яті наступної інструкції). Далі він зчитує Реєстр інструкцій та виконує бажану операцію. Наприклад, інструкцією може бути зчитування певного місця пам'яті в регістрі, або запис у якийсь реєстр, або виконання певної операції, використовуючи значення двох регістрів, і запис результатів у третій регістр. Як працює комп'ютер, він читає місце пам'яті, на яке посилається лічильник програм, в Реєстр інструкцій (і збільшує лічильник програм так, щоб він вказував на місце пам'яті наступної інструкції). Далі він зчитує Реєстр інструкцій та виконує бажану операцію. Наприклад, інструкцією може бути зчитування певного місця пам'яті в регістрі, або запис у якийсь реєстр, або виконання певної операції, використовуючи значення двох регістрів, і запис результатів у третій регістр. Як працює комп'ютер, він читає місце пам'яті, на яке посилається лічильник програм, в Реєстр інструкцій (і збільшує лічильник програм так, щоб він вказував на місце пам'яті наступної інструкції). Далі він зчитує Реєстр інструкцій та виконує бажану операцію. Наприклад, інструкцією може бути зчитування певного місця пам'яті в регістрі, або запис у якийсь реєстр, або виконання певної операції, використовуючи значення двох регістрів, і запис результатів у третій регістр.

Тепер, як комп'ютер виконує введення / вихід? Я дам дуже спрощену відповідь. Дивіться http://en.wikipedia.org/wiki/Input/output та http://en.wikipedia.org/wiki/Interrupt. для більш. Він використовує дві речі, третю частину пам'яті і щось, що називається Переривання. Кожен пристрій, підключений до комп'ютера, повинен мати можливість обмінюватися даними з процесором. Це робиться з використанням третьої частини пам'яті, згаданої раніше. Процесор виділяє шматочок пам'яті кожному пристрою, а пристрій і процесор спілкуються через цей фрагмент пам'яті. Але як процесор знає, яке розташування посилається на який пристрій і коли пристрою потрібно обмінюватися даними? Тут відбувається надходження переривань. Переривання - це, по суті, сигнал процесору, щоб призупинити те, що він є, і зберегти всі регістри у відомому місці, а потім почати робити щось інше. Там багато переривань, кожен ідентифікується унікальним числом. Для кожного переривання існує спеціальна програма, пов’язана з ним. Коли відбувається переривання, процесор виконує програму, відповідну перериванню. Тепер, залежно від біографії та того, як апаратні пристрої підключені до материнської плати комп'ютера, кожен пристрій отримує унікальний перерив і шматочок пам'яті. Під час завантаження операційної системи за допомогою біоси визначає місце переривання та пам'ять кожного пристрою та встановлює спеціальні програми для переривання для належного поводження з пристроями. Тому коли пристрою потрібні деякі дані або хочуть надіслати деякі дані, це сигналізує про перерву. Процесор призупиняє те, що робить, обробляє переривання і повертається до того, що робить. Існує багато видів переривань, таких як hdd, клавіатура тощо. Важливим із них є системний таймер, який викликає переривання через рівні проміжки часу. Також є опкоди, які можуть викликати переривання, звані програмними перериваннями.

Зараз ми майже можемо зрозуміти, як працює операційна система. Коли він завантажується, os встановлює таймер переривання, щоб він керував osм через рівні проміжки часу. Він також встановлює інші переривання для обробки інших пристроїв і т. Д. Тепер, коли на комп'ютері працює купа програм, а тимчасове переривання трапляється, осі отримує контроль і виконує важливі завдання, такі як управління процесами, управління пам’яттю і т.д. абстрактний спосіб доступу програм до апаратних пристроїв, а не дозволити їм отримати доступ безпосередньо до пристроїв. Коли програма хоче отримати доступ до пристрою, вона викликає якийсь код, наданий os, який потім спілкується з пристроєм. У них багато теорії, яка стосується паралельності, потоків, блокування, управління пам'яттю тощо.

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

Як ідеться про розробку процесора та мови складання. Щоб знати, що вам потрібно прочитати деякі книги з архітектури комп’ютера. (див. глави 1-7 книги, на яку посилається Джо-Інтернет). Це включає вивчення булевої алгебри, побудови простих комбінаторних схем для додавання, множення тощо, як побудувати пам'ять та послідовні схеми, як побудувати мікропроцесор тощо.

А тепер як писати комп'ютерні мови. Можна почати з написання простого асемблера в машинному коді. Потім використовуйте цей асемблер, щоб написати компілятор для простого підмножини C. Потім використовуйте цей підмножина C, щоб написати більш повну версію C. Нарешті, використовуйте C, щоб написати більш складну мову, наприклад python або C ++. Звичайно, щоб написати мову, ви повинні спершу її розробити (так само, як і для процесора). Ще раз подивіться на деякі підручники з цього приводу.

І як можна написати ос. Спочатку ви орієнтуєтесь на платформу, таку як x86. Тоді ви з'ясуєте, як вона завантажується і коли буде викликати ваш ос. Типовий ПК завантажується таким чином. Він запускається, і біос проводить деякі тести. Потім біос читає перший сектор hdd і завантажує вміст у певне місце в пам'яті. Потім він налаштовує процесор, щоб розпочати виконання цих завантажених даних. Це пункт, на який ви звертаєтесь. Типовий ос у цей момент завантажує спокій самої пам'яті. Потім він ініціалізує пристрої та налаштовує інші речі, і нарешті вітає вас з екраном входу.

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

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


4

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

Що зв'язало це, було знайти конкретний проект, який потрібно зробити (а потім з'ясувати, що мені потрібен лише невеликий підмножина всієї теорії).

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

Пограйте з декомпілятором та привіт, Всесвітній клас на Java. Прочитайте специфікацію JVM і спробуйте зрозуміти, що відбувається. Це дасть вам обґрунтоване розуміння того, що робить компілятор .

Потім пограйте з кодом, який створює клас Hello, World. (Насправді ви створюєте компілятор, що відповідає додатку, для вузькоспеціалізованої мови, на якій ви можете сказати лише Hello, World.)

Спробуйте написати код, який зможете прочитати в Hello, World, написаному якоюсь іншою мовою, і виведіть той самий клас. Зробіть так, щоб ви могли змінити рядок з "Привіт, світ" на щось інше.

Тепер спробуйте скласти (у Java) клас, який обчислює деякий арифметичний вираз, наприклад "2 * (3 + 4)". Візьміть цей клас окремо, напишіть «компілятор іграшок», який зможе знову скласти його.


3

1) Чудові відео лекції з Вашингтонського університету:

Конструкція компілятора CSE P 501 - осінь 2009 www.cs.washington.edu/education/courses/csep501/09au/lectures/video.html *

2) SICP http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/ І книга з такою ж назвою. Це насправді є обов'язковим для будь-якого інженера-програміста там.

3) Також про функціональне програмування, Haskell, обчислення лямбда, семантику (включаючи денотаційну) та реалізацію компілятора для функціональних мов. Ви можете почати з 2005-SS-FP.V10.2005-05-24.HDV, якщо ви вже знаєте Haskell. Відео Uxx - це відповіді. Спершу слідкуйте за відео Vxx .

http://video.s-inf.de/#FP.2005-SS-Giesl.(COt).HD_Videoaufzeichnung

(відео - англійською, інші курси - німецькою.)

  • нові користувачі можуть розміщувати максимум дві гіперпосилання.

3

ANTLR - хороша відправна точка. Це структура, що генерує мову, схожа на Lex та Yacc. Існує gui під назвою ANTLRWorks, який спрощує процес.

У світі .NET існує динамічний режим виконання мови, який можна використовувати для генерування коду у світі .NET. Я написав мову вираження під назвою Zentrum, яка генерує код за допомогою DLR. Він покаже вам, як розбирати та виконувати статичні та динамічно набрані вирази.


2

Для простого ознайомлення з тим, як працюють компілятори та як створити власну мову програмування, я рекомендував би нову книгу http://createyourproglang.com, яка зосереджується більше на теорії дизайну мови, не знаючи про внутрішні пристрої ОС / процесора, тобто лексеми, парсери , перекладачі тощо.

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


2

Якщо все, що ви говорите, вірно, у вас є профіль перспективного дослідника, і конкретне розуміння можна отримати лише одним шляхом: навчання. І я не кажу " Читай усі ці книги з інформатики високого рівня (особливо ці ), написані цим генієм !"; Я маю на увазі: ви повинні бути з людьми високого рівня, щоб бути комп'ютерними науковцями, такими як Чарльз Беббідж, Алан Тьюрінг, Клод Шеннон або Денніс Річі. Я не зневажаю самоуків (я один з них), але там не так багато людей, як ви. Я серйозно рекомендую програму Symbolic Systems (SSP) в університеті Стенфорда . Як говориться на їхньому веб-сайті:

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

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

2

Я підкажу щось із лівого поля: вивчіть Python (чи, можливо, Рубі, але я маю набагато більше досвіду роботи в Python, тому це я обговорюватиму). І не просто поспішати в ньому, а реально познайомитися з ним на глибокому рівні.

Я пропоную це кілька причин:

  1. Python - надзвичайно добре розроблена мова. У той час як у нього кілька бородавок, у ньому менше IMHO, ніж у багатьох інших мовах. Якщо ви є дизайнером з початкових мов, добре піддавати себе якомога більше хороших мов.

  2. Стандартна реалізація Python (CPython) є відкритим кодом та добре задокументована, що полегшує розуміння того, як мова працює під кришкою.

  3. Python складається з простого байтового коду, який легше зрозуміти, ніж збірка, і який працює однаково на всіх платформах, на яких працює Python. Тож ви дізнаєтесь про компіляцію (оскільки Python компілює ваш вихідний код у байт-код) та інтерпретацію (оскільки цей байт-код інтерпретується у віртуальній машині Python).

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

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

  6. Python дозволяє легко розширювати мову різними способами за допомогою декораторів, метакласів, імпортних гачків тощо, так що ви можете грати з новими мовними функціями в тій чи іншій мірі, фактично не залишаючи мови. (Вбік: блоки коду є першокласними об'єктами в Ruby, тому ви можете фактично писати нові структури управління, такі як петлі! У мене складається враження, що програмісти Ruby не обов'язково вважають, що розширення мови, хоча саме так ви програмуєте в Ruby. Але це дуже круто.)

  7. У Python ви можете фактично розібрати байт-код, сформований компілятором, або навіть написати свій власний з нуля і дозволити інтерпретатору виконати це (я це робив сам, і це було розумним згином, але весело).

  8. У Python є хороші бібліотеки для розбору. Ви можете проаналізувати код Python в абстрактному синтаксичному дереві, а потім маніпулювати ним за допомогою модуля AST. Модуль PyParsing корисний для розбору довільних мов, наприклад тих, які ви розробляєте. Теоретично ви можете написати свій перший компілятор мови в Python, якщо хочете (а це може генерувати вихід C, збірку чи навіть Python).

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

Веселіться!


Не копати на python, але це поруч із пунктом. У малюка вже є N мов для великих N; збільшення N не матиме великої різниці. Візьмемо, наприклад, С. Це стандартно. У ньому багато бібліотек. Це крос-платформа (коли ви дотримуєтесь стандарту). Ви можете розібрати вихід. Можна написати CFront. І так.
Ян

1

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

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

Серце операційної системи - це ядро, яке керує ресурсами (наприклад, розподілом пам'яті / розсилкою пам'яті) і перемикається між завданнями / процесами / програмами.

Асемблер - це перетворення тексту в> байт.

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

Я рекомендував би написати це на C; C - це lingua franca для цього рівня роботи.


1
З іншого боку, це прекрасне місце для мови на високому рівні. Поки ви можете диктувати окремі байти у файлі, ви можете зробити компілятор / асемблер (що простіше) будь-якою мовою. Скажи, перл. Або VBA. Небо, можливості!
Ян

1

Дивіться книгу Кеннета Лудена "Конструкція компілятора"

http://www.cs.sjsu.edu/~louden/cmptext/

Це забезпечує кращий практичний підхід до розробки компілятора.

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


1

Мене благословило, що я зазнав PDP-8, як моєї першої мови складання. PDP-8 мав лише шість інструкцій, які були настільки простими, що легко уявити їх реалізацію кількома стриманими компонентами, якими вони насправді були. Це дійсно вилучило «магію» з комп’ютерів.

Іншим шлюзом до того ж одкровення є мова «збірки», яку Кнут використовує у своїх прикладах. Сьогодні "Мікс" здається архаїчним, але він все ще має таку містифікуючу дію.


0

Компілятори та мови програмування (і все, включаючи побудову однієї, - наприклад, визначення обмеженої граматики та перетворення на складання) - дуже складна задача, яка потребує великого розуміння щодо систем в цілому. Цей тип курсу, як правило, пропонується як 3-й / 4-й курс Comp Sci класу в університеті.

Я настійно рекомендую спочатку краще зрозуміти Операційні системи взагалі та те, як існуючі мови компілюються / виконуються (наприклад, власне (C / C ++), в VM (Java) або інтерпретатором (Python / Javascript)).

Я вважаю, що ми використовували книгу Концепції операційної системи Авраама Сільберсхаца, Пітера Б. Галвіна, Грега Гагне в моєму курсі "Операційні системи" (на 2 курсі). Це була відмінна книга, яка детально ознайомилась з кожним компонентом операційної системи - трохи дорого, але варто того, і старіші / використані копії повинні плавати навколо.


Концепції ОС? Дуже мало цього потрібно для створення компілятора. Необхідне розуміння архітектури програмного забезпечення: розглядає пробіли, стеки, теми (якщо він хоче вивчити компілятори, то краще дізнайся про паралелізм, його майбутнє).
Іра Бакстер

Відразу після того, як сказав, що хоче вивчити мовний дизайн та компілятори, він сказав, що хоче дізнатися про ОС.
Девід Торнлі

@Ira - погодився. Я ніколи не заявляв, що для розуміння ОС потрібна побудова компілятора / мови, я просто пояснював, що це може бути простішою відправною точкою. Усі роблять акцент на «компіляторному» аспекті свого питання, але він також зазначив, що хоче краще розуміти ОС і бібліотеки. Для 15-річного віку, який ще вивчає архітектури, було б набагато корисніше зрозуміти управління пам'яттю, нарізування, блокування, введення / виведення тощо., Ніж навчитися визначати граматику з yacc (IMHO)
plafond

Вибачте ... пропустив питання про бажання дізнатися про (побудову?) ОС. Я можу сказати: йому не потрібно багато знань про ОС для компіляторів. Насправді, це зовсім інша тема, за винятком випадків, коли компілятор і ОС взаємодіють для досягнення певної колективної мети. (Multics вимагала від своїх компіляторів PL / 1 для побудови функціональних викликів певними способами, наприклад, для включення глобальної VM).
Іра Бакстер

0

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

Більшість компіляторів та / або перекладачів працюють так:

Токенізація : скануйте текст коду та розбийте його на список лексем.

Цей крок може бути складним, оскільки ви не можете просто розділити рядок на пробіли, ви повинні розпізнати, що if (bar) foo += "a string";це список з 8 лексем: WORD, OPEN_PAREN, WORD, CLOSE_PAREN, WORD, ASIGNMENT_ADD, STRING_LITERAL, TERMINATOR. Як бачите, просто розділити вихідний код на пробіли не вийде, вам потрібно прочитати кожен символ як послідовність, тому якщо ви зіткнетеся з буквено-цифровим символом, ви продовжуєте читати символи, поки не потрапите на нелітерний символ, і цей рядок ви щойно прочитане - це СЛОВ, яке згодом буде класифіковано далі. Ви можете самі вирішити, наскільки зернистий ваш токенізатор: чи він проковтує "a string"один маркер, який називається STRING_LITERAL, для подальшого розбору, чи він бачить"a string" як OPEN_QUOTE, UNPARSED_TEXT, CLOSE_QUOTE або будь-що інше, це лише один із багатьох варіантів, які ви повинні вирішити для себе, коли кодуєте його.

Лекс : Отже, тепер у вас є список жетонів. Ви, ймовірно, позначили деякі лексеми двозначною класифікацією на кшталт WORD, тому що під час першого проходу ви не витрачаєте занадто багато зусиль, намагаючись розібратися в контексті кожного рядка символів. Тож тепер знову прочитайте список переліку токенів-джерел та перекласифікуйте кожен неоднозначний жетон з більш конкретним типом маркера на основі ключових слів вашої мови. Отже, у вашому списку спеціальних ключових слів, що називаються символом, є такі слова, як "якщо" та "якщо", тож ви змінюєте тип символу цього маркера зі WORD на IF, а також будь-яке WORD, яке відсутнє у вашому спеціальному списку ключових слів , як-от WORD foo, є ідентифікатором.

Розбираємо : Отже , тепер ви повернули if (bar) foo += "a string";список lexed лексем , який виглядає так: IF OPEN_PAREN ідентіфікторов CLOSE_PAREN IDENTIFIER ASIGN_ADD STRING_LITERAL TERMINATOR. Крок - розпізнавання послідовностей лексем як висловлювань. Це розбір. Ви робите це за допомогою граматики, наприклад:

ЗАЯВЛЕННЯ: = ASIGN_EXPRESSION | IF_STATEMENT

IF_STATEMENT: = IF, PAREN_EXPRESSION, STATEMENT

ASIGN_EXPRESSION: = IDENTIFIER, ASIGN_OP, VALUE

PAREN_EXPRESSSION: = OPEN_PAREN, VALUE, CLOSE_PAREN

ЗНАЧЕННЯ: = IDENTIFIER | STRING_LITERAL | PAREN_EXPRESSION

ASIGN_OP: = РІВНЕ | ASIGN_ADD | ASIGN_SUBTRACT | ASIGN_MULT

Постановки, які використовують "|" між термінами означає "відповідати будь-якому з цих", якщо у ньому є коми між термінами, це означає "відповідати цій послідовності термінів"

Як ти цим користуєшся? Починаючи з першого жетона, спробуйте співставити свою послідовність жетонів з цими видами. Отже, спершу ви намагаєтеся зіставити свій список токенів із STATEMENT, тому ви прочитаєте правило для STATEMENT, і воно говорить "ЗВІТ про те, що це або ASIGN_EXPRESSION, або IF_STATEMENT", тому ви спершу намагаєтеся відповідати ASIGN_EXPRESSION, тому ви шукаєте правило граматики для ASIGN_EXPRESSION і він говорить: "ASIGN_EXPRESSION - це IDENTIFIER, за яким слідує ASIGN_OP, а потім - VALUE, тому ви шукаєте граматичне правило для IDENTIFIER, і ви бачите, що для IDENTIFIER немає граматики, тому це означає, що IDENTIFIER є" терміналом ". синтаксичний аналіз, щоб зрівняти його, тож ви можете спробувати співставити його безпосередньо з вашим маркером. Але ваш перший джерельний маркер - це АБО, а якщо ІФ не є ідентифікатором, тому збіг не вдався. Що тепер? Ви повертаєтесь до правила STATEMENT і намагаєтеся відповідати наступному терміну: IF_STATEMENT. Ви шукаєте IF_STATEMENT, він починається з IF, пошук IF, IF - термінал, порівняйте термінал з вашим першим жетоном, IF token match, awesome продовжуйте, наступний термін - PAREN_EXPRESSION, пошук PAREN_EXPRESSION, це не термінал, це перший термін, PAREN_EXPRESSION починається з OPEN_PAREN, пошук OPEN_PAREN, це термінал, відповідність OPEN_PAREN до наступного маркера, він відповідає, .... і так далі.

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

Кожен раз, коли синтаксичний аналіз () відповідає виробництву типу ASIGN_EXPRESSION, ви створюєте структуру, що представляє цей фрагмент коду. Ця структура містить посилання на початкові маркери джерела. Ви починаєте складати список цих структур. Ми назвемо всю цю структуру абстрактним синтаксичним деревом (AST)

Скомпілювати та / або виконати . Для певних виробництв у вашій граматиці ви створили функції обробника, які, якщо надати структуру AST, вона склала б або виконала цю частину AST.

Отже, давайте розглянемо фрагмент вашого AST, який має тип ASIGN_ADD. Тож як інтерпретатор ви маєте функцію ASIGN_ADD_execute (). Ця функція передається як фрагмент AST, який відповідає дереву розбору для foo += "a string", тому ця функція розглядає цю структуру, і вона знає, що перший член структури повинен бути IDENTIFIER, а другий член - VALUE, тому ASIGN_ADD_execute () передає термін VALUE функції VALUE_eval (), яка повертає об'єкт, що представляє оцінене значення в пам'яті, потім ASIGN_ADD_execute () робить пошук "foo" у вашій таблиці змінних і зберігає посилання на те, що було повернуто eval_value () функція.

Це перекладач. Натомість компілятор мав би функції обробника переводити AST в байт-код або машинний код, а не виконувати його.

Кроки від 1 до 3 та деякі 4 можуть бути спрощені за допомогою таких інструментів, як Flex та Bison. (він же. Лекс і Якк), але написання перекладача з нуля - це, мабуть, наймогутніша вправа, яку може досягти будь-який програміст. Усі інші проблеми програмування здаються тривіальними після цього саміту.

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

Прочитайте ці, і удачі!

http://www.iro.umontreal.ca/~felipe/IFT2030-Automne2002/Complements/tinyc.c

http://en.wikipedia.org/wiki/Recursive_descent_parser


2
Ви робите те, що вважаю класичною помилкою, коли люди думають про компіляцію: це вважає, що проблема полягає в розборі. ЧАСТИНА ТЕХНІЧНО ЛЕГКА; є чудові технології для цього. Важкою частиною компіляції є семантичний аналіз, оптимізація на високому та низькому рівнях представлення програми та генерація коду, зростаючи в цей час на коді PARALLEL. Ви довіряєте це повністю у своїй відповіді: "компілятор мав би функції обробника для переведення AST в байтний код". Там ховається 50 років теорії компілятора та техніки.
Іра Бакстер

0

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

Мій улюблений дуже базовий комп'ютер - це релейний комп'ютер Гаррі Портера . Це дає аромат того, як працює комп’ютер на базовому рівні. Тоді ви можете почати розуміти, чому потрібні такі речі, як мови та операційні системи.

Річ у тому, що важко щось зрозуміти, не розуміючи, що це потрібно . Удачі, і не просто читайте речі. Робіть речі.



-1

Ще однією хорошою вступною книгою є «Компілербау» Н. Віртта (1986 р. (Побудова компілятора)), яка становить близько 100 сторінок і пояснює стислий, добре розроблений код для іграшкової мови PL / 0, включаючи парсер, генератор коду та віртуальну машину. Він також показує, як написати парсер, який читається в граматиці для розбору в позначеннях EBNF. Книга німецькою мовою, але я написав резюме та переклав код на Python як вправу, див. Http://www.d12k.org/cmplr/w86/intro.html .


-1

Якщо ви зацікавлені в розумінні суті мов програмування, я б запропонував вам працювати над книгою PLAI (http://www.cs.brown.edu/~sk/Publications/Books/ProgLangs/), щоб зрозуміти поняття та їх реалізація. Це також допоможе вам створити власну мову.


-1

Якщо у вас справді є інтереси до компілятора, і ніколи цього не робили, ви можете почати з створення калькулятора для обчислення арифметичних формул (свого роду DSL, як згадував Ерік). Існує багато аспектів, які вам слід врахувати для цього типу компілятора:

  • Дозволені числа
  • Дозволені оператори
  • Пріоритети оператора
  • Перевірка синтаксису
  • Змінний механізм пошуку
  • Виявлення циклу
  • Оптимізація

Наприклад, у вас є наступні формули, ваш калькулятор повинен мати можливість обчислити значення x:

a = 1
b = 2
c = a + b
d = (3 + b) * c
x = a - d / b

Починати з цього не дуже важкого компілятора, але ви можете змусити вас задуматися про деякі основні ідеї того, що таке компілятор, а також допоможуть вам покращити свої навички програмування та контролювати якість свого коду (це насправді є ідеальною проблемою, Test Driven Development TDD може застосувати для покращення якості програмного забезпечення).

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