aboutsummaryrefslogtreecommitdiff
path: root/src/cljcc/compiler.clj
blob: 9e0a9a4a643aa05bdf7978dcb64acc2309bfded3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
(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))
      (concat fn-assembly [linux-assembly-end])
      fn-assembly)))

(conj [1 2 3] 1)

(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)

 ,)