Оператор ifelse
Позволяет выбрать в зависимости от условия выполнение одной или другой последовательности операторов. Его формат:
условие {op.1} {op>2} ifelse
Если результат выполнения условия true, выполняется последовательность {op.1}, иначе --
{op.2}.
У попа была собака
Эта фраза замечательна тем, что мы с детства получаем представление о рекурсии. PostScript поддерживает рекурсивный вызов процедур, т. е. когда процедура вызывает сама себя. Классический пример -- вычисление факториала:
/factorial % в стеке n
{dup 1 gt
{ dup 1 sub factorial mul} if
} def
% вызов
5 factorial
cvs show
Новый оператор cvs преобразует число из вершины стека и помещает его в заданную строку. Дело в том, что оператор show может печатать только строки. Кроме чисел, cvs преобразует и логические величины -- они заменяются в зависимости от значения словами true или false. Вот пример процедуры, печатающей целое число из стека:
/printint
{( ) cvs show} def % строка первоначально содержит 3 пробела
Оператор string создает строку длиной n. Определение строковой переменной
выглядит так:
/nstr 7 string def
где 7 -- длина строки (знаков).
Рекурсивный вызов процедур даёт возможность рисовать фрактальные картинки, но это мы попробуем сделать на следующем занятии, когда изучим конструкции циклов.
Занятие четвёртое
Начиная весной эту серию уроков у меня было сомнение -- хватит ли материала на семь занятий. Задав в Интернет поиск по ключевому слову PostScript и получив сообщение, что найдено более 99 тыс. документов, где оно встречается, я успокоился – об этом языке писать можно до 2000 года. Кроме того, обнаружилась книга по PostScript и на русском языке. Это изданный Физматлитом в 1993 г. учебник: Ф.Доймлинг, Д.Стиллеску "Язык программирования PostScript. 20 уроков быстрого освоения". В ней очень детально описывается то, что нами будет пройдено на четырех первых уроках. Следует отметить, что наши занятия методически следуют книге "PostScript Language Tutorial and Cookbook" (Adobe Systems & Addison Wesley, 1987), являющейся де-факто описанием стандарта языка и потому именуемой "Голубой книгой". Тем у кого это издание есть, я рекомендую подождать седьмого урока, который будет отчасти посвящён текущему состоянию языка, литературе и другим не описанным в "Голубой книге" вопросам.
Ну, а если у вас по ходу чтения уроков возникли вопросы, предложения или пожелания, вы можете связаться с автором по телефону (095)237-8901 или по адресу chief@pcweek.ru.
Циклы
В языке PostScript имеется три основных конструкции циклов: простой цикл, индексируемый цикл и условный цикл.
Простой цикл неявным образом уже использовался в примерах предыдущего занятия. Он реализуется с помощью оператора repeat, который берет из стека два операнда: счетчик цикла и повторяемую процедуру. Например, для очистки стека мы использовали следующий цикл:
4 {pop} repeat
Здесь всё достаточно прозрачно, непривычно, может быть, только то, что в качестве одного из аргументов выступает повторяемая процедура.
Задание. Нарисуйте последовательность из N вложенных кругов, квадратов, эллипсов.
Индексируемый цикл напоминает широко известную по Бейсику конструкцию for... to... next. Оператор for берет из стека четыре операнда: начальное значение счетчика цикла, его приращение, конечное значение счетчика цикла и повторяемую процедуру. За исключением последнего операнда всё выглядит как и в обычной конструкция for. Следует учитывать, что непосредственно перед выполнением этой процедуры for помещает в стек текущее значение счетчика и, если он не используется, то его следует оттуда явным образом удалять.
Следующая строка напечатает звездочку через каждые 15 единиц на странице:
0 15 450 {0 moveto (*) show } for
Задание. Нарисуйте пунктирную линию.
Вторая важная особенность for в том, что его операнды не обязательно должны быть целыми числами. Вот пример использования этого для возможной модификации шрифта:
/Helvetica findfont 30 scalefont setfont
/printword
{ 0 0 moveto (PC Magazine) show} def
200 300 translate
.95 -.05 0 % начало приращения, конец
{setgray printword -1.5 translate} for
1 setgray printword
showpage
<рис. файл p4_1.ps>
Условный цикл соответствует конструкции repeat...until в Паскале. Строится он из двух операторов: loop и exit. Опертор loop повторяет выполнение процедуры до тех пор пока в ней не встретится оператор exit, который заканчивает циклическое выполнение, причем не только в конструкции loop, но и в for, repeat и forall (об этой специальной форме цикла будет расказано ниже). Если в повторяемой процедуре нет оператора exit, то цикл будет бесконечным, например:
{(PC Magazine) show} loop
будет бесконечно печатать слово PC Magazine.
Нарисуем незамысловатую последовательность кругов просто, чтобы продемонстрировать работу loop - exit.
/pagewidth 8 72 mul def
/circle
{x y radius 0 360 arc stroke} def
/new-x
{x radius add
/x exch def} def
/dolineofcrle
{/y exch def
/radius exch def
/x 0 def
{x pagewidth le
{circle new-x}
{exit} ifelse
} loop
} def
% main
15 200 dolineofcrle
25 200 dolineofcrle
showpage