aboutsummaryrefslogtreecommitdiff
path: root/src/cljcc
diff options
context:
space:
mode:
authorShagun Agrawal <agrawalshagun07@gmail.com>2024-08-22 22:45:34 +0530
committerShagun Agrawal <agrawalshagun07@gmail.com>2024-08-22 22:45:34 +0530
commit7a3e7151ea7e05952ec58648d71d9ed33168109d (patch)
treed1fdb030ccbf3e91abdab0827e8cedac1f895219 /src/cljcc
parente88635d6d32055cc7d3a4ccf16c1a74cb5b88d1c (diff)
Add tacky generation for declarations, statements
Diffstat (limited to 'src/cljcc')
-rw-r--r--src/cljcc/analyzer.clj4
-rw-r--r--src/cljcc/tacky.clj70
2 files changed, 61 insertions, 13 deletions
diff --git a/src/cljcc/analyzer.clj b/src/cljcc/analyzer.clj
index 5eb03ee..504e8ab 100644
--- a/src/cljcc/analyzer.clj
+++ b/src/cljcc/analyzer.clj
@@ -68,7 +68,7 @@
{:body []
:variable-map {}}
(:body f))]
- (assoc f :body updated-body)))
+ (assoc f :body (:body updated-body))))
(defn validate [ast]
(map validate-function ast))
@@ -90,7 +90,7 @@ return 0;
}"))
(pp/pprint
- (p/parse-from-src
+ (validate-from-src
"int main (void) {
int x;
int a = -1;
diff --git a/src/cljcc/tacky.clj b/src/cljcc/tacky.clj
index b7d6e2e..ffa85b1 100644
--- a/src/cljcc/tacky.clj
+++ b/src/cljcc/tacky.clj
@@ -3,7 +3,8 @@
[clojure.pprint :as pp]
[cljcc.lexer :as l]
[cljcc.util :as u]
- [cljcc.parser :as p]))
+ [cljcc.parser :as p]
+ [cljcc.analyzer :as a]))
(defn- variable
([]
@@ -12,6 +13,10 @@
{:type :variable
:value (u/create-identifier! (str identifier))}))
+(defn- parsed-var->tacky-var [v]
+ {:type :variable
+ :value (:identifier v)})
+
(defn- label
([] (label "label"))
([ident] (u/create-identifier! ident)))
@@ -158,6 +163,13 @@
(copy-instruction (constant 1) res)
(label-instruction false-label)])}))
+(defn- assignment-exp-handler [e]
+ (let [var (parsed-var->tacky-var (:left e)) ; guaranteed to be parsed variable
+ rhs (expression-handler (:right e))]
+ {:val var
+ :instructions (flatten [(:instructions rhs)
+ (copy-instruction (:val rhs) var)])}))
+
(defn- expression-handler [e]
(when-let [exp-type (:exp-type e)]
(cond
@@ -168,30 +180,66 @@
:logical-and (logical-and-handler e)
:logical-or (logical-or-handler e)
(binary-expr-handler e)))
+ (= exp-type :variable-exp) {:val (parsed-var->tacky-var e)}
+ (= exp-type :assignment-exp) (assignment-exp-handler e)
:else (throw (ex-info "Tacky error. Invalid expression." {e e})))))
(defn- exp-instructions [exp]
(expression-handler exp))
-(defn- ret-instructions [exp]
- (let [e (exp-instructions exp)
- val (:val e)
- instructions (:instructions e)]
- (conj (vec instructions) (return-instruction val))))
-
-(defn ast-statement->tacky-instructions [statement]
- (remove nil? (ret-instructions (:value statement))))
+(defn- statement->tacky-instruction [s]
+ (condp = (:statement-type s)
+ :return (let [e (exp-instructions (:value s))
+ val (:val e)
+ instructions (:instructions e)]
+ (conj (vec instructions) (return-instruction val)))
+ :expression [(:instructions (exp-instructions (:value s)))]
+ :empty []
+ (throw (ex-info "Tacky error. Invalid statement." {:statement s}))))
+
+(defn- declaration->tacky-instruction [d]
+ (when (:initial d)
+ (let [var (parsed-var->tacky-var d) ; only needs :identifier key in declaration
+ rhs (exp-instructions (:initial d))]
+ (flatten [(:instructions rhs) (copy-instruction (:val rhs) var)]))))
+
+(defn- block-item->tacky-instruction [item]
+ (condp = (:type item)
+ :statement (statement->tacky-instruction item)
+ :declaration (declaration->tacky-instruction item)
+ (throw (ex-info "Tacky error. Invalid block item." {:item item}))))
+
+(defn- function-body->tacky-instructions [body]
+ (let [v (->> body
+ (remove nil?)
+ (map block-item->tacky-instruction)
+ flatten
+ (remove nil?))]
+ (conj (vec v) (return-instruction (constant 0)))))
(defn tacky-generate [ast]
(map (fn [f]
(-> f
- (assoc :instructions (flatten (map ast-statement->tacky-instructions (:statements f))))
- (dissoc :statements)))
+ (assoc :instructions (function-body->tacky-instructions (:body f)))
+ (dissoc :body)))
ast))
+(defn tacky-from-src [src]
+ (-> src
+ l/lex
+ p/parse
+ a/validate
+ tacky-generate))
+
(comment
(pp/pprint
+ (tacky-from-src
+ "int main(void) {
+2 + 2;
+}"))
+
+ (pp/pprint
(tacky-generate
(p/parse (l/lex "int main(void) {return -(~1);}"))))