aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cljcc/analyzer.clj9
-rw-r--r--src/cljcc/parser.clj60
-rw-r--r--src/cljcc/token.clj6
3 files changed, 65 insertions, 10 deletions
diff --git a/src/cljcc/analyzer.clj b/src/cljcc/analyzer.clj
index 7d82f53..5970be4 100644
--- a/src/cljcc/analyzer.clj
+++ b/src/cljcc/analyzer.clj
@@ -27,6 +27,9 @@
(resolve-exp (:right e) mp)
(:binary-operator e))
:unary-exp (p/unary-exp-node (:unary-operator e) (resolve-exp (:value e) mp))
+ :conditional-exp (p/conditional-exp-node (resolve-exp (:left e) mp)
+ (resolve-exp (:middle e) mp)
+ (resolve-exp (:right e) mp))
(throw (ex-info "Analyzer error. Invalid expression type" {:exp e}))))
(defn- resolve-declaration [d mp]
@@ -46,6 +49,12 @@
(condp = (:statement-type s)
:return (p/return-statement-node (resolve-exp (:value s) mp))
:expression (p/expression-statement-node (resolve-exp (:value s) mp))
+ :if (if (:else-statement s)
+ (p/if-statement-node (resolve-exp (:condition s) mp)
+ (resolve-statement (:then-statement s) mp)
+ (resolve-statement (:else-statement s) mp))
+ (p/if-statement-node (resolve-exp (:condition s) mp)
+ (resolve-statement (:then-statement s) mp)))
:empty (p/empty-statement-node)
(throw (ex-info "Analyzer error. Invalid statement." {:statement s}))))
diff --git a/src/cljcc/parser.clj b/src/cljcc/parser.clj
index b3e7eeb..0aec1dc 100644
--- a/src/cljcc/parser.clj
+++ b/src/cljcc/parser.clj
@@ -4,7 +4,7 @@
[cljcc.token :as t]
[clojure.pprint :as pp]))
-(declare parse parse-exp)
+(declare parse parse-exp parse-statement)
(defn- keyword->type [k]
(condp = k
@@ -57,6 +57,13 @@
:left l
:right r})
+(defn conditional-exp-node [l m r]
+ {:type :exp
+ :exp-type :conditional-exp
+ :left l
+ :middle m
+ :right r})
+
(defn- parse-factor [[{kind :kind :as token} :as tokens]]
(cond
(= kind :number) [(constant-exp-node (:literal token)) (rest tokens)]
@@ -77,12 +84,17 @@
tokens rst]
(let [[{kind :kind :as _token} :as tokens] tokens]
(if (and (t/binary-op? kind) (>= (t/precedence kind) min-prec))
- (if (t/assignment-op? kind)
- (let [[_ tokens] (expect kind tokens)
- [right rst] (parse-exp tokens (t/precedence kind))]
- (recur [(assignment-exp-node left right kind)] rst))
- (let [[right rst] (parse-exp (rest tokens) (+ (t/precedence kind) 1))]
- (recur [(binary-exp-node left right kind)] rst)))
+ (cond
+ (t/assignment-op? kind) (let [[_ tokens] (expect kind tokens)
+ [right rst] (parse-exp tokens (t/precedence kind))]
+ (recur [(assignment-exp-node left right kind)] rst))
+ (= :question kind) (let [[_ tokens] (expect :question tokens)
+ [middle tokens] (parse-exp tokens)
+ [_ tokens] (expect :colon tokens)
+ [right tokens] (parse-exp tokens (inc (t/precedence kind)))]
+ (recur [(conditional-exp-node left middle right)] tokens))
+ :else (let [[right rst] (parse-exp (rest tokens) (inc (t/precedence kind)))]
+ (recur [(binary-exp-node left right kind)] rst)))
[left tokens])))))
(defn return-statement-node [e]
@@ -99,6 +111,19 @@
{:type :statement
:statement-type :empty})
+(defn if-statement-node
+ ([cond then]
+ {:type :statement
+ :statement-type :if
+ :condition cond
+ :then-statement then})
+ ([cond then else]
+ {:type :statement
+ :statement-type :if
+ :condition cond
+ :then-statement then
+ :else-statement else}))
+
(defn- parse-return-statement [tokens]
(let [[_ rst] (expect :kw-return tokens)
[exp-node rst] (parse-exp rst)
@@ -116,12 +141,26 @@
(let [[_ rst] (expect :semicolon tokens)]
[(empty-statement-node) rst]))
+(defn- parse-if-statement [tokens]
+ (let [[_ tokens] (expect :kw-if tokens)
+ [_ tokens] (expect :left-paren tokens)
+ [exp-node tokens] (parse-exp tokens)
+ [_ tokens] (expect :right-paren tokens)
+ [then-stmt tokens] (parse-statement tokens)
+ else? (= :kw-else (:kind (first tokens)))]
+ (if (not else?)
+ [(if-statement-node exp-node then-stmt) tokens]
+ (let [[_ tokens] (expect :kw-else tokens)
+ [else-stmt tokens] (parse-statement tokens)]
+ [(if-statement-node exp-node then-stmt else-stmt) tokens]))))
+
(defn- parse-statement
"Parses a single statement. Expects a semicolon at the end."
[[{kind :kind} :as tokens]]
(cond
(= kind :semicolon) (parse-empty-statement tokens)
(= kind :kw-return) (parse-return-statement tokens)
+ (= kind :kw-if) (parse-if-statement tokens)
:else (parse-expression-statement tokens)))
(defn declaration-node
@@ -192,9 +231,10 @@
(pp/pprint (parse-from-src "
int main(void) {
-int a = b = 4;
-int var0 = 2;
-var0 = 41;
+if (123)
+ 123 ? 4 : 3;
+else
+ 523423 = 123;
}"))
(pp/pprint
diff --git a/src/cljcc/token.clj b/src/cljcc/token.clj
index 883dda8..2da74fd 100644
--- a/src/cljcc/token.clj
+++ b/src/cljcc/token.clj
@@ -107,6 +107,8 @@
:logical-or 10
+ :question 5
+
:assignment 1
:assignment-plus 1
:assignment-multiply 1
@@ -128,6 +130,8 @@
(def chrs-kind-map
{\( :left-paren
\) :right-paren
+ \? :question
+ \: :colon
\{ :left-curly
\} :right-curly
\= :assignment
@@ -170,6 +174,8 @@
"return" :kw-return
"void" :kw-void
"int" :kw-int
+ "if" :kw-if
+ "else" :kw-else
:identifier))
(defn create