=====> COMPILATION PROCESS <======
|
|----> Input is Source file(.c)
|
V
+=================+
| |
| C Preprocessor |
| |
+=================+
|
| ---> Pure C file ( comd:cc -E <file.name> )
|
V
+=================+
| |
| Lexical Analyzer|
| |
+-----------------+
| |
| Syntax Analyzer |
| |
+-----------------+
| |
| Semantic Analyze|
| |
+-----------------+
| |
| Pre Optimization|
| |
+-----------------+
| |
| Code generation |
| |
+-----------------+
| |
| Post Optimize |
| |
+=================+
|
|---> Assembly code (comd: cc -S <file.name> )
|
V
+=================+
| |
| Assembler |
| |
+=================+
|
|---> Object file (.obj) (comd: cc -c <file.name>)
|
V
+=================+
| Linker |
| and |
| loader |
+=================+
|
|---> Executable (.Exe/a.out) (com:cc <file.name> )
|
V
Executable file(a.out)
Препроцессор C: -
Предварительная обработка C является первым этапом компиляции.Он обрабатывает:
#define
операторов. #include
операторов. - Условные операторы.
- Макросы
Цель устройства - преобразовать исходный файл C в файл кода Pure C.
Компиляция C:
В модуле шесть шагов:
1) Lexical Analyzer:
Он объединяет символы в исходном файле, чтобы сформировать «TOKEN».Токен - это набор символов, который не имеет пробела, табуляции и новой строки.Поэтому эта единица компиляции также называется "TOKENIZER".Он также удаляет комментарии, генерирует записи таблицы символов и таблицы перемещения.
2) Синтаксический анализатор:
Этот блок проверяет синтаксис в коде.Например:
{
int a;
int b;
int c;
int d;
d = a + b - c * ;
}
Приведенный выше код сгенерирует ошибку разбора, поскольку уравнение не сбалансировано.Этот модуль проверяет это внутренне, генерируя дерево синтаксического анализатора следующим образом:
=
/ \
d -
/ \
+ *
/ \ / \
a b c ?
Поэтому этот модуль также называется PARSER.
3) Семантический анализатор:
Этот модуль проверяетсмысл в высказываниях.Например:
{
int i;
int *p;
p = i;
-----
-----
-----
}
Приведенный выше код генерирует ошибку «Назначение несовместимого типа».
4) Предварительная оптимизация:
Этот блок не зависит от ЦПесть два типа оптимизации
- Предоптимизация (не зависит от процессора)
- Постоптимизация (зависит от процессора)
Этот блок оптимизирует код следующим образомформы:
- I) Устранение мертвого кода
- II) Устранение субкода
- III) Оптимизация цикла
I) Мертвый кодисключение:
Например:
{
int a = 10;
if ( a > 5 ) {
/*
...
*/
} else {
/*
...
*/
}
}
Здесь компилятор знает значение 'a' во время компиляции, поэтому он также знает, что условие if всегда истинно.Следовательно, он исключает остальную часть в коде.
II) Исключение подкода:
Например:
{
int a, b, c;
int x, y;
/*
...
*/
x = a + b;
y = a + b + c;
/*
...
*/
}
можно оптимизировать следующим образом:
{
int a, b, c;
int x, y;
/*
...
*/
x = a + b;
y = x + c; // a + b is replaced by x
/*
...
*/
}
III) Оптимизация цикла:
Например:
{
int a;
for (i = 0; i < 1000; i++ ) {
/*
...
*/
a = 10;
/*
...
*/
}
}
В приведенном выше коде, если 'a' является локальным и не используется в цикле, тогда это может бытьоптимизируется следующим образом:
{
int a;
a = 10;
for (i = 0; i < 1000; i++ ) {
/*
...
*/
}
}
5) Генерация кода:
Здесь компилятор генерирует код сборки, чтобы наиболее часто используемые переменные сохранялись в регистрах.
6) Постоптимизация:
Здесь оптимизация зависит от процессора.Предположим, что если в коде более одного перехода, то они преобразуются в один из следующих элементов:
-----
jmp:<addr1>
<addr1> jmp:<addr2>
-----
-----
Элемент управления переходит к непосредственному.
Тогда последняя фаза - Linking (котораяисполняемый файл или библиотека).Когда исполняемый файл запущен, необходимые ему библиотеки загружаются.