aboutsummaryrefslogtreecommitdiff
path: root/src/cljcc/tacky.clj
diff options
context:
space:
mode:
authorShagun Agrawal <agrawalshagun07@gmail.com>2024-08-03 02:45:43 +0530
committerShagun Agrawal <agrawalshagun07@gmail.com>2024-08-03 02:45:43 +0530
commite0de6ddf16a37435966e31a73b4425a0300dc1e6 (patch)
treee99d8a9eeec4ae923e3c86e0ec436a542fcabe82 /src/cljcc/tacky.clj
parentec2e54a2977ff30e51eee15f464e52dc1e8390ab (diff)
Add tacky IR stage
Add Tacky IR stage General formatting etc
Diffstat (limited to 'src/cljcc/tacky.clj')
-rw-r--r--src/cljcc/tacky.clj118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/cljcc/tacky.clj b/src/cljcc/tacky.clj
new file mode 100644
index 0000000..e25c87f
--- /dev/null
+++ b/src/cljcc/tacky.clj
@@ -0,0 +1,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))
+
+ ,)