Ишакова Е.Н. Разработка компиляторов - Методические указания к курсовой работе (1082246), страница 5
Текст из файла (страница 5)
IE:=,
где «:=» - двуместная операция,
I, E – операнды операции присваивания;
I – означает, что операндом операции «:=» является адрес переменной I, а не ее значение.
Пример 2.14. Оператор x:=x+9 в ПОЛИЗе имеет вид: x x 9 + :=.
Оператор перехода в терминах ПОЛИЗа означает, что процесс интерпретации необходимо продолжить с того элемента ПОЛИЗа, который указан как операнд операции перехода. Чтобы можно было ссылаться на элементы ПОЛИЗа, будем считать, что все они пронумерованы, начиная с единицы (например, последовательные элементы одномерного массива). Пусть ПОЛИЗ оператора, помеченного меткой L, начинается с номера p, тогда оператору безусловного перехода goto L в ПОЛИЗе будет соответствовать:
p!, где ! – операция выбора элемента ПОЛИЗа, номер которого равен p.
Условный оператор. Введем вспомогательную операцию – условный переход «по лжи» с семантикой if (not B) then goto L. Это двуместная операция с операндами B и L. Обозначим ее !F, тогда в ПОЛИЗе она будет записываться:
B p !F, где p – номер элемента, с которого начинается ПОЛИЗ оператора, помеченного меткой L.
С использованием введенной операции условный оператор if B then S1 else S2 в ПОЛИЗе будет записываться:
B p1 !F S1 p2 ! S2, где p1 – номер элемента, с которого начинается ПОЛИЗ оператора S2, а p1 – оператора, следующего за условным оператором.
Пример 2.15. ПОЛИЗ оператора if x>0 then x:=x+8 else x:=x-3 представлен в таблице 2.3.
Таблица 2.3 – ПОЛИЗ оператора if
лексема | x | 0 | > | 13 | !F | x | x | 8 | + | := | 18 | ! | x | x | 3 | - | := | … |
номер | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
Оператор цикла. С учетом введенных операций оператор цикла while B do S в ПОЛИЗе будет записываться:
B p1 !F S po !, где po – номер элемента, с которого начинается ПОЛИЗ выражения B, а p1 – оператора, следующего за данным оператором цикла.
Операторы ввода и вывода языка М одноместные. Пусть R – обозначение операции ввода, а W – обозначение операции вывода, тогда оператор read(I) в ПОЛИЗе запишется как I R, а оператор write(E) – E W.
Составной оператор begin S1; S2;...; Sn end в ПОЛИЗе записывается как S1 S2... Sn.
Пример 2.16. ПОЛИЗ оператора while n>3 do begin write(n*n-1); n:=n-1 end представлен в таблице 2.4.
Таблица 2.4 – ПОЛИЗ оператора while
лексема | n | 3 | > | 19 | !F | n | n | * | 1 | - | W | n | n | 1 | - | := | 1 | ! | … |
номер | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
Синтаксически управляемый перевод
На практике СиА, СеА и генерация внутреннего представления программы осуществляется часто одновременно. Способ построения промежуточной программы – синтаксически управляемый перевод. В его основе лежит грамматика с действиями. Параллельно с анализом исходной цепочки лексем осуществляются действия по генерации внутреннего представления программы. Для этого грамматика дополняется вызовами соответствующих процедур.
Пример 2.17. Составим процедуры перевода в ПОЛИЗ программы на М языке.
ПОЛИЗ представляет собой массив, каждый элемент которого является парой вида (n, k), где n – номер таблицы лексем, k – номер лексемы в таблице. Расширяем набор лексем:
1) в таблицу ограничителей добавляем новые операции ! (18), !F (19), R (20), W (21);
2) для ссылок на номера элементов ПОЛИЗа введем нулевую таблицу лексем, т.е. пара (0, p) - это лексема, обозначающая p-ый элемент в ПОЛИЗе;
3) чтобы различать операнды-переменные и операнды-адреса переменных, обозначим переменные как четвертую таблицу лексем, а адреса – пятую.
Введем следующие обозначения переменных и процедур:
1) Р – переменная–массив, в который размещается генерируемая программа;
2) free – переменная, хранящая номер первого свободного элемента в массиве P;
3) LEX – переменная, хранящая очередную лексему;
4) put_lex(LEX) – запись очередной лексемы в массив P, т.е. P[free]:=LEX и free:=free+1;
5) put_l – запись текущей лексемы в массив P;
6) put_l5 – запись текущей лексемы в массив P с изменением четвертого класса лексем на пятый;
7) put_op - запись в массив P знака операции, считанного процедурой checkop;
8) make(k) - процедура, формирующая лексему-метку (0, k).
Правила, описывающие выражения языка М, с учетом действий перевода в ПОЛИЗ принимают вид.
Е Е1 {( > | < | = ) <instl> E1 <checkop; put_op >}
E1 Т {(+ | - | ) <instl> T <checkop; put_op >}
T F {( * | / | ) <instl> F<checkop; put_op >}
F I <checkid; put_l> | N <inst(‘int’); put_l> | L <inst(‘bool’); put_l>|
F <checknot; put_lex(‘’)>| (E)
Оператор присваивания, дополненный действиями, примет вид:
S I <checkid; put_l5> := E <eqtype; put_lex(‘:=’)>
При генерации ПОЛИЗа выражений и оператора присваивания элементы массива Р записываются последовательно. Семантика условного оператора такова, что значения операндов для операций безусловного перехода и перехода «по лжи» в момент генерации еще не неизвестны. Поэтому необходимо запоминать номера элементов массива Р, соответствующих этим операндам, а затем, когда станут известны их значения, заполнять пропущенное.
Правила условного оператора и оператора цикла примут вид:
S if E <egbool; p1:=free; free:=free+1; put_lex(‘!F’)> then S <p2:=free; free:=free+1; put_lex(‘!’); P[p1]:=make(free)> else S <P[p2]:=make(free)>
S while <p0:=free> E <egbool; p1:=free; free:=free+1; put_lex(‘!F’)> do S <P[free]:=make(p0); put_lex(‘!’); P[p1]:=make(free) >
Правила операторов ввода и вывода с учетом действий записи в ПОЛИЗ будут преобразованы следующим образом:
S write (E <put_lex(‘W’)>) | read (I <checkid; put_l5; put_lex_(‘R’)> )
Чтобы в конце ПОЛИЗа была точка, правило Р переписывается в виде:
Pprogram D1 B <put_lex(‘.’)>.
Таким образом, польская инверсная запись очищена от всех служебных слов, кроме true и false; от ограничителей остаются только знаки операций и знаки «:=», «.».
2.7 Интерпретатор программы
Запись программы в форме ПОЛИЗа удобна для последующей интерпретации (выполнения программы) с помощью стека. Массив ПОЛИЗа просматривается один раз слева направо, при этом:
1) если очередной элемент ПОЛИЗа является операндом, то его значение заносят в стек;
2) если очередной элемент – операция, то на «верхушке» стека находятся ее операнды, которые извлекаются из стека, над ними выполняется соответствующая операция, результат которой заносится в стек;
3) интерпретация продолжается до тех пор, пока не будет считана из ПОЛИЗа точка, стек при этом должен быть пуст.
Пример 2.18. Интерпретировать ПОЛИЗ программы, заданный таблицей 2.5 при введенном значении а равном 7.
Таблица 2.5 – ПОЛИЗ исходной программы
Лексема | a | r | a | 5 | > | 17 | !F | b | a | 3 | + |
(n, k) | (5,1) | (2,20) | (4,1) | (3,1) | (2,16) | (0,17) | (2,19) | (5,1) | (4,1) | (3,2) | (2,8) |
Номер | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
Продолжение таблицы 2.5 – ПОЛИЗ исходной программы
Лексема | := | b | W | 19 | ! | a | W | . |
(n, k) | (2,5) | (4,1) | (2,21) | (0,19) | (2,18) | (4,1) | (2,21) | (2,1) |
Номер | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
Процесс интерпретации программы на модельном языке М, записанной в форме ПОЛИЗа, показан в таблице 2.6.
Таблица 2.6 – Ход интерпретации ПОЛИЗа программы
Стек | Текущий элемент ПОЛИЗа | Операция | Таблицы переменных | |
адреса | значения | |||
пуст | 1 | адрес - в стек | 1) a 2) b | 1) - 2) - |
1 | 2 | извлечь из стека номер элемента таблицы значений и записать по нему число 7 | 1) a 2) b | 1) 7 2) - |
пуст | 3 | значение - в стек | 1) a 2) b | 1) 7 2) - |
7 | 4 | значение - в стек | 1) a 2) b | 1) 7 2) - |
7; 5 | 5 | в стек – true, т.к. 7>5 | 1) a 2) b | 1) 7 2) - |
true | 6 | метка - в стек | 1) a 2) b | 1) 7 2) - |
true; 6 | 7 | переход, к следующему элементу ПОЛИЗа, т.к. условие истинно | 1) a 2) b | 1) 7 2) - |
пуст | 8 | адрес - в стек | 1) a 2) b | 1) 7 2) - |
2 | 9 | значение переменной - в стек | 1) a 2) b | 1) 7 2) - |
2; 7 | 10 | число - в стек | 1) a 2) b | 1) 7 2) - |
2; 7; 3 | 11 | извлечь из стека 3 и 7 и поместить в стек их сумму | 1) a 2) b | 1) 7 2) - |
2; 10 | 12 | присвоить второму элементу таблицы значений число 10 | 1) a 2) b | 1) 7 2) 10 |
пуст | 13 | значение – в стек | 1) a 2) b | 1) 7 2) 10 |
10 | 14 | вывести на экран число из «верхушки стека» | 1) a 2) b | 1) 7 2) 10 |
Продолжение таблицы 2.6 – Ход интерпретации ПОЛИЗа программы
Стек | Текущий элемент ПОЛИЗа | Операция | Таблицы переменных | |
адреса | значения | |||
пуст | 15 | метка – в стек | 1) a 2) b | 1) 7 2) 10 |
19 | 16 | переход к элементу ПОЛИЗ с номером, извлекаемым из верхушки стека | 1) a 2) b | 1) 7 2) 10 |
пуст | 19 | интерпретация завершена | 1) a 2) b | 1) 7 2) 10 |
Пример 2.19. Построим интерпретатор ПОЛИЗа для языка М.