我已经使用C语言(使用lex和bison)创建了一种编译器,用于支持循环,函数内部的函数声明,递归调用等的动态类型编程语言。我还创建了一个虚拟机,该虚拟机运行由编译器创建的中间代码。
我现在正在考虑,而不是编译为自己的中间代码,而是将其编译为Java字节代码。
我看到关于创建JVM语言的问题已经存在 问但我认为答案并不十分有用。
所以这是我的问题:
我已经使用C语言(使用lex和bison)创建了一种编译器,用于支持循环,函数内部的函数声明,递归调用等的动态类型编程语言。我还创建了一个虚拟机,该虚拟机运行由编译器创建的中间代码。
我现在正在考虑,而不是编译为自己的中间代码,而是将其编译为Java字节代码。
我看到关于创建JVM语言的问题已经存在 问但我认为答案并不十分有用。
所以这是我的问题:
Answers:
我还将推荐ASM,但请看一下Jasmin,我在大学项目中使用了它(或:必须使用它),并且效果很好,我为使用java和jasmin的编程语言,因此生成JVM代码。我在这里上传了代码,有趣的部分应该是源代码本身。在文件夹“ bytecode / InsanelyFastByteCodeCreator.java”中,您可以找到一些将AST Tree转换为jasmin汇编程序输入格式的代码。是相当简单的。
源语言(由Lexer + Parser + Analyzer转换为AST)是Java的一个子集,称为MiniJava。它缺少一些“复杂”功能,例如继承,构造函数,静态方法,私有字段/方法。这些功能都不是很难实现的,但是还有另一个任务是编写X86后端(以便生成机器汇编程序),如果没有JVM处理某些事情,这些事情会变得很困难。
如果您想知道奇怪的类名:大学项目的任务是将AST转换为SSA Graph(这样就代表了输入代码的图形),然后对图形进行优化,然后将其转换为Java字节码。那大约是项目工作的3/4,而InsanlyFastByteCodeCreator只是测试所有内容的捷径。
看看Jon Meyer和Troy Downing的“ Java虚拟机”一书。本书大量引用了Jasmin-Assembler,对于理解JVM内部非常有帮助。
上学期,我参加了“编译器构建”课程。我们的项目正是您想要做的。
我以前用来写语言的语言是Scala。它运行在JVM上,但支持Java不支持的许多高级功能(仍与纯Java JVM完全兼容)。
为了输出Java字节码,我使用了Scala CAFEBABE库。有据可查,您无需深入Java类即可了解该怎么做。
除了这本书,我认为您可以通过我们在本课程中完成的实验来找到很多信息。
上周末,我问自己一个问题,将玩具语言移植到JVM。
我只花了几个小时来搜索信息,因此请参考一下。
语言实现模式。我讨厌antlr,但是这本书看起来很好。如果您都不喜欢antlr,那么解析“解析技术:实用指南”会很有帮助。
学习构建配置文件读取器,数据读取器,模型驱动的代码生成器,源到源转换器,源分析器和解释器。您不需要计算机科学的背景知识-ANTLR的创建者Terence Parr通过将语言实现分解为最常见的设计模式来消除其神秘感。逐个模式学习,您将学习实现自己的计算机语言所需的关键技能。
第10章共分30页(快速介绍IMO)。但是您可能还会对其他章节感兴趣。
- 10个建筑字节码解释器
http://pragprog.com/titles/tpdsl/language-implementation-patterns
- 10.1编程字节码解释器。。
- 10.2定义汇编语言语法
- 10.3字节码机器体系结构。。。。。
- 10.4从这里去哪里。。。。。。。。。。
- 第26页。字节码汇编器。。。。。。。。。。。
- 第27页。基于堆栈的字节码解释器。。。
- 第28页。基于寄存器的字节码解释器
Lua 5.0的实现这是一篇有关基于寄存器的字节码机器的好论文。甚至为了它读一读。
Lisp小块。本书教导了如何编写2个可编译为C的schme编译器。从本书中可以学到很多东西。我拥有这本书的副本,对任何感兴趣的人来说,这都是不错的选择,但也许不是您想要的。
这是对整个Lisp语言族(即Lisp,Scheme和相关方言)的语义和实现的全面说明。它描述了11个解释器和2个编译器...
http://www.amazon.com/Lisp-Small-Pieces-Christian-Queinnec/dp/0521562473
检查Dalvik7 VM,这是一个基于寄存器的VM。DVM对从Java编译器编译的Java类文件转换而来的字节码进行操作。
关于该主题的邮件列表,jvm-languages。
您打算将代码上传到任何地方吗?我想看看。
我建议您首先了解JVM程序集的工作原理(如果您还不了解的话)。
许多指令的形式为?name
,其中?
是i
如果该指令适用于带有整数类型和a
它是否与引用类型的作品。
基本上,JVM是没有寄存器的堆栈计算机,因此所有指令都直接在堆栈上处理数据。您可以使用来推送/弹出数据,?push/?pop
并在局部变量(偏移量引用的堆栈位置)和堆栈顶部之间移动数据?store/?load
。其他重要说明是invoke???
和if_???
。
对于我大学的编译器课程,我们使用Jasmin汇编程序。我不知道这是否是最好的方法,但是至少这是一个简单的起点。
首先,我退后一步,修改我的编译器以输出实际的Java而不是Java字节码(这意味着要创建比编译器更多的翻译器),并在任何方便的Java环境下编译Java输出(这可能会生成更好的目标代码)比我自己的编译器)。
您可以使用相同的技术(例如,编译为C#)生成CLI字节码,或编译为Pascal生成P代码,等等。
目前尚不清楚为什么要考虑使用Java代码而不是使用自己的VM,但是如果出于性能考虑,那么当然还应该考虑编译为实际的机器代码。