Основы программирования. Борисенко
.pdf4.4.2. Стек |
271 |
) {
onPush(line); |
// Добавить число в стек |
}else i f (strcmp(line, "pop") == 0) { onPop();
}else i f (strcmp(line, "clear") == 0) { onClear();
}else i f (strcmp(line, "show") == 0) { onShow();
}else i f (strcmp(line, "quit") == 0) {
|
|
break; |
|
// |
Завершить работу |
|
} else { |
|
// Неправильная команда => |
||
|
} |
printHelp(); // |
напечатать подсказку |
||
} |
|
|
|
|
|
|
0; |
|
|
|
|
return |
|
|
|
||
} |
|
|
|
|
|
static |
void |
onAdd() |
{ |
|
|
double |
y, x; |
|
{ |
|
|
i f |
(st_size() < 2) |
|
|||
|
printf("Stack |
depth < 2.\n"); |
|||
} |
return; |
|
|
|
|
|
|
|
|
|
|
y = st_pop(); |
|
|
|
||
x = st_pop(); |
|
|
|
||
st_push(x + y); |
|
|
|
||
display(); |
|
|
|
||
} |
|
|
|
|
|
static |
void |
onSub() |
{ |
|
|
double |
y, x; |
|
{ |
|
|
i f |
(st_size() < 2) |
|
|||
|
printf("Stack |
depth < 2.\n"); |
|||
} |
return; |
|
|
|
|
|
|
|
|
|
|
y = st_pop(); |
|
|
|
||
x |
= st_pop(); |
|
|
|
272 |
4.4. Простейшие структуры данных. Стек. Очередь |
st_push(x - y); display();
} |
|
|
|
|
|
|
|
static |
|
void |
onMul() |
{ |
|
|
|
double |
y, x; |
|
|
|
|
||
i f |
|
(st_size() < 2) { |
< |
2.\n"); |
|||
|
|
printf("Stack |
depth |
||||
} |
|
return; |
|
|
|
|
|
= |
st_pop(); |
|
|
|
|
||
y |
|
|
|
|
|||
x = st_pop(); |
|
|
|
|
|||
st_push(x * y); |
|
|
|
|
|||
display(); |
|
|
|
|
|||
} |
|
|
|
|
|
|
|
static |
|
void |
onDiv() |
{ |
|
|
|
double |
y, x; |
|
|
|
|
||
i f |
|
(st_size() < 2) { |
|
|
|||
|
|
printf("Stack |
depth |
< |
2.\n"); |
||
} |
|
return; |
|
|
|
|
|
= |
st_pop(); |
|
|
|
|
||
y |
|
|
|
|
|||
x = st_pop(); |
|
|
|
|
|||
st_push(x / y); |
|
|
|
|
|||
display(); |
|
|
|
|
|||
} |
|
|
|
|
|
|
|
static void onPush(const char* line) { double x = a t o f ( l i n e ) ;
st_push(x);
}
static void onSin() { double x;
i f (st_empty()) { printf("Stack empty.\n");
4.4.2. Стек |
273 |
return;
}
x = st_pop(); st_push(sin(x)); display();
}
static void onCos() { double x;
i f (st_empty()) { printf("Stack empty.\n"); return;
}
x = st_pop(); st_push(cos(x)); display();
}
static void onExp() { double x;
i f (st_empty()) { printf("Stack empty.\n"); return;
}
x = st_pop(); st_push(exp(x)); display();
}
static void onLog() { double x;
i f (st_empty()) { printf("Stack empty.\n"); return;
}
x = st_pop(); st_push(log(x));
274 |
4.4. Простейшие структуры данных. Стек. Очередь |
d i s p l a y ( );
} |
|
|
|
|
|
static |
void |
onSqrt() |
{ |
|
|
double |
x; |
|
|
||
i f |
(st_empty()) { |
empty.\n"); |
|||
|
printf("Stack |
||||
} |
return; |
|
|
||
(st_top() < 0.0) |
{ |
||||
i f |
|||||
|
printf("Arg . |
of |
square root i s negative.\n"); |
||
|
return; |
|
|
}
x = st_pop();
st_push(sqrt(x)); display();
}
static void onPop() { st_pop();
}
static |
void |
onClear() |
{ |
s t _ c l e a r ( ) ; |
|
||
} |
|
|
|
static |
void |
display() |
{ |
i f |
(!st_empty()) |
{ |
|
} |
printf("=/lf\n", st_top()); |
||
else |
{ |
empty\n"); |
|
} |
printf("stack |
||
|
|
|
|
} |
|
|
|
static |
void |
onShow() |
{ |
int d = |
s t _ s i z e ( ) ; |
||
printf("Depth of |
stack = /d.", d); |
4.4.2. Стек |
|
|
|
|
|
|
|
275 |
|
i f |
(d > 0) |
Stack |
elements:\n"); |
|
|||||
|
p r i n t f ( " |
|
|||||||
else |
|
|
|
|
|
|
|
|
|
|
printf("\n"); |
|
|
|
|
|
|
||
for |
(int i = 0; i < d; |
|
{ |
|
|
||||
} |
p r i n t f ( " |
/ l f \ n " , |
st_elementAt(i)); |
||||||
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static |
void |
printHelp() |
{ |
|
|
|
|
||
p r i n t f ( |
|
|
|
commands:\n" |
|
||||
|
"Stack Calculator |
|
|||||||
|
" |
<number> |
|
Push |
а number i n stack\n" |
||||
|
" |
+ » - » * » / |
|
Ariphmetic |
operations\n" |
||||
|
" |
s i n , cos, |
|
Calculate |
a function\n" |
||||
|
" |
exp, log, |
|
\n" |
|
|
|
|
|
|
" |
sqrt |
|
|
\n" |
|
the stack |
top\n" |
|
|
" |
= |
|
|
Display |
||||
|
" |
pop |
|
|
Remove |
the stack |
top\n" |
||
|
" |
show |
|
Show the |
stack\n" |
|
|||
|
" |
clear |
|
Clear |
the |
stack\n" |
|||
); |
" |
quit |
|
|
Terminate |
the program\n" |
|||
|
|
|
|
|
|
|
|
|
}
// Конец файла "stcalc.cpp"
Пример работы программы "stcalc". Пусть нужно вычислить вы ражение
V 3 • 3 + 4 • 4
Запишем выражение, используя обратную польскую запись:
3, 3, *, 4, 4, *, sqrt
(через sqrt обозначается операция извлечения квадратного корня). Последовательно отдаем соответствующие команды стековому каль кулятору. При работе программы stcalc получается следующий диа¬ лог:
276 |
4.4. Простейшие структуры данных. Стек. Очередь |
Stack Calculator commands: |
|
<number> |
Push а number i n stack |
+ , -, *, / |
Ariphmetic operations |
sin, cos, |
Calculate a function |
exp, log, |
|
sqrt |
|
=Display the stack top
pop |
Remove the stack top |
show |
Show the stack |
clear |
Clear the stack |
quit |
Terminate the program |
3 3 * |
|
=9.000000 |
|
4 4 * |
|
=16.000000 |
|
+ |
|
=25.000000 |
|
sqrt |
|
=5.000000 |
|
Обратная польская запись формул оказалась исключительно удобной при работе с компьютерами. Д л я вычислений используется стек, что позволяет работать с выражениями любой степени слож¬ ности. Реализация стекового вычислителя не представляет никакого труда. Имеется также простой алгоритм преобразования выражения из обычной записи, в которой знак операции указывается между ар¬ гументами, в ее обратную польскую запись. Все это привело к тому, что многие компиляторы языков высокого уровня используют обрат¬ ную польскую запись в качестве внутренней формы представления программы. Рассмотрим, к примеру, язык программирования Java. Как всякий объектно-ориентированный язык, он является интерпре тируемым, а не компилируемым языком. Это означает, что компи лятор Java преобразует исходную Java-программу не в машинные коды, а в промежуточный язык, предназначенный для выполнения (интерпретации) на специальной Java-машине. В случае Java этот промежуточный язык называют байткодом. Компилятор Java поме¬ щает байткод в файл с расширением ".class". Байткод представляет
4.4.2. Стек |
277 |
собой, упрощенно говоря, обратную польскую запись Java-прогаммы, а Java-машина — стековый вычислитель.
Я з ык PostScript
Другой яркий пример использования обратной польской записи — это графический язык PostScript. Он предназначен для печати тек стов высокого качества на лазерных принтерах; он является стандар¬ том представления текстов типографского качества, не зависящим от конкретной модели принтера.
То, что PostScript — язык программирования, для многих людей, знакомых с типографским делом, но далеких от программирования, звучит непривычно. Общепринятое мнение, что компьютер работает с числами и в основном что-то вычисляет, не вполне верно. Не менее часто компьютерная программа работает с текстами и с изображени¬ ями. Текст, содержащийся в обычном текстовом файле, можно рас¬ сматривать с двух точек зрения. М о ж н о трактовать его просто как текст статьи или книги. Рассмотрим, однако, процесс печати текста на обычном (не графическом) принтере. Принтер соединен с ком¬ пьютером кабелем, и компьютер просто посылает через этот кабель один за другим символы, составляющие текст. В этом случае букву A , входящую в текст, следует рассматривать как команду, предписы вающую принтеру напечатать символ A в текущей точке страницы, используя текущий шрифт. После этого коодинату x текущей точки надо увеличить на ширину буквы A . С этой точки зрения весь текст можно трактовать как программу его собственной печати. В случае обычного текстового файла эта программа весьма примитивна, в ней,
к примеру, нет команд смены шрифтов, изменения текущей |
позиции, |
рисования линий и т.д. Понятно, что текст типографского |
качества |
не может быть представлен обычным текстовым файлом. |
|
В случае использования языка PostScript файл, пересылаемый на PostScript-принтер, представляет собой программу печати текста. Язык PostScript имеет огромное количество возможностей, и вряд ли найдется много людей, владеющих им. Ч а щ е всего PostScript— программа создается другой программой обработки текста. Напри¬
мер, |
PostScript—файл создается TJEX-ОМ для печати на |
принтере. |
(TgX |
— это язык записи текстов, содержащих математические фор¬ |
|
мулы, созданный замечательным математиком и теоретиком |
програм- |
278 |
|
4.4. Простейшие структуры данных. Стек. Очередь |
||
мирования Дональдом Кнутом, см. книгу [2]. Фактически TJ?X пред¬ |
||||
ставляет |
собой язык программирования. Д а н н а я |
книга подготовлена |
||
в ТХ'е |
с использованием |
макропакета L T E X 2 е . ) |
Текстовые процес |
|
соры, |
такие, как Adobe Acrobat или M S Word, |
также в случае пе |
||
чати |
на |
профессиональном |
PostScript—принтере |
преобразуют текст |
в PostScript—программу. (Более точно, такое преобразование осу ществляется драйверами операционной системы.) PostScript—файлы очень удобны для распространения: поскольку это файлы в обычном текстовом формате, они будут напечатаны одинаково в любой стране независимо от национальных кодировок, операционных систем, на¬ личия шрифтов и т.п.
PostScript—программа представляет собой обратную польскую за¬ пись в том смысле, что всякая команда записывается после своих ар¬ гументов. При выполнении PostScript—программы используется стек. Рассмотрим для примера несложную программу, рисующую график функции y = sin(x). Вот какая картинка рисуется в результате вы¬ полнения этой программы:
(Подчеркнем особо, что все рисунки, содержащиеся в данном посо¬
бии, реализованы в виде PostScript—программ, написанных |
вручную |
без использования каких-либо графических редакторов.) |
|
Н и ж е приведен полный текст PostScript—программы, |
рисующей |
график функции. Отметим сразу, что символ процента % использу¬ ется в языке PostScript в качестве комментария:
% Файл "func.ps"
% Рисование графика функции y = f(x)
% Перейти от пунктов (1/72 дюйма) к миллиметрам 2.83 2.83 scale
4.4.2. Стек |
279 |
0.2 setlinewidth |
% Установить |
толщину |
линии |
||||
% Нарисовать координатную ось X: |
(1, 15) |
||||||
1 |
15 moveto |
% |
переместиться |
в точку |
|||
60 |
15 |
lineto |
% |
провести |
линию |
к точке |
(60, 15) |
|
|
|
% |
Рисуем стрелку: |
|
||
57 |
16 |
moveto |
% |
переместиться |
в точку |
(57, 16) |
|
60 |
15 |
lineto |
% |
провести |
линию |
к точке |
(60, 15) |
57 |
14 |
lineto |
% |
провести |
линию |
к точке |
(57, 14) |
stroke |
% |
нарисовать построенные |
линии |
||||
% Нарисовать координатную ось Y: |
(30, 1) |
||||||
30 |
1 moveto |
% |
переместиться |
в точку |
|||
30 |
30 |
lineto |
% |
провести |
линию |
к точке |
(30, 30) |
|
|
|
% |
Рисуем стрелку: |
|
||
29 |
27 |
moveto |
% |
переместиться |
в точку |
(29, 27) |
|
30 |
30 |
lineto |
% |
провести |
линию |
к точке |
(30, 30) |
31 |
27 |
lineto |
% |
провести |
линию |
к точке |
(31, 27) |
stroke |
% нарисовать |
построенные линии |
||
% |
Определение |
функции |
- 30) |
* 0.2 * 180/Pi) + 15 |
% |
f(x) = 5 * sin((x |
%Дано: число x на вершине стека.
%Надо: заменить вершину стека на f ( x ) . /Func {
30 sub 0.2 mul 57.296 mul s i n 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) ) |
} fo r |
% конец цикла |
|
|
280 |
|
4. 4. Простейшие структуры данных. Стек. Очередь |
||
stroke |
% нарисовать построенные линии |
|||
/Times-Roman |
findfont % загрузить шрифт Times-Roman |
|||
4 scalefont |
% установить размер шрифта 4 мм |
|||
setfont |
% установить |
текущий шрифт |
||
40 |
23 moveto |
% переместиться в точку |
(40, 23) |
|
(y |
= s i n x) show % напечатать |
текст "y = s i n x" |
||
% Надписи на осях координат |
|
(59, 11) |
||
59 |
11 moveto |
% переместиться в точку |
||
(x) |
show |
% напечатать |
текст "x" |
|
26 |
28 moveto |
% переместиться в точку |
(26, 28) |
|
(y) |
show |
% напечатать |
текст "y" |
|
showpage |
% напечатать |
страницу |
|
Разберем подробно некоторые элементы этой программы. В пер вой выполняемой строке устанавливается миллиметровая шкала:
2.83 2.83 scale
По умолчанию в языке PostScript единицей измерения является один пункт, или 1/72 дюйма. Всякий программист помнит, что один дюйм равен 25.4 миллиметра. Вычислим отношение одного миллиметра к одному пункту:
1 mm / 1 pt = 1 mm / (1/72)" =
= 1 mm / (25.4/72) mm = 2.834645
Таким образом, увеличивая масштаб в 2.83 раза, мы переходим от
пунктов к миллиметрам. Д л я изменения масштаба мы помещаем |
в |
стек два числа 2.83, соответствующих изменению масштабов по x |
и |
у. Затем выполняется команда scale (изменить масштаб). Со стека при этом снимаются два числа, и масштабы по x и по y изменяются.
Разные команды могут иметь различное число аргументов. На¬ пример, вторая строка устанавливает толщину линии.
0.2setlinewidth