网站规划与建设的案例分析,大力推广建设电子商务网站技术,软件开发可以做网站么,济南WordPress培训动手编写一个编译器#xff0c;学习一下较为底层的编程方式#xff0c;是一种学习计算机到底是如何工作的非常有效方法。
编译器通常被看作是十分复杂的工程。事实上#xff0c;编写一个产品级的编译器也确实是一个庞大的任务。但是写一个小巧可用的编译器却不是这么困难。…动手编写一个编译器学习一下较为底层的编程方式是一种学习计算机到底是如何工作的非常有效方法。
编译器通常被看作是十分复杂的工程。事实上编写一个产品级的编译器也确实是一个庞大的任务。但是写一个小巧可用的编译器却不是这么困难。
秘诀就是首先去找到一个最小的可用工程然后把你想要的特性添加进去。这个方法也是Abdulaziz Ghuloum在他那篇著名的论文“一种构造编译器的捷径”里所提到的办法。不过这个办法确实可行。你只需要按照这篇论文中的第一步来操作就可以得到一个真正可用的编译器当然它只能编译程序语言中的非常小的子集但是它确实是一个真实可用的编译器。你可以随意的扩展这个编译器然后从中学到更多更深的知识。
受到这篇文章的鼓舞我就写了一个C编译器。从某种意义上来说这比写一个scheme的编译器要困难一些因为你必须去解析C那复杂的语法但是在某些方面又很便利你不需要去处理运行时类型。要写这样一个编译器你只需要从你那个可用的最小的编译器开始。
对于我写的编译器来说我把它叫 babyc我选了这段代码来作为我需要运行的第一个程序 1 2 3 int main() { return 2; } 没有变量没有函数调用没有额外的依赖甚至连if语句循环语句都没有一切看起来是那么简单。
我们首先需要解析这段代码。我们将使用 Flex 和 Bison 来做到这点。这里有怎么用的例子可以参考幸好我们的语法是如此简单下面就是词法分析器 1 2 3 4 5 6 7 8 9 { { return {; } } { return }; } ( { return (; } ) { return ); } ; { return ;; } [0-9] { return NUMBER; } return { return RETURN; } int { return TYPE; } main { return IDENTIFIER; } 这里是语法分析器 1 2 3 4 5 6 7 function: TYPE IDENTIFIER ( ) { expression } ; expression: RETURN NUMBER ; ; 最终我们需要生成一些汇编代码。我们将使用32位的X86汇编因为它非常的通用而且可以很容易的运行在你的机器上。这里有X86汇编的相关网站。
下面就是我们需要生成的汇编代码 1 2 3 4 5 6 7 .text .global _start # Tell the loader we want to start at _start. _start: movl $2,%ebx # The argument to our system call. movl $1,%eax # The system call number of sys_exit is 1. int $0x80 # Send an interrupt 然后加上上面的词法语法分析代码把这段汇编代码写进一个文件里。恭喜你你已经是一个编译器的编写者了
Babyc 就是这样诞生的你可以在这里看到它最开始的样子。
当然如果汇编代码没办法运行也是枉然。让我们来用编译器生成我们所希望的真正的汇编代码。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # Heres the file we want to compile. $ cat return_two.c #include stdio.h int main() { return 2; } # Run the compiler with this file. $ ./babyc return_two.c Written out.s. # Check the output looks sensible. $ cat out.s .text .global _start _start: movl $2, %ebx movl $1, %eax int $0x80 非常棒接着让我们来真正的运行一下编译之后代码来确保它能得到我们所想的结果。 1 2 3 4 5 6 7 8 9 10 11 12 13 # Assemble the file. We explicitly assemble as 32-bit # to avoid confusion on x86_64 machines. $ as out.s -o out.o --32 # Link the file, again specifying 32-bit. $ ld -m elf_i386 -s -o out out.o # Run it! $ ./out # What was the return code? $ echo $? 2 # Woohoo! 我们踏出了第一步接下去怎么做就全看你了。你可以按照那篇文章所指导的全部做一遍然后制作一个更加复杂的编译器。你需要去写一个更加精巧的语法树来生成汇编代码。接下去的几步分别是1允许返回任意的值比如return 3; 一些可执行代码2添加对“非”的支持比如return 1; 一些可执行代码。每一个额外的特性都可以教你关于C语言的更多知识编译器到底是怎么执行的以及世界上其他编写编译器的人是如何想的。
这是构建 babyc 的方法。Babyc 现在已经拥有了if语句循环变量以及最基础的数据结构。欢迎你来check out它的代码但是我希望看完我的文章你能够自己动手写一个。
不要害怕底层的一些事情。这是一个非常奇妙的世界。