Самостоятельный компилятор

Вес товара: ~0.7 кг. Указан усредненный вес, который может отличаться от фактического. Не включен в цену, оплачивается при получении.
Описание товара
- Информация о товаре
- Фотографии


![]() |


![]() |




![]() |


![]() |


![]() |


Эта книга поможет читателям создать компилятор языка с нуля.Автор специально разработал язык C для этой книги.Можно сказать, что язык C является подмножеством языка C, которое реализует основные части языка C, включая арифметику указателей.
Компилятор, реализованный в этой книге, представляет собой компилятор языка C. Это настоящий компилятор, а не игрушка со множеством ограничений.Кроме того, помимо компилятора, в этой книге также упоминается рабочая среда языка программирования, в центре которой находится компилятор, то есть компилятор, ассемблер, компоновщик, аппаратное обеспечение, среда выполнения и т. д., а также представлены все аспекты выполнения программы.

Глава 1
Начать создавать компилятор 1
1.1 Обзор этой книги 2
Тема 2 этой книги
Компилятор 2, созданный по этой книге
Компилируем пример 2
Исполняемый файл 3
Скомпилировать 4
Среда выполнения программы 6
1.2 Процесс компиляции 8
4 этапа компиляции 8
Синтаксический анализ 8
Семантический анализ 9
Сгенерировать промежуточный код 9
Генерация кода 10
Оптимизация 10
Резюме 10
1.3 Компиляция с использованием C?компилятор 11
Необходимая среда для компилятора C 11
Установить С? Компилятор 11
C? Привет, мир! 12
Глава 2
С? и КБС 13
2.1 Обзор языка C 14
C? Привет, мир! 14
Функция удалена в C? 14
импортировать ключевое слово 15
Характеристики импорта файлов 16
2.2 Состав компилятора C cbc 17
дерево кодов cbc 17
сумка cbc 18
Классы в пакете компилятора 18
Реализация основной функции 19
Реализация командыОсновная функция 19
Дженерики Java5 20
Реализация функции сборки 20
Оператор foreach в Java 5 21
Реализация функции компиляции 21
Часть 1. Анализ кода
Глава 3
Краткое изложение грамматического анализа 24
3.1 Методы синтаксического анализа 25
Проблемы анализа кода 25
Общие правила анализа кода 25
Лексический анализ, синтаксический анализ, семантический анализ 25
Действие сканера 26
Виды и смысловые значения слов 27
token 28
Абстрактное синтаксическое дерево и узлы 29
3.2 Генератор парсера 30
Что такое парсер-генератор 30
Типы генераторов парсеров 30
Выбор генератора парсера 31
3.3 Обзор JavaCC 33
Что такое JavaCC 33
Синтаксис Описание Файл 33
Пример файла описания грамматики 34
Запуск JavaCC 35
Запуск парсера, созданного JavaCC 36.
Китайская обработка 37
Глава 4
Лексический анализ 39
4.1 Описание сканера на базе JavaCC 40
Цель настоящей главы 40
Регулярные выражения для JavaCC 40
Фиксированная строка 41
Соединение 41
Группа символов 41
Исключенная группа символов 41
Повторите 1 или более раз 42
Повторите 0 или более раз 42
Повторите n-m раз 42.
Повторите ровно n раз 43
можно опустить 43
Выберите 43
4.2 Сканирование слов без структуры 44
Команда ТОКЕН 44
Сканирование идентификаторов и зарезервированных слов 44
Выберите правило соответствия 45.
Значение сканирования 46
4.3 Сканирование слов, которые не генерируют токены 48
Команда SKIP и команда SPECIAL_TOKEN 48
Пропустить пробелы 48
Пропускать комментарии 49
4.4 Сканирование слов со структурой 50
Принцип самого длинного совпадения и его проблемы 50
Сканирование на основе миграции состояний 50
БОЛЬШЕ команда 51
Пропустить блокировку комментариев 52
Сканирование строковых литералов 53
Сканировать символьный литерал 53
Глава 5
Описание парсера на базе JavaCC 55
5.1 Описание на основе грамматики EBNF 56
Цель настоящей главы 56
Описание грамматики на основе JavaCC 56
Терминальные и нетерминальные символы 57
Обозначение EBNF для JavaCC 58
Соединение 58
Повторите 0 или более раз 59
Повторите 1 или более раз 59
Выберите 60
60 можно опустить
5.2 Грамматическая неоднозначность и предварительное сканирование токенов 61
Грамматическая двусмысленность 61
Ограничения JavaCC 62
Извлекаем общую часть слева 63
Предварительное сканирование токена 63
Правила и конфликты, которые можно опустить 64
Дублирование и конфликт 65
Более гибкое упреждающее сканирование 66
Меры предосторожности, связанные с упреждающим сканированием 66
Глава 6
Синтаксический анализ 68
6.1 Анализ определений 69
Символы, обозначающие всю программу 69
Грамматика Блоки 69
Синтаксис импортной декларации 70
Грамматика различных определений 71
Синтаксис определения переменной 72
Синтаксис определения функции 73
Синтаксис определения структуры и определения объединения 74
Синтаксис для членов структуры и членов объединения 75
Синтаксис оператора typedef 76
Синтаксис типа 76
Разница между языком C и C? в определении переменной 77
Синтаксис базового типа 77
6.2 Анализ заявлений 79
Синтаксис операторов 79
Синтаксис оператора if 80
Опустить операторы if и фигурные скобки 80
Синтаксис оператора while 81
Синтаксис оператора 81
Грамматика различных операторов перехода 82
6.3 Анализ выражений 83
Общая структура выражения 83
Правила для выражения 83
Условное выражение 84
Бинарные операторы 85
Анализ пункта 6.4 88
Правила предмета 88
Правила использования префиксов операторов 88
Правила для постфиксных операторов 89
Буквальные правила 89
Часть 2. Абстрактное синтаксическое дерево и промежуточный код
Глава 7
Действие JavaCC и абстрактное синтаксическое дерево 92
7.1 Действия JavaCC 93
Цель настоящей главы 93
Простое действие 93
Момент времени, когда действие выполняется 93
Действие 95, возвращающее семантическое значение.
Получить семантическое значение терминального символа 95
Свойства токена класса 96
Получить семантическое значение нетерминального символа 98
Структура синтаксического дерева 99
Выбор и действия 99
Повтор и действие 100
Краткое содержание этого раздела 102
7.2 Абстрактное синтаксическое дерево и узлы 103
Группа узлов 103
Определение класса узла 105
Представление абстрактного синтаксического дерева 105
Пример выражения на основе узлов 107
Глава 8
Генерация абстрактного синтаксического дерева 110
8.1 Абстрактное синтаксическое дерево выражений 111
Литеральное абстрактное синтаксическое дерево 111
Представление типов 112
Зачем нужен класс TypeRef 113
Абстрактное синтаксическое дерево для унарных операций 114
Абстрактное синтаксическое дерево для бинарных операций 116
Абстрактное синтаксическое дерево для условных выражений 117
Абстрактное синтаксическое дерево для выражений присваивания 118
8.2 Абстрактное синтаксическое дерево операторов 121
Абстрактное синтаксическое дерево оператора if 121
Абстрактное синтаксическое дерево оператора while 122
Абстрактное синтаксическое дерево для программных блоков 123
8.3 Объявленное абстрактное синтаксическое дерево 125
Дерево абстрактного синтаксиса для списка объявлений переменных 125
Абстрактное синтаксическое дерево определения функции 126
Абстрактное синтаксическое дерево, представляющее список объявлений 127
Абстрактное синтаксическое дерево, представляющее всю программу 128
Импортировать 128 внешних символов.
Резюме 129
8.4 Запуск парсера cbc 132
Генерация объектов парсера 132
Анализ файлов 133
Запуск парсера 134
Глава 9
Семантический анализ (1) Справочная резолюция 135
9.1 Обзор семантического анализа 136
Цель настоящей главы 136.
Обход абстрактного синтаксического дерева 137
Обработка абстрактных синтаксических деревьев без использования режима посетителя 137
Обработка абстрактного синтаксического дерева на основе шаблона посетителя 138
Обобщение паттерна Вистор 140
Реализация режима посетителя в cbc 141
Семантический анализ, связанный с классами CBC 142
9.2 Прекращение ссылок на переменные 144
Краткое описание проблемы 144
Резюме реализации 144
Древовидная структура области видимости 145
Свойства класса LocalResolver 146
Запуск класса LocalResolver 146
Добавление определений переменных 147
Обработка определений функций 148
метод pushScope 149
метод currentScope 149
метод popScope 150
Добавить временную область 150
Установите связь между VariableNode и определением переменной 151.
Получить определения переменных из дерева области действия 151
9.3 Разрешение имени типа 153
Краткое описание проблемы 153
Резюме реализации 153
Свойства класса TypeResolver 153
Запуск класса TypeResolver 154
Декларация типа 154
Типы и обход абстрактного синтаксического дерева 155
Разрешение типов определений переменных 156
Типовое разрешение определений функций 157
Глава 10
Семантический анализ (2) проверка статического типа 159
10.1 Проверка определений типов 160
Краткое описание проблемы 160
Резюме реализации 161
Алгоритмы обнаружения замкнутых петель в ориентированных графах 162
Циклическая проверка определения структур и объединений 163
10.2 Проверка достоверности выражений 165
Краткое описание проблемы 165
Резюме реализации 165
Запуск класса DereferenceChecker 166
Захват исключения SemanticError 167
Проверка операций со значениями неуказательного типа 167
Проверка получения адреса выражения, отличного от lvalue 168
Генерация неявного указателя 169
10.3 Проверка статического типа 170
Краткое описание проблемы 170
Резюме реализации 170
Типы операндов в C? 171
Неявное преобразование типов 172
Запуск класса TyperChecker 173
Проверка типов для бинарных операторов 174
Реализация неявного преобразования типов 175
Глава 11
Промежуточное преобразование кода 178
11.1 промежуточный код cbc 179
Классы, составляющие промежуточный код 180
Свойства классов узлов промежуточного кода 181
Операторы и типы промежуточного кода 182
Различные промежуточные коды 183
Значение промежуточного кода 184
11.2 Обзор класса IRGenerator 185
Обход абстрактного синтаксического дерева и возвращаемые значения 185
Запуск IRGenerator класса 185
Преобразование онтологии функции 186
Дискриминация выражений как утверждений 187
11.3 Преобразование операторов управления потоком 189
Краткое описание преобразования оператора if (1) 189
Преобразование оператора if (2) без части else 190
Преобразование оператора if (3), когда есть часть else 191
Преобразование оператора while 191
Преобразование оператора прерывания (1) Постановка задачи 192
Преобразование оператора прерывания (2) Рекомендации по реализации 193
Преобразование реализации оператора прерывания (3) 194
11.4 Преобразование выражений без побочных эффектов 196
Преобразование объектов UnaryOpNode 196
Преобразование объектов BinaryOpNode 197
Преобразование операций сложения и вычитания указателей 198
11.5 Преобразование значений lvalue 200
влево и вправо 200
lvalue и rvalue 200
Производительность значений lvalue в cbc 201
Смещение членов структуры 202
Преобразование ссылки на член (expr.memb) 203
Исключения из преобразований lvalue: массивы и функции 204
выражение ссылки на член (ptr->член) конверсия 205
11.6 Преобразование выражений с побочными эффектами 206
Побочные эффекты выражений 206
Рекомендации по преобразованию выражений с побочными эффектами 206
Оператор преобразования (1) простого выражения присваивания 207
Введение временных переменных 208
Преобразование простого выражения присваивания (2) в выражение 209
Постинкрементное преобразование 210
Часть 3. Ассемблерный код
Глава 12
Обзор архитектуры x86 214
12.1 Структура компьютерной системы 215
Процессор и память 215
Зарегистрироваться 215
Адрес 216
Физические и виртуальные адреса 216
Различные виды оборудования 217
Кэш 218
12.2 История процессоров серии x86 220
ЦП серии x86 220
32-битный процессор 220
Набор инструкций 221
Изменения ИА-32 222
64-битное расширение IA-32——AMD64 222
12.3 Краткое изложение IA-32 224
Регистр 224 ИА-32
Общий реестр 225
Машинный стек 226
Операции с машинным штабелем 227
Назначение машинного стека 227
Кадр стека 228
Указатель инструкций 229
Регистр флагов 229
12.4 Представление и формат данных 231
Представление целых чисел без знака 231
Представление целых чисел со знаком 231
Представление отрицательных целых чисел и дополнения до двух 232
Порядок байтов 233
Выравнивание 233
Представление структуры 234
Глава 13
программирование на ассемблере x86 236
13.1 Программирование на основе ассемблера GNU 237
ГНУ Ассемблер 237
Привет, Мир! 237 на ассемблере
Ассемблерный код на основе ассемблера GNU 238.
13.2 Синтаксис ассемблера GNU 240
Ассемблерная версия Hello, World! 240
Директива 241
Псевдооперации сборки 241
тег 241
Примечание 242
Мнемонический суффикс 242
Различные операнды 243
Косвенная ссылка на память 244
Обзор набора команд x86 245
13.3 Инструкции по передаче 246
инструкция перемещения 246
инструкция push и инструкция pop 247
Леа команда 248
Инструкция movsx и инструкция movzx 249
Расширение знака и нулевое расширение 250
13.4 Инструкции по арифметическим операциям 251
добавить команду 251
Нести флаг 252
поддиректива 252
директива imul 252
Директива idiv и директива div 253
инструкция вкл 254
декабрьская инструкция 255
отрицательная команда 255
13,5-битные инструкции по эксплуатации 256
и директива 256
или команда 257
инструкция xor 257
не командовать 257
Сал команда 258
сар команда 258
команда шр 259
13.6 Управление процессом 260
команда jmp 260
Инструкции условного перехода (jz, jnz, je, jne,…&черт возьми;) 261
команда cmp 262
тестовая команда 263
Команда получения бита флага (SETcc) 263
инструкция вызова 264
возврат инструкции 265
Глава 14
Функции и переменные 266
14.1 Соглашение о вызове программ 267
Что такое соглашение о вызовах программ 267?
Соглашение о вызове программ в Linux/x86 267
14.2 Вызовы функций в Linux/x86 269
Пока вызов функции не завершится 269
Пока функция не начнет выполняться 270
До возвращения к исходному потоку обработки 271
Пока операция очистки не будет завершена 271
Сводка вызовов функций 272
14.3 Подробности вызовов функций в Linux/x86 274
Сохранение и восстановление реестра 274
регистр сохранения вызывающего абонента и регистр сохранения вызываемого абонента 274
Гибкое применение регистра сохранения вызывающего абонента и регистра сохранения вызываемого абонента 275
Методы возврата больших чисел и чисел с плавающей запятой 276
Соглашения о вызове программ для других платформ 277
Глава 15
Составление выражений и утверждений 278
15.1 Подтверждение результатов компиляции 279
Как подтвердить с помощью cbc 279
Как подтвердить с помощью gcc 280
15.2 Объекты сборки x86 и DSL 282
Классы, представляющие сборку 282
Представляет объекты сборки 283
15.3 сборка x86 cbc DSL 285
Использование DSL для создания объектов сборки 285
Представляет регистр 286
Представляет непосредственные ссылки на данные и память 287.
Указывает команду 287
Представляет псевдооперации сборки, метки и комментарии 288
15.4 Обзор класса CodeGenerator 290
Поля класса CodeGenerator 290
Обзор обработки класса CodeGenerator 290
Реализация метода compileStmts 291
стратегия компиляции cbc 292
15.5 Составление простых выражений 294
Компиляция Int Node 294
Скомпилировать узел Str 294
Скомпилировать Uni node(1) побитовое отрицание 295
Компиляция узла Uni (2) логическое отрицание 297
15.6 Компиляция бинарных операций 298
Компилировать узел Bin 298
Реализация метода compileBinaryOp 299
Осуществить деление и остаток 300
Реализация операций сравнения 300
15.7 Справочные переменные и присвоение 301
Скомпилировать узел Var 301
Компилировать узел адреса 302
Компилировать узел Mem 303
Компилировать узел назначения 303
15.8. Компиляция операторов перехода 305
Скомпилируйте узел LabelStmt 305.
Компилировать узел перехода 305
Скомпилируйте узел CJump 305.
Компиляция узла вызова 306
Компиляция узла возврата 307
Глава 16
Выделить кадр стека 308
16.1 Стек операций 309
Стековая рамка в CBC 309
Принципы работы указателя стека 310
Порядок компиляции тела функции 310
16.2 Распределение памяти для параметров и локальных переменных 312
Обзор настоящего раздела 312
Распределение памяти для параметров 312
Распределение памяти для локальных переменных: принцип 313
Выделение памяти для локальных переменных 314
Обработка локальных переменных в области 315
Расчет выравнивания 316
Выделение памяти для переменных подобласти 316
16.3 Использование виртуального стека для размещения временных переменных 318
Роль виртуального стека 318
Интерфейс виртуального стека 319
Структура виртуального стека 319
Реализация метода virtualPush 320
Реализация метода VirtualStack#extend 320
Реализация метода VirtualStack#top 321
Реализация метода virtualPop 321
Реализация метода VirtualStack#rewind 321
Работа виртуального стека 322
16.4 Регулировка смещения доступа к стеку 323
Краткое содержание настоящего раздела 323
StackFrameInfo класс 323
Вычислить используемые регистры сохранения вызываемого абонента 324
Вычислить размер временной переменной области 325
Отрегулируйте смещение локальных переменных 325
Отрегулируйте смещение временных переменных 326
16.5 Пролог и эпилог порождающей функции 327
Краткое содержание настоящего раздела 327
Пролог порождающей функции 327
Создать эпилог функции 328
16.6 Реализация функции alloca 330
Что такое функция alloca 330
Реализация принципов 330
Влияние функции alloca 331
Реализация функции alloca 331
Глава 17
Метод оптимизации 333
17.1 Что такое оптимизация 334
Различные оптимизации 334
Вариант оптимизации 334
Постоянное складывание 334
Алгебраическое упрощение 335
Уменьшить интенсивность вычислений 335
Удалить общие подвыражения 335
Удалить неверные утверждения 336
Встраивание функций 336
17.2 Оптимизированная классификация 337
Оптимизационная классификация на основе методов 337
Классификация оптимизации по объему 337
Классификация оптимизации по этапу действия 338
17.3 Оптимизация в cbc 339
Принципы оптимизации в cbc 339
Оптимизация реализована в cbc 339
Реализация оптимизации в cbc 339
17.4 Глубокая оптимизация 341
Выбор директив на основе сопоставления с образцом 341
Регистр распределения 342
Анализ потока управления 342
Масштабный анализ потоков данных и формы SSA 342
Резюме 343
Часть 4. Связывание и загрузка
Глава 18
Генерировать целевые файлы 346
18.1 Структура файлов ELF 347
Назначение ELF 347
Разделы и сегменты ELF 348
Основной раздел ELF объектного файла 348
Используйте команду readelf для вывода заголовков разделов 349
Используйте команду readelf для вывода заголовка программы 350.
Используйте команду readelf для вывода таблицы символов 351.
Параметры команды readelf 351
Что такое формат DWARF 352
18.2 Глобальные переменные и их представление в файлах ELF 354
Назначается любому разделу ELF 354.
Отнесен к общему разделу 354 ELF.
Раздел Assignment.bss 355
Универсальные символы 355
Запишите символы, соответствующие глобальным переменным 357.
Дополнительная информация для записи символов 357
Запись дополнительной информации для универсальных символов 358
Резюме 358
18.3 Компиляция глобальных переменных 360
Реализация метода генерации 360
Реализация методаgenerAssemblyCode 360
Компилировать глобальные переменные 361
Скомпилируйте немедленно 362
Составление универсальных символов 363
Компиляция строковых литералов 364
Создать заголовок функции 365
Вычислить размер функционального кода 366
Резюме 366
18.4 Генерация целевых файлов 367
Краткое описание вызова команды 367
Ссылка на класс 367 GNUAssembler
Позвонить по команде 367
Глава 19
Ссылки и библиотеки 369
19.1 Обзор ссылок 370
Пример связанного выполнения 370
gcc и GNU ld 371
Файлы, обработанные компоновщиком 372
Часто используемые библиотеки 374
Ввод и вывод компоновщика 374
19.2 Что такое ссылка 375
Обработка во время соединения 375
Объединить раздел 375
Переезд 376
Разрешение символа 377
19.3 Динамическое связывание и статическое связывание 379
Два метода связывания 379
Преимущества динамической компоновки 379
Недостатки динамического связывания 380
Пример динамической ссылки 380
Пример статической ссылки 381
Правила поиска в библиотеке 381
19.4 Генерация библиотек 383
Создать статическую библиотеку 383
Управление общими библиотеками в Linux 383
Создание общих библиотек 384
Связывание созданных общих библиотек 385
Глава 20
Погрузчик 387
20.1 Загрузка разделов ELF 388
Использование системного вызова mmap для сопоставления файлов 388
Образ памяти процесса 389
Свойства области памяти 390
Объем памяти, соответствующий сегменту ELF, равен 390.
Область памяти, не соответствующая файлу ELF 392.
Реализация загрузки ELF-файла 393
20.2 Процесс динамического связывания 395
Загрузчик динамических ссылок 395
Процесс от запуска до завершения работы программы 395
Запустить ld.so 396
Информация, передаваемая ядром системы 397
Вектор AUX 397
Чтение общих библиотек 398
Разрешение символов и перемещение 399
Запустите код инициализации 400
Выполнить основную программу 401
Выполнить обработку завершения 402
Переменные среды, анализируемые ld.so 402
20.3 Динамическая нагрузка 404
Так называемая динамическая нагрузка 404
Динамическая загрузка 404 под Linux
Динамически загружаемая архитектура 405
20.4 Ссылки на GNU ld 406
Структура опции ld для cbc 406
Среда выполнения 407
Создать исполняемый файл 408
Создать общую библиотеку 408
Глава 21
Сгенерировать адресно-независимый код 410
21.1 Независимый от адреса код 411
Что такое адресно-независимый код 411
Таблица глобальных смещений (GOT) 412
Получить адрес GOT 412
Используйте адрес GOT для доступа к глобальным переменным 413.
Доступ к глобальным переменным внутри файлов с использованием адресов GOT 414
Таблица связей процессов (PLT) 414
Позвоните по номеру PLT 416.
Независимый от адреса исполняемый файл: PIE 416.
21.2 Реализация ссылки на глобальную переменную 418
Получить адрес GOT 418
Реализация функции PICThunk 418
Удалить дублирующиеся функции и установить невидимые свойства 419
Загрузить GOT-адрес 420
Реализация функцииlocateSymbols 421
Ссылка на глобальные переменные 421
Доступ к глобальным переменным: в случае адресно-независимого кода 422
Символы функций 423
Ссылки на строковые константы 424
21.3 Реализация вызовов компоновщика 425
Создать исполняемый файл 425
метод генерированияSharedLibrary 426
21.4 От разбора программы к выполнению 428
Процесс сборки и загрузки 428
Лексический анализ 429
Синтаксический анализ 429
Сгенерировать промежуточный код 430
Сгенерировать код 431
Сборник 432
Создание общих библиотек 432
Создать исполняемый файл 433
Загрузка 433
Глава 22
Дальнейшее чтение 434
22.1 Рекомендуемые справочники 435
Связанный с компилятором 435
Синтаксический анализ, связанный 435
Язык ассемблера 436
22.2 Связывание и загрузка 437
22.3 Функции различных языков программирования 438
Книги по инкапсуляции исключений 438
Сбор мусора 438
Книги по сбору мусора 439
Реализация объектно-ориентированных языков программирования 439
Функциональные языки 440
Приложение 441
А.1 Ссылки 442
A.2 Интернет-материалы 444
А.3 Исходный код 445

Аоки Минеро (писатель)
Программист, автор книг «Техники программирования на Ruby 268 (2-е издание)», «Полное объяснение исходного кода Ruby», «Программирование для Linux» и многих других работ, связанных с программированием, а также активно участвует в различных мероприятиях, таких как обслуживание стандартной библиотеки и обслуживание документации.
Ян Шэнъи (переводчик)
Окончил Шанхайский университет Цзяо Тонг.8 лет опыта разработки программного обеспечения, в течение этого времени работал в Японии.В настоящее время работает в компании Xiangneng Information Technology (Shanghai) Co., Ltd., занимается разработкой систем управления взаимоотношениями с клиентами и различных систем автоматизации маркетинга на базе облачных платформ.В переводе с «Эффективного развития команды: инструменты и методы».
Джуэюн (переводчик)
Окончил факультет программного обеспечения Университета Цинхуа.Когда-то он занимался разработкой программного обеспечения для обмена мгновенными сообщениями и социальных игр в японской креативной компании KAYAC, а в настоящее время является экспертом по интерфейсной архитектуре в Ant Financial.Он перевел такие книги, как «Книга алгоритмов для всех», и участвовал в рецензии на книгу «Думай как непрофессионал, практикуй как эксперт (пересмотренное издание)».

Сделать настоящий компилятор с нуля











