aboutsummaryrefslogtreecommitdiff
path: root/src/cljcc/tacky.clj
diff options
context:
space:
mode:
Diffstat (limited to 'src/cljcc/tacky.clj')
-rw-r--r--src/cljcc/tacky.clj151
1 files changed, 124 insertions, 27 deletions
diff --git a/src/cljcc/tacky.clj b/src/cljcc/tacky.clj
index 0c27271..52d830e 100644
--- a/src/cljcc/tacky.clj
+++ b/src/cljcc/tacky.clj
@@ -2,77 +2,128 @@
(:require
[clojure.pprint :as pp]
[cljcc.lexer :as l]
+ [clojure.string :as s]
[cljcc.parser :as p]))
(def counter "Global integer counter for generating unique identifier names." (atom 0))
-(defn create-identifier
- "Returns a unique identifier. Used for generating tacky variable names."
+(defn- create-identifier
+ "Returns a unique identifier. Used for generating tacky variable names.
+
+ Removes : from keywords.
+ Replaces all - with _ for generating valid assembly names."
([]
(create-identifier "tmp"))
([identifier]
(let [n @counter
_ (swap! counter #(+ % 1))]
- (str identifier "." n))))
+ (-> identifier
+ (str "." n)
+ (s/replace #":" "")
+ (s/replace #"-" "_")))))
-(defn variable
+(defn- variable
([]
{:type :variable
- :value (create-identifier)})
- ([^String identifier]
+ :value (create-identifier "var")})
+ ([identifier]
{:type :variable
- :value (create-identifier identifier)}))
+ :value (create-identifier (str identifier))}))
+
+(defn- label
+ ([] (create-identifier "label"))
+ ([ident] (create-identifier ident)))
-(defn constant-instruction [^Integer v]
+(defn constant [^Integer v]
{:type :constant
:value v})
-(defn- unary-operator [op]
+(defn- unary-operator
+ "Converts parser's unary operator to tacky representation."
+ [op]
(condp = op
- :complement :complement
- :hyphen :negate))
-
-(defn- binary-operator [binop]
+ :complement :bit-not
+ :hyphen :negate
+ :logical-not :logical-not
+ (throw (ex-info "Tacky Error. Invalid unary operator." {op op}))))
+
+(defn- binary-operator
+ "Converts parser's binary operator to tacky representation."
+ [binop]
(condp = binop
:plus :add
:hyphen :sub
:multiply :mul
:divide :div
:remainder :mod
+ :equal-to :equal
+ :not-equal-to :not-equal
+ :less-than :less-than
+ :greater-than :greater-than
+ :less-than-equal-to :less-or-equal
+ :greater-than-equal-to :greater-or-equal
:ampersand :bit-and
:bitwise-or :bit-or
:bitwise-xor :bit-xor
:bitwise-right-shift :bit-right-shift
- :bitwise-left-shift :bit-left-shift))
+ :bitwise-left-shift :bit-left-shift
+ (throw (ex-info "Tacky Error. Invalid binary operator." {binop binop}))))
+
+;;;; Instructions
-(defn- unary-instruction [unary-operator src dst]
+(defn- unary-instruction [op src dst]
{:type :unary
- :unary-operator unary-operator
+ :unary-operator op
:dst dst
:src src})
-(defn- binary-instruction [binary-operator src1 src2 dst]
+(defn- binary-instruction [op src1 src2 dst]
{:type :binary
- :binary-operator binary-operator
+ :binary-operator op
:src1 src1
:src2 src2
:dst dst})
-(defn return-instruction [val]
+(defn- return-instruction [val]
{:type :return
:val val})
+(defn- copy-instruction [src dst]
+ {:type :copy
+ :src src
+ :dst dst})
+
+(defn- jump-instruction [target]
+ {:type :jump
+ :identifier target})
+
+(defn- jump-if-zero-instruction [condition target]
+ {:type :jump-if-zero
+ :identifier target
+ :val condition})
+
+(defn- jump-if-not-zero-instruction [condition target]
+ {:type :jump-if-not-zero
+ :identifier target
+ :val condition})
+
+(defn- label-instruction [identifier]
+ {:type :label
+ :identifier identifier})
+
+;;;; Expression handlers
+
(declare expression-handler)
(defn- constant-expr-handler [e]
- {:val (constant-instruction (:value e))})
+ {:val (constant (:value e))})
(defn- unary-expr-handler [e]
(let [inner (expression-handler (:value e))
- dst (variable)
src (:val inner)
- unary-operator (unary-operator (:unary-operator e))
- instruction (unary-instruction unary-operator src dst)]
+ op (unary-operator (:unary-operator e))
+ dst (variable (str "var_" op))
+ instruction (unary-instruction op src dst)]
{:val dst
:instructions (flatten [(:instructions inner) instruction])}))
@@ -81,18 +132,60 @@
e2 (expression-handler (:right e))
src1 (:val e1)
src2 (:val e2)
- dst (variable)
- binary-operator (binary-operator (:binary-operator e))
- instruction (binary-instruction binary-operator src1 src2 dst)]
+ op (binary-operator (:binary-operator e))
+ dst (variable (str "var_" op))
+ instruction (binary-instruction op src1 src2 dst)]
{:val dst
:instructions (flatten [(:instructions e1) (:instructions e2) instruction])}))
+(defn- logical-and-handler [e]
+ (let [e1 (expression-handler (:left e))
+ e2 (expression-handler (:right e))
+ v1 (:val e1)
+ v2 (:val e2)
+ res (variable "and_result")
+ false-label (label "and_false")
+ end-label (label "and_end")]
+ {:val res
+ :instructions (flatten [(:instructions e1)
+ (jump-if-zero-instruction v1 false-label)
+ (:instructions e2)
+ (jump-if-zero-instruction v2 false-label)
+ (copy-instruction (constant 1) res)
+ (jump-instruction end-label)
+ (label-instruction false-label)
+ (copy-instruction (constant 0) res)
+ (label-instruction end-label)])}))
+
+(defn- logical-or-handler [e]
+ (let [e1 (expression-handler (:left e))
+ e2 (expression-handler (:right e))
+ v1 (:val e1)
+ v2 (:val e2)
+ res (variable "or_result")
+ false-label (label "or_false")
+ end-label (label "or_end")]
+ {:val res
+ :instructions (flatten [(:instructions e1)
+ (jump-if-not-zero-instruction v1 end-label)
+ (:instructions e2)
+ (jump-if-not-zero-instruction v2 end-label)
+ (copy-instruction (constant 0) res)
+ (jump-instruction false-label)
+ (label-instruction end-label)
+ (copy-instruction (constant 1) res)
+ (label-instruction false-label)])}))
+
(defn- expression-handler [e]
(when-let [exp-type (:exp-type e)]
(cond
(= exp-type :constant-exp) (constant-expr-handler e)
(= exp-type :unary-exp) (unary-expr-handler e)
- (= exp-type :binary-exp) (binary-expr-handler e)
+ (= exp-type :binary-exp) (let [op (:binary-operator e)]
+ (condp = op
+ :logical-and (logical-and-handler e)
+ :logical-or (logical-or-handler e)
+ (binary-expr-handler e)))
:else (throw (ex-info "Tacky error. Invalid expression." {e e})))))
(defn- exp-instructions [exp]
@@ -127,4 +220,8 @@
(tacky-generate
(p/parse (l/lex "int main(void) {return 1 * -2 / ~3 * (4 - 5);}"))))
+ (pp/pprint
+ (tacky-generate
+ (p/parse (l/lex "int main(void) {return (1 + 2) || (3 + 4);}"))))
+
())