Як працює компілятор мови c stack overflow російською

Мені потрібно опис роботи компілятора на естествeннoм мовою складене для того хто цієї мови не знає. Тобто підручник в дусі "уяви що ти компілятор, від цього рухаємося далі."

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

заданий 3 дек '15 о 12:29

Ви повинні думати в такий спосіб.

Загальна картина. Компілюються C-файли окремо, компілятор не знає нічого про інших файлах, якщо це не зазначено в файлі явно. Інші файли «втягуються» препроцесором. (Для пуристів, так, я можу згодувати і .h компілятору через Makefile, що не будемо ускладнювати картину без потреби.)

Препроцесор. Він проходиться по коду і виробляє тупі текстові макропідстановки. #define X (Y, Z) for (int i = 0; i

Препроцесор рядків. Усередині строкових і символьних літералів деякі послідовності символів замінюються на інші. Наприклад, \ n замінюється на символ з кодом 10. Також, для літералів широких рядків (wchar_t *) може застосовуватися перекодування з character set'а вихідного файлу в UCS-2 або UCS-4, в залежності від компілятора.

Власне компілятор. Ніякої магії у компілятора немає. Є ключові слова (for. If. Etc.) і функції. Наприклад, printf - це функція (зі стандартної бібліотеки), запис printf ( ". \ N", 15); виробляє в скомпільованому коді виклик функції printf і передачу їй параметрів ". \ n" і 15. Точно так же виклик printf ( ". \ n", ""); виробляє в виклик функції printf з параметрами ". \ n" і "" (цей виклик завершиться з помилкою часу виконання). Компілятор знає точну семантику рядка формату printf і має право видати підказку, якщо він бачить, що типи параметрів не підходять до форматної рядку.

Оптимізатор. Він має право всередині замінити будь-яку конструкцію на більш ефективну, користуючись правилом as if: якщо з точки зору кінцевого висновку і видимих ​​користувачеві значень це не змінює результат, перетворення допустимо. Приклад: якщо у вас є довге обчислення без побічних ефектів, результатом якого ви не користуєтеся (тобто, не виводьте його), оптимізатор має право викинути його. І також має право і не викидати. Наприклад, порядок обчислення доданків у виразі A () + B () не визначено, і навіть якщо функції A і B мають побічні ефекти, оптимізатор має право обчислювати їх в будь-якому порядку, може бути навіть упереміш. Якщо ви хочете гарантувати, що A () обчислити строго перед B (). користуйтеся явною додаткової змінної.

Undefined behaviour. Here be dragons. Існує досить великий набір рантайм-ситуацій (наприклад: разименовніе нульового покажчика, вихід за кордон масиву (!) Або знакова переповнення), коли компілятор перестає нести відповідальність за результат. Компілятор має право припускати, що такого ніколи не трапиться, робити з цього нетривіальні висновки, і застосовувати їх для спрощення коду. Наприклад: для коду

компілятор має право припустити, що звернення m [1] ніколи не відбувається, тому цикл не виконується, тому код повинен вийти на ранньому return. тому cond обов'язково одно true. значить, його можна не обчислювати, і спростити всю функцію до