首选语言:C/ c++、Java、Ruby。
我正在寻找一些关于如何编写自己的编译器的有用书籍/教程,只是为了教育目的。我最熟悉C/ c++、Java和Ruby,所以我更喜欢包含这三者之一的资源,但任何好的资源都是可以接受的。
首选语言:C/ c++、Java、Ruby。
我正在寻找一些关于如何编写自己的编译器的有用书籍/教程,只是为了教育目的。我最熟悉C/ c++、Java和Ruby,所以我更喜欢包含这三者之一的资源,但任何好的资源都是可以接受的。
当前回答
创建编译器的一个简单方法是使用bison和flex(或类似),构建一个树(AST)并用C生成代码,生成C代码是最重要的步骤。通过生成C代码,您的语言将自动在所有具有C编译器的平台上运行。
生成C代码就像生成HTML一样简单(只需使用打印或等效工具),这又比编写C解析器或HTML解析器容易得多。
其他回答
如果你没有时间,我推荐Niklaus Wirth的“编译器构造”(Addison-Wesley)。1996年),一本你一天就能读完的小册子,但它解释了基础知识(包括如何实现词法分析器、递归下降解析器和你自己的基于堆栈的虚拟机)。在那之后,如果你想深入了解,就像其他评论者建议的那样,没有办法绕过龙的书。
Donald Knuth的《计算机编程的艺术》最初是作为编译器编写的教程而写的,这让我很惊讶。
当然,Knuth博士对主题深入研究的倾向导致编译器写作教程被扩展到大约9卷,其中只有3卷真正出版了。这是一个关于编程主题的相当完整的阐述,涵盖了关于编写编译器需要了解的所有细节。
如果您不仅仅是在寻找书籍,而且还对有关于该主题的文章的网站感兴趣,我已经在博客中讨论了创建编程语言的各个方面。大部分文章都可以在我博客的“语言设计”类别中找到。
特别是,我介绍了手动生成Intel机器代码、自动生成机器码或字节码、创建字节码解释器、编写面向对象的运行时、创建简单的加载器以及编写简单的标记/清除垃圾收集器。所有这些都是非常实用和务实的方式,而不是用大量的理论让你感到无聊。
将感激反馈这些。
一般来说,编译器没有五分钟的教程,因为这是一个复杂的主题,编写一个编译器可能需要几个月的时间。你得自己去找。
Python和Ruby通常是解释型的。也许你也想从一个口译员开始。这通常比较简单。
The first step is to write a formal language description, the grammar of your programming language. Then you have to transform the source code that you want to compile or interpret according to the grammar into an abstract syntax tree, an internal form of the source code that the computer understands and can operate on. This step is usually called parsing and the software that parses the source code is called a parser. Often the parser is generated by a parser generator which transform a formal grammar into source oder machine code. For a good, non-mathematical explanation of parsing I recommend Parsing Techniques - A Practical Guide. Wikipedia has a comparison of parser generators from which you can choose that one that is suitable for you. Depending on the parser generator you chose, you will find tutorials on the Internet and for really popular parser generators (like GNU bison) there are also books.
为您的语言编写解析器可能非常困难,但这取决于您的语法。所以我建议保持你的语法简单(不像c++);LISP就是一个很好的例子。
在第二步中,抽象语法树从树形结构转换为线性中间表示。作为一个很好的例子,Lua的字节码经常被引用。但是中间表示实际上取决于你的语言。
如果您正在构建一个解释器,则只需解释中间表示即可。您还可以及时编译它。我推荐LLVM和libjit进行即时编译。为了使语言可用,你还必须包含一些输入和输出函数,也许还有一个小的标准库。
如果您要编译该语言,它将更加复杂。你必须为不同的计算机架构编写后端,并从这些后端的中间表示生成机器代码。对于这个任务,我推荐LLVM。
有一些关于这个主题的书,但我不能推荐他们一般使用。他们中的大多数要么太学术,要么太实际。没有“21天自学编译器写作”,因此,你必须买几本书才能很好地理解整个主题。如果你上网搜索,你会发现一些在线书籍和课堂笔记。也许你附近有一个大学图书馆,在那里你可以借到关于编译器的书籍。
我还建议你在理论计算机科学和图论方面有良好的背景知识,如果你想让你的项目认真起来的话。计算机科学学位也会很有帮助。
您可以使用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();
}