From 276b0c200e5159b1d099ff85aab544480c2ac757 Mon Sep 17 00:00:00 2001 From: Shagun Agrawal Date: Fri, 30 Aug 2024 18:49:17 +0530 Subject: Add compound assignment operators Added compound assignment operators ( >>==, += etc ) Pass chapter 5 extra credit tests --- src/cljcc/analyzer.clj | 6 ++--- src/cljcc/lexer.clj | 10 ++++++-- src/cljcc/parser.clj | 11 ++++++--- src/cljcc/tacky.clj | 66 +++++++++++++++++++++++++++++++++++++++++++++----- src/cljcc/token.clj | 48 +++++++++++++++++++++++++++++++++++- 5 files changed, 125 insertions(+), 16 deletions(-) (limited to 'src/cljcc') diff --git a/src/cljcc/analyzer.clj b/src/cljcc/analyzer.clj index 504e8ab..7d82f53 100644 --- a/src/cljcc/analyzer.clj +++ b/src/cljcc/analyzer.clj @@ -16,10 +16,12 @@ (throw (ex-info "Undeclared variable seen." {:variable e}))) :assignment-exp (let [left (:left e) right (:right e) + op (:assignment-operator e) left-var? (= :variable-exp (:exp-type left))] (if left-var? (p/assignment-exp-node (resolve-exp left mp) - (resolve-exp right mp)) + (resolve-exp right mp) + op) (throw (ex-info "Invalid lvalue." {:lvalue e})))) :binary-exp (p/binary-exp-node (resolve-exp (:left e) mp) (resolve-exp (:right e) mp) @@ -33,8 +35,6 @@ (let [ident (:identifier d) unique-name (unique-identifier ident) updated-mp (assoc mp ident unique-name) - _ (pp/pprint mp) - _ (pp/pprint updated-mp) init (when (:initial d) (resolve-exp (:initial d) updated-mp))] (if init {:declaration (p/declaration-node unique-name init) diff --git a/src/cljcc/lexer.clj b/src/cljcc/lexer.clj index 8525441..f074ab2 100644 --- a/src/cljcc/lexer.clj +++ b/src/cljcc/lexer.clj @@ -12,7 +12,7 @@ (defn lex ([source] (lex source 0 (lexer-ctx))) - ([[ch pk :as source] pos {:keys [line col] :as ctx}] + ([[ch pk th :as source] pos {:keys [line col] :as ctx}] (cond (empty? source) (update ctx :tokens #(conj % (t/create :eof line col))) (newline? ch) (recur (next source) @@ -20,6 +20,12 @@ (-> ctx (update :line inc) (update :col (fn [_] 1)))) + (contains? + t/chrs-kind-map (str ch pk th)) (recur (next (next (next source))) + (+ pos 3) + (-> ctx + (update :col #(+ % 3)) + (update :tokens #(conj % (t/create (get t/chrs-kind-map (str ch pk th)) line col))))) (contains? t/chrs-kind-map (str ch pk)) (recur (next (next source)) (+ pos 2) @@ -66,6 +72,6 @@ }" (pp/pprint - (lex "int main(void) {return 2;}")) + (lex "int main(void) {return int a = 2; a <<= 2;}")) ()) diff --git a/src/cljcc/parser.clj b/src/cljcc/parser.clj index 4cc6c3b..b3e7eeb 100644 --- a/src/cljcc/parser.clj +++ b/src/cljcc/parser.clj @@ -50,9 +50,10 @@ :left l :right r}) -(defn assignment-exp-node [l r] +(defn assignment-exp-node [l r op] {:type :exp :exp-type :assignment-exp + :assignment-operator op :left l :right r}) @@ -76,10 +77,10 @@ tokens rst] (let [[{kind :kind :as _token} :as tokens] tokens] (if (and (t/binary-op? kind) (>= (t/precedence kind) min-prec)) - (if (= kind :assignment) - (let [[_ tokens] (expect :assignment tokens) + (if (t/assignment-op? kind) + (let [[_ tokens] (expect kind tokens) [right rst] (parse-exp tokens (t/precedence kind))] - (recur [(assignment-exp-node left right)] rst)) + (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))) [left tokens]))))) @@ -192,6 +193,8 @@ (pp/pprint (parse-from-src " int main(void) { int a = b = 4; +int var0 = 2; +var0 = 41; }")) (pp/pprint diff --git a/src/cljcc/tacky.clj b/src/cljcc/tacky.clj index ffa85b1..6046045 100644 --- a/src/cljcc/tacky.clj +++ b/src/cljcc/tacky.clj @@ -34,6 +34,38 @@ :logical-not :logical-not (throw (ex-info "Tacky Error. Invalid unary operator." {op op})))) +(defn- assignment-operator + "Converts parser assignment operator to tacky representation." + [op] + (condp = op + :assignemnt :assignemnt + :assignment-plus :assignment-add + :assignment-multiply :assignment-mul + :assignment-minus :assignment-minus + :assignment-divide :assignment-div + :assignment-mod :assignment-mod + :assignment-bitwise-and :assignemnt-bit-and + :assignment-bitwise-or :assignemnt-bit-or + :assignment-bitwise-xor :assignemnt-bit-xor + :assignment-bitwise-left-shift :assignment-bit-left-shift + :assignment-bitwise-right-shift :assignment-bit-right-shift)) + +(defn- assignment-operator->binary-operator + "Converts parser assignment operator to binary operator keyword." + [op] + (condp = op + :assignemnt :assignemnt + :assignment-plus :plus + :assignment-multiply :multiply + :assignment-minus :hyphen + :assignment-divide :divide + :assignment-mod :remainder + :assignment-bitwise-and :ampersand + :assignment-bitwise-or :bitwise-or + :assignment-bitwise-xor :bitwise-xor + :assignment-bitwise-left-shift :bitwise-left-shift + :assignment-bitwise-right-shift :bitwise-right-shift)) + (defn- binary-operator "Converts parser's binary operator to tacky representation." [binop] @@ -164,11 +196,20 @@ (label-instruction false-label)])})) (defn- assignment-exp-handler [e] - (let [var (parsed-var->tacky-var (:left e)) ; guaranteed to be parsed variable - rhs (expression-handler (:right e))] - {:val var - :instructions (flatten [(:instructions rhs) - (copy-instruction (:val rhs) var)])})) + (let [asop (:assignment-operator e) + direct-assignment? (= asop :assignment) + var (parsed-var->tacky-var (:left e))] ; guaranteed to be parsed variable + (if direct-assignment? + (let [rhs (expression-handler (:right e))] + {:val var + :instructions (flatten [(:instructions rhs) + (copy-instruction (:val rhs) var)])}) + (let [bin-op (assignment-operator->binary-operator (:assignment-operator e)) + bin-exp (p/binary-exp-node (:left e) (:right e) bin-op) + rhs (expression-handler bin-exp)] + {:val var + :instructions (flatten [(:instructions rhs) + (copy-instruction (:val rhs) var)])})))) (defn- expression-handler [e] (when-let [exp-type (:exp-type e)] @@ -236,7 +277,20 @@ (pp/pprint (tacky-from-src "int main(void) { -2 + 2; +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); }")) (pp/pprint diff --git a/src/cljcc/token.clj b/src/cljcc/token.clj index dc1d125..883dda8 100644 --- a/src/cljcc/token.clj +++ b/src/cljcc/token.clj @@ -32,6 +32,16 @@ :bitwise-or :negate :assignemnt + :assignment-plus + :assignment-multiply + :assignment-minus + :assignment-divide + :assignment-mod + :assignment-bitwise-and + :assignment-bitwise-or + :assignment-bitwise-xor + :assignment-bitwise-left-shift + :assignment-bitwise-right-shift :increment :decrement @@ -48,6 +58,22 @@ :complement :hyphen}) +(def assignment-ops + #{:assignment + :assignment-plus + :assignment-multiply + :assignment-minus + :assignment-divide + :assignment-mod + :assignment-bitwise-and + :assignment-bitwise-or + :assignment-bitwise-xor + :assignment-bitwise-left-shift + :assignment-bitwise-right-shift}) + +(defn assignment-op? [op] + (contains? assignment-ops op)) + (defn unary-op? [op] (contains? unary-ops op)) @@ -81,7 +107,17 @@ :logical-or 10 - :assignment 1}) + :assignment 1 + :assignment-plus 1 + :assignment-multiply 1 + :assignment-minus 1 + :assignment-divide 1 + :assignment-mod 1 + :assignment-bitwise-and 1 + :assignment-bitwise-or 1 + :assignment-bitwise-xor 1 + :assignment-bitwise-left-shift 1 + :assignment-bitwise-right-shift 1}) (defn binary-op? [op] (contains? bin-ops op)) @@ -108,6 +144,16 @@ \> :greater-than "<=" :less-than-equal-to ">=" :greater-than-equal-to + "+=" :assignment-plus + "*=" :assignment-multiply + "-=" :assignment-minus + "/=" :assignment-divide + "%=" :assignment-mod + "&=" :assignment-bitwise-and + "|=" :assignment-bitwise-or + "^=" :assignment-bitwise-xor + "<<=" :assignment-bitwise-left-shift + ">>=" :assignment-bitwise-right-shift \^ :bitwise-xor \| :bitwise-or \& :ampersand -- cgit v1.2.3