aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShagun Agrawal <agrawalshagun07@gmail.com>2024-08-18 14:30:04 +0530
committerShagun Agrawal <agrawalshagun07@gmail.com>2024-08-18 14:30:04 +0530
commit702daa89c7f451f01933e659b59a4daaa01f10ab (patch)
treee92040dceb734996a0df5d1dc5c5cba13d7bb925
parent9867129bf45bb620ca56715c74243de3bde9de3c (diff)
Fix tacky, assembly, emit phase for chapter 3
-rw-r--r--src/cljcc/emit.clj2
-rw-r--r--src/cljcc/parser.clj67
-rw-r--r--src/cljcc/tacky.clj66
-rw-r--r--src/cljcc/token.clj8
4 files changed, 82 insertions, 61 deletions
diff --git a/src/cljcc/emit.clj b/src/cljcc/emit.clj
index 514cd45..d18edb3 100644
--- a/src/cljcc/emit.clj
+++ b/src/cljcc/emit.clj
@@ -48,7 +48,7 @@
(let [operand (operand-emit (:operand instruction))
assembly-operator (condp = (:unary-operator instruction)
:complement "notl"
- :hyphen "negl"
+ :negate "negl"
(throw (AssertionError. (str "Invalid unary operator: " instruction))))]
[(format " %s %s" assembly-operator operand)]))
diff --git a/src/cljcc/parser.clj b/src/cljcc/parser.clj
index f1da784..e8f1791 100644
--- a/src/cljcc/parser.clj
+++ b/src/cljcc/parser.clj
@@ -1,8 +1,11 @@
(ns cljcc.parser
(:require
[cljcc.lexer :as l]
+ [cljcc.token :as t]
[clojure.pprint :as pp]))
+(declare parse parse-exp)
+
(defn- expect [kind [token & rst]]
(if (= kind (:kind token))
[token rst]
@@ -15,25 +18,59 @@
(throw (ex-info "Parser Error." {:expected kinds
:actual token}))))
-(defn- parse-exp [[{kind :kind :as token} :as tokens]]
+(defn- constant-exp-node [v]
+ {:type :exp
+ :exp-type :constant-exp
+ :value v})
+
+(defn- unary-exp-node [op v]
+ {:type :exp
+ :exp-type :unary-exp
+ :unary-operator op
+ :value v})
+
+(defn- binary-exp-node [l r op]
+ {:type :exp
+ :exp-type :binary-exp
+ :binary-operator op
+ :left l
+ :right r})
+
+(defn- parse-factor [[{kind :kind :as token} :as tokens]]
(cond
- (= kind :number) [{:type :exp
- :exp-type :constant-exp
- :value (:literal token)}
- (rest tokens)]
+ (= kind :number) [(constant-exp-node (:literal token)) (rest tokens)]
(contains?
#{:complement :hyphen} kind) (let [operator kind
- [e rst] (parse-exp (rest tokens))]
- [{:type :exp
- :exp-type :unary-exp
- :unary-operator operator
- :value e}
- rst])
+ [e rst] (parse-factor (rest tokens))]
+ [(unary-exp-node operator e) rst])
(= kind :left-paren) (let [[e rst] (parse-exp (rest tokens))
[_ rst] (expect :right-paren rst)]
[e rst])
- :else (throw (ex-info "Parser Error." {:expected "number, (, -, ~"
- :actual token}))))
+ :else (throw (ex-info "Parser Error. Malformed token." {:token token}))))
+
+(defn- precedence [kind]
+ (kind t/bin-ops))
+
+(defn- parse-exp
+ ([tokens]
+ (parse-exp tokens 0))
+ ([tokens min-prec]
+ (loop [[left rst] (parse-factor tokens)
+ tokens rst]
+ (let [[{kind :kind :as _token} :as tokens] tokens]
+ (if (and (contains? t/bin-ops kind) (>= (precedence kind) min-prec))
+ (let [[right rst] (parse-exp (rest tokens) (+ (precedence kind) 1))]
+ (recur [(binary-exp-node left right kind)] rst))
+ [left tokens])))))
+
+(comment
+
+ (pp/pprint (parse (l/lex "
+ int main(void) {
+ return -1 * 2 + 3;
+ }")))
+
+ ())
(defn- parse-return-statement [tokens]
(let [[_ rst] (expect :kw-return tokens)
@@ -88,12 +125,12 @@
(pp/pprint (parse (l/lex "
int main(void) {
- return -(~~~(2));
+ return 1 * 2 - 3 * (4 + 5);
}")))
(pp/pprint
(l/lex
- "int main(void) {return (((2)))}"))
+ "int main(void) {return 1 + 2;}"))
(pp/pprint
(l/lex "
diff --git a/src/cljcc/tacky.clj b/src/cljcc/tacky.clj
index 1d0af27..5f09181 100644
--- a/src/cljcc/tacky.clj
+++ b/src/cljcc/tacky.clj
@@ -27,23 +27,23 @@
{:type :constant
:value v})
-(defn- unary-operator [^String unop]
- (condp = unop
- "~" :complement
- "-" :negate))
+(defn- unary-operator [op]
+ (condp = op
+ :complement :complement
+ :hyphen :negate))
(defn- binary-operator [binop]
(condp = binop
- :add-exp :add
- :sub-exp :sub
- :mul-exp :mul
- :div-exp :div
- :mod-exp :mod
- :bit-and-exp :bit-and
- :bit-or-exp :bit-or
- :bit-xor-exp :bit-xor
- :bit-right-shift-exp :bit-right-shift
- :bit-left-shift-exp :bit-left-shift))
+ :plus :add
+ :hyphen :sub
+ :multiply :mul
+ :divide :div
+ :remainder :mod
+ :bit-and :bit-and
+ :bit-or :bit-or
+ :bit-xor :bit-xor
+ :bit-right-shift :bit-right-shift
+ :bit-left-shift :bit-left-shift))
(defn- unary-instruction [unary-operator src dst]
{:type :unary
@@ -62,21 +62,6 @@
{:type :return
:val val})
-(def binary-exprs
- #{:add-exp
- :sub-exp
- :mul-exp
- :mod-exp
- :div-exp
- :bit-and-exp
- :bit-or-exp
- :bit-xor-exp
- :bit-right-shift-exp
- :bit-left-shift-exp})
-
-(defn- binary-expr? [v]
- (contains? binary-exprs v))
-
(declare expression-handler)
(defn- constant-expr-handler [e]
@@ -86,18 +71,18 @@
(let [inner (expression-handler (:value e))
dst (variable)
src (:val inner)
- unary-operator (:unary-operator e)
+ unary-operator (unary-operator (:unary-operator e))
instruction (unary-instruction unary-operator src dst)]
{:val dst
:instructions (flatten [(:instructions inner) instruction])}))
(defn- binary-expr-handler [e]
- (let [e1 (expression-handler (nth e 1))
- e2 (expression-handler (nth e 2))
+ (let [e1 (expression-handler (:left e))
+ e2 (expression-handler (:right e))
src1 (:val e1)
src2 (:val e2)
dst (variable)
- binary-operator (binary-operator (first e))
+ binary-operator (binary-operator (:binary-operator e))
instruction (binary-instruction binary-operator src1 src2 dst)]
{:val dst
:instructions (flatten [(:instructions e1) (:instructions e2) instruction])}))
@@ -107,7 +92,8 @@
(cond
(= exp-type :constant-exp) (constant-expr-handler e)
(= exp-type :unary-exp) (unary-expr-handler e)
- (binary-expr? exp-type) (binary-expr-handler e))))
+ (= exp-type :binary-exp) (binary-expr-handler e)
+ :else (throw (ex-info "Tacky error. Invalid expression." {e e})))))
(defn- exp-instructions [exp]
(expression-handler exp))
@@ -139,16 +125,6 @@
(pp/pprint
(tacky-generate
- (p/parse "int main(void) {return 1 * 2 & 3 * (4 + 5);}")))
-
- (pp/pprint
- (p/parse "int main(void) {return 1 * 2 - 3 * (4 + 5);}"))
-
- (pp/pprint
- (p/parse "int main(void) {return 1 + 2 + -3 + -(4 + 5);}"))
-
- (pp/pprint
- (tacky-generate
- (p/parse "int main(void) {return 1 + 2 + -3 + -(4 + 5);}")))
+ (p/parse (l/lex "int main(void) {return 1 * -2 / ~3 * (4 - 5);}"))))
())
diff --git a/src/cljcc/token.clj b/src/cljcc/token.clj
index 63c1eda..429e593 100644
--- a/src/cljcc/token.clj
+++ b/src/cljcc/token.clj
@@ -37,6 +37,14 @@
(def chrs
#{})
+(def bin-ops
+ "Binary operanrs and their precedence."
+ {:plus 40
+ :hyphen 40
+ :multiply 50
+ :divide 50
+ :remainder 50})
+
(def chrs-kind-map
{\( :left-paren
\) :right-paren