vak: (Default)
[personal profile] vak
Есть вариант, как небольшими усилиями соорудить Си компилятор для БЭСМ-6. Есть такой проект ELVM. Это универсальный компилятор Си на основе LLVM, но не для конкретных процессоров, а вообще. Он выдаёт код для некоторой абстрактной машины. И дальше строятся бекэнды для разнообразных от смешных типа Brainfuck или Conway's Life до реальных типа WebAssembly.

Для прикола народ скомпилировал простой компилятор Си на "машину" - скрипт для редактора VI. И оно работает! Хотя нешустро: компиляция "Hello World" в таком VI занимает двадцать минут: "C Compiler exists purely in VIM".

Идея аналогичная древнему компилятору BCPL, который позже превратился в B (предшественник Си). Выдаём код для абстрактной машины, и строим отдельные кодогенераторы, транслирующие абстрактный код в выполняемый бинарник для нужной архитектуры. Такой подход оказался успешным, и немало способствовал распространению BCPL пятьдесят лет назад.

Не вижу проблем повторить это дело для БЭСМ-6. Размер кодогенератора для архитектуры x86, к примеру - всего 309 строк.

Побробуем запустить классический пример "Hello World" через ELVM для архитектуры x86 под Линуксом.
Собираем компилятор:
git clone https://github.com/shinh/elvm.git
cd elvm
git submodule update --init
make
Результатом будут бинарники out/8cc (компилятор) и out/elc (кодогенератор). Возьмем простой вариант "Hello World":
int main() 
{
const char* p = "Hello, world!\n";
for (; *p; p++)
putchar(*p);
return 0;
}
Компилируем, получаем ассемблерный код абстрактной машины:
$ cd out
$ ./8cc -S hello.c
$ cat hello.s
.text
main:
#{push:main}
mov D, SP
add D, -1
store BP, D
mov SP, D
mov BP, SP
sub SP, 1
.file 1 "hello.c"
.loc 1 7 0
# }
.loc 1 4 0
# for (; *p; p++)
mov A, 0
mov B, SP
.data
.L3:
.string "Hello, world!\n"
.text
mov A, .L3
mov B, BP
add B, 16777215
store A, B
.loc 1 5 0
# putchar(*p);
.L0:
.loc 1 4 0
# for (; *p; p++)
mov B, BP
add B, 16777215
load A, B
mov B, A
load A, B
jeq .L4, A, 0
jmp .L5
.L4:
.loc 1 5 0
# putchar(*p);
jmp .L2
.L5:
.loc 1 4 0
# for (; *p; p++)
mov B, BP
add B, 16777215
load A, B
mov B, A
load A, B
mov D, SP
add D, -1
store A, D
mov SP, D
putc A
add SP, 1
.loc 1 5 0
# putchar(*p);
.L1:
.loc 1 4 0
# for (; *p; p++)
mov B, BP
add B, 16777215
load A, B
mov D, SP
add D, -1
store A, D
mov SP, D
add A, 1
mov B, BP
add B, 16777215
store A, B
load A, SP
add SP, 1
.loc 1 5 0
# putchar(*p);
jmp .L0
.L2:
.loc 1 7 0
# }
mov A, 0
mov B, A
#{pop:main}
exit
#{pop:main}
exit
Превращаем в бинарник для x86:
$ ./elc -x86 hello.s > hello.elf
$ file hello.elf
hello.elf: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, no section header
Запускаем:
$ ./hello.elf
Hello, world!
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

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org