`
梁利锋
  • 浏览: 81366 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

D Parser 之前:写一个简单的虚拟机

阅读更多

  最近写了一点儿 D 程序,除了感觉标准库太差之外,没有一个好的 IDE 也是一个很头疼的事,特别是没有智能提示,每次调用一个函数什么的,都要查文档或者直接看源代码,实在是太费劲了。

 

  所以决定自己尝试写一个支持智能提示的 D 的 IDE。因为 SharpDelelop 比较小,而且它对 C# 的支持也做到了智能提示、窗体编辑器等等,所以决定用它作为主框架,除了智能提示,也许还能加入 DFL 的窗体编辑之类的功能(Entice 做的窗体编辑已经不错了,只是没有事件支持)。目前,已经完成了语法加亮,代码折叠(目前和 notepad++ 一样只是通过大括号匹配来做的),下一步,就是智能提示了,而智能提示就牵涉到语法分析。

 

  找了几个分析器生成器,试用之后,觉得 Grammatica 还不错,生成的代码比较清晰,调试起来也比较方便。照它的例子写了一个四则运算的分析器,还不错。

 

  看了一下 D 的语法详细列表,那也不是一般的复杂。所以,决定先写一个简单的语言的分析器、编译器和虚拟机练练手。今天先把虚拟机做了出来。

 

  这种语言的语法非常简单,姑且称之为 Z 语言吧(还没有细化):

 

声明语句: int x;        // 只支持 int
赋值语句: x = 1;
条件语句: if(x > 1) { ... } else { ... }
跳转语句: goto lable
标签语句: :lable
输出语句: write(x);        // 只支持 int
注释语句: // ... <eol>

 

  而虚拟机部分,参照 x86 asm,定义如下:

寄存器:        EAX, EBX, ESP, EIP        // EAX,EBX操作数,ESP堆栈指针,EIP指令指针
内存:          200000B,0B~99999B为堆栈,100000B~199999B为程序
指令:
      为EAX赋值:                       set eax, 1                // 01 01 00 00 00
        将当前堆栈地址变量复制到eax:     mov eax, *esp             // 02
        为EAX赋值:                       set ebx, 1                // 03 01 00 00 00
        将当前堆栈地址变量复制到ebx:     mov ebx, *esp             // 04
        为当前堆栈地址变量赋值eax:       mov *esp, eax             // 05
        为当前堆栈地址变量赋值ebx:       mov *esp, ebx             // 06
        esp 加运算:                      add esp, 1                // 07 01 00 00 00
        eax 加运算:                      add eax, ebx              // 08
        eax大于ebx?结果放eax:           gt                        // 11
        eax大于等于ebx?结果放eax:       gteq                      // 12
        eax等于ebx?结果放eax:           eq                        // 13
        eax bool not:                    not                       // 14
        eax 为非 0 跳转(相对):         if eax jmp {sp}           // 21 {sp}
        无条件跳转(相对):              jmb {sp}                  // 22 {sp}
        输出 eax:                        out                       // 31
        结束:                            over                      // ff

  

   另外,虚拟机需要能显示寄存器值,显示当前堆栈顶值,显示输出。支持单步执行。

 

  再写一段小程序,用来验证虚拟机的运行情况,因为只支持 int,所以计算 1 到 100 的和是一个比较合适的小代码段, C 的代码如下:

int n = 0;
for(int i=1; i<=100; i++)
{
    n += i;
}
write(n);

  Z 语言不支持 for 循环,所以,相应的 Z 代码大体如下:

int n = 0;
int i = 1;
:next
if(i > 100) { goto end; }
n += i;
i++;
goto next;
:end
write(n);

  

  而根据上面定义的指令集,其相应的汇编代码如下:

 

// esp n, esp+4 i;
// int n = 0;
set eax, 0                               // 01 00 00 00 00
mov *esp, eax                            // 05
// int i = 1;
add esp, 4                               // 07 04 00 00 00
set eax, 1                               // 01 01 00 00 00
mov *esp, eax                            // 05
// :next
// if(i > 100) { goto end; }
mov eax, *esp                            // 02
set ebx, 100                             // 03 64 00 00 00
gt                                       // 11
if eax jmb <end>                         // 21 1B 00 00 00
// n += i;
mov ebx *esp                             // 04
add esp, -4                              // 07 FC FF FF FF
 mov eax *esp                             // 02
add eax, ebx                             // 08
mov *esp, eax                            // 05
add esp, 4                               // 07 04 00 00 00
// i++;
mov eax, *esp                            // 02
set ebx, 1                               // 03 01 00 00 00
add eax, ebx                             // 08
mov *esp, eax                            // 05
// goto next;
jmb <next>                               // 22 D9 FF FF FF
// :end
// write(n);
add esp, -4                              // 07 FC FF FF FF
mov eax, *esp                            // 02
out                                      // 31
over                                     // FF


  虚拟机的代码不算复杂,VM 类拥有 eax, ebx, esp, eip 等属性,然后有一个函数 Step 提供执行一条指令的功能,在 Step 中,使用一个 switch 来处理不同的指令。之后,运行程序,把上面的汇编代码的字节序列写入 add.bin 文件中,用虚拟机加载,运行,得到结果:5050。

 

  在把 Z 转换到汇编的过程中,发现写编译器的话,对于寄存器的使用,是一个很需要考虑的问题,而对于 D 智能提示,只需要分析器就够了,似乎写编译器有一些超出了,不过,既然都写了,就试着先把这个完成吧。

 

  下面是源代码和运行截图:

  • ZLan.zip (45.8 KB)
  • 描述: ZVM 源代码
  • 下载次数: 56
  • 描述: 运行截图
  • 大小: 12.7 KB
16
3
分享到:
评论
6 楼 oldrev 2008-01-07  
已经有现成的 parser了:
http://apaged.mainia.de/
还有用apaged这个 parser做的D语法分析工具,结合scite,可以来一点自动完成:
http://seatd.mainia.de/

楼主达人啊,为什么要自创一种虚拟机呢,直接给 DMD 做一个生成 .Net IL 的后端就功德无量了
5 楼 梁利锋 2008-01-06  
刚收到站内信件,在圈子里看不到附件的问题已经解决,javaeye 的反应速度真快啊
4 楼 梁利锋 2008-01-06  
奇怪,在圈子里直接浏览的话,就看不到附件,如果要看截图和下载源代码的话,直接访问 http://llf.iteye.com/blog/153501 吧。
3 楼 梁利锋 2008-01-06  
我没有对IDE做截图,因为现在只实现了语法加亮和代码折叠,有人提供过的 notepad++ 的定义文件也可以提供这两项功能。
2 楼 梁利锋 2008-01-06  
@player7
虚拟机截图的话,就在下面啊。

IDE使用C#写。

关于IDE,已经提供了基础框架的,对我来说也就三种选择,SharpDevelop,Eclipse,Visual Studio 2008 Shell。
Eclipse 和 Visual Studio 2008 Shell 太大,所以选择了 SharpDevelop。
1 楼 player7 2008-01-06  
? 图在哪?
IDE准备用C#写

相关推荐

    ua-parser-1.3.0

    ua-parser-1.3.0

    ua-parser-1.3.0.jar.rar

    ua-parser-1.3.0.jar,现在maven中http://maven.twttr.com/ua_parser/ua-parser/1.3.0/ua-parser-1.3.0.pom下载不下来。

    ua-parser-1.3.0.jar

    下载 ua-parser-master cd /app/ua-parser-master/java vi pom.xml &lt;version&gt;1.3.0&lt;/version&gt; 原来是&lt;version&gt;1.3.1-SNAPSHOT mvn package -DskipTests mvn install:install-file -Dfile="/app/ua-parser-master/...

    SGML::Parser::OpenSP-开源

    SGML::Parser::OpenSP 是一个Perl模块,它提供了一个用C++和XS编写的本地Perl接口,用于访问OpenSP(Open Source Parser)的SGML(Standard Generalized Markup Language)和XML(eXtensible Markup Language)解析...

    javaparservisited.pdf

    JavaParser 不仅仅是一个简单的语法解析器,它是一个完整的工具链,包括词法分析、语法分析、抽象语法树(AST)的构建以及对AST的遍历和修改。它支持Java语言的最新版本,可以处理现代Java代码的各种复杂特性。 这...

    javaparser-visited:《 JavaParser》一书的代码示例

    JavaParser:访问 该项目包含上书籍的代码示例 标题 JavaParser:已访问 作者 尼古拉斯·史密斯(Nicholas Smith),丹尼·范·布鲁根(Danny van Bruggen)和费德里科·托马塞蒂(Federico Tomassetti) 前导文字 ...

    视频编辑MP4 Parser代码与jar包

    《视频编辑MP4 Parser代码与jar包》 ...总的来说,MP4 Parser是一个强大的工具,对于需要处理MP4文件的开发者来说,它是不可或缺的资源。通过深入理解和实践提供的示例代码,你将能够自如地应对各种视频编辑任务。

    pull-parser-2.jar 工具類

    `pull-parser-2.jar`工具类库就是这样一个专门针对XML和JSON解析的利器,它为开发者提供了便捷、高效的解析方式,极大地优化了数据处理的流程。 XML(Extensible Markup Language)和JSON(JavaScript Object ...

    XMLParser iphone

    你可以创建一个`Item`类,然后在`parser(_:didStartElement:namespaceURI:qualifiedName:attributes:)`中开始创建新的`Item`实例,在`parser(_:foundCharacters:)`中收集属性值,并在`parser(_:didEndElement:...

    mp4parser工具箱中isoparser和muxer的jar包

    mp4parser中的视频处理方法需要依靠该jar包才能运行,该jar包是基于mp4parser-mp4parser-project-1.9.27打包的。使用方法可以参考我的CSDN博文,地址是http://blog.csdn.net/u014691453/article/details/53256605

    Perl-Parser-Combinators:Perl中的Parsec样式解析器组合器库

    Parser :: Combinators是一个解析器构件块(“ parser combinators”)库,其灵感来自Haskell( )中的Parsec解析器组合库。 。 这个想法是,您不是通过指定语法(例如yacc / lex或Parse :: RecDescent)来构建解析...

    IOS开发 XmlParser Demo

    本示例"IOS开发 XmlParser Demo"提供了一个简单的教程,帮助开发者理解如何在Xcode 4.2环境下集成并使用XMLParser。 首先,让我们了解XMLParser的基本工作原理。XMLParser遵循SAX(Simple API for XML)解析模式,...

    arg_parser 源码

    `arg_parser`是一个用于解析命令行参数的C++库,同时也支持C语言接口。这个库在软件开发中扮演着重要角色,特别是在需要通过命令行接口与用户交互的工具或服务中。下面我们将深入探讨`arg_parser`的核心概念、功能、...

    Parser_Generator.rar

    Parser_Generator是一个在Windows操作系统环境下使用的工具,主要用于生成解析器(Parser)和生成器(Generator)。解析器是计算机科学中的一个重要组件,它处理输入源代码,将其转化为抽象语法树(AST),这是理解...

    conch-parser:用于解析以Shell编程语言编写的程序的库

    快速开始首先,将其添加到您的Cargo.toml : [ dependencies ]conch-parser = " 0.1.0 " 接下来,您可以开始: use conch_parser :: lexer :: Lexer;use conch_parser :: parse :: DefaultParser;fn main () { // ...

    Simple-PHP-Code-Parser::red_heart:简单PHP代码解析器| php代码中的简单数据结构

    :red_heart: 简单PHP代码解析器 您可以简单地扫描字符串,文件或完整目录,并且可以从php代码中看到简单的数据结构。 类( PHPClass ) 属性( PHPProperties ) 常量( PHPConst ) 方法( PHPMethod ) 接口...

Global site tag (gtag.js) - Google Analytics