x86128: (Default)
x86128 ([personal profile] x86128) wrote2021-10-12 04:16 pm

Пару слов о компиляторе-интерпретаторе

Доброго времени!

Продолжаю эксперименты с компиляторо-строением.

Добавил возможность возвращать результаты работы процедуры через VAR-аргументы.

Поэтому подобный код компилируется и работает:

MODULE Samples;
const
    pass = 12345;
    fail = 54321;

var
    t : integer;

procedure gcd(a,b : integer; var res : integer);
begin
    while b > 0 do
        res := b;
        b := a mod b;
        a := res
    end
end gcd;

begin
    gcd(27+25*3-(10 div 5),15, t);
    if t = 5 then
        halt(pass)
    else
        halt(fail)
    end

END Samples.


Передача аргументов осуществляется через стек, на котором формируется рабочая область (фрейм) куда записываются аргументы процедуры и внутренние локальные переменные.

Схема такая:

| old frame | arg0 | arg1 | v0 | v1 | v2 | old_bp | return address | free RAM cells |
|-----------+------+------+----+----+----+--------+----------------+----------------|
|           |      |      |    |    |    | ^ BP   |                | ^ SP           |


Сделал я это для того, чтобы была возможность работы с рекурсией, но боком вышло то, что глобальные переменные по отношению к телу процедуры “дали прикурить” т.к. их адреса во время компиляции программы неизвестны (так же из-за возможности объявлять вложенные процедуры (своего рода замыкания)). Можно было ввести некоторый GP который бы показывал на локальные переменные вышестоящей области видимости, но тогда пришлось бы организовывать какой-то механизм многократной относительной адресации. Понятно, что эта задача решаема, но в книге по Оберону я пока не добрался до соотв. главы. Если запретить рекурсию, то задача размещения и адресации переменных становится тривиальной, т.к. все адреса можно вычислить прямо на этапе компиляции.

Результатом работы компилятора является такой питонячий объект:
{'c_mem': [12345, 54321],
 'consts': {'fail': {'line': 4, 'offset': 1, 'val': 54321},
            'pass': {'line': 3, 'offset': 0, 'val': 12345}},
 'main': 'Samples_main',
 'name': 'Samples',
 'p_text': [('LABEL', 'L0'),
            ('VLOAD', -2, 'b'),
            ('CONST', 0),
            ('RELOP', '>'),
            ('BR_ZERO', 'L1'),
            ('VLOAD', -2, 'b'),
            ('RSTOR', -1, 'res'),
            ('VLOAD', -3, 'a'),
            ('VLOAD', -2, 'b'),
            ('BINOP', 'MOD'),
            ('VSTOR', -2, 'b'),
            ('RLOAD', -1, 'res'),
            ('VSTOR', -3, 'a'),
            ('BR', 'L0'),
            ('LABEL', 'L1'),
            ('RETURN', ''),
            ('ALLOC', 1),
            ('CONST', 27),
            ('CONST', 25),
            ('CONST', 3),
            ('BINOP', '*'),
            ('BINOP', '+'),
            ('CONST', 10),
            ('CONST', 5),
            ('BINOP', 'DIV'),
            ('BINOP', '-'),
            ('CONST', 15),
            ('ADR_LOAD', -1, 't'),
            ('CALL', 0, 'gcd'),
            ('DEALLOC', 3),
            ('VLOAD', -1, 't'),
            ('CONST', 5),
            ('RELOP', '='),
            ('BR_ZERO', 'L3'),
            ('CLOAD', 0, 'pass'),
            ('SYSCALL', 'halt'),
            ('DEALLOC', 1),
            ('BR', 'L3'),
            ('LABEL', 'L2'),
            ('CLOAD', 1, 'fail'),
            ('SYSCALL', 'halt'),
            ('DEALLOC', 1),
            ('LABEL', 'L3'),
            ('STOP', '12345')],
 'proc_tab': {'Samples_main': {'offset': 16},
              'gcd': {'arg_sz': 3,
                      'args': {'a': {'offset': 2,
                                     'typ': 'integer',
                                     'var': False},
                               'b': {'offset': 1,
                                     'typ': 'integer',
                                     'var': False},
                               'res': {'offset': 0,
                                       'typ': 'integer',
                                       'var': True}},
                      'consts': {},
                      'offset': 0,
                      'v_size': 0,
                      'vars': {}}},
 'v_size': 1,
 'vars': {'t': {'offset': 0, 'size': 1, 'typ': 'integer'}}}


Интерес представляет поле p_text, в котором находится текст программы в виде инструкций для абстрактной виртуальной машины. Я выбрал одноадресное промежуточное представление чтобы быть ближе к инструкциям машины МЭСМ-6, третий аргумент у некоторых операций носит косметический характер и сохраняется для удобочитаемости человеком.

Трассировка вычисления НОД для чисел 100 и 15:
OP=('ALLOC', 1) PC=16 BP=1 SP=1 D_MEM=[0]
OP=('CONST', 27) PC=17 BP=1 SP=2 D_MEM=[0, 27]
OP=('CONST', 25) PC=18 BP=1 SP=3 D_MEM=[0, 27, 25]
OP=('CONST', 3) PC=19 BP=1 SP=4 D_MEM=[0, 27, 25, 3]
OP=('BINOP', '*') PC=20 BP=1 SP=3 D_MEM=[0, 27, 75]
OP=('BINOP', '+') PC=21 BP=1 SP=2 D_MEM=[0, 102]
OP=('CONST', 10) PC=22 BP=1 SP=3 D_MEM=[0, 102, 10]
OP=('CONST', 5) PC=23 BP=1 SP=4 D_MEM=[0, 102, 10, 5]
OP=('BINOP', 'DIV') PC=24 BP=1 SP=3 D_MEM=[0, 102, 2]
OP=('BINOP', '-') PC=25 BP=1 SP=2 D_MEM=[0, 100]
OP=('CONST', 15) PC=26 BP=1 SP=3 D_MEM=[0, 100, 15]
OP=('ADR_LOAD', -1, 't') PC=27 BP=1 SP=4 D_MEM=[0, 100, 15, 0]
OP=('CALL', 0, 'gcd') PC=28 BP=4 SP=6 D_MEM=[0, 100, 15, 0, 1, 29]
OP=('LABEL', 'L0') PC=0 BP=4 SP=6 D_MEM=[0, 100, 15, 0, 1, 29]
OP=('VLOAD', -2, 'b') PC=1 BP=4 SP=7 D_MEM=[0, 100, 15, 0, 1, 29, 15]
OP=('CONST', 0) PC=2 BP=4 SP=8 D_MEM=[0, 100, 15, 0, 1, 29, 15, 0]
OP=('RELOP', '>') PC=3 BP=4 SP=7 D_MEM=[0, 100, 15, 0, 1, 29, True]
OP=('BR_ZERO', 'L1') PC=4 BP=4 SP=6 D_MEM=[0, 100, 15, 0, 1, 29]
OP=('VLOAD', -2, 'b') PC=5 BP=4 SP=7 D_MEM=[0, 100, 15, 0, 1, 29, 15]
OP=('RSTOR', -1, 'res') PC=6 BP=4 SP=6 D_MEM=[15, 100, 15, 0, 1, 29]
OP=('VLOAD', -3, 'a') PC=7 BP=4 SP=7 D_MEM=[15, 100, 15, 0, 1, 29, 100]
OP=('VLOAD', -2, 'b') PC=8 BP=4 SP=8 D_MEM=[15, 100, 15, 0, 1, 29, 100, 15]
OP=('BINOP', 'MOD') PC=9 BP=4 SP=7 D_MEM=[15, 100, 15, 0, 1, 29, 10]
OP=('VSTOR', -2, 'b') PC=10 BP=4 SP=6 D_MEM=[15, 100, 10, 0, 1, 29]
OP=('RLOAD', -1, 'res') PC=11 BP=4 SP=7 D_MEM=[15, 100, 10, 0, 1, 29, 15]
OP=('VSTOR', -3, 'a') PC=12 BP=4 SP=6 D_MEM=[15, 15, 10, 0, 1, 29]
OP=('BR', 'L0') PC=13 BP=4 SP=6 D_MEM=[15, 15, 10, 0, 1, 29]
OP=('LABEL', 'L0') PC=0 BP=4 SP=6 D_MEM=[15, 15, 10, 0, 1, 29]
OP=('VLOAD', -2, 'b') PC=1 BP=4 SP=7 D_MEM=[15, 15, 10, 0, 1, 29, 10]
OP=('CONST', 0) PC=2 BP=4 SP=8 D_MEM=[15, 15, 10, 0, 1, 29, 10, 0]
OP=('RELOP', '>') PC=3 BP=4 SP=7 D_MEM=[15, 15, 10, 0, 1, 29, True]
OP=('BR_ZERO', 'L1') PC=4 BP=4 SP=6 D_MEM=[15, 15, 10, 0, 1, 29]
OP=('VLOAD', -2, 'b') PC=5 BP=4 SP=7 D_MEM=[15, 15, 10, 0, 1, 29, 10]
OP=('RSTOR', -1, 'res') PC=6 BP=4 SP=6 D_MEM=[10, 15, 10, 0, 1, 29]
OP=('VLOAD', -3, 'a') PC=7 BP=4 SP=7 D_MEM=[10, 15, 10, 0, 1, 29, 15]
OP=('VLOAD', -2, 'b') PC=8 BP=4 SP=8 D_MEM=[10, 15, 10, 0, 1, 29, 15, 10]
OP=('BINOP', 'MOD') PC=9 BP=4 SP=7 D_MEM=[10, 15, 10, 0, 1, 29, 5]
OP=('VSTOR', -2, 'b') PC=10 BP=4 SP=6 D_MEM=[10, 15, 5, 0, 1, 29]
OP=('RLOAD', -1, 'res') PC=11 BP=4 SP=7 D_MEM=[10, 15, 5, 0, 1, 29, 10]
OP=('VSTOR', -3, 'a') PC=12 BP=4 SP=6 D_MEM=[10, 10, 5, 0, 1, 29]
OP=('BR', 'L0') PC=13 BP=4 SP=6 D_MEM=[10, 10, 5, 0, 1, 29]
OP=('LABEL', 'L0') PC=0 BP=4 SP=6 D_MEM=[10, 10, 5, 0, 1, 29]
OP=('VLOAD', -2, 'b') PC=1 BP=4 SP=7 D_MEM=[10, 10, 5, 0, 1, 29, 5]
OP=('CONST', 0) PC=2 BP=4 SP=8 D_MEM=[10, 10, 5, 0, 1, 29, 5, 0]
OP=('RELOP', '>') PC=3 BP=4 SP=7 D_MEM=[10, 10, 5, 0, 1, 29, True]
OP=('BR_ZERO', 'L1') PC=4 BP=4 SP=6 D_MEM=[10, 10, 5, 0, 1, 29]
OP=('VLOAD', -2, 'b') PC=5 BP=4 SP=7 D_MEM=[10, 10, 5, 0, 1, 29, 5]
OP=('RSTOR', -1, 'res') PC=6 BP=4 SP=6 D_MEM=[5, 10, 5, 0, 1, 29]
OP=('VLOAD', -3, 'a') PC=7 BP=4 SP=7 D_MEM=[5, 10, 5, 0, 1, 29, 10]
OP=('VLOAD', -2, 'b') PC=8 BP=4 SP=8 D_MEM=[5, 10, 5, 0, 1, 29, 10, 5]
OP=('BINOP', 'MOD') PC=9 BP=4 SP=7 D_MEM=[5, 10, 5, 0, 1, 29, 0]
OP=('VSTOR', -2, 'b') PC=10 BP=4 SP=6 D_MEM=[5, 10, 0, 0, 1, 29]
OP=('RLOAD', -1, 'res') PC=11 BP=4 SP=7 D_MEM=[5, 10, 0, 0, 1, 29, 5]
OP=('VSTOR', -3, 'a') PC=12 BP=4 SP=6 D_MEM=[5, 5, 0, 0, 1, 29]
OP=('BR', 'L0') PC=13 BP=4 SP=6 D_MEM=[5, 5, 0, 0, 1, 29]
OP=('LABEL', 'L0') PC=0 BP=4 SP=6 D_MEM=[5, 5, 0, 0, 1, 29]
OP=('VLOAD', -2, 'b') PC=1 BP=4 SP=7 D_MEM=[5, 5, 0, 0, 1, 29, 0]
OP=('CONST', 0) PC=2 BP=4 SP=8 D_MEM=[5, 5, 0, 0, 1, 29, 0, 0]
OP=('RELOP', '>') PC=3 BP=4 SP=7 D_MEM=[5, 5, 0, 0, 1, 29, False]
OP=('BR_ZERO', 'L1') PC=4 BP=4 SP=6 D_MEM=[5, 5, 0, 0, 1, 29]
OP=('LABEL', 'L1') PC=14 BP=4 SP=6 D_MEM=[5, 5, 0, 0, 1, 29]
OP=('RETURN', '') PC=15 BP=1 SP=4 D_MEM=[5, 5, 0, 0]
OP=('DEALLOC', 3) PC=29 BP=1 SP=1 D_MEM=[5]
OP=('VLOAD', -1, 't') PC=30 BP=1 SP=2 D_MEM=[5, 5]
OP=('CONST', 5) PC=31 BP=1 SP=3 D_MEM=[5, 5, 5]
OP=('RELOP', '=') PC=32 BP=1 SP=2 D_MEM=[5, True]
OP=('BR_ZERO', 'L3') PC=33 BP=1 SP=1 D_MEM=[5]
OP=('CLOAD', 0, 'pass') PC=34 BP=1 SP=2 D_MEM=[5, 12345]

Program halted with code: 12345
SUCCESS

Post a comment in response:

This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting