编写Win32编译器的知识

时间:2010-04-12 16:51:56

标签: compiler-construction

我已经为我的编程语言(教育)创建了一个解释器,现在我想更进一步,为它创建一个编译器。我知道这很辛苦。

我所知道的是:

  • 我需要将输入语言翻译成汇编程序

很多,不是吗?现在我不知道的是:

  • 我需要什么汇编程序来创建Win32 PE可执行文件,例如Visual Studio呢?
  • 文件标题怎么样?

我不想使用MASM,但似乎我不得不这样做。

  • 如何将汇编程序与我的编译器结合使用?

1 个答案:

答案 0 :(得分:1)

您不需要将代码转换为汇编;你可以将它翻译成任何可以编译为本机可执行文件的语言。

让我们看一个非常简单的例子。假设我有一些毫无价值的虚构语言(以下称为Adder),其中输入文件由任意数量的行组成,每行包含一个以空格分隔的整数列表。输出是每一行的总和。

因此对于输入文件

1
1 2 3
200 50 6

输出将是

1
6
256

您可以在一行Ruby中为Adder编写解释器

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

(请注意,tccTiny 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将生成实际的本机可执行文件,但这可能不是您现在最关心的问题。