Как отмечали другие в комментариях, GHC почти полностью написан на Haskell (плюс некоторые расширения GHC) и предназначен для компиляции с самим собой. Фактически, единственная программа в мире, которая может скомпилировать компилятор GHC, — это компилятор GHC! В частности, синтаксический анализ и вывод типов реализованы в коде Haskell, и вы нигде не найдете спрятанной реализации C.
Лучшим источником для понимания внутренней структуры компилятора (и того, как он реализован) является Вики для разработчиков GHC и, в частности, ссылку «Комментарий GHC». Если у вас есть достаточно свободного времени, посмотрите серию видеороликов из Портленда. Хакатон GHC 2006 абсолютно захватывающий.
Обратите внимание, что идея написания компилятора на языке, который он компилирует, не является чем-то необычным. Многие компиляторы являются «самостоятельными», что означает, что они написаны на языке, который они компилируют, и предназначены для самостоятельной компиляции. См., например, этот вопрос на другом родственном сайте Stack Exchange: Почему самостоятельные компиляторы считаются обрядом посвящения в новые языки? или просто Google для "самостоятельного компилятора"
Как вы говорите, это «сложно», потому что вам нужен способ запустить процесс. Вот некоторые подходы:
Вы можете написать первый компилятор на другом языке, у которого уже есть компилятор (или написать его на ассемблере); затем, когда у вас есть работающий компилятор, вы можете портировать его на тот же язык, который он компилирует. Согласно этому ответу Quora, первый компилятор C был написан таким образом. Он был написан на «NewB», компилятор которого был написан на «B», компиляторе с самостоятельным размещением, который изначально был написан на ассемблере, а затем переписан сам по себе.
Если язык достаточно популярен, чтобы иметь другой компилятор, напишите компилятор на его собственном языке и скомпилируйте его поэтапно, сначала с помощью другого компилятора, затем с самим собой (как скомпилировано другим компилятором), затем снова с самим собой (как скомпилировано другим компилятором). сам). Последние два исполняемых файла компилятора можно сравнить как своего рода масштабную проверку правильности компилятора. Компилятор Gnu C может быть скомпилирован таким образом (и это, конечно, был стандартный способ установки из исходного кода, используя для начала [низший!] C-компилятор поставщика).
Если интерпретатор, написанный на другом языке, уже существует или его легко написать, интерпретатор может запустить компилятор для компиляции собственного исходного кода, после чего компилируемый компилятор может быть использован для компиляции самого себя. Первый компилятор LISP считается первым компилятор для начальной загрузки таким образом.
Процесс начальной загрузки часто можно упростить, написав компилятор (по крайней мере изначально) на ограниченном ядре языка, даже если сам компилятор способен скомпилировать полный язык. Затем существующий компилятор ниже номинала или упрощенный самозагружающийся компилятор или интерпретатор может запустить процесс.
Согласно записи GHC в Википедии, исходный компилятор GHC был написан в 1989 году на Lazy ML, затем в том же году переписан на Haskell. В наши дни новые версии GHC со всеми их блестящими новыми функциями компилируются на старых версиях GHC.
Ситуация с интерпретатором Python немного отличается. Интерпретатор, конечно, может быть написан на языке, который он интерпретирует, и в мире Лиспа есть много примеров написания интерпретаторов Лиспа на Лиспе (ради развлечения, или при разработке нового диалекта Лиспа, или потому что вы изобретая Лисп), но это не могут быть интерпретаторы на всем пути, так что в конце концов вы d нужен либо компилятор, либо интерпретатор, реализованный на другом языке. В результате большинство интерпретаторов не являются самостоятельными: основные интерпретаторы для Python, Ruby и PHP написаны на C. (Хотя PyPy — это альтернативная реализация интерпретатора Python, написанная на Python, так что...)
10.05.2017