Пару слов о компиляторе-интерпретаторе
Oct. 12th, 2021 04:16 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Доброго времени!
Продолжаю эксперименты с компиляторо-строением.
Добавил возможность возвращать результаты работы процедуры через VAR-аргументы.
Поэтому подобный код компилируется и работает:
Передача аргументов осуществляется через стек, на котором формируется рабочая область (фрейм) куда записываются аргументы процедуры и внутренние локальные переменные.
Схема такая:
Сделал я это для того, чтобы была возможность работы с рекурсией, но боком вышло то, что глобальные переменные по отношению к телу процедуры “дали прикурить” т.к. их адреса во время компиляции программы неизвестны (так же из-за возможности объявлять вложенные процедуры (своего рода замыкания)). Можно было ввести некоторый GP который бы показывал на локальные переменные вышестоящей области видимости, но тогда пришлось бы организовывать какой-то механизм многократной относительной адресации. Понятно, что эта задача решаема, но в книге по Оберону я пока не добрался до соотв. главы. Если запретить рекурсию, то задача размещения и адресации переменных становится тривиальной, т.к. все адреса можно вычислить прямо на этапе компиляции.
Результатом работы компилятора является такой питонячий объект:
Интерес представляет поле p_text, в котором находится текст программы в виде инструкций для абстрактной виртуальной машины. Я выбрал одноадресное промежуточное представление чтобы быть ближе к инструкциям машины МЭСМ-6, третий аргумент у некоторых операций носит косметический характер и сохраняется для удобочитаемости человеком.
Трассировка вычисления НОД для чисел 100 и 15:
Продолжаю эксперименты с компиляторо-строением.
Добавил возможность возвращать результаты работы процедуры через 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