
Трансляция условных операторов и циклов
Трансляция условных операторов и циклов несколько менее тривиальна. В этом случае нужно формировать команды перехода, для которых сам адрес перехода иногда еще неизвестен. Если обязательно, чтобы формируемые команды располагались строго последовательно в виде выходного файла, то необходима двухпроходная схема транслятора. На втором проходе неполные команды перехода дополняются адресами. Другое решение, реализованное в данном трансляторе — это помещение команды в массив, т. е. в память с непосредственным доступом, что позволяет вставлять недостающие адреса, как только они становятся известны. Такую операцию иногда называют фиксацией (fixup).
Единственное дополнительное действие, которое нужно выполнять при формировании такого перехода вперед, — это запоминание его местоположения, т. е. индекса в памяти для программы. Затем во время фиксации этот адрес используется для нахождения неполной команды.
Команды, соответствующие этим операторам, формируются по следующему шаблону (L1 и L2 означают адреса команд):
-
if С then S
while С do S
команды для условия С
L1: команды для С
JPC L1
JPC L2
команды оператора S
команды для S
L1: ...
JMP L1
L2:..
Генерация кода для оператора условного перехода
if <условие> then < оператор >
STMT = if LOGIC then STMT
STMT = ? LOGIC : STMT вариант с 1-символьным кл.словом
-
адрес
if LOGIC then STMT
команды для условия LOGIC
op_jmpc; L1
команды оператора STMT
L1:
...
STMT= if LOGIC then { gencode(op_jampc, 0) адреса перехода пока не знаем, запоминаем адрес команды для будущей модификации}
STMT {модифицируем команду, вставляя после нее нужный адрес}
if typeLex=ifsym
then begin
getsym;
LOGIC;
if typeLex=thensym
then getlex
else error(16);
buf:=curr_adr_code; запоминаем адрес
gencode(op_jmpc,0); формируем неполную команду
STMT;
code[buf].adr:= curr_adr_code модифицируем
команду
end
|
|
|
code[ ].op |
code[].adr |
|
|
|
◄ curr_adr_code указатель на св.адрес |
|
|
|
Генерация кода для оператора цикла
While <условие> do < оператор >
STMT= while LOGIC do STMT
STMT= # LOGIC ^ STMT
-
адрес
while LOGIC do S
L1:
команды для LOGIC
JPMC L2
команды для STMT
JMP L1
L2:
..
if typeLex =whilesym
then begin
buf1:= curr_adr_code;
getsym;
LOGIC;
buf2:= curr_adr_code;
gencode(jpc,0); выход из цикла
if typeLex =dosym
then getsym
else error(18);
STMT;
gencode(jmp,buf1); переход на начало цикла
code[buf2].adr:= curr_adr_code модификация jpc по
адресу L1
end;
Процедура формирования кода для виртуальной машины и ее отображения
Инициализация адреса 1 команды
curr_adr_code=1
Процедура формирования
Void TForm1:: gencode(AnsiString oper, int val);
{ code[curr_adr_code.op=oper; запись кода операции
code[curr_adr_code.adr=val; запись адреса переменной
curr_adr_code++ ; модификация адреса
ListBox_VIEW->Items->Add(oper + “___ “ + IntToStr(val)
Отображение команды
}
Упражнения
Написать код виртуальной машины с реализацией операций в соответствии с заданным вариантом:
№ |
Арифм |
сравнения |
|
логичес |
с адресом |
||
1 |
- унар |
|
> |
|
~ |
op_not |
op_jamp |
2 |
+ |
|
>= |
|
| |
op_or |
op_jampC |
3 |
- |
|
!> |
|
& |
op_and |
op_pushC |
4 |
* |
|
< |
|
|
op_xor |
op_pushV |
5 |
/ |
|
<= |
|
→ |
op_imp |
op_popV |
6 |
% |
|
!< |
|
↔ |
op_equ |
|
7 |
|x| |
abs |
= |
|
|
|
|
8 |
x2 |
|
!= |
|
|
|
+= |
9 |
sign |
|
<> |
|
|
|
-= |
10 |
++ |
|
|
|
|
|
*= |
11 |
-- |
|
|
|
|
|
/= |
12 |
|
|
|
|
|
|
%= |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Процедура генерации кода
Языки
Паскаль
С++
С#
Java
Процедура проверки правила
1 |
PRG |
|
2 |
DECLARE |
|
3 |
ELEM |
|
4 |
BLOCK |
|
5 |
STMT |
|
6 |
LOGIC |
|
7 |
EXPR |
|
8 |
MULT |
|
Преобразовать процедуру проверки правила в атрибутную процедуру, добавив команды генерации кода
Разработать правила описания логических выражений с операциями:
И или нет импликация тождественности сложения по модулю 2