我已经为我的编程语言(教育)创建了一个解释器,现在我想更进一步,为它创建一个编译器。我知道这很辛苦。
我所知道的是:
很多,不是吗?现在我不知道的是:
我不想使用MASM,但似乎我不得不这样做。
答案 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
(请注意,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将生成实际的本机可执行文件,但这可能不是您现在最关心的问题。