Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lektsii_TRPO / 9_BT_3.doc
Скачиваний:
53
Добавлен:
12.03.2015
Размер:
436.22 Кб
Скачать

5.4. Представление арифметического выражения в виде бд.

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

Пример. Пусть задано простое арифметическое выражение вида:

(A+B)*(C+D) - E (1)

Представим это выражение в виде дерева, в котором узлам соответствуют операции, а ветвям - операнды. Построение начнем с корня, в качестве которого выбирается операция, выполняющаяся последней. Левой ветви соответст­вует левый операнд операции, а правой ветви - правый. Дерево выражения (1) показано на рис. 5.2. Совершим обход дерева, которым будем пони­мать формирование строки символов из символов узлов и ветвей дерева. Обход будем совершать от самой левой ветви вправо и узел переписывать в выходную строку только после рассмотрения всех его ветвей (обход LRT). Результат обхода дерева имеет вид:

AB + CD +*E - (2)

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

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

7 5 2 - 4 * + { строка ОПЗ для выражения 7+(5-2)*4= } (3)

может быть проведено следующим образом.

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

  1. Если очередной символ входной строки - число, то кладем его в стек.

  2. Если очередной символ - знак операции, то извлекаем из стека два верхних числа, используем их в качестве операндов для этой операции, затем кладем результат обратно в стек.

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

Рассмотрим поочередно все символы:

Символ

7+(5-2)*4= → 7 5 2 - 4 * +

Действие

Состояние стека после совершенного действия

7

'7' - число. Помещаем его в стек.

7

5

'5' - число. Помещаем его в стек.

7 5

2

'2' - число. Помещаем его в стек.

7 5 2

-

'-' - знак операции. Извлекаем из стека 2 верхних числа ( 5 и 2 ) и совершаем операцию 5 - 2 = 3, результат которой помещаем в стек

7 3

4

'4' - число. Помещаем его в стек.

7 3 4

*

'*' - знак операции. Извлекаем из стека 2 верхних числа ( 3 и 4 ) и совершаем операцию 3 * 4 = 12, результат которой помещаем в стек

7 12

+

'+' - знак операции. Извлекаем из стека 2 верхних числа ( 7 и 12 ) и совершаем операцию 7 + 12 = 19, результат которой помещаем в стек

19

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

Пример программы вычисления арифметического выражения в ОПЗ:

Program OPZ;

Var z :String; {строка ОПЗ}

S: Array[1..100]Of Real; {стек}

h, i :Integer;

Procedure Op (Var h :Integer; ch :Char);

Begin

Case ch Of

'+' : S[h-1]:=S[h-1]+S[h];

'-' : S[h-1]:=S[h-1]-S[h];

'*' : S[h-1]:=S[h-1]*S[h];

'/' : S[h-1]:=S[h-1]/S[h];

End;

Dec(h);

End;

{ Головная программа }

Begin

z:='752-4*+'; { строка ОПЗ для выражения 7+(5-2)*4= }

Write(z);

h:=0;

For i:=1 To Length(z) Do

If z[i] In ['0'..'9']

Then Begin Inc(h); S[h]:=Ord(z[i])-Ord('0'); End

Else Op(h,z[i]);

Write(S[1]);

End.

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

Таблица 5.1. Приоритеты операций

Операция

Приоритет

(

0

)

1

+ -

2

* /

3

**

4

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

  • операция выталкивает из стека все операции с большим или равным приоритетом в выходную строку;

  • если очередной символ из исходной строки есть открывающая скобка, то он проталкивается в стек;

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

  • Процесс получения обратной польской записи выражения (1) схематично представлен ниже:

Просматриваемый символ

1

2

3

4

5

6

7

8

9

10

11

12

13

14

Входная строка

(

A

+

B

)

*

(

C

+

D

)

-

E

 

Состояние стека

(

(

+ (

+ (

 

*

( *

( *

+ (

*

+ ( *

*

-

-

 

Выходная строка

 

A

 

B

+

 

 

C

 

D

+

*

E

-

Программа преобразования выражения из инфиксной в ОПЗ:

Рrogram InfixToРostfix;

Uses Stack; {модуль стека}

Var h :u; {указатель стека}

s, d :String; {s – входная строка, d – выходная строка }

i :Integer; ch :Char;

Function Р (ch :Char) :Integer; { функция приоритета }

Begin

Case ch Of

'*', '/': Р:=3;

'+', '-': Р:=2;

'(', '#': Р:=1;

End; End;

Begin

s:='(a+b)*(c+d)-e';

d:=''; Рush(h,'#'); {# - барьер, чтобы упростить проверку "пустой" стек}

For i:=1 to Length(s) Do

Case s[i] Of

')' :Begin

While Toр(h) <> '(' Do d := d + Рoр(h);

ch:=Рoр(h);

End;

'a'..'z' :d:=d + s[i];

'(' :Рush(h, s[i] );

'*', '/', '+', '-' :Begin

While Р ( s[i] ) <= Р (Toр(h) ) Do d := d + Рoр(h);

Рush (h, s[i]);

End;

End;

While Toр(h) <> '#' Do d := d + Рoр(h);

Writeln(d);

End.

Соседние файлы в папке Lektsii_TRPO