2 заметки с тегом

postscript

Особенность языка Postscript

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

Единственная конструкция, которая должна смущать, это место, где происходит печать числа:

% печать числа
//=string cvs print

Дело в том, что операторы show и print, принимают на вход только строку, поэтому число на входе надо преобразовать. Для этого используется оператор cvs, на мой взгляд очень странный — он требует не один, как можно было бы ожидать, а два параметра — число, которое будет преобразовано и строку, которую оператор снимет со стека и положит вместо неё преобразованное в строку число. Причём по размеру строка должна быть не короче, чем строковое представление числа, которое мы надеемся преобразовать. Иначе мы получим ошибку «rangecheck». Видимо строковый параметр используется как какой-то буфер.

Чаще всего cvs используется так (правда это прямо запрещено
стилем кодирования Постскрипта, рекомендуется использовать не готовую строку, а формировать пустую строку оператором string, но всё равно широко встречается):

% печать числа 42
42 (  ) cvs print

Кладём на стек «42», потом строку из двух пробелов (скобки задают строку в Постскрипте), далее вызываем cvs, которая берёт со стека два значения, работает с ними и кладёт обратно строку, содержащую преобразованное число, print берёт значение со стека и выводит в консоль.

Но если места нужно много, нередко используют оператор =string, который кладёт на стек буфер в 128 байт, его хватит всем — таких больших числе в языке нет, любое гарантированно поместится:

% печать числа 10000000000, cvi нужно, чтобы преобразовать плавающее 1e+10 в целое
1e+10 cvi =string cvs print

Пока, надеюсь, всё просто и понятно. Далее надо знать такую вещь. Конструкция «{…}» кладёт на стек специальный тип — исполняемый блок, посмотрим как он выглядит на стеке:

% посмотрим как выглядит исполняемый блок на стеке:
{1e+10 cvi =string cvs print} ==
% выведет {1e+10 cvi =string cvs print}

Оператор «два равно» берёт значение со стека и выводит его на экран. Как видим блок попал на стек в неизменном виде. И вот тут можно сделать микрооптимизацию — если этот кусок кода кладётся не на стек, а в словарь (можно считать, что будет создана именованная функция) и мы рассчитываем вызвать его несколько раз, вызов =string можно сразу раскрыть в строку — это делается двумя слешами.

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

{1e+10 cvi //=string cvs print} ==
% выведет {1e+10 cvi (x255Unicode\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000...) cvs print}
10 марта   postscript   программирование

99 бутылок: Postscript

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

Люди на нём программы пишут крайне редко, в основном это делают другие программы — например, при печати на принтер. Этот же язык программирования используется внутри формата PDF.

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

%!
%%Title: (Beer song)
%%Creator: Evgeny Stepanischev
%%EndComments

/beer % (int) -> (int)
{
	dup 0 eq {
		(no bottles) print
	} {
		dup 1 eq {
			(1 bottle) print
		} {
			dup //=string cvs print ( bottles) print
		} ifelse
	} ifelse
} bind def

99 -1 1 {
	beer ( of beer on the wall, ) print beer (\n) print
	(Take one down and pass it around, ) print
	dup 1 sub beer pop
	( of beer on the wall.\n\n) print
} for

(No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.) print

quit
4 марта   99   postscript   программирование