Знания для написания компилятора для Win32 - PullRequest
1 голос
/ 12 апреля 2010

Я создал интерпретатор для своего языка программирования (образовательный), и теперь я хотел бы пойти еще дальше и создать для него компилятор.Я знаю, что это довольно тяжелая работа.

То, что я уже знаю:

  • Мне нужно перевести мой язык ввода на ассемблер

Многоне так ли?Теперь я не знаю:

  • Какой ассемблер мне нужен для создания исполняемых файлов Win32 PE, как, например, Visual Studio?
  • Как насчет заголовков файлов?

Я бы предпочел не использовать MASM, но, похоже, мне придется.

  • Как объединить ассемблер с моим компилятором?

1 Ответ

1 голос
/ 13 апреля 2010

Вам не нужно строго переводить код в сборку; вы можете перевести его на любой язык, который можно скомпилировать в собственный исполняемый файл.

Давайте рассмотрим чрезвычайно простой пример. Скажем, у меня был какой-то бесполезный воображаемый язык (в дальнейшем называемый 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 будет генерировать настоящие собственные исполняемые файлы, но, возможно, сейчас это не ваша главная задача.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...