aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShagun Agrawal <agrawalshagun07@gmail.com>2024-08-30 18:49:17 +0530
committerShagun Agrawal <agrawalshagun07@gmail.com>2024-08-30 18:49:17 +0530
commit276b0c200e5159b1d099ff85aab544480c2ac757 (patch)
tree8cb86289809936901b2a49344818528799fa81da
parent7a3e7151ea7e05952ec58648d71d9ed33168109d (diff)
Add compound assignment operators
Added compound assignment operators ( >>==, += etc ) Pass chapter 5 extra credit tests
-rw-r--r--src/cljcc/analyzer.clj6
-rw-r--r--src/cljcc/lexer.clj10
-rw-r--r--src/cljcc/parser.clj11
-rw-r--r--src/cljcc/tacky.clj66
-rw-r--r--src/cljcc/token.clj48
5 files changed, 125 insertions, 16 deletions
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)
@@ -21,6 +21,12 @@
(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)
(-> ctx
@@ -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