首选语言:C/ c++、Java、Ruby。

我正在寻找一些关于如何编写自己的编译器的有用书籍/教程,只是为了教育目的。我最熟悉C/ c++、Java和Ruby,所以我更喜欢包含这三者之一的资源,但任何好的资源都是可以接受的。


当前回答

看看下面这本书。作者是ANTLR的创建者。

语言实现模式:创建您自己的领域特定语言和通用编程语言。

其他回答

Python附带了一个用Python编写的Python编译器。您可以看到源代码,它包括从解析、抽象语法树、发出代码等所有阶段。 破解它。

如果你想使用功能强大的高级工具,而不是自己构建一切,那么阅读本课程的项目和阅读材料是一个很好的选择。这是一门语言课程,由Java解析器引擎ANTLR的作者编写。你可以从Pragmatic Programmers网站上获得这门课程的PDF版本。

The course goes over the standard compiler compiler stuff that you'd see elsewhere: parsing, types and type checking, polymorphism, symbol tables, and code generation. Pretty much the only thing that isn't covered is optimizations. The final project is a program that compiles a subset of C. Because you use tools like ANTLR and LLVM, it's feasible to write the entire compiler in a single day (I have an existence proof of this, though I do mean ~24 hours). It's heavy on practical engineering using modern tools, a bit lighter on theory.

顺便说一下,LLVM非常棒。在许多情况下,你可能会编译到汇编,你最好编译到LLVM的中间表示。它是更高级别的、跨平台的,LLVM非常擅长从中生成优化的程序集。

我认为这是一个相当模糊的问题;只是因为这个话题涉及的深度。然而,编译器可以被分解成两个独立的部分;上半身和下半身。上半部分通常采用源语言并将其转换为中间表示,下半部分负责特定于平台的代码生成。

尽管如此,解决这个问题的一个简单方法(至少是我们在编译器类中使用的方法)是在上面描述的两部分中构建编译器。具体来说,通过构建上半部分,您将对整个过程有一个很好的了解。

Just doing the top half lets you get the experience of writing the lexical analyzer and the parser and go to generating some "code" (that intermediate representation I mentioned). So it will take your source program and convert it to another representation and do some optimization (if you want), which is the heart of a compiler. The bottom half will then take that intermediate representation and generate the bytes needed to run the program on a specific architecture. For example, the the bottom half will take your intermediate representation and generate a PE executable.

关于这个主题的一些书,我发现特别有用的是编译器原理和技术(或者龙书,因为封面上有可爱的龙)。它有一些很棒的理论,而且肯定以一种非常容易理解的方式涵盖了上下文无关语法。此外,为了构建词法分析器和解析器,您可能会使用*nix工具lex和yacc。而且很无趣的是,这本名为《莱科斯和雅克》的书继承了《龙之书》这部分的内容。

我记得大约七年前问过这个问题,当时我对编程还是个新手。

我问的时候非常小心,令人惊讶的是,我没有像你们在这里受到那么多批评。然而,他们确实给我指出了“龙书”的方向,在我看来,这是一本真正伟大的书,解释了编写编译器所需知道的一切(当然,你必须掌握一两种语言)。你懂的语言越多越好。

是的,很多人说读那本书是疯狂的,你不会从中学到任何东西,但我完全不同意这种说法。

许多人还说编写编译器是愚蠢和毫无意义的。编译器开发之所以有用,原因有很多:

因为它很有趣。 它是有教育意义的,当你学习如何编写编译器时,你会学到很多计算机科学和其他技术,这些技术在编写其他应用程序时很有用。 如果没有人编写编译器,现有的语言就不会变得更好。

我没有立即编写自己的编译器,但在询问之后,我知道从哪里开始。现在,在学习了许多不同的语言和阅读了龙书之后,写作并不是什么大问题。(我也在学习计算机工程,但我对编程的大部分知识都是自学的。)

总之,《龙之书》是一个很棒的“教程”。但是在尝试编写编译器之前,先花些时间掌握一两种语言。不过,不要指望在未来十年左右成为编译器大师。

如果你想学习如何编写解析器/解释器,这本书也是不错的选择。

您可以使用Apache软件基金会的BCEL。使用这个工具,您可以生成类似汇编程序的代码,但它是带有BCEL API的Java。您可以学习如何生成中间语言代码(在本例中是字节代码)。

简单的例子

用这个函数创建一个Java类: maxAsString(int a, int b) { If (a > b) { 返回Integer.valueOf(一).toString (); } if (a < b) { 返回Integer.valueOf (b) .toString (); }其他{ 返回“=”; } }

现在用这个类运行BCELifier

BCELifier bcelifier = new BCELifier("MyClass", System.out);
bcelifier.start();

您可以在控制台上看到整个类的结果(如何构建字节代码MyClass.java)。该函数的代码如下:

private void createMethod_1() {
  InstructionList il = new InstructionList();
  MethodGen method = new MethodGen(ACC_PUBLIC, Type.STRING, new Type[] { Type.INT, Type.INT }, new String[] { "arg0", "arg1" }, "maxAsString", "MyClass", il, _cp);

  il.append(InstructionFactory.createLoad(Type.INT, 1)); // Load first parameter to address 1
  il.append(InstructionFactory.createLoad(Type.INT, 2)); // Load second parameter to adress 2
    BranchInstruction if_icmple_2 = InstructionFactory.createBranchInstruction(Constants.IF_ICMPLE, null); // Do if condition (compare a > b)
  il.append(if_icmple_2);
  il.append(InstructionFactory.createLoad(Type.INT, 1)); // Load value from address 1 into the stack
  il.append(_factory.createInvoke("java.lang.Integer", "valueOf", new ObjectType("java.lang.Integer"), new Type[] { Type.INT }, Constants.INVOKESTATIC));
  il.append(_factory.createInvoke("java.lang.Integer", "toString", Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
  il.append(InstructionFactory.createReturn(Type.OBJECT));
  InstructionHandle ih_13 = il.append(InstructionFactory.createLoad(Type.INT, 1));
  il.append(InstructionFactory.createLoad(Type.INT, 2));
    BranchInstruction if_icmpge_15 = InstructionFactory.createBranchInstruction(Constants.IF_ICMPGE, null); // Do if condition (compare a < b)
  il.append(if_icmpge_15);
  il.append(InstructionFactory.createLoad(Type.INT, 2));
  il.append(_factory.createInvoke("java.lang.Integer", "valueOf", new ObjectType("java.lang.Integer"), new Type[] { Type.INT }, Constants.INVOKESTATIC));
  il.append(_factory.createInvoke("java.lang.Integer", "toString", Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
  il.append(InstructionFactory.createReturn(Type.OBJECT));
  InstructionHandle ih_26 = il.append(new PUSH(_cp, "equals")); // Return "equals" string
  il.append(InstructionFactory.createReturn(Type.OBJECT));
  if_icmple_2.setTarget(ih_13);
  if_icmpge_15.setTarget(ih_26);
  method.setMaxStack();
  method.setMaxLocals();
  _cg.addMethod(method.getMethod());
  il.dispose();
}