Данная лекция вводит в проблему точного определения
Для создания, проверки и преобразования программ, построения систем программирования, а также для многих других нужд нам необходимо если не определение, то хотя бы описание алгоритмического языка. При этом требуются точные описания как текстов, так и их интерпретации. Рассмотрим существующие варианты.
Именно так пытались поступать на заре программирования, когда, скажем, легендарный язык FORTRAN создавался одновременно с первым транслятором с данного языка.
Первый вариант — совершенно неудовлетворительный путь, поскольку всякое изменение в программе-трансляторе может полностью изменить смысл некоторых конструкций языка со всеми вытекающими отсюда последствиями.
Второй вариант соответствует взгляду на язык как на множество правильно построенных последовательностей символов. Если последовательность символов принадлежит языку, то она считается синтаксически правильной. Для программы это означает, что транслятор на ней не выдает ошибки. Но синтаксическая правильность не гарантирует даже осмысленности программы. Таким образом, здесь определяется лишь одна сторона языка.
Третий вариант работает только вместе со вторым, поскольку структурные единицы должны соединиться в синтаксически правильную систему. Он раскрывает еще одну сторону языка.
Таким образом, мы видим, что каждый язык имеет три стороны:
Под внешним окружением понимаются характеристики машины, на которой исполняется программа (точность представления данных, объем памяти, другие программы, которые можно использовать при выполнении данной, и т. д.), и потоки входных данных, поступающие в программу в ходе ее исполнения.
Описание языка требует точного задания
Грамматика определяется системой синтаксических правил (чаще всего в описаниях языков называемых просто правилами ). На уровне грамматики определяются понятия, последовательное раскрытие которых, называемое выводом, в конце концов дает их представление в виде последовательностей символов. Символы называются также терминальными понятиями, а все остальные понятия нетерминальными. Понятия бывают смысловые, т. е. языковые конструкции, для которых определено то или иное действие абстрактного вычислителя, и вспомогательные, нужные лишь для построения текста, но самостоятельного смысла не имеющие. Минимальные смысловые понятия соответствуют лексемам. Некоторые понятия вводятся лишь для того, чтобы сделать текст читаемым для человека. Минимальные из них (они подобны знакам пунктуации) естественно считать вспомогательными лексемами.
Но даже задача полного описания
Понятие контекстно-свободной грамматики стало первым строгим
понятием в описаниях практических алгоритмических языков. За понятием
Содержательно можно охарактеризовать
Контекстные зависимости сужают множество
Неоднократные попытки формально описывать контекстные зависимости при
определении языков показали, что эта задача гораздо более сложная,
чем задание контекстно-свободного
Пример 4.2.1. Требование о том, что каждое имя должно быть описано (в частности, в языках Pascal и C), конкретизируется в следующей форме.
Такая совокупность требований достаточна для того, чтобы человек
мог проверить по тексту программы, как в данном месте понимается данное имя
В практических описаниях языков и в курсах программирования обычно довольствуются неформальным, но достаточно точным описанием контекстных зависимостей. Приведем пример такого описания.
Мы определили
Цель программиста - получить нужный ему эффект в результате
исполнения программы на конкретном оборудовании. Но, составляя
программу, он думает о программе как об абстрактной сущности и чаще
всего совсем не хочет знать о регистрах, процессоре и других объектах
конкретного оборудования. В соответствии с позицией программиста моделью вычислений языка программирования естественно считать то,
какой абстрактный вычислитель задается описанием языка. Эта позиция
подкрепляется также тем, что трансляция и исполнение может
осуществляться на разных конкретных вычислителях. Следуя этой точке
зрения, мы, говоря о
Понятие модели вычислений языка естественно распространяется на
случаи, когда используются библиотеки программ. Библиотеки,
стандартизованные описанием языка, можно считать частью реализации
языка независимо от того, как реализуются библиотечные средства: на
самом языке или нет. Иными словами, библиотечные средства -
дополнительные команды абстрактного вычислителя языка. Не зависящие
от определения языка библиотеки можно рассматривать как расширения
языка, т. е. как появление новых языков, включающих в себя исходный
язык. И хотя таких расширений может быть много, рассмотрение модели
вычислений для языка вместе с его библиотеками хорошо соответствует
стилю мышления человека, конструирующего программу
Задаваемое
Реализованный язык всегда является прагматическим компромиссом между абстрактной моделью вычислений и возможностями ее воплощения.
До сих пор речь шла об определении языка его абстрактным
вычислителем. Longint в системе Visual
C++ определяется как 32-разрядное двоичное число с фиксированной
точкой, занимающее слово памяти.
Та часть {$I+}, {$I-}
(включение/выключение контроля ввода-вывода). Многие из таких
комментариев практически во всех версиях одни и те же. В самом
стандарте языка явно предписана лишь их внешняя форма: {$...}.
Даже если язык ориентирован на реализацию в единственной операционной
обстановке (например, это какой-нибудь
Принципиально различаются два вида
Синтаксическая прагматика — это правила сокращения записи, можно
сказать, скоропись для данного языка. Пример, который можно
рассматривать как синтаксическую
<переменная>++; или ++<переменная>;
и
<переменная>--; или --<переменная>;
В С/С++ команды такого рода следует относить к модели вычислений языка, так как для нее постулируется, что язык является машинно-ориентированным и отражает особенности архитектуры вычислительного оборудования, а команды увеличения и уменьшения на единицу предоставляются программисту на уровне оборудования достаточно часто.
В Turbo Pascal и
Inc (<переменная>)
и
Dec (<переменная>)
соответственно. Если рассматривать Turbo Pascal как правильное
расширение стандартного языка Pascal, не содержащего обсуждаемые
команды, то эти команды — просто подсказка транслятору, как надо
программировать данное вычисление. Следовательно, указанные операторы
для данного языка можно относить к <переменная> ":=" <переменная /* та же самая */> "+" 1
и им подобные не представляет труда не только в тех случаях, когда <переменная> указана
явно, но и тогда, когда она вычисляется (индексирование,
Другой пример — возможность записи в языке Prolog вместо вызова +(X,Y) выражения X+Y.
Семантическая прагматика — это определение того, что в описании языка оставлено на усмотрение реализации или предписывается в качестве вариантов вычислений.
Например, стандарт языка Pascal утверждает, что при использовании
переменной с индексом на уровне вычислений контролируется выход
индекса за диапазон допустимых значений. Однако в объектном коде
постоянные проверки этого свойства могут показаться накладными и
избыточными (например, когда программа написана настолько хорошо, что
можно гарантировать соответствующие значения индексов). Стандарт
языка для таких случаев предусматривает сокращенный, т. е. без
проверок, режим вычислений. Выбор режимов управляется пользователем с
помощью прагматических указаний для транслятора, выражаемых в
Разработчики системы программирования должны прилагать специальные усилия, чтобы обеспечить явное выделение прагматического уровня. Без этого может сложиться превратное представление как о предлагаемой модели вычислений, так и о ее реализации. Вдобавок, резко ограничиваются возможности программиста в применении методов абстрагирования. Проиллюстрируем это.
Пример 4.4.1. Стандарт языка С предписывает, что системы
программирования на нем должны предусматривать специальный инструмент
для обработки программных текстов, который называется препроцессором.
Препроцессор делает массу полезных преобразований. Как уже
упоминалось, он берет на себя решение задачи подключения к программе
внешних (библиотечных) файлов, с его помощью можно скрывать утомительные
детали программирования, достигать ряда нужных эффектов, не
предусмотренных в основных средствах языка (например, именованные
константы). Постулируется, что программа на языке С есть то, что
получается после работы препроцессора с текстом (разумеется, если
результат такой работы окажется корректным). Следовательно, использование
препроцессора — синтаксическая
Пусть написано
if (x > 0) Firstmacro else PerformAction;
Кажется, что действие выполняется, если x $$\le$$ 0, но первый макрос раскрывается как
PrepareAction; if (x <= 0) CancelAction
Даже автор данной программы через некоторое время не поймет, почему же она так себя ведет.
Как это ни странно, подобные построения используются в практике программирования на С: они применяются, чтобы в одном тексте задать несколько вариантов выполняемых программ, которые разграничиваются при работе препроцессора, т. е. до выполнения.
Наложение команд препроцессора на текст программы — это смешение
двух моделей вычислений: одна из них — модель базового языка С,
другая — '#'. Такие строки представляют
команды, управляющие работой препроцессора. Например, #include . ..
заставляет препроцессор вставить некоторый файл в перерабатываемый текст (не следует
понимать это буквально — нужно просто обеспечить соответствующий эффект). Другой
пример: #define two 2
дает указание препроцессору на то, что в оставшейся части текста идентификатор two
должен заменяться числом 2. Результат вычислений препроцессора — текст, который не
содержит его команд.
Разработчики С и С++ с самого начала не задумывались о соблюдении концептуальной целостности. Это приводило к тому, что при развитии языка он становился все более эклектичным.
Во многих языках, в частности в
Даже концептуально
Модель вычислений стандартного языка Pascal изначально была довольно
целостна, поскольку в ней четко проводились несколько хорошо
согласованных базовых идей и не было ничего лишнего. Но она не во
всем удовлетворяла практических программистов. В языке Pascal, в
частности, не было модульности, и требовалась значительно более
глубокая проработка
Далее пришел черед модных средств ООП, которые также были интегрированы в язык с минимальным ущербом для его концептуальной целостности.
Таким образом, создатели линии Turbo Pascal успешно решили трудную
задачу расширения языка при сохранении концептуального единства и
отделения
Однако со столь трудной проблемой не удалось справиться тем же
разработчикам, когда они взялись за конструирование принципиально
новой системы программирования Delphi и ее языка
Внимание!
Есть большая опасность, связанная с добавлением новых возможностей к хорошей системе без глубокой концептуальной проработки. Сплошь и рядом то, что хорошо работало раньше, после таких модификаций перестает устойчиво работать.
При рассмотрении приемов программирования и примеров на разных языках
необходимо как можно больше отвлекаться от частных особенностей и
учиться видеть за ними общее с тем, чтобы оставшиеся различия были бы
уже принципиальными. Отделить существенное от несущественного
помогает, в частности, соотношение между
Обычное синтаксическое определение языка задает конкретные синтаксические правила построения программы как строки символов. При этом определяется, какие структурные элементы могут быть выделены в тексте программы (конкретное представление программы).
Действия абстрактного вычислителя определяются на структурном
представлении программы и не зависят от многих особенностей =, := или, скажем, LET ) совершенно не важен. Более того, неважно, в
каком порядке расположены составные части присваивания в тексте
программы. Например, конструкция языка COBOL
MOVE X+Y TO Z
выражающая присваивание получателю Z значения выражения X+Y,
совершенно аналогична обычному оператору присваивания.
Для того, чтобы четко отличать конкретное представление от
существенной структуры, стоит рассматривать
Аналогично, три оператора
X = a * b + c * d; X = (a * b) + (c * d); (4.1) X = ((a * b) + (c * d));
и подобные им полностью эквивалентны с точки зрения
Таким образом, нужна структура синтаксических понятий, которая
соответствует некоторому
Фрагментом абстрактно-синтаксического представления является чаще
всего применяемый на практике ход. Задают понятие синтаксической
эквивалентности, которое очевидным образом согласуется с
функциональной эквивалентностью. Так, например, предложения,
перечисленные в примере 4.1, могут описываться следующим понятием
синтаксической эквивалентности: скобки вокруг подвыражений, связанных
операцией более высокого приоритета, чем операция, примененная к их
результату, могут опускаться. В данном смысле присваивание
рассматривается как операция, имеющая более низкий приоритет, чем
любая из арифметических операций. Таким образом, например,
определяется эквивалентность выражений в языке Prolog. Подвыражение X
+ 3, скажем, является в нем всего лишь другим вариантом записи для +(X,3), и при вычислении характеристик выражения оно прежде всего
преобразуется в форму без знаков операций.
Еще одну возможность, открываемую переходом к абстрактно-синтаксическим определениям, можно увидеть, если определить эквивалентность подвыражений для сложения и умножения
$$A + B \leftrightarrow B + A.$$Здесь абстрактная эквивалентность выражает свойство самой операции.
Опыт показывает, что дальше учета ассоциативности и коммутативности в
(рис 4.1) Оператор печатиПример на рис. 4.1 иллюстрирует вызов функции:
printf ("\nX1 = %f, X2 = %f\n", X1, X2);
Показанная на рисунке структура
Рассмотрим более сложный пример, показывающий родство
. . .
if ( D > 0 )
{
D = sqrt ( D );
(рис 4.2) Представление фрагмента текста программы Данная лекция вводит в проблему точного определения
Для создания, проверки и преобразования программ, построения систем программирования, а также для многих других нужд нам необходимо если не определение, то хотя бы описание алгоритмического языка. При этом требуются точные описания как текстов, так и их интерпретации. Рассмотрим существующие варианты.
Именно так пытались поступать на заре программирования, когда, скажем, легендарный язык FORTRAN создавался одновременно с первым транслятором с данного языка.
Первый вариант — совершенно неудовлетворительный путь, поскольку всякое изменение в программе-трансляторе может полностью изменить смысл некоторых конструкций языка со всеми вытекающими отсюда последствиями.
Второй вариант соответствует взгляду на язык как на множество правильно построенных последовательностей символов. Если последовательность символов принадлежит языку, то она считается синтаксически правильной. Для программы это означает, что транслятор на ней не выдает ошибки. Но синтаксическая правильность не гарантирует даже осмысленности программы. Таким образом, здесь определяется лишь одна сторона языка.
Третий вариант работает только вместе со вторым, поскольку структурные единицы должны соединиться в синтаксически правильную систему. Он раскрывает еще одну сторону языка.
Таким образом, мы видим, что каждый язык имеет три стороны:
Под внешним окружением понимаются характеристики машины, на которой исполняется программа (точность представления данных, объем памяти, другие программы, которые можно использовать при выполнении данной, и т. д.), и потоки входных данных, поступающие в программу в ходе ее исполнения.
Описание языка требует точного задания
Грамматика определяется системой синтаксических правил (чаще всего в описаниях языков называемых просто правилами ). На уровне грамматики определяются понятия, последовательное раскрытие которых, называемое выводом, в конце концов дает их представление в виде последовательностей символов. Символы называются также терминальными понятиями, а все остальные понятия нетерминальными. Понятия бывают смысловые, т. е. языковые конструкции, для которых определено то или иное действие абстрактного вычислителя, и вспомогательные, нужные лишь для построения текста, но самостоятельного смысла не имеющие. Минимальные смысловые понятия соответствуют лексемам. Некоторые понятия вводятся лишь для того, чтобы сделать текст читаемым для человека. Минимальные из них (они подобны знакам пунктуации) естественно считать вспомогательными лексемами.
Но даже задача полного описания
Понятие контекстно-свободной грамматики стало первым строгим
понятием в описаниях практических алгоритмических языков. За понятием
Содержательно можно охарактеризовать
Контекстные зависимости сужают множество
Неоднократные попытки формально описывать контекстные зависимости при
определении языков показали, что эта задача гораздо более сложная,
чем задание контекстно-свободного
Пример 4.2.1. Требование о том, что каждое имя должно быть описано (в частности, в языках Pascal и C), конкретизируется в следующей форме.
Такая совокупность требований достаточна для того, чтобы человек
мог проверить по тексту программы, как в данном месте понимается данное имя
В практических описаниях языков и в курсах программирования обычно довольствуются неформальным, но достаточно точным описанием контекстных зависимостей. Приведем пример такого описания.
Мы определили
Цель программиста - получить нужный ему эффект в результате
исполнения программы на конкретном оборудовании. Но, составляя
программу, он думает о программе как об абстрактной сущности и чаще
всего совсем не хочет знать о регистрах, процессоре и других объектах
конкретного оборудования. В соответствии с позицией программиста моделью вычислений языка программирования естественно считать то,
какой абстрактный вычислитель задается описанием языка. Эта позиция
подкрепляется также тем, что трансляция и исполнение может
осуществляться на разных конкретных вычислителях. Следуя этой точке
зрения, мы, говоря о
Понятие модели вычислений языка естественно распространяется на
случаи, когда используются библиотеки программ. Библиотеки,
стандартизованные описанием языка, можно считать частью реализации
языка независимо от того, как реализуются библиотечные средства: на
самом языке или нет. Иными словами, библиотечные средства -
дополнительные команды абстрактного вычислителя языка. Не зависящие
от определения языка библиотеки можно рассматривать как расширения
языка, т. е. как появление новых языков, включающих в себя исходный
язык. И хотя таких расширений может быть много, рассмотрение модели
вычислений для языка вместе с его библиотеками хорошо соответствует
стилю мышления человека, конструирующего программу
Задаваемое
Реализованный язык всегда является прагматическим компромиссом между абстрактной моделью вычислений и возможностями ее воплощения.
До сих пор речь шла об определении языка его абстрактным
вычислителем. Longint в системе Visual
C++ определяется как 32-разрядное двоичное число с фиксированной
точкой, занимающее слово памяти.
Та часть {$I+}, {$I-}
(включение/выключение контроля ввода-вывода). Многие из таких
комментариев практически во всех версиях одни и те же. В самом
стандарте языка явно предписана лишь их внешняя форма: {$...}.
Даже если язык ориентирован на реализацию в единственной операционной
обстановке (например, это какой-нибудь
Принципиально различаются два вида
Синтаксическая прагматика — это правила сокращения записи, можно
сказать, скоропись для данного языка. Пример, который можно
рассматривать как синтаксическую
<переменная>++; или ++<переменная>;
и
<переменная>--; или --<переменная>;
В С/С++ команды такого рода следует относить к модели вычислений языка, так как для нее постулируется, что язык является машинно-ориентированным и отражает особенности архитектуры вычислительного оборудования, а команды увеличения и уменьшения на единицу предоставляются программисту на уровне оборудования достаточно часто.
В Turbo Pascal и
Inc (<переменная>)
и
Dec (<переменная>)
соответственно. Если рассматривать Turbo Pascal как правильное
расширение стандартного языка Pascal, не содержащего обсуждаемые
команды, то эти команды — просто подсказка транслятору, как надо
программировать данное вычисление. Следовательно, указанные операторы
для данного языка можно относить к <переменная> ":=" <переменная /* та же самая */> "+" 1
и им подобные не представляет труда не только в тех случаях, когда <переменная> указана
явно, но и тогда, когда она вычисляется (индексирование,
Другой пример — возможность записи в языке Prolog вместо вызова +(X,Y) выражения X+Y.
Семантическая прагматика — это определение того, что в описании языка оставлено на усмотрение реализации или предписывается в качестве вариантов вычислений.
Например, стандарт языка Pascal утверждает, что при использовании
переменной с индексом на уровне вычислений контролируется выход
индекса за диапазон допустимых значений. Однако в объектном коде
постоянные проверки этого свойства могут показаться накладными и
избыточными (например, когда программа написана настолько хорошо, что
можно гарантировать соответствующие значения индексов). Стандарт
языка для таких случаев предусматривает сокращенный, т. е. без
проверок, режим вычислений. Выбор режимов управляется пользователем с
помощью прагматических указаний для транслятора, выражаемых в
Разработчики системы программирования должны прилагать специальные усилия, чтобы обеспечить явное выделение прагматического уровня. Без этого может сложиться превратное представление как о предлагаемой модели вычислений, так и о ее реализации. Вдобавок, резко ограничиваются возможности программиста в применении методов абстрагирования. Проиллюстрируем это.
Пример 4.4.1. Стандарт языка С предписывает, что системы
программирования на нем должны предусматривать специальный инструмент
для обработки программных текстов, который называется препроцессором.
Препроцессор делает массу полезных преобразований. Как уже
упоминалось, он берет на себя решение задачи подключения к программе
внешних (библиотечных) файлов, с его помощью можно скрывать утомительные
детали программирования, достигать ряда нужных эффектов, не
предусмотренных в основных средствах языка (например, именованные
константы). Постулируется, что программа на языке С есть то, что
получается после работы препроцессора с текстом (разумеется, если
результат такой работы окажется корректным). Следовательно, использование
препроцессора — синтаксическая
Пусть написано
if (x > 0) Firstmacro else PerformAction;
Кажется, что действие выполняется, если x $$\le$$ 0, но первый макрос раскрывается как
PrepareAction; if (x <= 0) CancelAction
Даже автор данной программы через некоторое время не поймет, почему же она так себя ведет.
Как это ни странно, подобные построения используются в практике программирования на С: они применяются, чтобы в одном тексте задать несколько вариантов выполняемых программ, которые разграничиваются при работе препроцессора, т. е. до выполнения.
Наложение команд препроцессора на текст программы — это смешение
двух моделей вычислений: одна из них — модель базового языка С,
другая — '#'. Такие строки представляют
команды, управляющие работой препроцессора. Например, #include . ..
заставляет препроцессор вставить некоторый файл в перерабатываемый текст (не следует
понимать это буквально — нужно просто обеспечить соответствующий эффект). Другой
пример: #define two 2
дает указание препроцессору на то, что в оставшейся части текста идентификатор two
должен заменяться числом 2. Результат вычислений препроцессора — текст, который не
содержит его команд.
Разработчики С и С++ с самого начала не задумывались о соблюдении концептуальной целостности. Это приводило к тому, что при развитии языка он становился все более эклектичным.
Во многих языках, в частности в
Даже концептуально
Модель вычислений стандартного языка Pascal изначально была довольно
целостна, поскольку в ней четко проводились несколько хорошо
согласованных базовых идей и не было ничего лишнего. Но она не во
всем удовлетворяла практических программистов. В языке Pascal, в
частности, не было модульности, и требовалась значительно более
глубокая проработка
Далее пришел черед модных средств ООП, которые также были интегрированы в язык с минимальным ущербом для его концептуальной целостности.
Таким образом, создатели линии Turbo Pascal успешно решили трудную
задачу расширения языка при сохранении концептуального единства и
отделения
Однако со столь трудной проблемой не удалось справиться тем же
разработчикам, когда они взялись за конструирование принципиально
новой системы программирования Delphi и ее языка
Внимание!
Есть большая опасность, связанная с добавлением новых возможностей к хорошей системе без глубокой концептуальной проработки. Сплошь и рядом то, что хорошо работало раньше, после таких модификаций перестает устойчиво работать.
При рассмотрении приемов программирования и примеров на разных языках
необходимо как можно больше отвлекаться от частных особенностей и
учиться видеть за ними общее с тем, чтобы оставшиеся различия были бы
уже принципиальными. Отделить существенное от несущественного
помогает, в частности, соотношение между
Обычное синтаксическое определение языка задает конкретные синтаксические правила построения программы как строки символов. При этом определяется, какие структурные элементы могут быть выделены в тексте программы (конкретное представление программы).
Действия абстрактного вычислителя определяются на структурном
представлении программы и не зависят от многих особенностей =, := или, скажем, LET ) совершенно не важен. Более того, неважно, в
каком порядке расположены составные части присваивания в тексте
программы. Например, конструкция языка COBOL
MOVE X+Y TO Z
выражающая присваивание получателю Z значения выражения X+Y,
совершенно аналогична обычному оператору присваивания.
Для того, чтобы четко отличать конкретное представление от
существенной структуры, стоит рассматривать
Аналогично, три оператора
X = a * b + c * d; X = (a * b) + (c * d); (4.1) X = ((a * b) + (c * d));
и подобные им полностью эквивалентны с точки зрения
Таким образом, нужна структура синтаксических понятий, которая
соответствует некоторому
Фрагментом абстрактно-синтаксического представления является чаще
всего применяемый на практике ход. Задают понятие синтаксической
эквивалентности, которое очевидным образом согласуется с
функциональной эквивалентностью. Так, например, предложения,
перечисленные в примере 4.1, могут описываться следующим понятием
синтаксической эквивалентности: скобки вокруг подвыражений, связанных
операцией более высокого приоритета, чем операция, примененная к их
результату, могут опускаться. В данном смысле присваивание
рассматривается как операция, имеющая более низкий приоритет, чем
любая из арифметических операций. Таким образом, например,
определяется эквивалентность выражений в языке Prolog. Подвыражение X
+ 3, скажем, является в нем всего лишь другим вариантом записи для +(X,3), и при вычислении характеристик выражения оно прежде всего
преобразуется в форму без знаков операций.
Еще одну возможность, открываемую переходом к абстрактно-синтаксическим определениям, можно увидеть, если определить эквивалентность подвыражений для сложения и умножения
$$A + B \leftrightarrow B + A.$$Здесь абстрактная эквивалентность выражает свойство самой операции.
Опыт показывает, что дальше учета ассоциативности и коммутативности в
(рис 4.1) Оператор печатиПример на рис. 4.1 иллюстрирует вызов функции:
printf ("\nX1 = %f, X2 = %f\n", X1, X2);
Показанная на рисунке структура
Рассмотрим более сложный пример, показывающий родство
. . .
if ( D > 0 )
{
D = sqrt ( D );
(рис 4.2) Представление фрагмента текста программы Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.