Стандарты языков программирования кратко

Обновлено: 07.07.2024

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

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

Создатели языков по-разному толкуют понятие язык программирования. К наиболее распространённым утверждениям, признаваемым большинством разработчиков, относятся следующие:

Содержание

Стандартизация языков программирования [ ]

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

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

Типы данных [ ]

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

Особая система, по которой данные организуются в программе, — это система типов языка программирования; разработка и изучение систем типов известна под названием теория типов. Языки могут быть классифицированы как системы со статической типизацией и языки с динамической типизацией.

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

Структуры данных [ ]

Системы типов в языках высокого уровня позволяют определять сложные, составные типы, так называемые структуры данных. Как правило, структурные типы данных образуются как декартово произведение базовых (атомарных) типов и ранее определённых составных типов.

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

Семантика языков программирования [ ]

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

Наиболее широко распространены разновидности следующих трёх: операционного, денотационного (математического) и деривационного (аксиоматического).

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

Деривационная семантика описывает последствия выполнения конструкций языка с помощью языка логики и задания пред- и постусловий.

Денотационная семантика оперирует понятиями, типичными для математики— множества, соответствия, а также суждения, утверждения и др.

Парадигма программирования [ ]

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

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

Языки программирования могут быть реализованы как компилируемые и интерпретируемые.

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

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

Разделение на компилируемые и интерпретируемые языки является условным. Так, для любого традиционно компилируемого языка, как, например, Common Language Runtime .

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

Используемые символы [ ]

Современные языки программирования рассчитаны на использование ASCll , то есть доступность всехграфических символов ASCII является необходимым и достаточным условием для записи любых конструкций языка. Управляющие символы ASCII используются ограниченно: допускаются только возврат каретки CR, перевод строки LF и горизонтальная табуляция HT (иногда также вертикальная табуляция VT и переход к следующей странице FF).

Ранние языки, возникшие в эпоху 6-битных символов, использовали более ограниченный набор. Например, алфавит Фортрана включает 49 символов (включая пробел): A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 = + - * / () . , $ ' :

Заметным исключением является язык Delphi 2006 , Смотрите также [ ]

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

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

  • Процедурные языки, которые представляют собой последовательность выполняемых операторов . Если рассматривать состояние ПК как состояние ячеек памяти, то процедурный язык – это последовательность операторов, изменяющих значение одной или нескольких ячеек. К процедурным языкам относятся FORTRAN, C, Ada, Pascal, Smalltalk и некоторые другие. Процедурные языки иногда также называются императивными языками. Код программы на процедурном языке может быть записан следующим образом:

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

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

Стандартизация языков программирования

Концепция языка программирования неотрывно связана с его реализацией. Для того чтобы компиляция одной и той же программы различными компиляторами всегда давала одинаковый результат, разрабатываются стандарты языков программирования. Существует ряд организаций, целенаправленно занимающихся вопросами стандартизации. Это Американский национальный институт стандартов ANSI (American National Standards Institute), Институт инженеров по электротехнике и электронике IEEE (Institute of Electrical and Electronic Engineers ), Организация международных стандартов ISO ( International Organization for Standardization ).

Как правило, при создании языка выпускается частный стандарт, определяемый разработчиками языка. Если язык получает широкое распространение, то со временем появляются различные версии компиляторов, которые не точно следуют частному стандарту. В большинстве случаев идет расширение зафиксированных первоначально возможностей языка. Для приведения наиболее популярных реализаций языка в соответствие друг с другом разрабатывается согласительный стандарт. Очень важным фактором стандартизации языка программирования является своевременность появления стандарта – до широкого распространения языка и создания множества несовместимых реализаций. В процессе развития языка могут появляться новые стандарты, отражающие современные нововведения. Так, язык FORTRAN первоначально был стандартизирован в 1966 году. В результате был издан стандарт FORTRAN 66. Далее этот стандарт несколько раз пересматривался (в 1977 году был выпущен FORTRAN 77, затем появился и FORTRAN 90).

Язык Java , ставший в последнее время весьма распространенным, постепенно был значительно расширен и модифицирован: новая спецификация получила название Java 2.

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

Среда проектирования

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

Компилятор языка программирования выступает как составная часть среды проектирования. Сама программа наряду с конструкциями, предусмотренными стандартом, как правило, использует библиотечные функции и классы, предоставляемые средой проектирования. Так, интегрированная среда разработки VisualStudio. NET содержит библиотеку классов MFC (Microsoft Foundation Classes), значительно упрощающую процесс разработки приложений, использующих оконный интерфейс .

Для проектирования приложений на языке Object Pascal используется интегрированная среда проектирования Delphi.

Наиболее удобной средой разработки программ на языке Java является интегрированная среда проектирования JBuilder.

Большинство алгоритмических языков программирования, таких как Си и Паскаль, были созданы на рубеже 60 и 70-х годов. Иными словами, их возраст (за исключением Java) перевалил за третий десяток, что для компьютерной индустрии срок немалый. Они старше Internet, Windows да и собственно ПК не менее чем на десятилетие. Стоит отметить, что новые языки не переставали регулярно появляться, однако ни один из них не задержался в практике программирования, хотя приносимые ими идеи становились достоянием известных языков (как это произошло с объектно-ориентированным программированием).

Наконец, появление ПК и ОС с графическим интерфейсом (прежде всего Mac OS и Windows) привело к переносу внимания разработчиков ПО из сферы языков программирования в другие области средств разработки, такие как визуальное или объектно-ориентированное программирование, сетевые протоколы или модели баз данных. Сегодня программист использует в качестве инструмента не столько язык, сколько конкретную среду программирования (например, Delphi), а какой язык является базовым, не так уж важно.

Сопоставительный анализ

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

Цикл с параметром

В качестве первого примера воспользуемся оператором цикла с параметром (for). Это наиболее часто используемый составной (т.е. содержащий другие операторы) оператор в любом языке. Он всегда содержит следующие компоненты:

  • переменную - счетчик цикла
  • выражение - начальное значение цикла
  • выражение - конечное значение цикла
  • список операторов - тело цикла

Кроме того, цикл с параметром может содержать признак увеличения/уменьшения счетчика цикла (Паскаль) или способ модификации счетчика (Си и Java). Реализация на Паскале:

Реализация на Си и Java:

  • список полей с указанием имени поля и его типа
  • список вариантных частей (union в Си)

Реализация на Паскале:

Реализация на Си:

Реализация на Java:

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

Синтаксис и семантика

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

Стандарты языков программирования

Существующая ныне система стандартизации языков программирования не способствует выполнению этой задачи. Главная проблема состоит в том, что при описании стандарта семантическая составляющая не отделена от синтаксиса и лексики. Кроме того, при модернизации стандартов комитеты ISO/ANSI предпочитают скорее добавлять в язык новые возможности, чем исключать редко используемые, что приводит к неоправданному синтаксическому расширению языков.

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

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

Семантическое описание оператора while. ЦиклСПредусловием должен содержать следующие обязательные компоненты:

УсловиеПродолженияЦикла представляет собой выражение логического (булевого) типа.

ТелоЦикла — оператор или список операторов языка программирования.

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

Синтаксическое описание оператора while. ЦиклСПредусловием выглядит следующим образом в разных языках программирования:

ТипУказатель должен содержать следующие обязательные компоненты:

ИмяТипа представляет собой идентификатор.

БазовыйТип — имя встроенного или ранее описанного типа языка программирования.

ТипУказатель — это адрес конструкции БазовыйТип. Его размер фиксирован и зависит от платформы программирования (для Win32 он составляет 4 байта).

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

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

Содержание семантического и синтаксического стандартов языка

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

  • Список компонент, из которых состоит конструкция (в ТипУказатель это компоненты ИмяТипа и БазовыйТип)
  • Описание каждой компоненты
  • Описание конструкции в целом

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

Компиляторы с общей семантической базой

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

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

Язык будущего

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

В языках, созданных под влиянием Паскаля (Модула 2, Ада), параметр цикла может изменяться только с шагом 1. В Си-подобных языках семантика цикла с параметром допускает не только любой шаг переменной, но и вообще любой оператор, произвольно изменяющий значение параметра. Кроме того, условие окончания цикла в Си может быть любым логическим выражением (а не только достижением переменной порогового значения). Иными словами, цикл с параметром в Си может вообще не содержать параметра (в этом случае он становится аналогом цикла while). Ниже приведены примеры одного и того же цикла:

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

  • задание констант (наиболее распространенный вариант)
  • задание inline-функций
  • создание настраиваемых модулей (из других языков они есть только в Аде)

Директива define — безусловный анахронизм. Неслучайно в современных вариантах Си (Си++ и Java) ее область действия стараются ограничить, вводя дополнительные конструкции (директиву const и скалярные типы).

Набор конструкций языка программирования будущего

Структурный редактор

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

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

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

Программа — не текст, а набор конструкций

С точки зрения компьютера программа вовсе не является текстом. Это набор операторов, описаний типов, процедур и т. д. Ошибки компиляции — не что иное, как результат непонимания друг друга компилятором и программистом: компилятор просит программиста объяснить, что тот имел в виду. Текст — не оптимальный способ представления программ: он неоднозначен и позволяет каждую конструкцию записывать разными способами.

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

Преимущества структурного редактора

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

Псевдотекст

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

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

Разумеется, должны быть доступны и основные операции работы с текстом (главным образом, работа с блоками).

Перспективы семантического подхода

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

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

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

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

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

Язык программирования используется для написания компьютерных программ, представляющих собой набор правил, которые позволяют компьютеру выполнить какой-либо вычислительный процесс, организовать управление различными объектами и т. п. Отличие языка программирования от естественного языка в том, что он предназначен для взаимодействия человека с ЭВМ, а естественный язык – для общения людей между собой. У большинства языков программирования для определения и манипулирования структурами данных и управления процессом вычислений используются специальные конструкции.

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

  1. Стандарт языка – набор спецификаций, которые определяют его синтаксис и семантику; стандарт языка может исторически развиваться.
  2. Воплощения (реализации) стандарта – сами программные средства, которые обеспечивают работу соответственно определенному варианту стандарта языка. Они отличаются производителем, маркой и вариантом (версией), временем выпуска, полнотой воплощения стандарта, дополнительными возможностями; зачастую имеют определённые ошибки или особенности воплощения, которые влияют на практику использования языка или даже на его стандарт.

Готовые работы на аналогичную тему

Стандартизация языков программирования

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

Способы реализации языков

Языки программирования могут быть реализованы в виде компилируемых, интерпретируемых и встраиваемых.

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

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

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

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

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

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

При таком подходе удобно использовать плюсы и интерпретаторов, и компиляторов. Существуют языки, которые имеют интерпретатор и компилятор (например, Форт).

Используемые символы

Современные языки программирования поддерживают использование ASCII, т. е. доступность всех графических символов ASCII является необходимым и достаточным условием для записи любых конструкций языка. Из управляющих символов ASCII допускается только использование возврата каретки CR, перевода строки LF и горизонтальной табуляции HT (иногда также вертикальной табуляции VT и перехода к следующей странице FF).

Читайте также: