Опубликован: 16.09.2005 | Уровень: для всех | Доступ: свободно | ВУЗ: Московский государственный университет имени М.В.Ломоносова
Лекция 11:

Структуры данных: общее понятие, реализация. Простейшие структуры данных: очередь, стек. Использование стека и обратная польская запись

Язык PostScript

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

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

В случае использования языка PostScript файл, пересылаемый на PostScript-принтер, представляет собой программу печати текста. Язык PostScript имеет огромное количество возможностей, и вряд ли найдется много людей, владеющих им. Чаще всего PostScript-программа создается другой программой обработки текста. Например, PostScript-файл создается TEX-ом для печати на принтере. (TEX — это язык записи текстов, содержащих математические формулы, созданный замечательным математиком и теоретиком программирования Дональдом Кнутом. Фактически TEX представляет собой язык программирования. Данная книга подготовлена в TEX'е с использованием макропакета LaTEX 2 \varepsilon.) Текстовые процессоры, такие, как Adobe Acrobat или MS Word, также в случае печати на профессиональном PostScript-принтере преобразуют текст в PostScript-программу. (Более точно, такое преобразование осуществляется драйверами операционной системы.) PostScript-файлы очень удобны для распространения: поскольку это файлы в обычном текстовом формате, они будут напечатаны одинаково в любой стране независимо от национальных кодировок, операционных систем, наличия шрифтов и т.п.

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


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

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

% Файл "func.ps"
% Рисование графика функции y = f(x)

% Перейти от пунктов (1/72 дюйма) к миллиметрам
2.83 2.83 scale

0.2 setlinewidth  % Установить толщину линии

% Нарисовать координатную ось X:
1 15 moveto   % переместиться в точку (1, 15)
60 15 lineto  % провести линию к точке (60, 15)
              % Рисуем стрелку:
57 16 moveto  % переместиться в точку (57, 16)
60 15 lineto  % провести линию к точке (60, 15)
57 14 lineto  % провести линию к точке (57, 14)
stroke        % нарисовать построенные линии

% Нарисовать координатную ось Y:
30 1 moveto   % переместиться в точку (30, 1)
30 30 lineto  % провести линию к точке (30, 30)
              % Рисуем стрелку:
29 27 moveto  % переместиться в точку (29, 27)
30 30 lineto  % провести линию к точке (30, 30)
31 27 lineto  % провести линию к точке (31, 27)
stroke        % нарисовать построенные линии

% Определение функции
%   f(x) = 5 * sin((x - 30) * 0.2 * 180/Pi) + 15
% Дано: число x на вершине стека.
% Надо: заменить вершину стека на f(x).
/Func {
    30 sub 0.2 mul 57.296 mul sin 5 mul 15 add
} def

% Рисуем график функции

0.3 setlinewidth  % установить толщину линии
2 2 Func moveto   % переместиться в точку (2, f(2))
2.5 0.5 58 { % цикл для x от 2.5 до 58 шаг 0.5
    dup      %   удвоить вершину стека
    Func     %   заменить x в вершине стека на f(x)
    lineto   %   провести линию к точке (x, f(x))
} for        % конец цикла
stroke       % нарисовать построенные линии

/Times-Roman findfont % загрузить шрифт Times-Roman
4 scalefont       % установить размер шрифта 4 мм
setfont           % установить текущий шрифт

40 23 moveto      % переместиться в точку (40, 23)
(y = sin x) show  % напечатать текст "y = sin x"

% Надписи на осях координат
59 11 moveto      % переместиться в точку (59, 11)
(x) show          % напечатать текст "x"

26 28 moveto      % переместиться в точку (26, 28)
(y) show          % напечатать текст "y"

showpage          % напечатать страницу

Разберем подробно некоторые элементы этой программы. В первой выполняемой строке устанавливается миллиметровая шкала:

2.83 2.83 scale

По умолчанию в языке PostScript единицей измерения является один пункт, или 1/72 дюйма. Всякий программист помнит, что один дюйм равен 2.54 сантиметра. Вычислим отношение одного миллиметра к одному пункту:

1 mm / 1 pt = 1 mm / (1/72)" =
        = 1 mm / (2.54/72) mm = 2.834645

Таким образом, увеличивая масштаб в 2.83 раза, мы переходим от пунктов к миллиметрам. Для изменения масштаба мы помещаем в стек два числа 2.83, соответствующих изменению масштабов по x и y. Затем выполняется команда scale (изменить масштаб). Со стека при этом снимаются два числа, и масштабы по x и по y изменяются.

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

0.2 setlinewidth

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

Третья строка перемещает текущую позицию в точку с координатами x = 1, y = 15.

1 15 moveto   % переместиться в точку (1, 15)

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

Большинство строк программы понятны благодаря комментариям, которые в языке PostScript можно записывать в конце любой строки после символа %. Отметим две конструкции, которые использованы в программе. Фрагмент

/Func {
    30 sub 0.2 mul 57.296 mul sin 5 mul 15 add
} def

определяет функцию с именем Func. Функцию затем можно вызвать, просто записав ее имя, как это делается, например, в строке

Func     % заменить x в вершине стека на f(x)

Вызов функции в PostScript'е эквивалентен записи тела функции в точке вызова. Параметры и результат функции передаются через стек.

Тело функции при ее определении записывается внутри фигурных скобок. В данном случае это строка

30 sub 0.2 mul 57.296 mul sin 5 mul 15 add

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

5 * sin((x - 30) * 0:2 * 57:296) + 15

Здесь используются масштабирующие множители, чтобы график выглядел красиво на печати. Так, масштаб по обеим осям равен 5 мм, поэтому мы умножаем значение sin на 5, а аргумент sin на 0.2, т.е. на 1/5. Центр графика смещается в точку с координатами (30,15), поэтому мы прибавляем к значению sin число 15, а от аргумента вычитаем 30. Наконец, аргумент функции sin в языке PostScript задается в градусах. Чтобы перейти от радианов к градусам, мы умножаем агрумент в радианах на множитель 57.296 = 180/\pi. Сравните выражения:

5 * sin((x - 30) * 0:2 * 57:296) + 15
    x 30 sub 0.2 mul 57.296 mul sin 5 mul 15 add

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

Фрагмент

2.5 0.5 58 { % цикл для x от 2.5 до 58 шаг 0.5
        dup      %   удвоить вершину стека
        Func     %   заменить x в вершине стека на f(x)
        lineto   %   провести линию к точке (x, f(x))
    } for        % конец цикла

представляет собой арифметический цикл. На вершину стека последовательно помещается число x в диапазоне от 2.5 до 58 с шагом 0.5. Для каждого значения выполняется тело цикла, заключенное в фигурные скобки. В теле цикла вершина стека сначала удваивается командой dup, после ее выполнения в вершине стека будут лежать два одинаковых значения x, x. Затем вызывается функция Func, которая заменяет значение x в вершине стека на y, где y равно значению функции. Затем проводится линия от предыдущей точки к точке (x,y). При этом команда lineto удаляет оба значения x, y из стека.

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

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

Кирилл Юлаев
Кирилл Юлаев
Федор Антонов
Федор Антонов

Здравствуйте!

Записался на ваш курс, но не понимаю как произвести оплату.

Надо ли писать заявление и, если да, то куда отправлять?

как я получу диплом о профессиональной переподготовке?