Clojure编译器开发中的惯用语

4
我想探索使用Clojure进行编译器开发的能力,但我找不到可以入手的示例。
我是一个完全的新手(来自Ruby),但我相信Clojure应该是这个目的的理想选择。
让我们明确一下我在寻找什么:
  • 从Clojure中定义的简单AST开始(比如一个简单的顺序语言:if、while、func、assign、expression)
  • 为这个AST编写一个简单的visitor(例如漂亮的打印机)
  • 我对词法分析/解析不是很感兴趣(因为我认为s表达式已足够满足我的DSL语法要求)
Clojure中正确的习惯用法是什么?

你不必仅限于 Clojure 的示例来搜索。还有许多其他 Lisp 的示例可以轻松地移植到 Clojure 中。例如,http://bit.ly/3t1DX 或 http://bit.ly/I2LFdr。 - SK-logic
我同意。这个评论也适用于一般的函数式语言,但我想限制在Clojure上,因为它似乎比旧的Lisp更容易接近/有吸引力,适合非Lisp程序员。有人说过“最好的Lisp”? - JCLL
不,函数式语言总体来说是一个完全不同的话题。Clojure 是一种 Lisp,从某种意义上说,它具有 Lisp 的最重要部分——一个体面的宏系统。这实际上使 Lisp 与其他任何语言相比更适合编译器开发。看看我的第二个链接,它使用了一种专门的 DSL 来定义访问者。这正是 Lisp 做事情的惯用方式。而且在所有的 Lisp 中都是如此。至于“最好的 Lisp”,我个人不会同意。没有 cons 的 Lisp 不太像 Lisp。而 recur 真是太可怕了。 - SK-logic
顺便提一下,你也可以看看Racket - 整个东西非常出色,并且它内部实现了许多不同的编译器。它可能是最丰富的惯用Lisp编译器代码的单一来源。 - SK-logic
1个回答

4
这是我能想到的最简单的例子,使用从带有关键字运算符的s表达式构建的AST树:
;; functions map, can be easily extended with new functions
;; map is of keyword -> code generating function
(def funcs {:if 
                 (fn [cond exp1 exp2] `(if ~cond ~exp1 ~exp2))
            :neg 
                 (fn [exp1] `(- 0 ~exp1))
            :plus 
                 (fn [& exps] `(+ ~@exps))})

;; compile directly to Clojure source code
(defn my-compile [code]
 (cond 
   (sequential? code)   ;; if we have a list, look up the function in funcs
     (cons (funcs (first code)) (map compile (rest code))) 
   :else                ;; treat anything else as a constant literal
     code))

;; example compilation to a Clojure expression
(my-compile `(:if true (:neg 10) (:plus 10 20 30)))
=> (if true (clojure.core/- 0 10) (clojure.core/+ 10 20 30))

;; evaluate compiled code
(eval (my-compile `(:if true (:neg 10) (:plus 10 20 30))))
=> -10

希望这些足以为您提供一些想法/让您开始了解。显而易见的扩展包括:

  • 将代码编译成带有元数据的AST树,而不是直接编译成Clojure源代码。Clojure defrecord 可以作为AST节点表示。
  • 添加其他运算符、循环结构、"goto"等。
  • 简单的优化,例如在编译时对常量表达式进行求值。
  • 拥有某种执行上下文,允许赋值、动态变量查找等操作。编译器输出可以是一个函数,它以初始上下文作为输入并返回最终上下文。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接