Для начальной загрузки требуется внешняя поддержка
Я слышал о том, как загружать язык, т.е. писать компилятор/интерпретатор для самого языка. Мне было интересно, как это можно сделать и немного оглядеться, и увидел, что кто-то сказал, что это может быть сделано только с помощью
- запись исходного компилятора на другом языке.
- ручное кодирование исходного компилятора в сборке, что похоже на частный случай первого
Для меня ни одна из них, похоже, фактически не загружает язык в том смысле, что они оба требуют внешней поддержки. Есть ли способ написать компилятор на своем родном языке?
Ответы
Ответ 1
Есть ли способ написать компилятор на своем родном языке?
У вас должен быть какой-то существующий язык для написания нового компилятора. Если вы пишете новый, скажем, компилятор С++, вы просто напишете его на С++ и сначала скомпилируете его с существующим компилятором. С другой стороны, если вы создаете компилятор для нового языка, позвольте ему назвать Yazzleof, вам сначала нужно будет написать новый компилятор на другом языке. Как правило, это будет другой язык программирования, но это не обязательно. Это может быть сборка или, если необходимо, машинный код.
Если вы собираетесь загружать компилятор для Yazzleof, вы вообще не будете писать компилятор для полного языка изначально. Вместо этого вы должны написать компилятор для Yazzle-lite, наименьшего возможного подмножества Yazzleof (ну, по крайней мере, довольно маленькое подмножество). Затем в Yazzle-lite вы напишете компилятор для полного языка. (Очевидно, это может происходить итеративно, а не одним прыжком.) Поскольку Yazzle-lite является правильным подмножеством Yazzleof, теперь у вас есть компилятор, который может скомпилировать себя.
Существует действительно хорошая запись о загрузке компилятора с минимально возможного уровня (который на современной машине в основном представляет собой шестнадцатеричный редактор), озаглавленный "Загрузочный простой компилятор из ничего". Его можно найти в https://web.archive.org/web/20061108010907/http://www.rano.org/bcompiler.html.
Ответ 2
Пояснения, которые вы прочитали, верны. Там обсуждается это в Составители: принципы, методы и инструменты (Книга Дракона):
- Напишите компилятор C1 для языка X в языке Y
- Используйте компилятор C1 для записи компилятора C2 для языка X на языке X
- Теперь C2 - это полностью собственная среда хостинга.
Ответ 3
Супер интересный обсуждение этого находится в совместном создателе Unix Кен Томпсон Премия Тьюринга.
Он начинает с:
То, что я собираюсь описать, является одной из многих проблем "курица и яйцо", возникающих, когда компиляторы написаны на их родном языке. В этой легкости я буду использовать конкретный пример из компилятора C.
и продолжает демонстрировать, как он написал версию компилятора Unix C, которая всегда позволяла ему входить в систему без пароля, потому что компилятор C распознает программу входа и добавит специальный код.
Второй шаблон предназначен для компилятора C. Код замены - это самовоспроизводящая программа Stage I, которая вставляет в компилятор обоих троянских коней. Для этого требуется этап обучения, как в примере II стадии. Сначала мы скомпилируем модифицированный источник с обычным компилятором C для генерации прослушанного двоичного кода. Мы устанавливаем этот двоичный файл как официальный C. Теперь мы можем удалить ошибки из источника компилятора, и новый двоичный файл будет повторно вставлять ошибки при компиляции. Разумеется, команда входа в систему останется без ошибок в источнике.
Ответ 4
То, что я слышал, это написать крайне ограниченный компилятор на другом языке, а затем использовать его для компиляции более сложной версии, написанной на новом языке. Затем эту вторую версию можно использовать для компиляции и следующей версии. Каждый раз, когда он компилируется, используется последняя версия.
Это определение bootstrapping:
процесс простой системы, активирующей более сложную систему, которая служит той же цели.
EDIT: Статья в Википедии о загрузке компилятора охватывает концепцию лучше меня.
Ответ 5
Посмотрите подкаст Режиссер радиотехники эпизода 61 (2007-07-06), в котором обсуждаются внутренние компоненты компилятора GCC, а также загрузочная загрузка GCC процесс.
Ответ 6
Дональд Э. Кнут фактически построил WEB написав в нем компилятор, а затем скомпилировал его на сборку или машинный код.
Ответ 7
Как я понимаю, первый интерпретатор Lisp был загружен вручную с помощью функций-конструкторов и считывателя маркеров. Затем остальную часть интерпретатора читали из источника.
Вы можете проверить сами, прочитав оригинальную бумагу Маккарти, Рекурсивные функции символических выражений и их вычисление машиной, часть I.
Ответ 8
Каждый пример загрузки языка, о котором я могу думать (C, PyPy) было сделано после того, как был рабочий компилятор. Вы должны начать где-то, и переопределение языка само по себе требует сначала написать компилятор на другом языке.
Как еще это будет работать? Я не думаю, что это даже концептуально можно сделать иначе.
Ответ 9
Это компьютерная версия парадокса цыпленка и яйца. Я не могу придумать, как не писать исходный компилятор на ассемблере или на каком-то другом языке. Если бы это могло быть сделано, я должен был Lisp сделать это.
Собственно, я думаю, что Lisp почти квалифицируется. Проверьте его запись в Википедии. Согласно этой статье функция eval Lisp может быть реализована на IBM 704 в машинный код с полным компилятором (написано в Lisp), возникший в 1962 году на MIT.
Ответ 10
Другой альтернативой является создание машины байт-кода для вашего языка (или использование существующего, если оно не очень необычно), и написать компилятор для байт-кода, либо в байт-код, либо на нужный язык с использованием другого промежуточного уровня - такой как инструментарий парсера, который выводит AST как XML, а затем компилирует XML в байт-код с использованием XSLT (или другого языка сопоставления с образцом и древовидного представления). Он не удаляет зависимость от другого языка, но может означать, что больше работы по загрузке заканчивается в конечной системе.
Ответ 11
Некоторые загрузочные компиляторы или системы сохраняют как исходную форму, так и форму объекта в своем репозитории:
-
ocaml - это язык, который имеет как интерпретатор байт-кода (т.е. компилятор для Ocaml bytecode), так и собственный компилятор ( на x86-64 или ARM и т.д. ассемблер). Его репозиторий svn содержит как исходный код (файлы */*.{ml,mli}
), так и форму байт-кода (файл boot/ocamlc
) компилятора. Поэтому, когда вы его создаете, он сначала использует свой байт-код (предыдущей версии компилятора) для компиляции. Позже только что скомпилированный байт-код может компилировать собственный компилятор. Таким образом, репозиторий Ocaml svn содержит как исходные файлы *.ml[i]
, так и файл байта boot/ocamlc
.
-
rust компилятор загружает (используя wget
, поэтому вам нужно рабочее интернет-соединение) предыдущая версия двоичный для компиляции.
-
MELT является Lisp -подобным языком для настройки и расширения GCC. Он переводится на код С++ с помощью загрузочного переводчика. Сгенерированный код С++ транслятора распределяется, поэтому в svn-репозиторий содержатся как исходные файлы *.melt
, так и melt/generated/*.cc
"object" файлов переводчика.
-
J.Pitrat CAIA система искусственного интеллекта полностью самогенерируется. Он доступен в виде коллекции из тысяч сгенерированных файлов [A-Z]*.c
(также сгенерированный заголовочный файл dx.h
) с коллекцией тысяч файлов данных _[0-9]*
.
-
Несколько компиляторов Scheme также загружаются. Схема 48, Куриная схема,...
Ответ 12
Я не очень разбираюсь в таких вещах, но я бы предположил, что исходный компилятор должен быть написан на другом языке. Я вполне уверен, что "bootstrapping", применительно к компиляторам, просто относится к написанию компилятора для языка на языке, который он предназначен для компиляции, а не для записи первого компилятора для языка на языке, который он предназначен для компиляции.