x86128: (Default)
x86128 ([personal profile] x86128) wrote2021-10-19 04:25 pm

Преобразования кода ВМ в код условной БЭСМ-6

Продолжаю эксперименты со строительством компилятора.
Реализовал преобразование кода виртуальной машины в код виртуальной целочисленной БЭСМ-6 методом “курильщика” так же известного как Poor Man’s codegen 😅️.

В качестве программы для тестирования возьмем вычисление выражения:

var
    a : integer;

begin
    a := 5  - 3 * 8 div 6;
    writeint(a);
    writeln


В обратной польской записи получается так:

5 3 8 * 6 / - >a


Преобразуется в такой код “первой” виртуальной машины:

 ('CLOAD', 0),
 ('CLOAD', 1),
 ('CLOAD', 2),
 ('BINOP', '*'),
 ('CLOAD', 3),
 ('BINOP', 'DIV'),
 ('BINOP', '-'),
 ('VSTOR', -1, 'a'),
 ('VLOAD', -1, 'a'),
 ('SYSCALL', 'writeint'),
 ('DEALLOC', 1),
 ('SYSCALL', 'writeln'),
 ('STOP', '12345'),

Таблица констант:
 ('LABEL', 'const_table'),
 ('WORD', 5),
 ('WORD', 3),
 ('WORD', 8),
 ('WORD', 6),
 ('WORD', 0),
 ('LABEL', 'locals_base'),
 ('LABEL', 'stack_base')]

Место для локальной переменной a:
 ('WORD', 0),
 ('LABEL', 'locals_base'),
 ('LABEL', 'stack_base')]


Метод курильщика заключается в том, что каждую команду первой машины мы преобразуем буквально в код БЭСМ без каких либо оптимизаций, будто выполняется условный эмулятор первой ВМ на процессоре БЭСМ.

Пусть у нас регистр M1 указывает на последнюю локальную переменную текущего кадра + 1, регистр M2 - на начало блока констант, а М15 - на первый пустой элемент стека, который растет в сторону увеличения адресов.

Работать метод будет тоже со стеком, но пока без учета архитектуры БЭСМ, где аккумулятор является вершиной стека, поэтому код генерируется такой:

00005:           XTA      0         ,M2
00006:           ATX      0         ,M15
00007:           XTA      1         ,M2
00008:           ATX      0         ,M15
00009:           XTA      2         ,M2
00010:           ATX      0         ,M15
00011:           XTA      -2        ,M15
00012:           A*X      -1        ,M15
00013:           ATX      -2        ,M15
00014:           UTM      -1        ,M15
00015:           XTA      3         ,M2
00016:           ATX      0         ,M15
00017:           XTA      -2        ,M15
00018:           A/X      -1        ,M15
00019:           ATX      -2        ,M15
00020:           UTM      -1        ,M15
00021:           XTA      -2        ,M15
00022:           A-X      -1        ,M15
00023:           ATX      -2        ,M15
00024:           UTM      -1        ,M15
00025:           XTA      0         ,M15
Сохранение результата
00026:           ATX      -1        ,M1
Печать числа
00027:           XTA      -1        ,M1
00028:           ATX      0         ,M15
00029:           *77      0         
00030:           UTM      -1        ,M15
Печать перевода строки
00031:           *77      2         
00032:           STOP     12345     


Вот такой вот глупый код, но при этом рабочий.

Рассмотрим как это можно записать с учетом того что аккумулятор является вершиной стека:

5 3 8 * 6 / - >a

XTA =5
XTS =3
A*X =8
A/X =6
X-A ,M15
ATX =a


Как говорится, разница на лицо. Есть над чем поработать.