浏览 2604 次
锁定老帖子 主题:D Parser 之前(二):汇编编译器
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-01-08
在《D Parser 之前:写一个简单的虚拟机》里,其中计算 1 到 100 之和的程序 add.bin,是使用十六进制编辑器直接编辑出来的。虚拟机制作完后,考虑了一下,如果直接写 Z 的编译器,难度还是不小,所以决定,先写一个汇编语言的编译器,实现从汇编代码到机器代码的编译工作。
大体来说,汇编编译基本上是一条一条对照生成,不过,行号的需求使得其中多了一些复杂性,另外,我还决定加入注释的支持。所以,这也是一个比较好的机会实践一下分析器生成器的使用。
汇编语言部分做了少量修改,over 改为 end,行号改为加 @ 前缀,完成的 Grammatica 的分析文件如下: %header% GRAMMARTYPE = "LL" DESCRIPTION = "A asm grammar for zvm." AUTHOR = "Lephone Liang" VERSION = "1.0" DATE = "7 January 2008" LICENSE = "." COPYRIGHT = "Copyright (c) 2008 Lephone. All rights reserved." %tokens% EAX = "eax" EBX = "ebx" ESP = "esp" EIP = "eip" SET = "set" MOV = "mov" TJMP = "jmp" ADD = "add" TGT = "gt" TGTEQ = "gteq" TEQ = "eq" TNOT = "not" IF = "if" TOUT = "out" TEND = "end" POINT = "*" COMMA = "," NUMBER = <<(-)?([0-9])+>> LABEL = <<@[a-z]+>> COMMENT = <<;[^\n\r]*[\r\n]>> %ignore% WHITESPACE = <<[ \t\n\r]+>> %ignore% %productions% Expression = Atom [Expression]; Atom = SetEax | MovEax8Esp | SetEbx | MovEbx8Esp | Mov8EspEax | Mov8EspEbx | AddEsp | AddEaxEbx | Gt | Gteq | Eq | Not | IfEaxJmp | Jmp | Out | End | LineLabel ; SetEax = SET EAX COMMA NUMBER; MovEax8Esp = MOV EAX COMMA POINT ESP; SetEbx = SET EBX COMMA NUMBER; MovEbx8Esp = MOV EBX COMMA POINT ESP; Mov8EspEax = MOV POINT ESP COMMA EAX; Mov8EspEbx = MOV POINT ESP COMMA EBX; AddEsp = ADD ESP COMMA NUMBER; AddEaxEbx = ADD EAX COMMA EBX; Gt = TGT; Gteq = TGTEQ; Eq = TEQ; Not = TNOT; IfEaxJmp = IF EAX TJMP LABEL; Jmp = TJMP LABEL; Out = TOUT EAX; End = TEND; LineLabel = LABEL;
生成代码后,加入新建的 ZasmC 工程,参照 Grammatica 的例子调试了一会儿,增加一些处理代码后,编译器可以正常工作了。用它编译上一次的的 1 到 100 和的汇编代码,发现几个汇编代码的格式错误 后,编译成功,加载入虚拟机,运行得到结果:5050。
还想再写一个程序验证一下,Fibonacci 序列是一个不错的例子,于是编写 d 的原型如下: import std.stdio; static void main(char[][] args) { int i=0; int a=1; write(a); int b=1; write(b); int t; next: t = a + b; write(t); a = b; b = t; i++; if(i<10) goto next; } void write(int n) { writefln("%d", n); }
改写为汇编代码如下: ; 斐波那契 ; esp i, esp+4 a, esp+8 b, esp+12 t ; int i=0; set eax, 0 mov *esp, eax ; int a=1; ; write(a); set eax, 1 add esp, 4 ; a mov *esp, eax out eax ; int b=1; ; write(b); add esp, 4 ; b mov *esp, eax out eax add esp, -8 ; i ; int t; @next ; t = a + b; ; write(t); add esp, 4 ; a mov eax, *esp add esp, 4 ; b mov ebx, *esp add eax, ebx add esp, 4 ; t mov *esp, eax out eax ; a = b; ; b = t; add esp, -4 ; b mov eax, *esp add esp, -4 ; a mov *esp, eax add esp, 8 ; t mov eax, *esp add esp, -4 ; b mov *esp, eax ; i++; add esp, -8 ; i mov eax, *esp set ebx, 1 add eax, ebx mov *esp, eax set ebx, 10 ; 循环次数 gteq not if eax jmp @next end
用 ZasmC 编译,生成 Fibonacci.bin,加载到虚拟机,第一次运行错误,后来发现是 d 转汇编的时候的疏忽,修正汇编代码后,编译,加载运行,得到正确的结果。
下一步就是写 Z 的编译器了,这一步可能要花比较长的时间,准备把 Z 编译成汇编代码,然后再用这个汇编编译器编译成机器代码,这样,Z 编译器就不需要处理行号问题了。
下面是虚拟机和汇编编译器的源代码,以及运行 Fibonacci 的截图:
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |