Вам не нужно строго переводить код в сборку; вы можете перевести его на любой язык, который можно скомпилировать в собственный исполняемый файл.
Давайте рассмотрим чрезвычайно простой пример. Скажем, у меня был какой-то бесполезный воображаемый язык (в дальнейшем называемый Adder), где входной файл состоял из любого числа строк, каждая из которых содержала разделенный пробелами список целых чисел. Выходными данными является сумма каждой строки.
Так что для входного файла
1
1 2 3
200 50 6
вывод будет
1
6
256
Вы можете написать интерпретатор для Adder в одной строке Ruby:
puts($_.split.map(&:to_i).inject(0, :+)) while gets
Что если я захочу перевести программу ввода в отдельный скрипт на Ruby? Простой:
while line = gets
num = line.split.map(&:to_i).inject(0, :+)
puts "puts(#{num})"
end
Выход:
$ ruby adder2rb.rb nums.txt
puts(1)
puts(6)
puts(256)
$ ruby adder2rb.rb nums.txt | ruby -
1
6
256
Хорошо, теперь, что если мы захотим перевести это в нечто, что на самом деле компилируется в собственный исполняемый файл - скажем, C? Нам вряд ли нужно что-то менять:
puts '#include <stdio.h>'
puts 'int main() {'
while line = gets
num = line.split.map(&:to_i).inject(0, :+)
puts " printf(\"%ld\\n\", #{num}L);"
end
puts ' return 0;'
puts '}'
Вывод сеанса:
$ ruby adder2c.rb nums.txt
#include <stdio.h>
int main() {
printf("%ld\n", 1L);
printf("%ld\n", 6L);
printf("%ld\n", 256L);
return 0;
}
$ ruby adder2c.rb nums.txt | tcc -
$ ./a.out
1
6
256
(Обратите внимание, что tcc
- это Tiny C Compiler , что может быть очень полезно для вашего проекта, если вы хотите, чтобы конечные пользователи могли генерировать исполняемые файлы из ваших сгенерированных файлов C.)
Хотите перевести на другой язык высокого уровня? Как насчет Хаскелла?
$ cat adder2hs.rb
puts 'main = do'
while line = gets
num = line.split.map(&:to_i).inject(0, :+)
puts " print #{num}"
end
$ ruby adder2hs.rb nums.txt
main = do
print 1
print 6
print 256
$ ruby adder2hs.rb nums.txt | runghc
1
6
256
Конечно, переводчик кода для любого языка с более чем одной конструкцией будет значительно более полон, чем приведенные выше примеры; однако основная идея остается той же: у вас будут общие шаблоны, которым вы будете следовать для своего языка вывода.
Теперь, если вы решите, что вы все еще действительно хотите генерировать сборку вместо высокоуровневого кода, вы не ограничены ни одной реализацией. Несколько проще, чем прямая сборка, переводить байт-код виртуальной машины. MSIL даст вам исполняемые файлы .NET, или вы можете использовать средства генерации кода LLVM . Если вам больше нравится Java, вы можете выдать JVM байт-код. Один чуть менее распространенный выбор будет Parrot .
Из этих виртуальных машин только AFAIK LLVM будет генерировать настоящие собственные исполняемые файлы, но, возможно, сейчас это не ваша главная задача.