УДК 004.4 DOI: 10.17213/0321-2653-2017-3-35-42
СЕМАНТИЧЕСКИЙ ИНТЕРФЕЙС ДЛЯ ПРОГРАММ НА С++
© 2017 г. Е.А. Зуев
Университет Иннополис, г. Иннополис, Россия
SEMANTIC INTERFACE FOR C++ PROGRAMS
E.A. Zouev
Innopolis University, Innopolis, Russia
Зуев Евгений Александрович - канд. физ.-мат. наук, доцент, Университет Иннополис, г. Иннополис, Россия. E-mail: [email protected]
Zouev Eugene Aleksandrovich - Candidate of Physical and Mathematical Sciences assistant professor, Innopolis University, Innopolis, Russia. E-mail: [email protected]
Рассматриваются актуальные проблемы, приводящие к необходимости повышения качества и глубины анализа программ на языке С++. Обсуждаются возможные пути решения проблем повышения надежности и безопасности программ. В качестве основы различных систем анализа предлагается концепция семантического представления (СП). Обсуждаются преимущества СП, определяются основные требования к ней, важнейшие характеристики, функциональные возможности и возможные сферы применения.
Ключевые слова: язык С++; анализ программ; семантическое представление; семантический интерфейс.
Actual problems with C+ + programs' reliability and safety are discussed. The techniques and tools aimed to improve the quality of the programs require mechanisms for deeper analyses. The notion of semantic representation is introduced as a promising basis for such analyses. Various design aspects of such a representation and its API as well as possible application areas are discussed.
Keywords: the C++ language; program analysis; semantic representation; semantic interface.
Введение
В настоящее время размеры и сложность программных продуктов и систем увеличились многократно. Фактически сложность программ вплотную подошла к пределу, за которым традиционные методы оценки корректности и надежности программ и их соответствия исходным требованиям становятся принципиально неприменимыми. В то же время возросшая ответственность программных систем настоятельно требует серьёзных гарантий их качества.
Решение этой проблемы лежит на пути создания автоматизированных и автоматических систем статического и динамического анализа (аудита) программ.
Данная проблематика имеет достаточно общий характер и актуальна практически для любого современного языка программирования, используемого в разработке промышленного ПО. Предлагаемая статья, однако, ограничивается обсуждением проблем семантического анализа программ на языке С++. Этот язык, будучи одним из наиболее распространенных инструментальных средств, страдает многими хорошо известными недостатками, которые не способствуют созданию по-настоящему надежного ПО.
Актуальные направления
Представляется, что наиболее актуальными направлениями в этой сфере являются следующие:
ISSN 0321-2653 IZVESTIYA VUZOV. SEVERO-KAVKAZSKIIREGION.
TECHNICAL SCIENCE. 2017. No 3
- аудит исходных текстов программ на предмет выявления потенциальных уязвимостей, которые могут вызывать нерегламентированное поведение программы, в том числе вызвать сбои и/или поломки программ или среды, в которой они работают;
- оптимизационный анализ текстов программ с целью совершенствования их структуры или функциональных свойств, повышения их производительности и ослабления чрезмерно высоких требований на потребляемые ресурсы;
- анализ программ на предмет заимствований фрагментов исходного текста из сторонних программ (инструменты «антиплагиата»);
- динамическое профилирование - тестовое исполнение программы в модельной среде, что может выявить специфические ошибки, связанные с этапом выполнения программ и не выявляемые методами статического анализа исходных текстов;
- автоматизация тестирования. Автоматическое создание тестовых покрытий и управление тестированием.
Текущее состояние
Одним из первых успешных подходов к решению проблемы анализа программ следует считать комплекс ASIS (Ada Semantic Interface Specification [1]), задающий множество высокоуровневых интерфейсов доступа к программам на языке Ada. ASIS определяет стандартную совокупность запросов в терминах входного языка, оставляя их реализацию на усмотрение разработчиков.
Первой из аналогичных по назначению систем для языка С++ следует считать комплекс программ SAGE (впоследствии эволюционировавший в SAGE++ [2], SAGE II, ROSE [3]).
К настоящему времени важность и актуальность проблемы анализа программ вполне осознана как их пользователями (корпоративными и индивидуальными), так и сообществом разработчиков программных средств. Рынок инструментов анализа переживает явный подъем. Сейчас доступен весьма широкий спектр программ систем различного качества, масштаба и ассортимента функций - от небольших свободно доступных инструментов до мощных многофункциональных систем коммерческого характера.
Однако практически все известные системы статического анализа базируются либо на некотором внутреннем представлении программ,
порождаемом компиляторами третьих компании (видимо, наиболее популярным таким инструментом является компилятор переднего плана компании Edison Design Group [4]), либо на собственных программах разбора.
Оба подхода страдают фундаментальными недостатками. Промежуточное представление программ, генерируемое сторонними компиляторами, практически никогда не содержит адек-ватноИ информации о семантике исходных программ, что очень сильно ограничивает возможности их анализа. Кроме того, использование промежуточного представления приводит к сильнои зависимости разработчика анализатора от текущего состояния этих компиляторов: формат промежуточного представления, как правило, не фиксирован, может изменяться в непредсказуемые моменты времени произвольным образом, и сами поставщики компиляторов, как правило, не рекомендуют полагаться на этот формат (или прямо запрещают это делать). Примером описанного подхода может служить проект Pivot [5, 6], развиваемыИ при участии создателя языка С++ Б. Страуструпа.
Многие производители инструментов анализа используют собственные средства разбора программ. Однако в большинстве случаев такоИ разбор осуществляет весьма поверхностный анализ исходных текстов, опять-таки, игнорируя большое число семантических особенностеИ, существенных для качественного и глубокого анализа. Среди немногочисленных исключениИ следует отметить систему llvm/clang [7], которая включает статический анализатор [8], построен-ныИ на собственном компиляторе переднего плана С++.
Из вышеизложенного следует, что достичь решающего преимущества на пути создания высококачественного и конкурентоспособного инструментария для анализа программ можно было бы на пути повышения степени глубины анализа программ.
Базовая идея
В основе проекта лежит фундаментальная идея, которая заключается в том, чтобы создать унифицированное, регулярное и удобное для программного использования семантическое представление (далее - СП) для программ, написанных на языке С++.
Идея некоторого специального представления программ, альтернативного исходному текстовому виду, не нова. Компилятор любого ЯП в процессе обработки входной программы
ISSN 0321-2653 IZVESTIYA VUZOV. SEVERO-KAVKAZSKIIREGION.
преобразует её в некоторое промежуточное или внутреннее представление - с тем, чтобы обеспечить контроль синтаксической и семантической корректности и выполнить генерацию целевого кода для некоторой аппаратной архитектуры.
Фундаментальные отличия предлагаемого СП от известных промежуточных представлений программ заключаются в следующих аспектах:
- принципиально ориентируется на широкий спектр применений, не ограничиваясь внутренними задачами конкретного компилятора по генерации целевого кода;
- содержит полную семантическую информацию об исходной программе, а не только подмножество этой информации, необходимое для создания кода;
- семантическая информация представляется строго в терминах Стандарта входного языка [9], а не во внутренних терминах, специфичных для данного компилятора;
- включает скрытую семантику, т.е. такую информацию, которая непосредственно не выражена в исходной программе, но подразумевается согласно определению ЯП.
Типичным примером скрытой семантики служат вызовы деструкторов С++ для объектов классовых типов, объявленных в некоторой области действия, при выходе из этой области действия. Такие вызовы не присутствуют явно в программе, однако, подразумеваются семантикой языка (см., например, [10]);
- является открытым и снабжается удобным программным интерфейсом. Иными словами, СП - это набор классов и методов, посредством которых можно получить любую информацию о структуре программы, ее компонентах, связях и отношениях между компонентами с любой степенью детализации;
- обеспечивает двусторонний доступ: как по чтению, так и по записи. Это означает, что с помощью СП можно как получать семантическую информацию о программе, так и модифицировать его, добавляя или удаляя те или иные компоненты;
- является полностью независимой системой, которая не использует каких-либо сторонних программных анализаторов, компиляторов или иных инструментов.
Это свойство принципиально отличает СП от систем и проектов аналогичного назначения, которые в подавляющем большинстве представ-
TECHNICAL SCIENCE. 2017. No 3
ляют собой конгломерат различных продуктов (в частности, свободно-доступных компиляторов) и технологий, слабо связанных между собой посредством «фильтров», «переходников» и других средств. Подобные комплексы характеризуются весьма сложными технологическими схемами использования и являются сильно ограниченными по своим возможностям.
Семантическое представление, основные особенности которого перечислены выше, вместе с программным интерфейсом для доступа к нему будет дальше называться Semantic API.
Структура Semantic API
Несмотря на своё название, представляемый интерфейс обеспечивает доступ не только к семантике программ на языке С++, но и к другим его аспектам, охватывая тем самым язык во всей совокупности его свойств. Так, интерфейс включает следующие три уровня:
- лексический интерфейс;
- синтаксический интерфейс;
- семантический интерфейс.
Ниже кратко представлены основные возможности перечисленных компонентов Semantic API.
Лексический интерфейс. Для определенного класса прикладных задач бывает необходимо и достаточно информации о лексических аспектах исходной программы. Так например, утилитам вроде «претти-принтеров» для целей форматирования программ согласно определенным правилам достаточно информации об отдельных лексемах в точном порядке их следования в исходной программе. Несколько более продвинутые утилиты, возможно, могут требовать развернутую информацию о входной программе до и после её обработки препроцессором. Это касается и информации о доступных в любой точке программы макроопределениях и директивах включения (include).
Помимо подобных, сравнительно несложных и очевидных возможностей, описываемый интерфейс предоставляет и более развитые средства, связанные со «смыслом» лексем. Дело в том, что неоднородная лексико-синтаксическая структура С++ приводит к неоднозначному толкованию некоторых лексем в различных контекстах. Так, лексема * («звезда») может трактоваться либо как знак операции умножения, либо (в объявлениях) как спецификатор указательного типа. Знаки < и > обозначают операции сравнения, а также служат угловыми
скобками для параметров шаблонов. Подобные неоднозначности свойственны также лексемам &, && и некоторым другим. Даже такая простая, казалось бы, лексема, как «запятая», которая обычно служит разделителем различных списковых структур, в некоторых контекстах должна трактоваться, согласно определению языка, как знак определённой операции.
Наличие подобной «семантической» информации о смысле лексем может быть полезно и необходимо для реализации программ, реализующих операции над текстами на С++. Лексическая часть представляемого интерфейса позволяет получить смысловую информацию о конкретном вхождении любой лексемы.
Синтаксический интерфейс. Под «синтаксической» информацией о программе понимается прежде всего знание о её структуре: областях действия объявлений, их характере и относительной вложенности. Синтаксическая структура языка С++ достаточно сложна и включает различные категории областей действия, внутри которых видимость объявлений может подчиняться различным правилам. Например, в области действия тела функции применяется традиционное текстуальное следование «сначала объявление - потом использование», в то время как тела функций-членов класса по определению находятся в контексте всего класса; иными словами, из тела функции доступны все члены класса, независимо от их текстуального расположения их объявлений (до или после тела функции). Специфические правила действуют также для доступа к параметрам шаблонов. Наконец, правила доступа к членам базовых классов отличаются от традиционных правил блочности. Синтаксическая часть интерфейса позволяет получить доступ ко всем подобным особенностям входной программы.
Синтаксический интерфейс может непосредственно использоваться для целей визуализации, структурного анализа программ, оптимизации на уровне входного языка. Кроме того, построение графа потоков управления (control flow graph, CFG), на основе которого, как правило, реализуется генерация целевого кода и тонкие оптимизации, строится на основе доступа к структурной информации о программе.
Семантический интерфейс. Эта часть является центральным и наиболее сложным для реализации компонентом Semantic API. Она предоставляет средства для получения смысловой информации обо всех программных сущностях -
объектах, функциях, классах и типах, шаблонах, их настройках и специализациях.
Видимо, наиболее существенным и практически необходимым аспектом семантической части интерфейса следует считать доступ к информации о разнообразных отношениях между программными сущностями. В эту категорию входят как относительно традиционные отношения вида «объект - тип» или «объявление - использование», так и отношения, специфичные для С++, такие как отношение «производный класс - базовые классы» (включая производное отношение вида «статический тип объекта - динамический тип»), «виртуальная функция в базовом классе - перекрытия этой функции в производном классе», «объявление шаблона -множество настроек и/или специализаций этого шаблона».
Кроме того, семантический интерфейс позволяет получить информацию о совместно-используемых в некоторой области действия функциях и операциях, идентифицировать функцию-операцию, задействованную в точке конкретного использования соответствующего знака операции, данные о характере отношений между типами (например, имеется ли для двух заданных типов стандартное или пользовательское преобразование), и многое другое.
Отдельно следует упомянуть о «скрытой семантике». Как известно, при выходе потока управления из некоторой области действия должны быть выполнены вызовы деструкторов для объектов классовых типов, объявленных в этой области действия. Такие вызовы не присутствуют в программе в явном виде, однако предусматриваются семантикой языка. Семантический интерфейс позволяет получить для любой области действия такую информацию. То же относится к неявным преобразованиям типов: цепочки стандартных и пользовательских преобразований, приводящих от одного типа к другому, полностью раскрываются.
Реализация Semantic API
Семантический интерфейс реализован на основе всеобъемлющего использования принципов ООП. Структурные аспекты семантического представления программ реализованы с использованием понятия наследования вместе с активным использованием интерфейсов, а функциональность и собственно интерфейс к семантическому представлению базируются на механизме
ISSN 0321-2653 IZVESTIYA VUZOV. SEVERO-KAVKAZSKIIREGION.
виртуальных функций. Более подробное описание реализации приводится ниже.
Структура семантического представления. В основе подхода к реализации структурных свойств семантического представления служит принцип «одно понятие языка - одна структура, его представляющая». Иными словами, каждое понятие языка представляется в виде специальной программной единицы (класса), члены которого выражают те или иные свойства или структурные связи данного понятия. Например, понятие «условный оператор» представляется классом IF_STATEMENT, члены которого соответствуют структурным элементам условного оператора - условию (класс, соответствующий понятию «выражение») и классам для операторов, соответствующих «истинной» и «ложной» альтернативам.
Для каждого понятия С++ предусмотрен класс, соответствующий этому понятию и выражающий его семантику. Такие понятия, как «тип», «функция», «оператор», «выражение» и т.д., непосредственно отображаются на классы СП.
Таким образом, система понятий С++ отображается на множество классов семантического представления. Так как система языковых понятий носит отчётливо иерархический характер, это находит своё отражение в иерархии соответствующих классов семантического представления. Иными словами, все классы семантического представления образуют иерархию, в которой более общим понятиям (например, «тип») соответствует базовый класс (для данного примера TYPE), а совокупность конкретных типов (целый, указатель, классовый тип и т.д.) представляется классами, производными от TYPE.
Структурные взаимосвязи компонентов СП (примером может служить структура условного оператора, кратко описанная выше) соответствуют синтаксической структуре программы. В процессе синтаксического разбора создаются экземпляры классов, соответствующих распознаваемым конструкциям входной программы, и они образуют узлы структуры, которая фактически представляет собой традиционное абстрактное синтаксическое дерево (abstract syntax tree, AST).
Кроме того, и это составляет принципиальное обстоятельство, в процессе разбора синтаксическое дерево «нагружается» семантической информацией, которая представляется в виде разнообразных связей между узлами
TECHNICAL SCIENCE. 2017. No 3
синтаксического дерева. Каждая такая связь отражает определенное семантическое отношение между узлами AST. Таким образом, СП в целом представляет собой ориентированный граф, узлами которого служат образы конструкций входной программы, а ребра этого графа представляют структурные и семантические отношения между элементами программы.
Функциональность СП и программный интерфейс. Помимо структурных и семантических атрибутов, каждый класс СП включает набор операций над узлами соответствующего типа. Имеется набор служебных операций общего характера (проверка структурной корректности узла, а также правильности его семантических атрибутов согласно определению языка). Кроме того, каждый класс содержит набор операций, специфичных для представляемой классом конструкции языка. Например, для узлов выражений имеются операции приведения типов операндов, предусмотренных правилами языка, и вычисления значений константных выражений; для классов, представляющих различные типы языка С++, задаются операции, проверяющие корректность преобразования типов, и т.д.
Для всех классов узлов определены операции сопоставления поддеревьев с образцами (для поддержки действий по семантическому поиску), а также операции общего характера для задания произвольных действий над узлами и их поддеревьями (тем самым обеспечивается возможность расширения стандартной функциональности СП).
Все операции реализованы как виртуальные функции, имеющие общие сигнатуры и специфичные для конкретных узлов алгоритмы, что позволяет осуществлять необходимые операции над деревьями единственным вызовом таких функций.
Области применения Semantic API
Semantic API может использоваться для реализации широкого спектра операций над программами. Природа и назначение таких операций могут быть произвольными и, в принципе, ничем не ограниченными. Ниже следует список возможных операций:
- выявление потенциальных уязвимостей, скрытых ошибок, «мёртвого» кода, «закладок», заимствованного кода;
- статический анализ программ в широком смысле; снятие метрических характеристик, статическое профилирование и т.д.;
ISSN 0321-2653 IZVESTIYA VUZOV. SEVERO-KAVKAZSKIIREGION.
- рефакторинг - оптимизация программ по различным критериям;
- конвертирование программ - преобразование с одного ЯП на другой с сохранением семантической эквивалентности и функциональности;
- разработка компиляторов ЯП;
- генерация тестов, контроль тестовых покрытий;
- формальная верификация программ;
- генерация документации и отчетов;
- интерпретация программ - динамическое профилирование; разработка систем отладки.
Приведенный список является, очевидно, неполным; архитектура Semantic API допускает эффективное использование и для многих других областей анализа.
Примеры программных клиентов Semantic API
В заключительной части статьи приведём примеры практического использования предлагаемого семантического интерфейса. Перед описанием конкретных клиентов необходимо сделать два замечания.
Во-первых, следует иметь в виду, что представляемые клиентские приложения, так же, как и семантический интерфейс в целом, находятся в процессе проектирования и реализации. Поэтому делать какие-либо окончательные выводы о полезности и эффективности представляемых компонентов преждевременно. Скорее, речь может идти о том, что обычно называется «proof of concept»: о проверке перспективности самой идеи семантического представления для конкретных областей применения.
Во-вторых, в качестве примеров намеренно выбраны клиентские приложения, находящиеся в некотором смысле на противоположных полюсах сложности: от достаточно простой, но наглядной программы, назначение и полезность которой понятны непосредственно, до весьма сложной (и амбициозной) многофункциональной подсистемы, на первый взгляд ломающей привычные схемы использования языков программирования. Реализация различных по сложности и назначению приложений позволит полнее выявить сильные и слабые стороны предлагаемого семантического интерфейса и тем самым повлиять на его структуру и функционал.
Обе программы непосредственно используют семантическое представление программ на С++.
TECHNICAL SCIENCE. 2017. No 3
Визуализатор. Назначение этой программы представляется вполне очевидным: она предоставляет разработчикам инструмент для наглядного визуального представления программ на С++. Идея, лежащая в основе программы, заключается в том, чтобы поддержать взаимодействие программистов в процессе коллективной разработки, а также облегчить понимание программ, написанных другими (в частности, программ с открытым исходным кодом).
Реализация визуализатора основана, в основном, на синтаксической части интерфейса. Визуализатор отображает программу в виде дерева, структура которого соответствует структурным элементам программы - классам, функциям, шаблонам и т.д. Внутри каждого такого элемента отображаются объявления, заданные в нём, а также исполняемые операторы. Для каждого объявления в наглядном виде представляется полная информация, характеризующая его, включая категорию, имя, тип и начальное значение. При этом информация обо всех элементах отображается в виде, более удобном для восприятия человеком, нежели стандартный синтаксис входного языка.
Каждый элемент дерева программы может быть представлен либо в сокращенном виде -как узел, содержащий только имя и категорию сущности, либо развернут в поддерево, содержащее максимально подробную информацию.
В отличие от многих аналогичных средств, присутствующих в составе интегрированных сред разработки, визуализатор умеет отображать не только объявления сущностей, но и с такой же степенью детализации показывать исполняемые части программы - операторы, вызовы функций и т.д.
Планы последующего развития визуализа-тора предусматривают превращение его из средства просмотра в инструмент редактирования программ. Такая функциональность позволит разработчикам вносить изменения в программу, манипулируя непосредственно ее компонентами, представленными в графическом виде, без использования текста. В целях функциональной полноты предусматривается обратная генерация текста программы из представления в виде дерева (например, для целей хранения или для компиляции).
Виртуальная машина С++. Идея виртуальной машины для языка С++, на первый взгляд, может показаться странной и неуместной. В самом деле, суть этого языка заключается
в том, чтобы, используя современные высокоуровневые языковые концепции, создавать предельно эффективные целевые программы, исполняемые непосредственно на аппаратуре, без каких-либо программных «посредников».
С другой стороны, известные проблемы, связанные с языком С++, сильно усложняют процесс разработки и отладки программ и зачастую не обеспечивают приемлемого уровня их надежности. Важно отметить, что эти проблемы, в целом, могут быть не связаны с недостаточной квалификацией программистов или с неэффективным менеджментом, а коренятся в самом понятийном базисе этого языка. Попросту говоря, сам дизайн языка поощряет создание ненадежных и трудных для восприятия и сопровождения программ.
Для преодоления проблем, связанных с недостаточной надежностью С++, разработано большое количество методик, технологий и инструментов. Предлагаемая в данном разделе виртуальная машина С++ является одной из таких попыток.
Коротко говоря, идея виртуальной машины в данном случае заключается в том, чтобы за счёт использования интерпретационного механизма исполнения и на основе полной информации о семантике программ превратить С++ из эффективного, но ненадежного инструмента пусть в несколько менее эффективный, но надежный.
В основе подхода к реализации виртуальной машины лежит идея непосредственной интерпретации семантического представления без использования какого-либо промежуточного представления («байт-кода»). Такой подход исключает дополнительные накладные расходы, связанные с преобразованиями из одного представления в другое, и позволяет в максимально возможной степени использовать знание о конкретных особенностях программы в целях ее контролируемого выполнения.
Последнее обстоятельство дает возможность считать виртуальную машину реализацией динамической семантики С++. Вместе с семантическим представлением, которое по существу служит формой статической семантики языка, представленная композиция в совокупности полностью определяет язык и, что существенно в практическом плане, обеспечивает полный контроль корректности выполнения программы за счет предотвращения типичных ошибок вроде
выхода индекса за границу массива, разыменования пустых указателей и т.п.
Разумеется, природа интерпретационного исполнения существенно снижает его эффективность. В некоторых обстоятельствах такое снижение может оказаться неприемлемым, однако, на наш взгляд, существует достаточный круг задач, для решения которых эффективность интерпретационного исполнения будет достаточной. В качестве примера можно привести отладку и тестирование программ и их компонентов (unit testing).
Кроме того, требования к эффективности небольших программ служебного характера (скриптов) с большой вероятностью не будут высокими, что может расширить сферу применения С++, сделав его пригодным для областей, в которых традиционно используются скрипто-вые языки.
Литература
1. ISO/IEC 15291:1999 Information technology - Programming languages - Ada Semantic Interface Specification (ASIS).
2. Bodin F. [et. al.], Sage++: An object-oriented toolkit and class library for building Fortran and C++ restructuring tools, Proceedings of the Second Annual Object-Oriented Numerics Conference, 1994.
3. Quinlan D., ROSE: Compiler Support for Object-Oriented Frameworks, Parallel Processing Letters, Vol. 10, also Proceedings of Conference on Parallel Compilers (CPC2000), Aussois, France, January 2000.
4. Edison Design Group, http://www.edg.com (дата обращения 19.05.2017).
5. The Pivot Project, http://parasol.tamu.edu/pivot/ (дата обращения 19.05.2017).
6. The Pivot: A brief overview. Bjarne Stroustrup and Gabriel Dos Reis, https://parasol.tamu.edu/pivot/publications/ reis1.pdf (дата обращения 19.03.2017).
7. The LLVM Compiler Infrastructure, http://llvm.org (дата обращения 19.05.2017).
8. Clang Static Analyzer, https://clang-analyzer.llvm.org/ (дата обращения 19.03.2017).
9. Working Draft, Standard for Programming Language C++, Document Number: N4659, Date: 2017-03-21, www.open-std.org/jtc1/sc22/wg21/docs/ papers/2017/n4659.pdf (дата обращения 19.05.2017).
10. Hidden copying constructor C++, http://stackoverflow.com/questions/ 9068024/hidden-copying-constructor-c (дата обращения 19.05.2017).
ISSN 0321-2653 IZVESTIYA VUZOV. SEVERO-KAVKAZSKIIREGION TECHNICAL SCIENCE 2017. № 3
References
1. ISO/IEC 15291:1999 Information technology. Programming languages. Ada Semantic Interface Specification (ASIS).
2. Bodin F. et. al., Sage++: An object-oriented toolkit and class library for building Fortran and C++restructuring tools, Proceedings of the Second Annual Object-Oriented Numerics Conference, 1994.
3. Quinlan D., ROSE: Compiler Support for Object-Oriented Frameworks, Parallel Processing Letters, Vol. 10, also Proceedings of Conference on Parallel Compilers (CPC2000), Aussois, France, January 2000.
4. Edison Design Group. Available at: http://www.edg.com (accessed 19.05.2017).
5. The Pivot Project. Available at: http://parasol.tamu.edu/pivot/ (accessed 19.05.2017).
6. The Pivot: A brief overview. Bjarne Stroustrup and Gabriel Dos Reis. Available at: https://parasol.tamu.edu/pivot/publications/reis1.pdf (accessed 19.03.2017).
7. The LLVM Compiler Infrastructure. Available at: http://llvm.org (accessed 19.05.2017).
8. Clang Static Analyzer. Available at: https://clang-analyzer.llvm.org/ (accessed 19.03.2017).
9. Working Draft, Standard for Programming Language C++, Document Number: N4659, Date: 2017-03-21. Available at: www.open-std.org/jtc1/sc22/wg21/docs/ papers/2017/n4659.pdf (accessed 19.05.2017).
10. Hidden copying constructor C++. Available at: http://stackoverflow.com/questions/ 9068024/hidden-copying-constructor-c (accessed 19.05.2017).
Поступила в редакцию /Received 03 мая 2017 г. /May 03, 2017