Несколько вопросов о компиляторах C ++: GCC, MSVC, Clang, Comeau и т. Д. - PullRequest
6 голосов
/ 16 марта 2011

У меня есть несколько вопросов о компиляторах C ++

  • Обязательны ли компиляторы C ++ однопроходный компилятор ? Стандарт говорит об этом где-нибудь?

  • В частности, является ли GCC однопроходным компилятором? Если это так, то почему он генерирует следующую ошибку дважды в в этом примере (хотя аргумент шаблона отличается в каждом сообщении об ошибке)?

    ошибка: объявление ‘сумматора элемент’ затеняет параметр
    ошибка: объявление ‘adder item’ скрывает параметр

Более общий вопрос


Полезные ссылки:

Ответы [ 5 ]

5 голосов
/ 16 марта 2011

Стандарт не устанавливает никаких требований в отношении того, как реализован компилятор.Но что вы подразумеваете под «однопроходным»?Большинство компиляторов сегодня читают входной файл только один раз.Они создают представление в памяти (часто в форме некоего вида дерева разбора) и могут сделать несколько проходов по нему.И почти наверняка сделать несколько проходов по его частям.Например, компилятор должен «проходить» по внутреннему представлению шаблона каждый раз при его создании;нет способа избежать этого.G ++ также «пропускает» шаблон, когда он определен, перед любой его реализацией и затем сообщает о некоторых ошибках.(Стандартный комитет специально разработал шаблоны, чтобы обеспечить максимальное обнаружение ошибок в точке определения. Это мотивация, например, для требования к названию типа в определенных местах.) Даже без шаблонов компилятору обычно приходится выполнять два прохода.над определением класса, если в нем определены функции.

Что касается более общего вопроса, опять же, я думаю, вам придется точно определить, что вы подразумеваете под "однопроходным".Сегодня я не знаю ни одного компилятора, который читает исходный файл несколько раз, но почти все будут посещать некоторые или все узлы в дереве разбора более одного раза.Это однопроходный или многоходовой?Различие было более значительным в прошлом, когда памяти было недостаточно для сохранения большей части исходного кода во внутреннем представлении.Такие языки, как Pascal и, в меньшей степени, C, иногда создавались так, чтобы их было легко реализовать с помощью однопроходного компилятора, поскольку однопроходный компилятор был бы значительно быстрее.Сегодня эта проблема в значительной степени неактуальна, и современные языки, включая C ++, имеют тенденцию игнорировать ее;где C ++, кажется, соответствует потребностям однопроходного компилятора, это в основном по причинам совместимости с C, и где совместимость с C не является проблемой (например, в определении класса), это часто делает порядок объявления неуместным.

3 голосов
/ 16 марта 2011

Из того, что я знаю, 30 лет назад было важно, чтобы компилятор был однопроходным, потому что чтение и запись на диск (или на магнитную ленту) были очень медленными и не хватало памяти для хранения всего кода (спасибо Джеймсу)Kanze).Кроме того, для сценариев / интерактивных языков требуется однопроходное.

В настоящее время компиляторы обычно не однопроходные, есть несколько промежуточных представлений (например, Абстрактное синтаксическое дерево или Статическая единичная форма назначения ), в которую код преобразуется, а затем анализируется / оптимизируется.

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

Что обычно происходит , а не , это то, что исходный код не анализируется несколько раз - в этом нет необходимостидля этого.Таким образом, вы не должны сталкиваться с одной и той же синтаксической ошибкой несколько раз.

2 голосов
/ 16 марта 2011
  1. Нет, я был бы удивлен, если бы вы нашли интенсивно используемый однопроходный компилятор C ++.
  2. Нет, он выполняет несколько проходов и даже различные оптимизации на основе флагов, которые вы передаете.

Преимущества (однопроходные): быстро! Поскольку весь источник необходимо проверить только один раз, фаза компиляции (и, следовательно, начало выполнения) может произойти очень быстро. Это также модель, которая привлекательна, потому что она делает компилятор простым для понимания и зачастую «более легким» для реализации. (Я работал над однопроходным компилятором Pascal один раз, но не часто с ними сталкиваюсь, тогда как однопроходные интерпретаторы встречаются часто)

Недостатки (sinlge-pass): Оптимизация, семантический / синтаксический анализ. Иногда один просмотр кода позволяет легко проходить через простые механизмы за несколько проходов. (вроде почему у нас есть такие вещи, как JSLint)

Преимущества (многоходовые): оптимизации, семантический / синтаксический анализ. Даже псевдоинтерпретируемые языки, такие как «JRuby», проходят процесс конвейерной компиляции, чтобы получить байт-код java / jvm перед выполнением, вы можете рассмотреть этот многоходовый проход, и множественный взгляд на изменяющиеся представления (и, следовательно, результирующие оптимизации) кода может сделать это очень быстро.

Недостатки (многоходовые): сложность, иногда время (в зависимости от того, используется ли AOT / JIT в качестве метода компиляции)

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

1 голос
/ 21 марта 2011

Уолтер Брайт, разработчик первого компилятора C ++, заявил, что он считает, что невозможно скомпилировать C ++ без как минимум 3 проходов.И, да, это означает 3 полных преобразования текста в источнике, а не только обходы через внутреннее представление дерева.См. его статью в журнале доктора Добба , "Почему компиляция C ++ такая медленная?"Так что любая надежда найти настоящий однопроходный компилятор кажется обреченной.(Я думаю, что это было частью мотивации, которую Брайту пришлось разработать D, его альтернативу C ++.)

1 голос
/ 16 марта 2011

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

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

...