aboutsummaryrefslogtreecommitdiff
path: root/src/cljcc/tacky.clj
blob: e25c87f72ee51e9f00de16e2efe9752b7d9d65ec (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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
(ns cljcc.tacky
  (:require
   [clojure.pprint :as pp]
   [instaparse.core :as insta]
   [cljcc.parser :as p]))

(def counter "Global integer counter for generating unique identifier names." (atom 0))

(defn create-identifier
  "Returns a unique identifier. Used for generating tacky variable names."
  ([]
   (create-identifier "tmp"))
  ([identifier]
   (let [n @counter
         _ (swap! counter #(+ % 1))]
     (str identifier "." n))))

(defn variable
  ([]
   {:type :variable
    :value (create-identifier)})
  ([^String identifier]
   {:type :variable
    :value (create-identifier identifier)}))

(defn constant [^String v]
  {:type :constant
   :value (Long. v)})

(defn unop-operator [^String unop]
  (condp = unop
    "~" :complement
    "-" :negate))

(defn unary-instruction [unop src dst]
  {:type :unary
   :unary-operator unop
   :dst dst
   :src src})

(defn return-instruction [val]
  {:type :return
   :val val})

(defn exp-instructions [exp]
  (when-let [expr (second exp)]
    (condp = (first expr)
      :constant {:val (constant (second expr))}
      :unop-exp (let [inner (exp-instructions (nth expr 2))
                      dst (variable)
                      src (:val inner)
                      unop (unop-operator (second (second expr)))
                      inst (unary-instruction unop  src dst)]
                  {:val dst
                   :instructions (conj (:instructions inner) inst)}))))

(defn ret-instructions [exp]
  (let [e (exp-instructions exp)
        val (:val e)
        instructions (:instructions e)]
    (conj instructions (return-instruction val))))

(defn statement-transform [_ret-keyword exp]
  (reverse (ret-instructions exp)))

(defn tacky-generate [ast]
  (insta/transform {:statement statement-transform} ast))

(comment

  (reset! counter 0)

  (pp/pprint (tacky-generate (p/parse "int main(void) {return -~-8;}")))

  (pp/pprint
   (exp-instructions [:exp [:constant "2"]]))

  (pp/pprint
   (exp-instructions [:exp [:constant "2"]]))

  (pp/pprint
   (exp-instructions [:exp [:unop-exp [:unop "-"] [:exp [:constant "2"]]]]))

  (def ex-exp
    [:exp
     [:unop-exp
      [:unop "-"]
      [:exp
       [:unop-exp
        [:unop "~"]
        [:exp [:unop-exp [:unop "-"] [:exp [:constant "8"]]]]]]]])

  (def ex-ret
    [:statement "return"
     [:exp
      [:unop-exp
       [:unop "-"]
       [:exp
        [:unop-exp
         [:unop "~"]
         [:exp [:unop-exp [:unop "-"] [:exp [:constant "8"]]]]]]]]])

  (pp/pprint
   (exp-instructions ex-exp))

  (pp/pprint
   (ret-instructions ex-ret))

 (def exprg
   "int main(void) {
     return -(~(-8));
   }")

 (pp/pprint (parse "int main(void) {return 2;}"))

 (pp/pprint (parse exprg))

 ,)