Зачем на С ++ писать компилятор?

14

Мне было интересно, почему C ++ является хорошим выбором для написания компилятора. Конечно, C также хорош для этой цели, потому что многие компиляторы написаны либо на C, либо на C ++, но в этот раз меня больше интересует C ++. Есть веские причины? Я искал это в Интернете, но не могу найти веских причин.

Кобра
источник
3
«Многие компиляторы написаны [...] на C ++» - есть ссылки? Какие? Что заставляет вас думать, что C ++ чаще используется для построения компиляторов, чем другие популярные языки?
Док Браун
6
@DocBrown Ну, Clang и MSVC написаны в основном на C ++, в gcc теперь есть немного C ++, Java JVM написана на C ++ stackoverflow.com/questions/410320/what-is-java-written-in, а также в роли superuser. ru / questions / 136136 /…
Klaim
@DocBrown DMD ссылочный компилятор для D написан на C ++
трещотка урод
3
Кто сказал, что это хороший выбор?
Фил
1
@Phil Как вы думаете, они сделали этот выбор без рассмотрения альтернатив? Это не «хороший» выбор, это «эффективный» выбор.
Klaim

Ответы:

25

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

Oleksi
источник
11
Насколько я знаю, большая часть логики внутри компилятора носит функциональный характер (преобразование сложных структур данных в другие структуры данных), поэтому я не уверен, есть ли объектно-ориентированные средства (которые в большей степени ориентированы на программирование в целом). архитектурные аспекты) дают реальное преимущество компилятору по сравнению со стилем процедурного программирования. Просто мои 2 цента.
Джорджио
5
@ Джорджио Наличие объектов помогает во многих других аспектах написания компилятора. Например, существует много состояний, с которыми приходится сталкиваться компилятору при оптимизации, и такие вещи хорошо подходят для ООП. Кроме того, ООП и функциональное программирование могут быть весьма комплиментарными, так как то, что алгоритмы могут быть в основном функциональными, не означает, что объекты не помогут.
Олекси
3
@ Джорджио и Олекси: Я могу подтвердить вас обоих. Я написал компилятор с Haskell для языка реального мира. Это было действительно хорошо подходит. Но иногда я пропускал некоторые OO вокруг. Если бы мне пришлось написать другой компилятор, я бы определенно выбрал Haskell, но это действительно особый случай. Я не стал бы выбирать Haskell без колебаний для других типов проектов.
шарфридж
27
Зачем вам нужен язык с «низкоуровневой стороной» для генерации кода? Я не вижу, как эти двое связаны каким-либо образом.
phant0m
5
Вам не нужна «низкоуровневая сторона» для генерации кода больше, чем нужны юникодные идентификаторы, чтобы иметь возможность записывать японский текст в файл.
dan04
17

Мой опыт не согласуется с вашей предпосылкой здесь. Фактически, для языков общего назначения высокого уровня, очень распространенной практикой является написание компилятора на том же языке, что и исходный (компилируемый язык). Например:

  • Java компилятор Sun написан на Java
  • Компилятор Scala написан на Scala
  • Моно C # компилятор написан на C #
  • Squick's Smalltalk компилятор написан на Smalltalk
  • ... и многое другое

Исключением являются внешние интерфейсы компилятора, написанные для существующих сред компиляторов, таких как GCC, LLVM или Polyglot, которые затем пишутся на языке платформы, или компиляторы, которые полагаются на существующие генераторы синтаксических анализаторов, такие как Yacc. Поскольку GCC, LLVM и Yacc являются распространенными, устоявшимися инструментами, написанными на C и C ++, это дает стимул авторам компиляции использовать их, что может привести к тому, что C и C ++ получат большую долю в распределении языков реализации компилятора.

дуб
источник
2
Я думаю, что это гораздо больше связано с тем, что люди, пишущие компилятор, хорошо знают и любят язык, для которого пишут компилятор, чем по объективным техническим причинам.
Томас Бонини
1
@Krelp Я согласен, что речь идет не об объективной технической причине, но на самом деле это не «симпатия» - это просто считается неким обрядом для языка - «достаточно ли он зрел, чтобы быть способным служить собственным языком реализации» компилятор».
Дуб
1
Java-компилятор Sun написан на C ++: stackoverflow.com/questions/410320/what-is-java-written-in
Klaim
12
@ Klaim вы путаете два продукта здесь. Одним из них является компилятор Java Sun ( javacкомандная строка), который компилирует Java в Java Bytecode. Он написан на Java - я сам много раз его модифицировал, и вы можете просматривать его источники в Интернете . Другой - это компилятор, работающий точно в срок, встроенный в JVM Hotspot, который компилирует байт-код Java в машинный код. Как и большая часть JVM, она написана на C ++, но не является компилятором Java - фактически, она ничего не знает о языке Java.
Дуб
@ Ок, абсолютно правильно! Другими словами, JVM! = Javac
Пол Дрейпер
6

Компилировать что к чему? Компилятор преобразует исходный код с одного языка (исходный язык) на другой (язык назначения), что ничего не говорит о низком уровне языка назначения.

  • CoffeeScript компилируется в JavaScript, а компилятор пишется на CoffeeScript.
  • Скрипт # компилирует C # в JavaScript, компилятор пишется, если я хорошо помню, C #.
  • и т.п.

Язык, который вы выбираете для написания компилятора, зависит от контекста. Например, работая над проектом, который компилирует язык, производный от PHP, в нативный PHP-код, я использовал смесь PHP и C # для написания компилятора, потому что для меня это было наиболее целесообразно, учитывая мои навыки. Другой человек выбрал бы Python, или Java и PHP, или C ++ с небольшим количеством JavaScript, или что-то еще.

C или C ++ является популярным выбором из-за поддержки инструментов, связанных с компилятором (см. Ответ Telastyn), а также потому, что эти два языка позволяют вам работать по-настоящему. Но нет ничего плохого в выборе другого языка.

Обратите внимание, что для большей увлеченности вы можете выбрать исходный язык для написания самого компилятора. Это то, что произошло с компилятором CoffeeScript и многими другими компиляторами. Он также популярен среди IDE: одна из первых Visual Studio была построена с использованием той же Visual Studio.

Арсений Мурзенко
источник
5
Самостоятельный хостинг не отвратительный, это важное свойство для портирования компилятора.
5
Причина в том, что он сразу позволяет самому компилятору быть тестовой программой. Скорее всего, это будет самая большая программа для этого компилятора на долгое время.
6

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

Хотя немного зависит от языка, который вы компилируете. Для небольших простых языков C и Pascal работают довольно хорошо. Если вы собираетесь скомпилировать что-то большое и сложное, ваш компилятор тоже станет большим и сложным - в этом случае дополнительные функции C ++ для организации и работы с более крупными программами, очевидно, пригодятся. Это на самом деле не очень специфично для компиляции, просто функции, полезные для больших программ в целом.

Я думаю, что стоит упомянуть еще один момент. Начинающие (кажется) думают о компиляторах, как в основном выполняющих манипуляции с текстом, поэтому они думают, что что-то вроде Perl будет огромной помощью при написании компиляторов. На самом деле, большинство интересных частей компиляции начинаются только после того, как вы создали AST. Хотя я уверен, что Perl может отлично справиться с этой задачей, его возможности манипулирования текстом на самом деле тоже не дают ему огромного преимущества (манипулирование текстом в основном в лексере, и генераторы лексеров для таких вещей, как C, все равно поддерживают RE).

Джерри Гроб
источник
2
AST = Абстрактное синтаксическое дерево, RE = Регулярные выражения
chaotic3quilibrium
5

Компиляторы могут быть реализованы на любом современном языке. Однако одно из самых важных требований компилятора - это быть быстрым.

С ++ имеет явное преимущество здесь. Оптимизация в C ++ не обходится дешево. Однако из-за низкоуровневой природы этого языка можно вручную оптимизировать код C ++ больше, чем на любом другом языке (кроме Assembly, который не является переносимым).

Лиор Коган
источник
11
Другим важным требованием является правильность сгенерированного кода - я предпочел бы иметь медленный компилятор, которому я могу доверять, чем быстрый, который генерирует некорректный код.
2
Хотя, безусловно, можно очень сильно оптимизировать C ++, существует довольно много… ну… далеко не оптимального кода C ++.
Donal Fellows
2
@DonalFellows Переверните все наоборот: на любом языке можно написать код, который не является оптимальным, но есть оптимизации, которые невозможно включить на других языках, кроме C ++ (кроме Assembler. Я не включаю C из-за отсутствия структур высокого уровня, позволяющих более сильное встраивание).
Klaim
3

Я подозреваю, что основным мотивом для их использования является то, что вывод Lex / Yacc / Bison (главным образом) в C. Так как это было стандартом так долго, у него есть импульс.

Не то чтобы это были веские причины ...

Telastyn
источник
На самом деле это не удовлетворяет меня, но спасибо за попытку.
Кобра
Это не отвечает на вопрос «зачем выбирать C ++ вместо C для компиляции».
Док Браун
3
Это не очень хорошая причина. Аналогичные инструменты для Lex и Yacc существуют для многих платформ. PLY и ANTLR, например.
user16764
Более того, большинство популярных реальных компиляторов (например, я точно знаю, что такое Clang и GCC) используют рукописные парсеры.
@delnan: Да, но они, вероятно, начали, используя сгенерированный, чтобы получить вещи от земли. Генерация парсера руками - это шаг оптимизации, который вы на самом деле не хотите делать, пока не докажете, что другие вещи работают.
Мартин Йорк,
1

У меня есть опыт в этом вопросе. Я написал компиляторы на C и C ++. Основное различие между C и C ++ состоит в том, что C не имеет автоматического управления динамической памятью. Все управление памятью в C должно быть сделано явно. Написание компилятора очень важно для обработки строк и управления массивами. В C вы вынуждены думать о размере каждой строки и каждого объявленного вами массива, а также проверять индексы при доступе к этим объектам (если вы хотите, чтобы ваш код был безопасным и стабильным). Конечно, в C вы можете иметь динамическое управление памятью, но ничего не происходит автоматически. Вы должны явно выделять и освобождать память, используя malloc () и free (), сохраняя размер ваших динамических объектов в разделенных переменных, чтобы быть уверенным, что вы не обращаетесь к ним за пределами.

В C ++ вы можете иметь те же механизмы, но это действительно экономит время разработки, потому что все управление вашей памятью может быть заключено в конструкторы и деструкторы, которые вам не нужно вызывать явно. Таким образом, компилятор выделяет и освобождает ресурсы для вас. Размер ваших динамических объектов также может быть инкапсулирован, если вы создаете свои собственные классы, и индексы могут быть проверены на граничный доступ с помощью оператора перегрузки []. Эти абстракции помогают сделать ваш код чище, проще для понимания и отладки и, безусловно, ускоряют разработку.

Если вы создадите компилятор в C, это наверняка займет больше времени. C ++ заставит вас закончить ваш проект за меньшее время. C и C ++ имеют одинаковую производительность, но C ++ имеет много преимуществ, которых нет у C.

Диего Марин
источник
0

Проект CompCert - это исследовательский компилятор C, который написан не на C или C ++, а на Ocaml и Coq.

Заметьте, что C ++ раньше переводили в C (в Cfront ). Теперь вы можете использовать интерфейс GCC для Gimple , затем выгрузить Gimple в некоторую базу данных, а затем написать Gimple для вашего ассемблерного переводчика. Но юридические причины ( исключение библиотеки времени выполнения GCC ) требуют, чтобы такой компилятор был открытым исходным кодом. Узнайте подробности у своего адвоката, я не юрист. Старые варианты GCC были написаны на C (+ несколько доменных языков) с внешним интерфейсом для некоторого варианта C ++. OpenWatcom может быть компилятором C ++, написанным на C (я оставляю вас проверить это).

Источник Compcert находится в свободном доступе для академических и исследовательских целей. Если вы хотите использовать его в промышленности (и на законных основаниях), вам необходимо получить лицензию от Absint.

Смотрите также это и это ответы на два связанных вопроса.

Если бы в 2020 году мне было поручено написать компилятор C (или C ++) с нуля (работающий в Linux, может быть, кросс-компилятор ), я, вероятно, не буду писать его на C ++. Я хотел бы написать это с помощью Ocaml , Go или Rust . И я мог бы основывать это на Frama-C, если это позволено. Если бы мне потребовалось кодировать на C или C ++, я бы сначала написал для него библиотеку сборщика мусора , возможно, некоторый постоянный уровень - очень полезный для оптимизации всей программы, - а затем я бы рассмотрел подход метапрограммирования (генерирующий большую часть кода C или C ++ из компилятор с моими специальными инструментами, возможно Bismon или RefPerSys если позволено).

Вы можете найти некоторые (более или менее с открытым исходным кодом) компиляторы C, написанные на Common Lisp или Python (например, ShivyC или nqcc ). Посмотрите также на ZetaC .

Обратите внимание, что последние версии GCC технически не кодируются на чистом C ++, они представляют собой дюжину доменных языков, участвующих в GCC (некоторые из них являются Turing-complete ). Смотрите также мой старый проект GCC MELT .

Я не удивлюсь, если в будущих версиях GCC в них будет встроен какой- либо интерпретатор Python или Guile (например, в качестве замены для менеджера проходов GCC).

Смотрите также в проект MILEPOST GCC .

Василий Старынкевич
источник