aboutsummaryrefslogtreecommitdiff
path: root/src/cljcc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cljcc')
-rw-r--r--src/cljcc/analyzer.clj67
-rw-r--r--src/cljcc/compiler.clj4
-rw-r--r--src/cljcc/driver.clj2
-rw-r--r--src/cljcc/parser.clj54
-rw-r--r--src/cljcc/tacky.clj55
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