diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cljcc/analyzer.clj | 67 | ||||
| -rw-r--r-- | src/cljcc/compiler.clj | 4 | ||||
| -rw-r--r-- | src/cljcc/driver.clj | 2 | ||||
| -rw-r--r-- | src/cljcc/parser.clj | 54 | ||||
| -rw-r--r-- | src/cljcc/tacky.clj | 55 |
5 files changed, 120 insertions, 62 deletions
diff --git a/src/cljcc/analyzer.clj b/src/cljcc/analyzer.clj index 5970be4..b8b0141 100644 --- a/src/cljcc/analyzer.clj +++ b/src/cljcc/analyzer.clj @@ -8,11 +8,13 @@ ([] (unique-identifier "analyzer")) ([identifier] (u/create-identifier! identifier))) +(declare resolve-block) + (defn- resolve-exp [e mp] (condp = (:exp-type e) :constant-exp e :variable-exp (if (contains? mp (:identifier e)) - (p/variable-exp-node (get mp (:identifier e))) + (p/variable-exp-node (:name (get mp (:identifier e)))) (throw (ex-info "Undeclared variable seen." {:variable e}))) :assignment-exp (let [left (:left e) right (:right e) @@ -33,11 +35,12 @@ (throw (ex-info "Analyzer error. Invalid expression type" {:exp e})))) (defn- resolve-declaration [d mp] - (if (contains? mp (:identifier d)) + (if (and (contains? mp (:identifier d)) (:from-current-block (get mp (:identifier d)))) (throw (ex-info "Analyzer error. Duplicate variable declaration." {:declaration d})) (let [ident (:identifier d) unique-name (unique-identifier ident) - updated-mp (assoc mp ident unique-name) + updated-mp (assoc mp ident {:name unique-name + :from-current-block true}) init (when (:initial d) (resolve-exp (:initial d) updated-mp))] (if init {:declaration (p/declaration-node unique-name init) @@ -55,6 +58,11 @@ (resolve-statement (:else-statement s) mp)) (p/if-statement-node (resolve-exp (:condition s) mp) (resolve-statement (:then-statement s) mp))) + :compound (let [updated-mp (zipmap (keys mp) + (map (fn [m] + (update m :from-current-block (fn [_] false))) + (vals mp)))] + (p/compound-statement-node (:block (resolve-block (:block s) updated-mp)))) :empty (p/empty-statement-node) (throw (ex-info "Analyzer error. Invalid statement." {:statement s})))) @@ -62,22 +70,39 @@ (let [type (:type item)] (cond (= type :declaration) (let [v (resolve-declaration item mp)] - {:item (:declaration v) + {:block-item (:declaration v) :variable-map (:variable-map v)}) - (= type :statement) {:item (resolve-statement item mp) + (= type :statement) {:block-item (resolve-statement item mp) :variable-map mp} :else (throw (ex-info "Analyzer Error. Invalid statement/declaration." {item item}))))) +(defn- resolve-block + ([block] + (resolve-block block {})) + ([block var-mp] + (reduce (fn [acc block-item] + (let [v (resolve-block-item block-item (:variable-map acc))] + {:block (conj (:block acc) (:block-item v)) + :variable-map (:variable-map v)})) + {:block [] + :variable-map var-mp} + block))) + (defn- validate-function [f] - (let [updated-body (reduce - (fn [acc item] - (let [v (resolve-block-item item (:variable-map acc))] - {:body (conj (:body acc) (:item v)) - :variable-map (:variable-map v)})) - {:body [] - :variable-map {}} - (:body f))] - (assoc f :body (:body updated-body)))) + (let [updated-body (resolve-block (:body f))] + (assoc f :body (:block updated-body)))) + +(comment + + (resolve-block + [{:type :declaration + :identifier "a", + :initial {:type :exp, :exp-type :constant-exp, :value 1}} + {:type :statement, + :statement-type :return, + :value {:type :exp, :exp-type :constant-exp, :value 0}}]) + + ()) (defn validate [ast] (map validate-function ast)) @@ -94,19 +119,17 @@ (pp/pprint (validate-from-src "int main (void) { -; -return 0; +int a = 3; +{ + int a = a = 4; +} +return a; }")) (pp/pprint (validate-from-src "int main (void) { -int x; -int a = -1; -int b = 2; - -int c = b = 4 + 4; -return 12 / 12321312 + 12312 % 4; +int x = 1 + x; }")) ()) diff --git a/src/cljcc/compiler.clj b/src/cljcc/compiler.clj index a7ee8c9..c14fc53 100644 --- a/src/cljcc/compiler.clj +++ b/src/cljcc/compiler.clj @@ -2,7 +2,8 @@ (:require [cljcc.parser :as p] [clojure.pprint :as pp] [cljcc.tacky :as t] - [cljcc.lexer :as l])) + [cljcc.lexer :as l] + [cljcc.analyzer :as a])) (def registers #{:ax :dx :r10 :r11 :cx :cl}) @@ -309,6 +310,7 @@ (-> source l/lex p/parse + a/validate t/tacky-generate tacky-ast->assembly)) diff --git a/src/cljcc/driver.clj b/src/cljcc/driver.clj index 4ad0051..b7b14c1 100644 --- a/src/cljcc/driver.clj +++ b/src/cljcc/driver.clj @@ -78,7 +78,7 @@ (let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i") file (io/file preprocessed-file-path) source (slurp file) - output (t/tacky-generate (p/parse (l/lex source)))] + output (t/tacky-generate (a/validate (p/parse (l/lex source))))] (log/info (str "Successfully generated Tacky IR.\n" (with-out-str (pp/pprint output)))))) diff --git a/src/cljcc/parser.clj b/src/cljcc/parser.clj index 6525c24..f1fac64 100644 --- a/src/cljcc/parser.clj +++ b/src/cljcc/parser.clj @@ -4,7 +4,15 @@ [cljcc.token :as t] [clojure.pprint :as pp])) -(declare parse parse-exp parse-statement) +(declare parse parse-exp parse-statement parse-block) + +(defn- parse-repeatedly [tokens parse-f end-kind] + (loop [tokens tokens + res []] + (if (= end-kind (:kind (first tokens))) + [res tokens] + (let [[node rst] (parse-f tokens)] + (recur rst (conj res node)))))) (defn- keyword->type [k] (condp = k @@ -21,12 +29,6 @@ (throw (ex-info "Parser Error." {:expected kind :actual (:kind token)})))) -(defn- expect-in [kinds [{kind :kind :as token} & rst]] - (if (contains? kinds kind) - [token rst] - (throw (ex-info "Parser Error." {:expected kinds - :actual token})))) - (defn constant-exp-node [v] {:type :exp :exp-type :constant-exp @@ -111,6 +113,11 @@ {:type :statement :statement-type :empty}) +(defn compound-statement-node [block] + {:type :statement + :statement-type :compound + :block block}) + (defn if-statement-node ([cond then] (if-statement-node cond then nil)) @@ -151,6 +158,10 @@ [else-stmt tokens] (parse-statement tokens)] [(if-statement-node exp-node then-stmt else-stmt) tokens])))) +(defn- parse-compound-statement [tokens] + (let [[block-items tokens] (parse-block tokens)] + [(compound-statement-node block-items) tokens])) + (defn- parse-statement "Parses a single statement. Expects a semicolon at the end." [[{kind :kind} :as tokens]] @@ -158,6 +169,7 @@ (= kind :semicolon) (parse-empty-statement tokens) (= kind :kw-return) (parse-return-statement tokens) (= kind :kw-if) (parse-if-statement tokens) + (= kind :left-curly) (parse-compound-statement tokens) :else (parse-expression-statement tokens))) (defn declaration-node @@ -185,13 +197,11 @@ (parse-declaration tokens) (parse-statement tokens))) -(defn- parse-repeatedly [tokens parse-f end-kind] - (loop [tokens tokens - res []] - (if (= end-kind (:kind (first tokens))) - [res tokens] - (let [[node rst] (parse-f tokens)] - (recur rst (conj res node)))))) +(defn- parse-block [tokens] + (let [[_ tokens] (expect :left-curly tokens) + [block-items tokens] (parse-repeatedly tokens parse-block-item :right-curly) + [_ tokens] (expect :right-curly tokens)] + [block-items tokens])) (defn- parse-function [tokens] (let [[fn-type-token rst] (expect :kw-int tokens) @@ -199,9 +209,7 @@ [_ rst] (expect :left-paren rst) [fn-parameter-token rst] (expect :kw-void rst) [_ rst] (expect :right-paren rst) - [_ rst] (expect :left-curly rst) - [block-items rst] (parse-repeatedly rst parse-block-item :right-curly) - [_ rst] (expect :right-curly rst)] + [block-items rst] (parse-block rst)] [{:type :function :return-type (keyword->type (:kind fn-type-token)) :identifier (:literal fn-identifier-token) @@ -228,10 +236,14 @@ (pp/pprint (parse-from-src " int main(void) { -if (123) - 123 ? 4 : 3; -else - 523423 = 123; +int a = 1; + { +int a = 2; + { +int a = 4; +} +} +return 0; }")) (pp/pprint diff --git a/src/cljcc/tacky.clj b/src/cljcc/tacky.clj index 8bb9c6d..a28ca80 100644 --- a/src/cljcc/tacky.clj +++ b/src/cljcc/tacky.clj @@ -233,7 +233,7 @@ (defn- exp-instructions [exp] (expression-handler exp)) -(declare statement->tacky-instruction) +(declare statement->tacky-instruction block-item->tacky-instruction) (defn if-statement-handler [s] (let [cond-exp (exp-instructions (:condition s)) @@ -256,6 +256,9 @@ then-instructions (label-instruction end-label)]))) +(defn- compound-statement-handler [s] + (flatten (map block-item->tacky-instruction (:block s)))) + (defn- statement->tacky-instruction [s] (condp = (:statement-type s) :return (let [e (exp-instructions (:value s)) @@ -264,6 +267,7 @@ (conj (vec instructions) (return-instruction val))) :expression [(:instructions (exp-instructions (:value s)))] :if (if-statement-handler s) + :compound (compound-statement-handler s) :empty [] (throw (ex-info "Tacky error. Invalid statement." {:statement s})))) @@ -301,30 +305,47 @@ a/validate tacky-generate)) +(def ex + {:type :function, + :return-type "int", + :identifier "main", + :parameters :kw-void, + :body + [{:type :declaration, + :identifier "a.0", + :initial {:type :exp, :exp-type :constant-exp, :value 3}} + {:type :statement, + :statement-type :compound, + :block + [{:type :declaration, + :identifier "a.1", + :initial + {:type :exp, + :exp-type :assignment-exp, + :assignment-operator :assignment, + :left {:type :exp, :exp-type :variable-exp, :identifier "a.1"}, + :right {:type :exp, :exp-type :constant-exp, :value 4}}}]} + {:type :statement, + :statement-type :return, + :value {:type :exp, :exp-type :variable-exp, :identifier "a.0"}}]}) + (comment (pp/pprint (tacky-from-src - "int main(void) { -int a = 11; - int b = 12; - a &= 0 || b; - b ^= a || 1; - - int c = 14; - c |= a || b; - - int d = 16; - d >>= c || d; - - int e = 18; - e <<= c || d; - return (a == 1 && b == 13 && c == 15 && d == 8 && e == 36); + "int main (void) { +int a = 3; +{ + int a = a = 4; +} +return a; }")) (pp/pprint (tacky-generate - (p/parse (l/lex "int main(void) {return -(~1);}")))) + (p/parse (l/lex "int main(void) { +int a = 1; +return 1;}")))) (pp/pprint (tacky-generate |
