Как мог первый компилятор C ++ быть написан на C ++?

48

Страуструп утверждает, что Cfront, первый компилятор C ++, был написан на C ++ ( Stroustrup FAQ ).

Однако как вообще возможно, чтобы первый компилятор C ++ был написан на C ++?

Код, составляющий компилятор, тоже должен быть скомпилирован, и поэтому первый компилятор C ++ не мог быть написан на C ++, не так ли?

Pacerier
источник

Ответы:

57

Ключ прямо здесь:

Первый компилятор C ++ (Cfront) был написан на C ++. Чтобы построить это, я сначала использовал C для написания препроцессора "C with Classes" -to-C. «C with Classes» был диалектом C, который стал непосредственным предком C ++. Этот препроцессор переводил конструкции «C with Classes» (такие как классы и конструкторы) в C. Это был традиционный препроцессор, который не понимал весь язык, оставил большую часть проверки типов для выполнения компилятором C, и перевел индивидуальный строит без полного знания. Затем я написал первую версию Cfront в «C с классами».

Поэтому первая версия Cfront была написана не на C ++, а на промежуточном языке. Возможность создавать компиляторы и препроцессоры C непосредственно в C привела ко многим нововведениям (и огромным дырам в безопасности ) в C. Таким образом, вы пишете свой новый препроцессор, который превращает код «C with Classes» в прямой C (потому что прямой C может делать что-нибудь), а затем вы используете "C с классами", чтобы написать компилятор C ++ (не то, что вы не можете сделать это в C, просто это займет некоторое время), а затем вы используете этот компилятор C ++, чтобы написать более эффективный / полный компилятор в C ++. Понял?

Кристофер Биббс
источник
5
+1 за включение ссылки на одну из моих любимых историй о том, что можно сделать (и не следует).
jwernerny
3
Компилятор был написан в допустимом коде C ++, но использовал только некоторые из полных функций C ++, которые поддерживались препроцессором «C with Classes». Он использовал подмножество полного языка, поэтому он также скомпилировал результат (первая рабочая версия Cfront). После выполнения этого шага «начальной загрузки» ему, вероятно, больше никогда не понадобилось использовать препроцессор.
Joeytwiddle
2
@jwernerny - я всегда находил эту статью неудовлетворительной. Он замалчивает самую сложную и нетривиальную часть: «Ошибка будет соответствовать коду в команде« входа »в UNIX. Код замены будет неправильно компилировать команду входа в систему, чтобы он мог принять либо предполагаемый зашифрованный пароль, либо определенный известный пароль. " Но как это сделать? Было ли это когда-либо на самом деле продемонстрировано?
детально
3
«привело ко многим нововведениям (и огромным дырам в безопасности) в C»: насколько я знаю, эти приемы можно использовать на любом языке, не только на C. Поэтому любой другой язык может иметь такие же дыры в безопасности.
Джорджио
2
@detly: Сейчас это звучит тривиально, но в 1983 году это была новая атака, сделанная жизнеспособной из-за отсутствия разнообразия реализации. Тогда мы больше доверяли двоичным файлам, отчасти потому, что компиляция всего из исходного кода была гораздо большим испытанием, чем сейчас.
Blrfl
17

Это было начато. Как только функция C ++ была добавлена ​​в cfront, cfront может также использовать эту функцию с этого момента (но не для реализации этой самой функции). Это работало, потому что у cfront была возможность преобразовать код C ++ в код C. Поэтому, если появится какая-то новая платформа, вы можете использовать cfront на другой платформе для преобразования cfront из C ++ в C, а затем использовать компилятор C новой платформы, чтобы завершить компиляцию из C в объектный код.

Дэвид Шварц
источник
9

Я думаю, что BS отвечает на этот вопрос:

Первый компилятор C ++ (Cfront) был написан на C ++. Чтобы построить это, я сначала использовал C для написания препроцессора "C with Classes" -to-C. «C with Classes» был диалектом C, который стал непосредственным предком C ++. Этот препроцессор переводил конструкции «C with Classes» (такие как классы и конструкторы) в C. Это был традиционный препроцессор, который не понимал весь язык, оставил большую часть проверки типов для выполнения компилятором C, и перевел индивидуальный строит без полного знания.

Затем я написал первую версию Cfront в «C с классами». Cfront был традиционным компилятором, который выполнял полную синтаксическую и семантическую проверку исходного кода C ++. Для этого у него был полный синтаксический анализатор, построены таблицы символов и построено полное представление внутреннего дерева каждого класса, функции и т. Д. Он также провел некоторую оптимизацию на уровне исходного кода для своего внутреннего представления дерева конструкций C ++ перед выводом C. Версия, которая сгенерированный C, не полагался на C для какой-либо проверки типа. Он просто использовал C в качестве ассемблера. Полученный код был бескомпромиссно быстрым.

Сначала он создал что-то, что он назвал «C с классами», реализованный простым препроцессором в C. Это был в основном C ++, но препроцессор почти не проверял. Затем он использовал это для написания Cfront, более мощной версии переводчика C ++ в C, с проверкой типов, таблиц символов и т. Д.

Майк Данлавей
источник
1
так что, в основном, когда мы компилируем программу на C ++, она конвертируется в C, затем после конвертации в C она снова компилируется в машинный код?
Pacerier
@Pacerier: Изначально да, но не сейчас, я думаю.
Майк Данлавей
Я не совсем понимаю ваш комментарий. Вы имеете в виду, что теперь есть компиляторы, которые пропускают второй шаг и просто берут исходный код C ++ и компилируют в машинный код?
Pacerier
7
@Pacerier: Ну, они не идут напрямую на язык ассемблера или машинный код. Обычно они сначала переходят к независимому от машины промежуточному представлению (тройки или четверки) и анализируют его для оптимизации. Из этого они генерируют сборку или машинный код. Если вы возьмете книгу по дизайну компиляторов (Aho & Ullman), я уверен, что вам будет интересно.
Майк Данлавей
1
Важно отметить, что созданный им C ++ также был частью существующего языка. В нем не было шаблонов, не было новых библиотек, использовалось только приведение C, и, если я правильно помню, исключений не было.
Gort Робот
2

Я добавлю этот ответ, так как ни один ответ не охватывал этот аспект.

Технически вам не нужно программное обеспечение для компиляции кода. Пока у вас есть необходимые спецификации компилятора, вы можете выполнить фактическую компиляцию вручную. Это не то, как был скомпилирован первый компилятор C ++. Я просто говорю, что это возможно.

Сравните с языком ассемблера. Когда они использовались в первые дни, не было программного обеспечения на ассемблере для преобразования кода сборки в машинный код. Это было сделано вручную, но язык ассемблера дал программистам лучший обзор.

klutt
источник