【问题标题】:How to approach creating a JVM programming language?如何接近创建 JVM 编程语言?
【发布时间】:2011-03-23 18:29:08
【问题描述】:

我已经用 C 语言创建了一个编译器(使用 Lex 和 Bison),用于支持循环、函数内部的函数声明、递归调用等的动态类型编程语言。我还创建了一个虚拟机来运行由编译器。

我正在考虑将其编译为 Java 字节码,而不是我自己的中间代码。

我看到关于创建JVM语言的问题已经asked,但我发现答案信息量不大。

所以这是我的问题:

  1. 我想为JVM创建一种语言必须阅读JVM specification这本书,你能推荐什么其他的书(当然除了Dragon Book)?我最关心的是关于如何创建 JVM 语言的书籍或教程,而不是一般的编译器。
  2. 有许多 Java 库可以读取、写入和更改 .class 文件,例如 jclasslibbcelgnu bytecode 等。您建议使用哪一个?另外,您是否知道有相同功能的 C 库?
  3. 我正在考虑看看另一种以 JVM 为目标的语言,例如 Clojure、Jython 或 JRuby。但是所有这些语言都非常高级且复杂(为它们创建编译器)。我一直在寻找一种更简单的(我不介意它是未知的还是未使用的)以 JVM 为目标并带有开源编译器的编程语言。有什么想法吗?

【问题讨论】:

    标签: compiler-construction programming-languages jvm jvm-languages


    【解决方案1】:

    我也会推荐 ASM,但请看一下 Jasmin,我在大学项目中使用它(或者说,必须使用它),并且效果很好。我为使用 Java 和 Jasmin 的编程语言编写了 lexer-parser-analyzer-optimizer-generator 组合,因此它正在生成 JVM 代码。我上传了代码here;有趣的部分应该是source code itself。在文件夹bytecode/InsanelyFastByteCodeCreator.java 中,您可以找到一段将 AST 树转换为 Jasmin 汇编器的输入格式的代码。这很简单。

    源语言(由 lexer-parser-analyzer 转换为 AST)是 Java 的一个子集,称为 MiniJava。它缺少一些“复杂”的特性,如继承、构造函数、静态方法、私有字段和方法。这些功能都不难实现,但是还有另一个任务是编写一个 x86 后端(以便生成机器汇编程序),如果你没有处理其中一些事情的 JVM,这些事情往往会变得困难。

    如果您对奇怪的类名感到疑惑:大学项目的任务是将 AST 转换为 SSA Graph(表示输入代码),优化该图,然后将其转换为 Java字节码。这大约是项目工作的 ¾,InsanlyFastByteCodeCreator 只是测试所有内容的捷径。

    看看 Jon Meyer 和 Troy Downing 的“Java 虚拟机”一书。本书大量引用了 Jasmin 汇编器;这对于理解 JVM 内部非常有帮助。

    【讨论】:

    • 谢谢你的回答,我去看看Jasmin。如果你能上传源代码,我会很高兴,这样我可以看看。关于你推荐的书,它看起来很有趣,但它已经绝版并且很旧了:(。
    • 这本书是非常便宜的二手书。我花了几美元找到了一本。
    • 看看我上面的编辑,如果您有任何问题,我很乐意为您提供帮助。
    • “源代码本身”的链接已损坏。虽然我猜这是 8 年后的预期。
    • @LlewVallis,如果我正确解释所有信息,代码似乎在这里:github.com/replimoc/compiler
    【解决方案2】:

    当然曾经可以用Java写一门新的语言。使用 Java 反射 API,您可以实现很多目标。如果速度不太重要,我会优先考虑 Java 而不是 ASM。 Java (恕我直言) 中的编程更容易且不易出错。看看 RPN 语言7th。 它完全是用 Java 编写的。

    【讨论】:

      【解决方案3】:

      上学期我参加了“编译器构造”课程。我们的项目正是您想要做的。

      我用来编写语言的语言是Scala。它在 JVM 上运行,但支持许多 Java 不支持的高级功能(仍然与纯 Java JVM 完全兼容)。

      为了输出 java 字节码,我使用了Scala CAFEBABE library。有据可查,您无需深入了解 Java 类即可了解该做什么。

      除了本书之外,我认为您可以通过我们在课程中完成的labs 找到很多信息。

      【讨论】:

      • 这听起来像是一门很棒的课程。您介意分享您的笔记或代码吗?
      • 没问题,我会检查我的备份在哪里,并在此处发布链接,以便您尽快下载。
      • 很好,我一直在寻找一个针对 JVM 的动手编译器课程,所有材料都在线自学。
      【解决方案4】:

      首先我会退后一步,修改我的编译器以输出实际的 Java 而不是 Java 字节码(这意味着创建的翻译器比编译器更多),并使用任何方便的 Java 环境编译 Java 输出(这可能会生成比我自己的编译器更好的目标代码)。

      您可以使用相同的技术(例如,编译为 C#)来生成 CLI 字节码,或编译为 Pascal 以生成 P 代码等。

      不清楚为什么要考虑使用 Java 代码而不是使用自己的 VM,但如果是为了性能,那么当然你也应该考虑编译成实际的机器代码。

      【讨论】:

      • 为 JVM 编译将允许一个人的代码比编译为本机代码更广泛地运行。此外,编译为字节码将使代码能够完成一些 Java 语言本身无法完成的事情。
      【解决方案5】:

      上周末,我问自己同样的问题,将我的玩具语言移植到 JVM。

      我只花几个小时搜索信息,所以请谨慎对待这些参考资料。

      • 语言实现模式。 我讨厌antlr,但这本书看起来很不错。如果你也不喜欢 antlr,有一个很好的关于解析的“Parsing Techniques. A Practical Guide”。

        学习构建配置文件阅读器、数据阅读器、模型驱动的代码生成器、源代码到源代码的翻译器、源代码分析器和解释器。您不需要计算机科学背景——ANTLR 的创建者 Terence Parr 通过将语言实现分解为最常见的设计模式来揭开它的神秘面纱。逐个模式,您将学习实现自己的计算机语言所需的关键技能。

        第 10 章用 30 页(为了加快 IMO)涵盖了这个主题。但是还有其他章节可能您会感兴趣。

        • 10 构建字节码解释器
          • 10.1 编程字节码解释器。 .
          • 10.2 定义汇编语言语法
          • 10.3 字节码机器架构。 . . . .
          • 10.4 从这里到哪里去。 . . . . . . . . .
          • 第 26 页。字节码汇编器。 . . . . . . . . . .
          • 第 27 页。基于堆栈的字节码解释器。 . .
          • 第 28 页。基于寄存器的字节码解释器
          http://pragprog.com/titles/tpdsl/language-implementation-patterns
        • Lua 5.0 的实现 这是一篇关于寄存器的好论文—— 基于字节码的机器。即使是为了它,也要阅读它。

        • Lisp in Small Pieces. 这本书教如何编写 2 个 schme 编译器来编译为 C。从这本书中可以学到很多东西。我拥有这本书的副本,对于任何有趣的是 lisp 的人来说,这真的很好,但也许不是你的那杯茶。

          这是对整个 Lisp 语言家族(即 Lisp、Scheme 和相关方言)的语义和实现的全面说明。它描述了 11 个解释器和 2 个编译器......

        http://www.amazon.com/Lisp-Small-Pieces-Christian-Queinnec/dp/0521562473

      检查基于寄存器的虚拟机 Dalvik7 虚拟机。 DVM 对从 Java 编译器编译的 Java 类文件转换而来的字节码进行操作。

      有一个关于主题 jvm-languages 的邮件列表。

      您打算将代码上传到任何地方吗?我想看看。

      【讨论】:

      • Are you planning to upload the code to anyplace? 我不为那个代码感到骄傲:( ...我可能会重写整个事情。无论如何,如果我这样做,我会告诉你。非常感谢你的建议。
      【解决方案6】:

      如果您还不知道,我建议您先了解 JVM 汇编的工作原理。

      许多指令的形式为?name,其中?i,如果指令适用于整数类型,a,如果它适用于引用类型。

      基本上,JVM 是一个没有寄存器的堆栈机器,因此所有指令都直接在堆栈上处理数据。您可以使用?push/?pop 推送/弹出数据,并使用?store/?load 在局部变量(由偏移量引用的堆栈位置)和堆栈顶部之间移动数据。其他一些重要说明是invoke???if_???

      对于my university's compiler course,我们使用Jasmin 来组装程序。我不知道这是否是最好的方法,但至少这是一个容易开始的地方。

      Here is an instruction reference 用于旧版本的 JVM,它包含的指令可能比新版本少。

      【讨论】:

        【解决方案7】:

        我想看看也许 另一种针对 JVM 的语言 像 Clojure、Jython 或 JRuby。但所有 这些语言非常高级 并且复杂(创建一个编译器 为他们)。

        建议:你可以看看Lua Programming Language,有它的JVM实现,比如LuaJ

        轻量级、快速、以 Java 为中心的 Lua 解释器为 J2ME 和 J2SE 编写, 带有基本的、字符串的库, 表、包、数学、io、os、调试 和协程包,一个编译器, luajava 绑定和 JSR-233 可插入的脚本引擎绑定。

        (不要与使用带有 JNI 方法的本机库的 LuaJava 混淆。)

        【讨论】:

        • 谢谢。我去看看
        【解决方案8】:

        ASM 可以作为生成字节码的解决方案。首先,请查看有关从 manual 生成 元素 的主题。

        【讨论】:

          猜你喜欢
          • 2014-11-17
          • 2013-02-25
          • 2011-04-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-23
          • 2018-03-26
          相关资源
          最近更新 更多