diff options
| author | Shagun Agrawal <agrawalshagun07@gmail.com> | 2024-08-19 23:11:19 +0530 |
|---|---|---|
| committer | Shagun Agrawal <agrawalshagun07@gmail.com> | 2024-08-19 23:11:19 +0530 |
| commit | c637bd3156aa80e845668f8466e5423ba5539aae (patch) | |
| tree | b110c147e5155aded9a972548b6f90f9f99104c6 /src/cljcc | |
| parent | 5d09a16488112ab5d611a3693efcf1e73479a835 (diff) | |
Add tacky for relational and logical operators
Diffstat (limited to 'src/cljcc')
| -rw-r--r-- | src/cljcc/emit.clj | 2 | ||||
| -rw-r--r-- | src/cljcc/parser.clj | 2 | ||||
| -rw-r--r-- | src/cljcc/tacky.clj | 151 |
3 files changed, 126 insertions, 29 deletions
diff --git a/src/cljcc/emit.clj b/src/cljcc/emit.clj index 2bce107..e69f07a 100644 --- a/src/cljcc/emit.clj +++ b/src/cljcc/emit.clj @@ -49,7 +49,7 @@ (defn- unary-instruction-emit [instruction] (let [operand (operand-emit (:operand instruction)) assembly-operator (condp = (:unary-operator instruction) - :complement "notl" + :bit-not "notl" :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 f0ee777..7e4323f 100644 --- a/src/cljcc/parser.clj +++ b/src/cljcc/parser.clj @@ -121,7 +121,7 @@ (pp/pprint (parse (l/lex " int main(void) { - return 1 * 2 - 3 * (4 + 5); + return 1 == 2 - 3 * (4 + 5); }"))) (pp/pprint 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);}")))) + ()) |
