diff options
| author | Shagun Agrawal <agrawalshagun07@gmail.com> | 2024-07-24 18:51:24 +0530 |
|---|---|---|
| committer | Shagun Agrawal <agrawalshagun07@gmail.com> | 2024-07-24 18:51:24 +0530 |
| commit | ab32a441a6aafb29cf615e14dcd284e9f62786ef (patch) | |
| tree | c4f3cdd4e75bc0e9a0f6f2bf5405fccc0bbe87ad /src/cljcc/compiler.clj | |
| parent | 76041390b66ae1a7e903bfd40b3b176dc895b385 (diff) | |
Add initial compiler implementation
Diffstat (limited to 'src/cljcc/compiler.clj')
| -rw-r--r-- | src/cljcc/compiler.clj | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/src/cljcc/compiler.clj b/src/cljcc/compiler.clj new file mode 100644 index 0000000..6a4d13d --- /dev/null +++ b/src/cljcc/compiler.clj @@ -0,0 +1,87 @@ +(ns cljcc.compiler + (:require [cljcc.parser :as p] + [instaparse.core :as insta] + [clojure.edn :as edn] + [cljcc.util :refer [get-os]] + [clojure.string :as str])) + +(defn transform-function [return-type identifier args body] + {:op :function + :identifier identifier + :args args + :body body}) + +(defn ast->compile [ast] + (insta/transform + {:function transform-function + :identifier str + :constant (comp edn/read-string str) + :exp (fn [v] + {:op :movl + :src v + :dst :eax}) + :statement (fn [_ v] + [v {:op :ret}])} + ast)) + +(defn handle-function-name [name] + (if (= :mac (get-os)) + (str "_" name) + name)) + +(defn emit-instruction + ([inst] + (str " " (symbol inst))) + ([inst src dst] + (str " " (symbol inst) " " "$" src ", %" (symbol dst)))) + +(defn statement-fn [stmt] + (condp = (:op stmt) + :ret (emit-instruction :ret) + :movl (emit-instruction (:op stmt) (:src stmt) (:dst stmt)))) + +(statement-fn {:op :movl :src 1 :dst :eax}) + +(defn emit-function-assembly [fn-ast] + (let [name (handle-function-name (:identifier fn-ast)) + globl-line (str " .globl " name) + fn-start-line (str name ":") + body-statements (map statement-fn (:body fn-ast))] + (flatten [globl-line fn-start-line body-statements]))) + +(def linux-assembly-end ".section .note.GNU-stack,\"\",@progbits") + +(defn il->assembly [il] + (let [fn-assembly (emit-function-assembly (first il))] + (if (= :linux (get-os)) + (conj fn-assembly linux-assembly-end) + fn-assembly))) + +(defn join-assembly [assembly-lines] + (str/join "\n" assembly-lines)) + +(defn run-compile [source] + (-> source + p/parse + ast->compile + il->assembly + join-assembly)) + +(comment + + (def ex "int main(void) {return 2;}") + + (-> ex + p/parse) + + (-> ex + p/parse + ast->compile) + + (-> ex + p/parse + ast->compile + il->assembly + join-assembly) + + ,) |
