Принципы и методы создания компилятора переднего плана Стандарта Cu ++ тема диссертации и автореферата по ВАК РФ 05.13.11, кандидат физико-математических наук Зуев, Евгений Александрович

  • Зуев, Евгений Александрович
  • кандидат физико-математических науккандидат физико-математических наук
  • 1999, Москва
  • Специальность ВАК РФ05.13.11
  • Количество страниц 174
Зуев, Евгений Александрович. Принципы и методы создания компилятора переднего плана Стандарта Cu ++: дис. кандидат физико-математических наук: 05.13.11 - Математическое и программное обеспечение вычислительных машин, комплексов и компьютерных сетей. Москва. 1999. 174 с.

Оглавление диссертации кандидат физико-математических наук Зуев, Евгений Александрович

Оглавление

Введение

Стандартизация ЯП

Процесс стандартизации Ада и Си++

Новый взгляд на задачу компиляции

Современные подходы к архитектуре СП

Язык Си++ и компилятор переднего плана Си++

Цели и задачи диссертационной работы

Результаты, апробация и новизна работы

Глава 1. Фазы компиляции и организация лексического разбора

1.1. Фазы компиляции. Различные формы реализации фаз

1.2. Предварительная обработка исходного текста: фазы 1-2

1.3. Особенности препроцессорной обработки: фазы 3-4

1.4. Завершение лексического разбора. Концепция непрерывной компиляции

1.5. Лексическая структура Си++

1.5.1. Подход к определению базового множества лексем

1.5.2. Классификация лексем базового множества

1.5.3. Модификация базового множества. Суперлексемы

1.5.4. Агрегация

1.5.5. Сепарация

1.5.6. Динамическое расширение 55 Заключение. Выводы главы 1

Глава 2. Синтаксический анализ языка Си++

2.1. Введение. Общая структура компилятора

2.2. Интерфейс фазы синтаксического анализа

и требования к его реализации

2.3. Основной принцип реализации синтаксического анализатора

2.4 Операция динамического расширения и механизм состояний

2.5 Разбор выражений языка Си++

Выводы главы 2

Глава 3. Управление контекстом компиляции и структура

семантических таблиц

3.1. Правила видимости имен в языке Си

3.2. Правила видимости в Си++

3.2.1. Единое пространство имен

3.2.2. Область действия объявления класса

3.2.3. Лексическая вложенность и отношения областей действия

3.2.4. Механизм наследования

3.2.5. Особенности вложенных и локальных классов

3.2.6. Дружественные функции

3.2.7. Пространства имен

3.3. Проблемы и требования

3.4. Традиционная организация семантических таблиц

3.5. Модель организации семантических таблиц для Си++

3.6. Обсуждение, замечания и примеры

3.7. Модельные операции управления контекстом 107 Заключение. Выводы главы 3

Глава 4. Механизм шаблонов и модель компиляции для Си++

4.1. Типовая параметризация структур данных и алгоритмов

4.2. Основные требования к реализации шаблонов

4.3. Модель семантических таблиц и механизм шаблонов

4.4. Представление параметров шаблона

4.5. Семантические отношения для механизма шаблонов

4.5.1. Отношение настройки

4.5.2. Отношение специализации

4.6. Модельные операции для механизма шаблонов

4.7. Модель программы Си++:

раздельная компиляция или модульность

4.8. Раздельная компиляция и механизм шаблонов

4.9. Поддержка механизма шаблонов на уровне системы программирования

4.10. Семантические таблицы и продвинутая модель компиляции

4.11. Концепция непрерывной компиляции

4.12. Расширенное множество операций модели семантических таблиц

Выводы главы 4

Заключение

Литература

Рекомендованный список диссертаций по специальности «Математическое и программное обеспечение вычислительных машин, комплексов и компьютерных сетей», 05.13.11 шифр ВАК

Введение диссертации (часть автореферата) на тему «Принципы и методы создания компилятора переднего плана Стандарта Cu ++»

Введение

Развитие и совершенствование языков программирования (ЯП) и соответствующих инструментальных средств разработки представляет собой одно из основополагающих направлений современной информатики, технологии и практики индустриального программирования. Потребность в мощных, гибких и надежных языковых инструментах, адекватных предельному уровню сложности и ответственности задач, решаемых программным обеспечением (ПО), определяет высокую активность исследований и разработок в данной области.

В настоящее время сложились две основных тенденции, связанные с проектированием и реализацией ЯП.

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

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

Рассмотрим эти направления подробнее.

Стандартизация ЯП

За последние пять лет в области языков программирования сложилась явная тенденция, которую можно охарактеризовать как процесс приведения распространенных ЯП промышленного назначения к унифицированным и международно признанным формам. Эта тенденция проявилась в активности международной организации (ISO - International Standard Organization) и авторитетных национальных институтов (прежде всего, ANSI - American National Standard Institute), воплотившейся в успешной стандартизации нескольких крупных ЯП. Ряд других ЯП находятся в настоящее время на различных стадиях процесса стандартизации.

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

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

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

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

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

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

Годы, предшествовавшие последнему пятилетию, дали несколько примеров стандартизации, заслуживающих упоминания в контексте позднейшей тенденции. Наряду с выдающимся успехом, связанным с созданием и стандартизацией языка Ада [1], следует отметить

относительную неудачу стандартизации языков Pascal [7] и Modula-2 [9]. Так, по общему мнению язык Паскаль был стандартизован до того, как были осознаны требования к этому языку как к инструменту практического программирования. В результате в стандарт не вошли некоторые важные черты (в частности, модульность и гибкие средства работы с массивами), предложенные позднее и зарекомендовавшие себя с положительной стороны. Язык, определенный стандартом, получился недостаточно мощным и развитым и оказался практически непригоден для промышленного использования. Это привело к существенному обесценению принятого стандарта и не послужило преградой появлению многочисленных диалектов и расширений, например Pascal фирмы Borland, объектно-ориентированные версии языка (входной язык системы Delphi, Pascal Plus [89], Pascal++ [90]) и т.п. Этими причинами было вызвано принятие уже через год нового стандарта расширенного Паскаля [13], которое в целом не изменило ситуацию к лучшему.

Следующий этап этого процесса, начало которого можно условно датировать серединой 90-х гг., знаменует собой успешное завершение ряда крупных проектов, среди которых можно упомянуть стандартизацию новой редакции языка Ада [2] (далее - Ада95), языка LISP [10] и языка Си++ [11]. Завершается стандартизация новой редакции языка Си [12], начался процесс стандартизации языка Java [99].

Из упомянутых выше проектов наиболее интересно проследить историю возникновения, развитие и стандартизацию таких мощных и развитых общецелевых языков программирования, как Ада и Си++.

Процесс стандартизации Ада и Си++

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

Что касается Ада95, то это в настоящее время практически единственный универсальный язык программирования, сравнимый с Си++ как по широте возможностей, общецелевому характеру предполагаемого применения, так и по достаточно полному и строгому концептуальному базису. Си++ и Ada95 являются наиболее развитыми современными проектами языков программирования с объектно-ориентированной парадигмой.

Оба этих языка возникли не на пустом месте. Их основой являются, соответственно, язык Си и предыдущая (1983 года) редакция языка Ада (далее - Ада83), хорошо зарекомендовавшие себя в практическим

программировании. Как уже говорилось, оба языка-предшественника были стандартизованы как ANSI, так и ISO [14], [1]; стандарт языка Ада95 принят в 1995 году, стандарт Си++ - в 1998 г.

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

Вместе с тем, характер проектирования и история развития этих языков существенно различны. Язык Си - предшественник Си++ -первоначально был создан как инструмент разработки новой операционной системы UNIX и предназначался для использования коллективом разработчиков в качестве системного языка реализации среднего уровня как альтернатива устаревшим к тому времени языкам типа BCPL [91]. Ничуть не умаляя достоинств Си, можно утверждать, что своим успехам он в значительной степени обязан выдающемуся успеху ОС UNIX. Стандартизация Си в 1989 году, скорее, была призвана зафиксировать сложившийся образ языка и остановить его "расползание" в виде многочисленных диалектов и фирменных расширений.

Язык Ада83, напротив, изначально проектировался как стандартный инструмент реализации широкого класса программных систем, причем конкретный вид языка определялся в ходе систематического процесса проектирования, начиная от выверенной концептуальной базы и совокупности исходных требований [71] до структуры языка и синтаксиса и семантики его конкретных конструкций.

Аналогичная ситуация сложилась с созданием Си++ и Ада95. Си++ возник в той же организации, что и Си и по существу в том же коллективе разработчиков. Первоначально язык представлял собой попытку просто расширить Си понятиями объектно-ориентированного прграммирования, как они сложились к началу 80-х годов. Название языка - "Си с классами" [44] - в точности отражало вполне скромные намерения авторов, что подтверждает и препроцессорная схема его реализации, предложенная в той же статье.

Последующие этапы развития языка [118], которые можно проследить по работам [47], [45], [114], а также начавшийся в 1990 году процесс его стандартизации [16-17], наглядно иллюстрируют хаотический и спонтанный характер превращения "Си с классами" в полноценный объектно-ориентированный язык общего назначения, в котором его создатели сремятся, с одной стороны, преодолеть ряд известных недостатков языка Си [77-79], сохранив в то же время совместимость с ним, с другой стороны, обеспечить приемлемую степень надежности, достаточную для использования Си++ в ответственных проектах, и, наконец, реализовать в языке как можно больше концепций и возможностей, возникших и утвердившихся в программировании к настоящму моменту. В результате типичной

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

Несмотря на то, что процесс стандартизации языка начался еще в 1990 году, срок завершения этого процесса неоднократно переносился. В результате Международный Стандарт был принят только в 1998 году, более чем с четырехлетним опозданием. Чрезмерно затянутая процедура формирования и принятия Стандарта привела к тому, что язык вступил в конфликт со своими реализациями: за это время появилось значительное число компиляторов Си++ промышленного уровня, содержащих собственные интерпретации многочисленных непроясненных Стандартом мест языка. В результате окончательная версия Стандарта содержит большое число компромиссов между решениями различных фирм-производителей компиляторов, а также между рабочей группой WG21 ANSI/ISO и разработчиками компиляторов. Примером может служить использование настроек шаблонов в многомодульных программах (проблема раздельной компиляции шаблонов), описанная в разд. 4.8.

Заметим, что процесс стандартизации языка Си++, как таковой, включая историию принятия и отказа от тех или иных черт языка, содержание и характер обсуждений и дискуссий, отраженные в многочисленных документах рабочих групп комитетов ISO и ANSI, наконец, эволюцию языка в виде последовательных редакциях предварительного стандарта, по нашему мнению, заслуживают самого тщательного изучения. Такое исследование было бы очень полезно для понимания современных взглядов на программистскую деятельность, текущего уровня развития науки программирования, характера требований, предъявляемых к инструментальным языковым средствам со стороны прикладных областей, и, между прочим, для оценки уровня квалификации и глубины анализа, выказываемых мировыми специалистами в программировании.

В противоположность Си++, проектирование языка Ада95 носило в высшей степени тщательный, последовательный и систематический характер. Как и в случае предыдущей версии языка - Ада83,- были сформулированы причины, приведшие к необходимости развития языка (было решено именно развивать существующий язык, а не проектировать новый), и требования к его новой версии [72]. Новые возможности введены в язык очень аккуратно; как правило, они ортогональны уже имеющимся, не пересекаясь с ними. Уточнения и расширения существующих свойств языка производились только при наличии существенных потребностей. Полностью актуальным оставался принцип "Программа - прежде всего средство общения людей друг с другом и только после этого - средство общения человека с компьютером". Иными словами, Ада95, обогатившись новыми концепциями и возможностями и избавившись от некоторых недостатков своего предшественника, нисколько не потерял в читабельности и наглядности программ.

Помимо собственно стандарта языка и параллельно с ним был разработан целый ряд важных дополнительных документов как нормативного, так и рекомендательного характера, в том числе, обоснование языка [5], аннотированный стандарт [4], описание изменении языка по сравнению с предыдущей его редакцией [3], руководство по стилю программирования [6], порядок перехода к новой редакции [73] и т.д. Подробные сведения об истории создания языка Ада95 содержатся в работе [76].

В результате, Ада95, нисколько не проигрывая Си++ по набору возможностей, выглядит заметно стройнее, целостнее, надежнее и проще для изучения и использования. Предмет диссертационной работы не предполагает детального сравнения этих языков; содержательный сравнительный анализ Си++ и Ада95, проведенный как с позиций противников и сторонников одного из этих языков, так и нейтральные по своему характеру, можно найти в работах [80-87]. Здесь заметим только, что, несмотря на лучшую проработанность проекта Ада95, этот язык уступает в распространенности Си++. Причиной тому является множество обстоятельств, в том числе ряд устоявшихся предрассудков относительно языка Ада, большинство которых убедительно опровергается в [74].

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

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

ЯП, определенные в виде международных стандартов, фактически являются своего рода островами стабильности в бурном море сменяющих друг друга программных технологий, парадигм и даже поколений аппаратных средств. Установленный ISO пятилетний срок пересмотра стандартов на ЯП предоставляет достаточную перспективу для использования таких стандартов. С другой стороны, анализ конкретных случаев пересмотра стандартов (например, Ada 83 [1] и Ada 95 [2], Си [14] и проект стандарта С9Х [12]) показывает, что новые стандарты обеспечивают весьма тесную преемственность со своими предшественниками (вплоть до совместимости снизу вверх). Понятно, что такая совместимость увеличивает реальный "срок службы"

стандартного ЯП и придает дополнительную уверенность при выборе такого языка в качестве инструмента промышленного программирования.

Что же касается направления исследований, заявленных в названии диссертационной работы, и конкретной реализации Си++, лежащей в ее основе, то приведенные соображения одновременно являются аргументами для выбора Си++ как предмета исследований и объекта компиляции. Ниже в данном Введении мы рассмотрим ряд дополнительных аргументов в пользу выбора этого языка.

Новый взгляд на задачу компиляции

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

Рис.1 Традиционное понимание задачи компиляции

Возрастающая сложность программных систем, индустриализация процесса их создания, повышенные требования к их надежности и необходимость увеличения производительности труда разработчиков ПО привели к необходимости "некомпилирующих" системных средств дополнительного характера. Примером служат символьные отладчики, которые позволяли бы проводить отладку программ в терминах исходного ЯП. Требования расширения арсенала разработчиков привели к частичному переосмыслению описанной схемы. Теперь результирующий код, сформированный компилятором, трактуется не только как объект, подлежащий выполнению, но и как исходная информация для проведения ряда качественно иных работ.

Так, объектный код программы, дополненный информацией, связывающей его с исходным текстом, служит основой для отладочного исполнения программы с выдачей (в терминах исходного ЯП) разнообразной информации о процессе ее выполнения. Далее, компилятор может включить в объектный код дополнительную функциональность, направленную на снятие динамических характеристик ("профиля") программы (утилита gprof в системе GNU, Turbo Profiler фирмы Borland). Еще один характерный пример - так называемое обратная компиляция (reverse compilation, decompilation [31]) или "дизассемблирование" - восстановление программы по ее объектному коду в удобном для восприятия человеком формате (в частности, в виде текста на исходном ЯП).

Общим для перечисленных и других подобных дополнительных средств является то, что все они базируются на сгенерированном компилятором объектном коде, возможно, дополненным структурами, которые традиционно называются отладочной информацией. Это общее свойство является одновременно и принципиальным недостатком подобных средств. В распространенных форматах объектного кода, в частности, в COFF [108] и ELF [109] отладочная информация носит вторичный, дополнительный характер и содержит далеко не полное знание об исходном тексте программы. Специальные форматы для хранения отладочной информации, например, STABS [110], и в особенности DWARF [111], предоставляют более развитые средства, однако и их возможности ограничены. Характерными выглядят попытки преодолеть этот недостаток, например, в компиляторе GNAT для языка Ада95: объектный код, формируемый этим компилятором, содержит полный исходный текст единицы компиляции!

С другой стороны, легко видеть, что структуры, генерируемые компилятором в процессе работы, прежде всего, таблицы символов и дерево программы, по своему назначению как раз и призваны максимально адекватно соответствовать исходной программе. Более того, любой компилятор в процессе семантического анализа выявляет ряд скрытых (неявно присущих программе) свойств и отображает их в указанных структурах. Типичными примерами таких неявных свойств служат обработка совместно используемых операций Си++ [11, глава 13], семантика которых предполагает вызов специальных функций-операций, а также настройка шаблонов функций, в процессе которой может осуществляться глубокое перестроение их алгоритмов.

Далее, возрастающая сложность создаваемого ПО и, что самое главное, расширение задач, стоящих перед индустрией программирования, постепенно привели к изменению во взглядах на то, что в отечественной литературе традиционно называется системой программирования [19] или окружение программирования [36]. Более адекватным современному пониманию целей и задач СП является трактовка задачи компиляции в более широком смысле, нежели ранее -не только как генерацию кода, пригодного для исполнения, но и как широкий спектр операций над текстами программ.

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

1. Компиляция (в узком смысле - как получение исполняемого кода) остается основной функцией систем программирования. При этом особое значение придается таким задачам, как межъязыковое связывание (конструирование программ, компоненты которых написаны на различных ЯП, интероперабельность (динамическое взаимодействие программ) и в особенности межмодульная и глобальная оптимизация получаемого кода (например, [61], [37]). Мы вернемся к этим задачам немного далее.

2. Возникает целый комплекс задач, связанных с пониманием программ человеком. Несмотря на существенные усилия, предпринятые для повышения читабельности программ, анализ больших программных

текстов, приобретая очень важное значение в современной индустрии ПО, остается одним из самых трудоемких и тяжелых задач. В связи с этим за последние годы был предложен ряд методик, призванных отобразить различные характеристики программ (структуру, связи между подпрограммами и модулями, информационные потоки, потоки управления и т.п.) в форме, облегчающей их восприятие человеком. Такие методики (наиболее известной и развитой является нотация Г. Буча), как правило, являются обратимыми, то есть могут использоваться как для анализа существующих программ, так и для проектированиия нового ПО. С некоторой долей огрубления указанный комплекс задач можно назвать визуализацией. Помимо методологии и графической нотации UML, основанной на работах Г. Буча и реализованной для широко распространенных ЯП (см., например [30]), имеется ряд менее масштабных, но весьма практичных разработок, предлагающих удобные способы графического представления программ, например, система GRASP [26], созданная в университете Auburn и поддерживающая Ada95, Си++ и Java.

3. Относительно известной, но остающейся принципиально важной является задача верификации программ. Под этим понимается многоаспектная деятельность как по выявлению тонких ошибок, случаев использования допустимых, но потенциально опасных свойств того или иного языка, сомнительных с точки зрения эффективности фрагментов программ, так и проверка программы на предмет соблюдения корпоративных или отраслевых стандартов на стиль программирования (например, Ada Style Guide [6]) или локальных ограничений. Одним из наиболее известных подобных средств является стандартная в ОС UNIX утилита lint для языка Си и ее позднейшие версии для Си++ [28]. Хотя формально некоторые из перечисленных задач являются, скорее, задачей традиционной компиляции, с практической точки зрения бывает более целесообразно выделить их в отдельную функциональность.

4. Сохраняет свою актуальность и задача статического анализа программ. С момента появления первых исследований, связанных с формальной оценкой программ по различным метрикам [27], было предложено много различных метрик и систем метрик (например, [29]). Во многих случаях статический анализ является необходимым элементом жизненного цикла разработки ПО и потому нуждается в соответствующей программной поддержке.

5. В последнее время, прежде всего в связи с успехом языка Java [99], вновь возник интерес к интерпретационной схеме исполнения программ. Существенно возросшая производительность вычислительных систем поставила интерпретацию в ряд практичных подходов для многих реальных применений, не требующих предельной эффективности. Для некоторых ЯП, например, для Си++ интерпретационная схема (или интерпретирующая трансляция, interpretive translation [32]), не отменяя очевидных достоинств непосредственного выполнения, потенциально может дать ряд преимуществ. Основной выгодой интерпретационного подхода является повышенный диагностический сервис периода исполнения, недостижимый в полном объеме для традиционного исполнения на

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

Как известно, модель исполнения, разработанная для Java, основана на концепции виртуальной машины ([104], [105]). Для повышения уровня и возможностей отладки, а также для целей повышения надежности при исполнении программ на Си++ вполне практичным и актуальным становится создание интерпретирующих и отладочных систем на основе виртуальной машины Си++ [126], [127].

Решение перечисленных задач базируется на совокупности алгоритмов лексического, синтаксического и семантического анализа исходных программ, то есть, на алгоритмах, составлявших существо традиционного понимания компиляции. Таким образом, перечисленные компоненты традиционного компилятора, часто называемые компилятором переднего плана (front end compiler [18]), выступают в качестве ядра современных систем разработки. Информационное взаимодействие между компилятором переднего плана и другими компонентами такой системы осуществляется посредством информационных структур (основные из которых - дерево программы и таблица символов), которые в данном случае перестают быть внутренними структурами компилятора и логически выносятся вовне его, образуя промежуточное представление программы (ПП, intermediate representation, IR [100]). Описанная модель представлена на рис. 2.

Еще раз отметим преимущества такой схемы. Во-первых, промежуточное представление, сформированное фазами анализа, по своему назначению и смыслу в точности соответствует исходной программе на ЯП. Оно несет в себе полное знание об исходной программе, в том числе, и такие его аспекты, которые присутствуют в исходной программе неявно.

Во-вторых, промежуточное представление содержит только ту информацию, которая относится к синтаксису и семантике исходной программы, и не включает каких-либо узкоспециализированных структур (например, объектный код). Тем самым, ПП может выступать в роли универсального интерфейса между компилятором переднего плана и разнообразных языко-ориентированных компонент систем разработки.

В-третьих, промежуточное представление, в отличие от многих форматов (где отладочная информация носит дополнительный и вторичный характер), может быть сконструировано таким образом, чтобы обеспечить максимально эффективный доступ ко всем его элементам.

Рис.2 Компилятор переднего плана как ядро системы разработки ПО

Современные подходы к архитектуре СП

В дополнение к проведенному рассмотрению необходимо упомянуть еще о трех весьма важных и характерных подходах к созданию систем программирования, в которых модель "компилятор переднего плана - промежуточное представление программы" играет центральную роль. Речь идет о многоязыковых и многоплатформенных системах программирования, о продвинутых схемах комплексирования программ и о концепции семантического интерфейса.

Исторически понятие компилятора переднего плана возникло (см., например, [18]) именно в связи с созданием многоязыковых систем программирования, ориентированных на различные аппаратные архитектуры. Наиболее ярким примером многоязыковой системы служит комплекс GCC, создаваемый в рамках проекта GNU [24] под эгидой Фонда свободного ПО (Free Software Foundation). Система GCC подерживает такие входные языки, как Си, Objective С, Си++, Ада, Ада 95, и обеспечивает генерацию оптимизированного объектного кода для более полутора десятков программно-аппаратных платформ, среди которых процессоры компаний Inel, Motorola, Sun и т.д.

На аналогичной архитектуре основаны компиляторы семейства TopSpeed (языки Си, Pascal и Modua-2 для РС-совместимых персональных компьютеров), а также разработки компании АСЕ: система CoSy [22] для операционных систем Solaris, Linux, HP-UX, Windows NT; ее входными языками являются Си различных диалектов, Си++, Fortran-95, HPF, Java.

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

Выгода такой архитектуры наглядно представлена на следующих таблицах. Если система программирования рассчитана на п входных языков и m целевых процессоров, то при традиционной организации необходимо т*п компиляторов (Таблица 1).

Таблица 1. Традиционное построение системы программирования.

Входной язык Li Входной ЯЗЫК l_2 Входной ЯЗЫК U

Целевой процессор Pi Компилятор Lr>Pi Компилятор L2->Pi Компилятор Ln->Pi

Целевой процессор Р2 Компилятор Li->P2 Компилятор 1_2->Р2 Компилятор Ln->P2

Целевой процессор Рт Компилятор Li->Pm Компилятор L2->Pm Компилятор Ln->Pm

Если же строить систему программирования как конструкцию с явно выделенными языко-зависимыми частями (компиляторами переднего плана) и аппаратно-зависимыми генераторами объектного кода, взаимодействующими посредством единого промежуточного представления (см. Таблицу 2), то общее число компонент сокращается до т+п. При этом, чтобы добавить в систему дополнительные возможности, например, реализовать поддержку нового ЯП, то достаточно разработать для этого языка компилятор переднего плана. В результате почти автоматически обеспечивается реализация нового ЯП для всех аппаратных архитектур, уже поддерживаемых таким комплексом. Аналогично, добавление генератора кода для некоторой новой архитектуры дает возможность разрабатывать программы для этой архитектуры на любом ЯП из числа реализованных.

Таблица 2. Система программирования как композиция языко- и платформенно-зависимых компонент

Входной ЯЗЫК 1_1 Входной ЯЗЫК 1_2 Входной язык Ln

Компилятор переднего плана Li->IR Компилятор переднего плана l_2->IR Компилятор переднего плана Ln->IR

Целевой процессор Pi Генератор кода IR->Pi

Целевой процессор Рт Генератор кода IR->Pm

Заметим однако, что на структуру промежуточного представления в подобных системах накладываются специфические ограничения. По очевидным причинам ПП должно быть архитектурно-нейтральным [112], то есть иметь относительно высокий уровень, и быть достаточно мощным и развитым, чтобы отображать семантику языковых конструкций всего набора поддерживаемых ЯП. На практике удовлетворение этих требований осуществляется за счет определенных отступлений от идеальной схемы, описанной выше: так например, компилятор GNAT формирует собственное промежуточное представление, отличное от принятого в GCC, и обеспечивает совместимость со всей системой GCC за счет введения дополнительной фазы конвертации своего ПП в стандартный формат системы (программа gigi).

Второе направление, в рамках которого концепция промежуточного представления программы играет центральную роль,- нетрадиционный подход к комплексированию программ.

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

независимо от других модулей. Редактор связей воспринимает множество объектных кодов модулей, разрешает межмодульные ссылки и формирует исполняемый код всей программы.

Рис. 3 Традиционный подход к формированию исполняемой программы

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

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

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

Для ликвидации этого эффекта (который невозможно обнаружить в случае раздельной компиляции модулей) предлагается ряд методов и специализированных инструментов, некоторые примеры которых описаны в работах [66], [20], [69]: к ним относятся пост-линкеры, многоступенчатые схемы работы компилятора и комплексатора, особая дисциплина именования и хранения модулей, специальные правила программирования и т.д. Стратегия и тактика применения этих методик и средств часто практически целиком ложатся на разработчика, требуют глубокого анализа структуры всей программы и в целом не гарантируют полной оптимизации настроек шаблонов.

Предлагаются и в некотором смысле противоположные методики, в которых основная нагрузка по ликвидации размножения кода ложится на оптимизирующие комплексаторы, выявляющие повторные вхождения настроек и удаляющие их из результирующего кода. Заметим, что такой подход требует существенного усложнения функциональности комплексатора и не приводит к полному решению проблемы, хотя бы потому, что идентичные настройки остаются в объектных кодах отдельных модулей.

Наконец, третий существенный недостаток традиционной схемы с раздельной компиляцией и комплексировнием низкоуровневых объектных кодов заключается в ограниченных возможностях межмодульной и глобальной оптимизации программы [37]. В условиях, когда значительная часть информации об исходной программе потеряна, редактор связей (либо специальный оптимизатор, который работает по скомплексированной программе), имея дело, по существу, с машинным кодом, как правило, не в состоянии провести должный анализ особенностей исходной программы в целом. В частности, не располагая семантическим деревом всей программы и таблицами объектов, крайне затруднительно анализировать такие характерные особенности программы, как использование встраиваемых функций и шаблонов, полный граф вызовов функций, контролировать характер использования глобальных и статических объектов, границы распространения исключительных ситуаций, оптимизировать работу с динамическими объектами и т.д.

Необходимость преодоления указанных недостатков традиционной схемы комплексирования привела к появлению альтернативной схемы, которая (с теми или иными вариациями) реализована в таких системах, как компилятор Ultra С++ для операционной системы OS-9 фирмы Microware [61] и VisualAge for С++ фирмы IBM [62].

Например, компилятор Ultra С++, в отличие от традиционных, компилирует исходный текст единицы трансляции не в ассемблерный код конкретного процессора, а в специальное промежуточное представление (l-Code), не зависящее от входного языка и целевого процессора. Промежуточные представления модулей комплексируются

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

Рис. 4 Усовершенствованная схема комппексирования программ

Более того, такой подход позволяет значительно усовершенствовать методы разработки программ и стиль программирования. Так, механизм межмодульного взаимодействия в языках Си и Си++, специфицируемый посредством include-файлов, приводит к трудноуловимым ошибкам и многочисленным проблемам и, в частности, вынуждает программиста постоянно поддерживать в актуальном состоянии схему зависимостей модулей, используя средства, подобные make [25] и gendep [23]. По этим причинам данный механизм давно подвергается обоснованной критике [79]. Продвинутая схема комплексирования позволяет решить указанные проблемы, используя единый репозиторий программного проекта, представленный

в виде промежуточного представления. Например, компилятор VisualAge for С++ позволяет формировать и компилировать модули проекта способом, наиболее адекватным с точки зрения логической структуры программы, без учета межмодульных зависимостей. В результате использование include-файлов может быть практически полностью исключено.

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

Наконец, кратко рассмотрим третье важное понятие, реализация которого существенно основывается на промежуточном представлении программ. Речь идет о концепции семантического интерфейса.

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

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

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

Заметный толчок концепция семантического интерфейса получила в последнее время, прежде всего в связи с процессом разработки и принятия в 1998 году Международного Стандарта ASIS (Ada Semantic Interface Specification) [8]. Аналогичные проекты для языка Си++ пока не носят характер стандартизации и находятся в стадии разработки; в качестве наиболее известной системы такого рода можно упомянуть SAGE++ [57].

Тесную связь между задачей компиляции и реализацией семантического интерфейса можно проиллюстрировать подходом, принятым при реализации стандарта ASIS [75], [120], для Ада-компилятора GNAT. Интерфейсные запросы, входящие в состав ASIS, реализуются на основе доступа к промежуточному представлению (аннотированному дереву программы и таблице символов), формируемому компилятором GNAT и доступному его клиентам. Таким образом, компилятор переднего плана берет на себя всю работу по синтаксическому и семантическому анализу входной программы, а интерфейс ASIS выступает в качестве стандартной "прослойки" между промежуточным представлением и специализированными конечными процессорами ("back-ends").

Принципиальную архитектуру системы, основанной на концепции семантического интерфейса, можно представить в виде следующей схемы:

Исходный текст программы или модуля

^ Чтение текста

I

Рис.5 Система программирования на основе семантического интерфейса

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

В заключение данного раздела кратко остановимся на современном опыте проектирования и реализации промежуточного представления. В настоящее время эта область оформляется в самостоятельное направление исследований: создается большое разнообразие структур ПП, в зависимости от задач, стоящих перед разработчиками, проводятся конференции и семинары по данной проблематике, например [100]. Спектр подходов можно охарактеризовать следующим образом. На одном конце спектра располагается низкоуровневый код, представляющий собой, по существу, обобщенный ассемблер для процессора с традиционной архитектурой [94], либо язык некоторой абстрактной стековой машины [103-105], [107]. Другой конец этого спектра образуют полноценные языки программирования, в качестве которых может выступать, например, Си [21] или некоторый специально спроектированный ЯП [113]. В некоторых многоязыковых и многоплатформных системах встречаются сочетания этих "краевых" подходов [21].

Упомянутые подходы имеют очевидные основания и преимущества, однако вызывают также справедливую критику. "Обобщенный ассемблер" удобен для многоплатформных систем программирования, однако уже обсуждавшиеся проблемы соответствия с исходным текстом не позволяют считать его приемлемым решением для современных СП. ПП, ориентированное на абстрактную машину, критикуется во многом по тем же причинам; кроме того, такой подход слишком однозначно ориентирован на интерпретационную стратегию исполнения программ и, следовательно, затрудняет традиционную реализацию ЯП. Анализ недостатков подхода, связанного с понятием абстрактной машины, можно найти в известной работе [106].

С другой стороны, использование в качестве промежуточного представления некоторого ЯП приводит к ряду проблем, связанных с неизбежным "семантическим зазором" между исходным и целевым языком; для преодоления этого зазора разработчикам приходится прибегать к различного рода "трюкам" [21]. Это может существенно обесценить преимущества такого подхода. Кроме того, данная схема, по существу, переносит проблемы адекватного представления информации об исходной программе на систему программирования (компилятор и пр.) целевого языка. Наконец, использование ЯП в качестве целевого языка весьма неэффективно. Так, по оценке компании Microtec [69] переход от компиляции Си++ в Си к прямой компиляции в промежуточное представление дает 30-процентное повышение общего времени компиляции.

По этим причинам наиболее перспективным представляется подход, в котором в качестве промежуточного представления выступают структуры, традиционно формируемые компилятором в процессе обработки текстов исходных программ,- абстрактное синтаксическое дерево (или дерево, "аннотированное" семантическими атрибутами, или семантический граф программы), а также семантические таблицы (в зарубежной литературе обычно называемые таблицами символов). Например, дерево программы и таблицы символов использует в качестве ПП семейство компиляторов компании Green Hills Software [67].

Показательным примером служит GNAT - компилятор языка Ada95. Первоначально GNAT, будучи интегрированным в систему GCC, вырабатывал общее для всех компиляторов этой системы низкоуровневое промежуточное представление в формате RTL (Register Transfer Language). Однако в процессе реализации интерфеса ASIS для этого компилятора разработчики обеспечили в качестве альтернативного результата трансляции полное дерево исходной Ada-программы, которое GNAT формирует в процессе работы.

Язык Си++ и компилятор переднего плана Си++

Базовым языком для обсуждения в диссертационной работе выбран язык Си++. Это решение основывается на ряде обстоятельств, некоторые из которых были отмечены выше.

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

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

Помимо широкой распространенности и популярности, в том числе, и в отчественной практике программирования, язык Си++ служит технологической основой перспективной парадигмы, возникшей в недавнее время,- обобщенного программирования (generic programming, [50]). Основным инструментом реализации обобщенного программирования на языке Си++ служит механизм шаблонов [11, глава 14]; наиболее развернутым и убедительным примером использования этой парадигмы является Стандартная Библиотека Шаблонов (Standard

Template Library, STL), разработанная А.Степановым и М.Ли [52] и вошедшая в 1994 г. [51] в состав стандартной библиотеки Си++.

Еще одно обстоятельство, обусловившее выбор языка Си++ как базового для данной диссертационной работы,- принятие в конце 1998 г. Международного Стандарта ANSI/ISO этого языка. Факт стандартизации для такого большого, сложного и современного языка, как Си++, трудно переоценить. Если говорить коротко, Си++ становится инструментом промышленного программирования в общемировом масштабе. Приверженность все большего числа корпоративных разработчиков ПО к использованию типовых решений и стандартизованных инструментальных средств дает твердую уверенность в успешных перспективах Си++, по крайней мере, на ближайшие десять-пятнадцать лет (примерный срок смены поколений языков программирования).

Дополнительным аргументом является опыт, полученный автором в процессе проектирования и реализации компилятора переднего плана языка Си++ [114], [117-119], [121-124], [126-127]. Найденные проектные и технические решения послужили практической основой и подтверждением рассмотрений и выводов, составляющих содержание последующих глав.

При этом необходимо заметить, что информация о принципах и методах трансляции Си++, реализованных в конкретных зарубежных компиляторах, крайне скудна, прежде всего, по причине коммерческой ориентации большинства таких проектов. Имеется ограниченное количество публикаций преимущественно академического характера, среди которых следует отметить [56] и [54], относящиеся к ранним этапам эволюции Си++. Среди других работ интерес представляют [55] и [45], которые рассматривают отдельные аспекты компиляции Си++. Сведения о коммерческих проектах, основанных на языке Си++ [63] [6569], хотя и позволяют получить представление о современном уровне решения проблем, связанных с реализацией Си++, как правило, ограничиваются изложением общих принципов и подходов и потребительскими характеристиками компиляторов.

Тем не менее, анализ отмеченных во Введении особенностей и тенденций в построении современных окружений программирования позволяет предложить следующую принципиальную модель ядра системы программирования для языка Си++. Модель (см. рис. 6) включает две основные сущности: компилятор переднего плана Си++ и промежуточное представление программы на Си++.

Компилятор переднего плана Си++

Лексичес- Синтакси- Семанти- Конструиро-

ким чески и ческий вание и

анализ анализ анализ анализ ТТТ

Рис. 6. Принципиальная модель компиляции

Промежуточное представление, конструируемое компилятором, представляет собой композицию трех основных компонент:

• Дерево программы, отражающее синтаксическую структуру исходной программы на Си++. Узлы дерева содержат дополнительные атрибуты, уточняющие семантические свойства конструкций.

• Семантические таблицы, содержащие семантические атрибуты всех объектов программы и представляющие иерархию областей действия.

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

По начальным буквам английских эквивалентов перечисленных компонент (Trees, Tables, Types) промежуточное представление получило аббревиатуру ТТТ.

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

промежуточного представления,- конструктор/анализатор ТТТ. Эта компонента (которая может быть либо интегрирована в компилятор, либо реализована в виде отдельной системной библиотеки в составе СП) позволяет как строить ТТТ, так и воспринимать ранее построенное. Такая особенность дает компилятору принципиальную возможность обрабатывать отдельную единицу трансляции в контексте других, ранее откомпилированных модулей всей программы.

Такая архитектура компилятора, помимо удовлетворения потребности в полном сохранении информации об исходных программах, позволит достичь следующих важных целей:

Во-первых, компиляция единицы трансляции в контексте ранее откомпилированных единиц ("непрерывная" компиляция) устранит потребность в отдельном этапе обработки программы - разрешении внешних ссылок и, тем самым, позволит обойтись без использования традиционного редактора связей (linkage editor). Исключение этапа комплексации должно существенно увеличить общую эффективность системы программирования, а возможные ошибки в межмодульных связях будут выявляться непосредственно компилятором, что повысит точность и качество диагностики.

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

В-третьих, единое промежуточное представление программы открывает возможность глубокой глобальной оптимизации, основанной на доступе к полной информации о программе.

Структура компилятора переднего плана, основанная на представленной выше принципиальной модели, рассматривается в начале главы 2. Механизм, реализующий непрерывный подход к компиляции, более подробно обсуждается в главе 4.

Цели и задачи диссертационной работы

На основе предложенной выше принципиальной модели компилятора переднего плана Си++ можно следующим образом сформулировать цели и задачи настоящей диссертационной работы.

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

В соответствии с этой целью были определены следующие конкретные задачи:

• Разработать подход к реализации начальных фаз трансляции, обеспечивающий более высокую, по сравнению с традиционными реализациями, эффективность лексического анализа.

• Предложить методы реализации синтаксического анализа, учитывающие особенности синтаксиса и семантики входного языка.

• Описать и реализовать модель семантических таблиц компилятора, адекватную понятию области действия Си++ и правилам видимости имен и эффективно поддерживающую правила поиска имен Си++.

• Обосновать применимость модели семантических таблиц для реализации механизма шаблонов Си++ и для нетрадиционного подхода к компиляции.

Некоторые другие аспекты сформулированной цели, в частности, приницпы отображения системы типов в промежуточном представлении, реализация поисковых алгоритмов компилятора и семантика механизма исключительных ситуаций, рассматриваются в диссертационной работе [59].

Результаты, апробация и новизна работы

В процессе проведения исследований автором получены следующие результаты:

• Спроектирована общая структура промежуточного представления программ на Си++, включающая дерево программы, семантические таблицы и систему типов.

• Реализована система семантических таблиц, используемая для анализа, хранения и последующей обработки семантической информации о программных сущностях Си++ и иерархии контекстов, а также интерфейсный пакет функций доступа к семантическим таблицам.

• Разработана общая структура компилятора переднего плана Стандарта Си++.

• Разработаны и реализованы компоненты компилятора переднего плана, выполняющие лексический, синтаксический и (частично) семантический анализ. Общий объем компонент, реализованных лично автором, составляет более 70.000 строк на языке Си++.

• Создан первый в России промышленный компилятор языка Си++ и один из первых компиляторов, реализующих полный стандарт Си++.

Результаты, полученные в работе, изложены в ряде печатных публикаций, докладывались на научных конференциях и семинарах, в частности:

• на Первой российской конференции "Индустрия программирования'96", Москва, 3-4 октября 1996 г.;

• на IV Международной конференции "Развитие и применение открытых систем", Н.Новгород, 27-31 октября 1997 г.;

• на Интернет-форуме компании Инфоарт "Языки программирования и Интернет", июль 1998;

• на Ломоносовских чтениях в МГУ им. Ломоносова в 1993-1999 гг.

Научная новизна представляемой работы может быть охарактеризована следующими тезисами:

1. Исследованы современные тенденции создания средств и систем программирования, ориентированных на промышленное использование.

2. На основе выполненных исследований разработаны архитектура и принципы построения компилятора переднего плана языка Си++ как системообразующего ядра многоцелевой системы программирования, включающей набор компонент для выполнения различных операций над текстами программ.

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

4. Проведен подробный анализ понятия области действия Си++, предложена и реализована модель семантических таблиц компилятора, адекватно отражающая это понятие.

5. Исследована семантика параметризуемых типов и алгоритмов Си++, предложены и реализованы принципы реализации механизма шаблонов в компиляторе переднего плана. Показана адекватность модели семантических таблиц семантике шаблонов классов и функций.

Похожие диссертационные работы по специальности «Математическое и программное обеспечение вычислительных машин, комплексов и компьютерных сетей», 05.13.11 шифр ВАК

Заключение диссертации по теме «Математическое и программное обеспечение вычислительных машин, комплексов и компьютерных сетей», Зуев, Евгений Александрович

целом. Результаты работы каждой компоненты, существенные для поддержания адекватности исходного текста и ПП, не теряются, а помещаются в ПП.

4. Концептуально компилятор переднего плана является однопроходным. Все его компоненты взаимодействуют по подпрограммному принципу, что исключает использование каких-либо громоздких промежуточных структур. Введение в реализацию дополнительного второго прохода не является принципиальным решением; оно продиктовано стремлением сделать общую структуру компилятора более обозримой и сопровождаемой и тем самым провести частичную "декомпозицию сложности" семантики Си++. Дополнительный проход компилятора не связан с порождением каких-либо новых структур и представляет собой однократный проход по уже построенному дереву программы с вычислением ряда семантических атрибутов и локальными преобразованиями поддеревьев.

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

Также в процессе исследований получены следующие результаты:

• Предложена модель промежуточного представления программ на языке Си++, образуемая системой семантических таблиц, деревом программы и представлением системы типов программы.

Основной компонентой ПП является система семантических таблиц. Выполнена реализация этой модели в действующем компиляторе переднего плана Си++. Показано, что устройство модели семантических таблиц компилятора обладает необходимой общностью, что позволяет без серьезных затрат реализовать в ее рамках концепцию непрерывной компиляции.

• Разработана общая архитектура компилятора переднего плана Стандарта Си++, а также компонентная структура компилятора.

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

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

• Создан первый в России промышленный компилятор языка Си++ и один из первых компиляторов, реализующих полный стандарт Си++.

Заключение

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

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

Концепция непрерывной компиляции образуется из следующих аспектов:

1. Фаза препроцессирования рассматривается как составная часть функциональности лексического анализатора, в противоположность традиционным подходам, реализующим препроцессирование в виде отдельной компоненты системы программирования. Данное решение повышает общую эффективность компилятора, исключая операции с промежуточным текстовым представлением программы, и делает лексический анализ "гладким". Исключение фазы препроцессирования, не ограничивая возможностей Си++ и потребностей программистов, создает предпосылки для поддержания полной семантической адекватности исходного текста и результирующих структур компиляции.

2. Внутренние структуры компилятора - семантические таблицы, дерево программы и представление системы типов - обычно используемые исключительно для внутренних целей генерации результирующего кода, логически выносятся вовне компилятора переднего плана и становятся результатом его работы. Указанные структуры играют роль промежуточного представления (ПП) исходной программы и интерфейса компилятора переднего плана с различными конечными процессорами, в частности, с генератором кода.

3. Процедуры идентификации имен переносятся на этап лексического анализа. В сочетании с практически полной однопроходностью это означает, что все компоненты компилятора участвуют в построении семантических таблиц и результирующего ПП в

Список литературы диссертационного исследования кандидат физико-математических наук Зуев, Евгений Александрович, 1999 год

Литература

Международные и национальные Стандарты, рабочие материалы по стандартизации ЯП

1. United States Department of Defense. Reference Manual for the Ada Programming Language (ANSI/MIL-STD-1815A). Washington DC, 1983.

2. ISO/IEC 8652:1995 Information technology - Programming languages -Ada.

3. ISO/IEC 8652:1995(E) Changes to Ada - 1987 to 1995. Language and Standard Libraries. Version 5.95, 25 November 1994.

4. ISO/IEC 8652:1995(E) Annotated Ada Reference Manual. Language and Standard Libraries. Version 6.0, 21 December 1994.

5. Ada 95 Rationale. The Language and Standard Libraries. January 1995. Intermetrics, Inc.

6. Ada 95 Quality and Style. Guidelines for Professional Programmers, SPC-94093-CMC, Version 01.00.10, October 1995. Prepared for the Department of Defense Ada Joint Program Office. Produced by the Software Productivity Concortium.

7. ISO 7185:1990 Information technology - Programming languages -Pascal.

8. ISO/IEC 15291:1999 Information technology - Programming languages

- Ada Semantic Interface Specification (ASIS).

9. ISO/IEC 10514-1:1996 Information technology - Programming languages - Part 1 : Modula-2, Base Language.

10. ISO/IEC 13816:1997 Information technology - Programming languages, their environments and system software interfaces - Programming language ISLISP.

11. ISO/IEC 14882:1998 Programming languages - С++.

12. ISO/IEC DIS 9899 Programming languages - C.

13. ISO/IEC 10206:1991 Information technology - Progamming languages -

- Extended Pascal.

14. ISO/IEC 9899:1990 Programming languages - C.

15. ISO/IEC 10646-1:1993 Information technology - Universal Multiple-Octet Coded Character Set (UCS) - Part 1 : Architecture and Basic Multilingual Plane.

16. Andrew Koenig (editor): The Working Papers for the ANSI-X3J16/ISO-SC22-WG21 С++ standards committee.

17. Andrew Koenig (editor): Draft Proposed International Standard for Information Systems - Programming Language С++. ANSI Standards Secretariat. CBEMA, 1250 Eye Street NW, Suite 200, Washington DC20005, USA. 1995.

Системы программирования и их компоненты

18. Benjamin М. Brosgol, TCOLAda and the "Middle End" of the PQCC Ada Compiler, 1980 ACM 0-89791-030-3/80/1200/01001.

19. Лебедев B.H. Введение в системы программирования. М., "Статистика", 1975,- 312 е., с ил.

20. John R. Levine, Linkers and Loaders, Morgan-Kauffman, 1999.

http://linker.iecc.com

21. К John Gough, Multi-language, Multi-target Compiler Development: Evolution of the Gardens Point Compiler Project, Queensland University of Technology, Brisbane, Australia, 1997.

22. The CoSy Compilation System, Associated Computer Experts, 1999,

http://www.ace.nl/products/cosytech.htm.

23. TAU™ The ACE Unix™. Reference Manuals Distr & Pack, Release 2.2, Associated Computer Experts bv, Netherlands, 1991.

24. Richard M. Stallman, Status of the GNU project, 6 May 1991.

25. Stuart I. Feldman, Make - a program for maintaining computer programs, Software - Practice & Experience, 9(4):255-265, 1979.

26. James H. Cross II, Kai H. Chang, and T. Dean Hendrix, GRASP/Ada 95: Visualization with Control Structure Diagrams, Auburn University, 1997,

http://www.eng.auburn.edu/grasp.

27. Холстед M. X. Начала науки о программах / Пер. с англ.- М.: Финансы и статистика, 1981,-128 е., ил.

28. PC-lint, Gimpel Software, http: //www.gimpel.com/lintinfo.htm.

29. QualGen - Metrics Analysis, Measurement, Reporting, and Tracking, Scientific Toolworks, Inc., http://www.scitools.com.

30. Романов В.Ю. Основные графические обозначения, предназначенные для объектно-ориентированного проектирования программ, и их интерпретация для языка С++. Препринт N3 от 29.04.96. Москва, НИВЦ МГУ, Высшая компьютерная школа.

31. Cristina Cifuentes, К. John Gough, Decompilation of Binary Programs, School of Computing Science, Queensland University of Technology, GPO Box 2434, Brisbane, QLD 4001, Australia.

32. Peter Magnusson, Partial Translation, Parallel Computer Systems, Swedish Institute of Computer Science, Box 1263, S-164 28 KISTA, October 1993, SWEDEN. ISSN 1100-3154.

33. Замулин А. В. Системы программирования баз данных и знаний.-Новосибирск: Наука. Сиб. отд-ние, 1990.-352 с. ISBN 5-02-029673-2.

Трансляция ЯП

34. Д. Грис. Конструирование компиляторов для цифровых вычислительных машин- М.: "Мир", 1975.

35. Д. Кнут. Искусство программирования для ЭВМ. Том 3 Сортировка и поиск. Москва: "Мир", 1978.

36. И.В.Поттосин. Текущее состояние российских исследований и разработок в области трансляции II Новосибирск, 1995, 32 с. -(Препр./РАН Сиб. отделение, ИСИ; №30). См. также И.В.Поттосин, Российские исследования по языкам программирования и трансляции, http://www.infoart.ru/congress/article/ potosin.htm.

37. Craig Chambers, Jeffrey Dean, and David Grove, Whole-Program Optimization of Object-Oriented Languages, Technical Report 96-06-02, June 1996, Department of Computer Science and Engineering, University of Washington.

38. S. C. Johnson, YACC - yet another compiler compiler, CSTR 32, Bell Laboratories, Murray Hill, N. J. (1974).

39. M. E. Lesk, LEX - a lexical analyzer generator, CSTR 39, Bell Laboratories, Murray Hill, N. J. (1975).

40. Charles Donnelly and Richard Stallman, Bison - The YACC-compatible Parser Generator, Version 1.20, Free Software Foundation, Inc., December 1992.

41. Ф. Льюис, Д. Розенкранц, P. Стирнз. Теоретические основы проектирования компиляторов.- Пер. с англ., Москва, "Мир", 1979.

42. Graham S.L., Joy W.N., Hashed Symbol Tables for Languages with Explicit Scope Control, SIGPLAN Notices 1979, v. 14, №8, pp 50-57.

43. Н.Вирт. Алгоритмы + Структуры данных = Программы- Пер. с англ. Москва, "Мир", 1985.

Работы Б.Страуструпа

44. В. Stroustrup: Adding Classes to the С Language: An Exercise in Language Evolution Software - Practice and Experience, pp 139-161. February, 1983.

45. Ellis, Margaret A., and Bjarne Stroustrup, The Annotated С++ Reference Manual (ARM), ISBN 0-201-51459-1 Reading, MA: Addison-Wesley, 1990. Имеется русский перевод: Эллис М., Строуструп В. Справочное руководство по языку программирования С++ с комментариями: Пер. с англ.- М.: Мир, 1992,- 445с., ил. ISBN 5-03002868-4.

46. Bjarne Stroustrup, A Brief Look at С++, AT&T Bell Laboratories, Murray Hill, New Jersey 07974.

47. Bjarne Stroustrup, A Perspective on ISO С++, AT&T Bell Laboratories, Murray Hill, New Jersey 07974.

48. Bjarne Stroustrup, What is "Object-Oriented Programming"? (1991 revised version), AT&T Bell Laboratories, Murray Hill, New Jersey 07974.

49. Bjarne Stroustrup, Why С++ is not just an Object-Oriented Programming Language, AT&T Bell Laboratories, Murray Hill, New Jersey 07974. Invited talk given at OOPSLA'95 in Austin Texas.

Стандартная библиотека шаблонов (STL)

50. David R. Musser, Alexander A. Stepanov, Generic Programming, First International Joint Conference of ISAAC-88 and AAECC-6, Rome, Italy June 4-8, 1988. См. также Lecture Notes in Computer Science 358, Springer-Verlag, 1989, pp 13-25.

51. Alexander Stepanov and Meng Lee: The Standard Template Library. ISO Programming language С++ project. Doc No: X3J16/94-0095, WG21/N0482. May 1994.

52. Alexander A. Stepanov and Meng Lee, The Standard Template Library, Technical Report, Hewlett-Packard Laboratories, September 20, 1994, revised February 7, 1995. См. также ftp://ftp.cs.rpi.edu/

pub/stl/doc .ps. Z.

53. Al Stevens, Alexander Stepanov and STL, Dr. Dobb's Journal, March 1995.

Вопросы реализации Си++

54. Steven P.Reiss, Tony Davis, Experiences Writing Object-Oriented Compiler Front Ends, Department of Computer Science, Brown University, Providence, Rl 02912, January 11, 1995.

55. G. Ramalingam and Harini Srivasan, A Member Lookup Algorithm for С++, IBM T.J.Watson Research Center, 1997.

56. Stephen C.Dewhurst, Гибкая структура таблицы символов для компиляции Си++, Software - Practice and Experience, Vol. 17(8), 503512 (August 1987).

57. SAGE++ - A Class Library for Building Fortran 90 and С++ Restructuring Tools. Extreme! Computing Group, Indiana University, May 1996,

http://www.extreme.indiana.edu/sage/docs.html.

58. Anil Admal and Chris Tarr, Templates and Today Compilers, ObjectSpace, Inc., www.objectspace.com/products/cpp-whitePapers.htm, August 1997. Первоначальная версия статьи см. в C/C++ User's Journal, Vol. 15, No 01, January 1997.

59. Кротов A.H. Принципы реализации семантики языка Си++ в системе ЗС++. Диссертация на соискание ученой степени кандидата физико-математических наук. Москва, 1999 (представлена к защите).

Фирменные материалы по компиляторам Си++

60. Richard М. Stallman, Using and Porting GNU CC, Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, November, 1995, ISBN 1-882114-66-3.

61. Ultra C/C++ Optimizing Compiler for OS-9, Microware Technology Brief, Microware Systems Corporation, 1999.,

http://www.microware.com/ProductsServices/Technologi-es/ultrac_c_technology_brief.html

62. IBM VisualAge for С++ v4.0 Goes Incremental. IBM Corporation, Monday, August 04, 1997.

63. Developing Quality С and С++ Applications with CenterLine's C++Expert - A CenterLine White Paper, CenterLine Software, 1998,

http://www.centerline.com.

64. Diab Data С & С++ Compiler, 1998, http: //www. ddi. com.

65. EPC's С++ Compiler - Paving the Way Ahead, Edinburgh Portable Compilers, 1998, http://www.epc.co.uk/ecpp.html.

66. The С++ Front End. Internal documentation (excerpt), Version 2.40, December 8, 1998, Edison Design Group, Inc. http://www.edg.com/

cpp. html.

67. Green Hills С++, Green Hills Software, Inc, 1999, http://www.

ghs. com.

68. You Deserve the Best, Kuck & Associates, 1999,

http : //www. kai . com/C_plus_plus/index .html.

69. С++ Under the Hood, Microtec Research, 1997, http:// www.mentorg.com/embedded.

Языки Ада и Ада95

70. Ichbiah, J.D. et.al.: Rationale for the Design of the Ada Programming Language. SIGPLAN Notices, Vol 14, No 6. June 1979.

71. Department Of Defense Requirements for High Order Computer Programming Languages: "Steelman", U.S. Department of Defense. June 1978, http://www.adahome.com/History/Steelman/ intro. htm.

72. Ada 9X Requirements Rationale. Ada 9X Project Report, Office of the Under Secretary of Defense for Acquisition, Washington, D.C. 20301, May 1991.

73. Ada 9X Project Report. Transition Plan, May 1992.

74. Paul Pukite, Top 10 myths and misconceptions about Ada, Newsgroups: comp.lang.ada, Thu, 16 Mar 95 10:33:33 CST.

75. В.Фофанов, С.Рыбин. Интерфейс ASIS: подспорье в разработке инструментов на языке Ada. ComputerWeekly, №43, 1998, стр. 7.

76. С.И.Рыбин. Проект ADA9X: история и современное состояние. Программирование, 1994,№3, стр. 64-82.

Сравнительный анализ ЯП

77. Ian Joyner, С++?? A Critique of С++, 2nd Edition, с/- Unisys - ACUS, 115 Wicks Rd, North Ryde, Australia 2113, 1992.

78. Markku Sakkinen, The darker side of С++ revisited, Department of Computer Science and Information Systems, University of Jyvaskyla, PL 35, SF-40351 Jyvaskyla, Finland, 1993-1-13.

79. Peter J. Moylan, The case against C, The ModulaTor, Vol. 3, No 6, pp 111, ModulaWare GmbH, 1993. Имеется русский перевод: Питер Мойлан. Критика языка С II Технология программирования, Т.1, с. 34-40, 1995.

80. David L. Shang, A Critical Comparison on Transframe, Java & С++, Object Currents.

81. David A. Wheeler, Ada, C, С++, and Java vs. The Steelman, Institute for Defense Analyses, 1801 N. Beauregard St., Alexandria, VA 22311-1772,

1996.

82. Seidewitz, Ed. Another Look at Ada 95, Object Magazine, October 1996, NY: SIGS Publications Inc.

83. Jim Rogers, Comparison of Ada and С++ Features, Ada Home, March 4,

1997, http : / /www. adahome . com.

84. S. Tucker Taft, A Comparison of Ada, C, and С++, Intermetrics, Inc., February 1995.

85. Edward Colbert, Technical Comparison of the Ada & С++ Languages, Absolute Software Co.,Inc., 1991.

86. Edmond Schonberg, Contrasts: Ada 9X and С++, NYUAda 9X Project, New York University, April 22, 1992. Ada Information Clearinghouse, 1-800-AdalC-11, 703/685-1477.

87. Jesper Jorgensen, Rod Ellis, A Comparison of the Object Oriented Features of Ada 95 and С++, DDC-I, Inc., 1996.

88. С.Свердлов, Арифметика синтаксиса, PC Week/RE № 42-43, 1998.

См. http://www.uni-Vologda.ac.ru/CS/SYNTAX/index.htm.

Прочие языки программирования

89. J. Welshand, D.W.Bustard, Pascal plus - another programming language for modular multiprogramming, Software - Practice and Experience, 9:947-957, 1979.

90. F. Andersen, Anders V. Olsen, The Pascal++ Language and Its Implementation, FAVOR Software, Denmark, 1994.

91. Martin Richards and Colin Whitby-Strevens: BCPL - the Language and Its Compiler. Cabridge University Press, Cambridge, England, 1980 ISBN 0-521-21965-5.

92. Bertrand Meyer, Eiffel: The Language, Prentice-Hall, 1992, ISBN 0-13245-925-7.

93. Brian W. Kernighan and Dennis M. Ritchie: The С Programming Language. Prentice-Hall. Englewood Cliffs, New Jersey. 1978.

94. C.S.Johnson, A Tour Through the Portable С Compiler,

http : //plan9 .bell-labs . com/7thEdMan/vol2/port-tour .bun.

95. MBK "Эльбрус". Общее системное программное обеспечение. Транслятор с языка Эль-76. Описание программы. ИЫ 00001-01 13 02.

96. H.Mossenbock, N.Wirth, The Programming Language Oberon-2, Institut fur ComputerSysteme, ETH, Zurich, 1992, ftp://ftp.inf.ethz.ch/

pub/software/Oberon/OberonV4/Docu/Oberon2.Report.Text.

97. Кэмпбелл-Келли M. Введение в макросы: Пер. с англ./Под ред. Э.З.Любимского,- М., Сов. Радио, 1978,-152 е., ил.

98. П. Браун. Макропроцессоры и мобильность программного обеспечения. Пер. с англ. А.Л.Александрова.- М., Мир, 1977.

99. Ken Arnold and James Gosling. The Java Programming Language: Addison Wesley, 1996. Есть русский перевод: Д. Гослинг, К.Арнольд. Язык программирования Java / Перев. с англ.-СПб.: Питер, 1997.304 с.:ил. ISBN 5-88782-218-Х.

Промежуточное представление программ, форматы объектного кода

100. ACM SIGPLAN Workshop on Intermediate Representations (IR '95), January 22, 1995, San Francisco, California, http://www.research .microsoft.com/research/analysts/mernst/ir95-cpf.html.

101. G. Goos and Wm. A. Wulf, Diana Reference Manual, Carnegie-Mellon, March 1981.

102. David S. Rosenblum and Alexander L. Wolf, Representing semantically analyzed С++ code with Reprise, Proceedings of the Third USENIX С++ Conference, pp. 119-134 (April 1991).

103. Niclaus Wirth, The Design of the Pascal Compiler, Software - Practice and Experience, Volume 4, pp 309-333, 1971.

104. Tim Lindholm, Frank Yellin, The Java Virtual Machine Specification, Addison-Wesley, September 1996.

105. Bill Venners, Inside the Java Virtual Machine, McGraw-Hill, 1997, ISBN 0-07-913248-0. См. также http: //www. arithma. com/insidej vm.

106. Michael Franz, Code-Generation On-the-Fly, Doct. Diss ETH, No 10497, Zurich, 1994.

107. К John Gough, The Dcode Intermediate Program Representation: Reference Manual and Report, ftp://ftp.fit.qut.edu.au/pub/

papers /jmlc2 .ps . Z.

108. COFF - Common Object File Format, ACE Documentation, Release 920.1 of August, 1992, Netherlands.

109. Hongjiu Lu, ELF: From The Programmer's Perspective, NYNEX Science & Technology, Inc., May 1995.

110. Julia Menapace, Jim Kingdon, David MacKenzie, The "stabs" debugging information format, Free Software Foundation, Inc., 1993. Contributed by Cygnus Support.

111. DWARF Debugging Information Format Specification, Version 2.0, Tool Interface Standards (TIS), TIS Committee, May 1995.

112. Jens-Ulrik Toft, Formal specification of ANDF semantics, ESPRIT Project 6062 OMI/GLUE, DDC-I, 1995. См. также

http://riwww.osf.org:8001/andf/index.html.

113. Simon P. Jones, Thomas Nordin, and Dino Oliva, C—: A Portable Assembly Language, Department of Computer Science, University of Glasgow; Pacific Software Research Center, Oregon Graduate Institute.

Работы автора

114. Зуев E.A., Кротов А.Н. Новые возможности Си++. PC Magazine/ Russian Edition, Октябрь 1994.

115. Sergey Rybin, Alfred Strohmeier, and Eugene Zueff, ASIS for GNAT: Goals, Problems and Implementation Strategy, Ada-Europe'95 Conference, Frankfurt, Germany, October 1995.

116. Sergey Rybin, Alfred Strohmeier, and Eugene Zueff, ASIS Implementation for the GNAT Compiler, First Workshop on Free Software, Universidad Carlos III, Madrid, Spain, September 1995.

117. Зуев E.A. Системное программное обеспечение цифрового нейронного процессора с переменной разрядностью операндов. Известия ВУЗов. Приборостроение, том 39, №7, 1996.

118. Зуев Е.А., Кротов А.Н., Сухомлин В.А. Язык программирования Си++: этапы эволюции и современное состояние. Тез. докл. Первой российской конференции "Индустрия программирования'96", Москва, 3-4 октября 1996 г.

119. Зуев Е.А., Кротов А.Н., Сухомлин В.А., Давыдов Д., Недиков Н.Н. Система программирования тройного стандарта ЗС++. Тез. докл. Первой российской конференции "Индустрия программирования'96", 3-4 октября 1996 г., Москва.

120. Sergey Rybin, Alfred Strohmeier, and Eugene Zueff, ASIS for GNAT: Goals, Problems and Implementation Strategy, Ada Letters, Volume XVI, No. 2, March/April 1996.

121. Зуев Е.А. Редкая профессия. PC Magazine/Russian Edition. Спецвыпуск №5(75), 1997.

122. Зуев Е.А. Общий подход к созданию базового программного обеспечения нейропроцессора. Известия ВУЗов. Приборостроение, том 40, №3, 1997.

123. Зуев Е.А., Кротов А.Н. Компилятор полного стандарта Си++. Известия ВУЗов. Приборостроение, том 40, №3, 1997.

124. Зуев Е.А., Кротов А.Н., Сухомлин В.А. Система программирования тройного стандарта ЗС++. Тез. докл. IV Международной конференции "Развитие и применение открытых систем", Н.Новгород, 27-31 октября 1997 г.

125. Зуев Е.А., Котиков С.В., Челюбеев И.А. Язык ассемблера нейропроцессора и его реализация в инструментальной среде. Известия ВУЗов. Приборостроение, том 40, №3, 1997.

126. Евгений Зуев. Реализация компилятора полного стандарта Си++ и виртуальной машины Си++, Интернет-форум "Языки программирования и Интернет", ИнфоАрт, июль 1998,

http://www.infoart.ги/.

127. Зуев Е.А. Русские "плюсы". Мир ПК, № 4, 1999.

Обратите внимание, представленные выше научные тексты размещены для ознакомления и получены посредством распознавания оригинальных текстов диссертаций (OCR). В связи с чем, в них могут содержаться ошибки, связанные с несовершенством алгоритмов распознавания. В PDF файлах диссертаций и авторефератов, которые мы доставляем, подобных ошибок нет.