aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShagun Agrawal <agrawalshagun07@gmail.com>2024-12-08 21:57:39 +0530
committerShagun Agrawal <agrawalshagun07@gmail.com>2024-12-08 21:57:39 +0530
commit24397e5682514f2988072d7039ed39c08e3ba7ef (patch)
treed4048d1d689356eca9ebaaa5fdfc7a291d3bb1fc
parentfa049cc22c6c7b64b51e6e10b33a259fa58945d7 (diff)
Add tacky phase for long type generation
Tacky phase generation for for long types Refactor expression handling for Tacky phase by using postwalk function Refactor symbol namespaces
-rw-r--r--src/cljcc/analyze/label_loops.clj5
-rw-r--r--src/cljcc/analyze/typecheck.clj90
-rw-r--r--src/cljcc/emit.clj6
-rw-r--r--src/cljcc/parser.clj12
-rw-r--r--src/cljcc/schema.clj131
-rw-r--r--src/cljcc/symbol.clj38
-rw-r--r--src/cljcc/symbols.clj10
-rw-r--r--src/cljcc/tacky.clj540
-rw-r--r--src/cljcc/token.clj21
9 files changed, 613 insertions, 240 deletions
diff --git a/src/cljcc/analyze/label_loops.clj b/src/cljcc/analyze/label_loops.clj
index 94cefc2..56fffc9 100644
--- a/src/cljcc/analyze/label_loops.clj
+++ b/src/cljcc/analyze/label_loops.clj
@@ -2,6 +2,7 @@
(:require [cljcc.parser :as p]
[cljcc.exception :as exc]
[cljcc.analyze.resolve :as r]
+ [cljcc.schema :as s]
[cljcc.util :as util]
[malli.dev.pretty :as pretty]))
@@ -87,14 +88,14 @@
label-loops)
(pretty/explain
- p/Program
+ s/Program
(-> "./test-programs/example.c"
slurp
p/parse-from-src
r/resolve-program))
(pretty/explain
- p/Program
+ s/Program
(-> "./test-programs/example.c"
slurp
p/parse-from-src
diff --git a/src/cljcc/analyze/typecheck.clj b/src/cljcc/analyze/typecheck.clj
index 7f8134a..122e5be 100644
--- a/src/cljcc/analyze/typecheck.clj
+++ b/src/cljcc/analyze/typecheck.clj
@@ -4,51 +4,22 @@
[cljcc.parser :as p]
[cljcc.token :as t]
[cljcc.schema :as s]
+ [cljcc.symbol :as sym]
[cljcc.analyze.resolve :as r]
[cljcc.analyze.label-loops :as l]
[cljcc.exception :as exc]))
(declare typecheck-block typecheck-declaration to-static-init)
-(defn- create-symbol [type attribute]
- {:type type
- :attribute attribute})
-
-(defn- local-attribute []
- {:type :local})
-
-(defn- static-attribute [initial-value global?]
- {:type :static
- :initial-value initial-value
- :global? global?})
-
-(defn- set-type
+(defn set-type
"Assocs onto an expression given type."
[e t] (assoc e :value-type t))
-(defn- get-type [e] (:value-type e))
+(defn get-type [e] (:value-type e))
(defn- symbol-function? [s]
(= :function (:type (:type s))))
-(defn- no-initializer-iv []
- {:type :no-initializer})
-
-(defn- tentative-iv []
- {:type :tentative})
-
-(defn- initial-iv [static-init]
- {:type :initial
- :static-init static-init})
-
-(defn- int-init [v]
- {:type :int-init
- :value v})
-
-(defn- long-init [v]
- {:type :long-init
- :value v})
-
(defmulti typecheck-exp
"Returns the expression, after typechecking nested expressions."
(fn [{:keys [exp-type]} _ident->symbol] exp-type))
@@ -93,7 +64,7 @@
(set-type (p/cast-exp-node t e) t)))
(defmethod typecheck-exp :binary-exp
- [{:keys [left right binary-operator] :as e} ident->symbol]
+ [{:keys [left right binary-operator] :as _e} ident->symbol]
(let
[typed-left-e (typecheck-exp left ident->symbol)
typed-right-e (typecheck-exp right ident->symbol)]
@@ -113,7 +84,7 @@
(set-type typed-binary-exp {:type :int}))))))
(defmethod typecheck-exp :assignment-exp
- [{:keys [left right assignment-operator] :as e} ident->symbol]
+ [{:keys [left right assignment-operator] :as _e} ident->symbol]
(let
[typed-left (typecheck-exp left ident->symbol)
typed-right (typecheck-exp right ident->symbol)
@@ -130,7 +101,7 @@
common-type (get-common-type (get-type t-middle) (get-type t-right))
convert-right (convert-to-exp t-right common-type)
convert-middle (convert-to-exp t-middle common-type)
- typed-cond-e (p/conditional-exp-node t-left t-middle t-right)]
+ typed-cond-e (p/conditional-exp-node t-left convert-middle convert-right)]
(set-type typed-cond-e common-type)))
(defmethod typecheck-exp :function-call-exp
@@ -194,14 +165,18 @@
[return-type {:keys [condition body] :as stmt} m]
(let [typed-cond (typecheck-exp condition m)
typed-body (typecheck-statement return-type body m)]
- {:statement (merge stmt (p/while-statement-node typed-cond typed-body))
+ {:statement (merge stmt (p/while-statement-node
+ typed-cond
+ (:statement typed-body)))
:ident->symbol (:ident->symbol typed-body)}))
(defmethod typecheck-statement :do-while
[return-type {:keys [condition body] :as stmt} m]
(let [typed-cond (typecheck-exp condition m)
typed-body (typecheck-statement return-type body m)]
- {:statement (merge stmt (p/do-while-statement-node typed-cond typed-body))
+ {:statement (merge stmt (p/do-while-statement-node
+ typed-cond
+ (:statement typed-body)))
:ident->symbol (:ident->symbol typed-body)}))
(defn- typecheck-optional-expression [e m]
@@ -220,6 +195,9 @@
m' (if (:declaration f-init)
(:ident->symbol f-init)
m)
+ f-init (if (:declaration f-init)
+ (:declaration f-init)
+ f-init)
t-condition (typecheck-optional-expression condition m')
t-post (typecheck-optional-expression post m')
typed-body-statement (typecheck-statement return-type body m')]
@@ -246,7 +224,7 @@
(defmethod typecheck-statement :compound
[return-type {:keys [block]} m]
(let [typed-block (typecheck-block return-type block m)]
- {:statement (p/compound-statement-node typed-block)
+ {:statement (p/compound-statement-node (:block typed-block))
:ident->symbol (:ident->symbol typed-block)}))
(defn- typecheck-item [return-type {:keys [type] :as item} m]
@@ -274,8 +252,8 @@
(cond
constant-exp? (to-static-init initial variable-type)
(nil? initial) (if (= :extern storage-class)
- (no-initializer-iv)
- (tentative-iv))
+ (sym/no-initializer-iv)
+ (sym/tentative-iv))
:else (exc/analyzer-error "Non-constant initializer." declaration))))
(defn- const-convert [{ttype :type :as _target-type} {const-type :type value :value :as const}]
@@ -292,9 +270,9 @@
(cond
(= :constant-exp exp-type) (let [c-const (const-convert var-type value)]
(cond
- (= :int (:type c-const)) (initial-iv (int-init (:value c-const)))
- (= :long (:type c-const)) (initial-iv (long-init (:value c-const)))))
- (nil? e) (initial-iv (int-init 0))
+ (= :int (:type c-const)) (sym/initial-iv (sym/int-init (:value c-const)))
+ (= :long (:type c-const)) (sym/initial-iv (sym/long-init (:value c-const)))))
+ (nil? e) (sym/initial-iv (sym/int-init 0))
:else (exc/analyzer-error "Non-constant initializer on static variable." e)))
(defn- validate-file-scope-variable-declaration
@@ -336,7 +314,7 @@
{:declaration d
:ident->symbol (assoc ident->symbol
identifier
- (create-symbol variable-type (static-attribute initial-value global?)))}))
+ (sym/create-symbol variable-type (sym/static-attribute initial-value global?)))}))
(defn- typecheck-local-scope-variable-declaration
[{:keys [identifier variable-type storage-class initial] :as d} ident->symbol]
@@ -352,20 +330,20 @@
ident->symbol
(assoc ident->symbol
identifier
- (create-symbol variable-type (static-attribute (no-initializer-iv) true))))]
+ (sym/create-symbol variable-type (sym/static-attribute (sym/no-initializer-iv) true))))]
{:declaration d
:ident->symbol symbols})
:static (let [initial-value (to-static-init initial variable-type)
updated-symbols (assoc ident->symbol
identifier
- (create-symbol variable-type (static-attribute initial-value false)))]
+ (sym/create-symbol variable-type (sym/static-attribute initial-value false)))]
{:declaration d
:ident->symbol updated-symbols})
(let [updated-symbols (assoc ident->symbol
identifier
- (create-symbol
+ (sym/create-symbol
variable-type
- (local-attribute)))
+ (sym/local-attribute)))
casted-e (if (nil? initial)
initial
(convert-to-exp initial variable-type))
@@ -373,11 +351,6 @@
{:declaration (assoc d :initial t-e)
:ident->symbol updated-symbols})))
-(defn- fun-attribute [defined? global?]
- {:type :fun
- :defined? defined?
- :global? global?})
-
(defn- validate-old-fn-decl-return-attribute
[cur-decl prev-symbol]
(let [prev-function? (= :function (get-in prev-symbol [:type :type]))
@@ -410,7 +383,7 @@
ident->symbol
(flatten
(map (fn [p t]
- [p (create-symbol t (local-attribute))])
+ [p (sym/create-symbol t (sym/local-attribute))])
parameters
(:parameter-types function-type))))))
@@ -423,10 +396,10 @@
(validate-old-fn-decl-return-attribute d prev-symbol)
{:defined? false
:global? (not= :static storage-class)})
- function-attribute (fun-attribute (boolean (or defined? body?)) global?)
+ function-attribute (sym/fun-attribute (boolean (or defined? body?)) global?)
updated-symbols (assoc ident->symbol
identifier
- (create-symbol
+ (sym/create-symbol
function-type
function-attribute))]
(if body?
@@ -438,7 +411,7 @@
body
(assoc with-parameter-symbols
:at-top-level false))]
- {:declaration d
+ {:declaration (assoc d :body (:block with-body-symbols))
:ident->symbol (assoc (:ident->symbol with-body-symbols)
:at-top-level true)})
{:declaration d
@@ -473,7 +446,8 @@
program (:program v)
m (dissoc (:ident->symbol v) :at-top-level)
_ (m/coerce s/Program program)
- _ (m/coerce s/SymbolMap m)]
+ ;_ (m/coerce s/SymbolMap m)
+ ]
{:program program
:ident->symbol m}))
diff --git a/src/cljcc/emit.clj b/src/cljcc/emit.clj
index d753473..a0933c7 100644
--- a/src/cljcc/emit.clj
+++ b/src/cljcc/emit.clj
@@ -2,8 +2,7 @@
(:require
[cljcc.util :refer [get-os]]
[cljcc.compiler :as c]
- [clojure.string :as str]
- [cljcc.symbols :as symbols]))
+ [clojure.string :as str]))
(defn- handle-label [identifier]
(condp = (get-os)
@@ -19,7 +18,8 @@
(defn- handle-current-translation-unit [name]
(if (= :mac (get-os))
(handle-symbol-name name)
- (if (contains? @symbols/symbols name)
+ (if (;check if sym exists inside symbol map
+ )
name
(str name "@PLT"))))
diff --git a/src/cljcc/parser.clj b/src/cljcc/parser.clj
index 7e0ca06..6b9024f 100644
--- a/src/cljcc/parser.clj
+++ b/src/cljcc/parser.clj
@@ -3,6 +3,7 @@
[cljcc.lexer :as l]
[cljcc.token :as t]
[malli.core :as m]
+ [malli.dev.pretty :as pretty]
[clojure.math :refer [pow]]
[cljcc.schema :as s]
[cljcc.exception :as exc]
@@ -53,25 +54,30 @@
(defn function-call-exp-node [identifier arguments]
{:type :exp
:exp-type :function-call-exp
+ :children [:arguments]
:identifier identifier
- :arguments arguments})
+ :arguments (vec arguments)})
(defn cast-exp-node [target-type e]
{:type :exp
:exp-type :cast-exp
:target-type target-type
+ :typed-inner e ; copy of e, for use in tacky phase
+ :children [:value]
:value e})
(defn unary-exp-node [op v]
{:type :exp
:exp-type :unary-exp
:unary-operator op
+ :children [:value]
:value v})
(defn binary-exp-node [l r op]
{:type :exp
:exp-type :binary-exp
:binary-operator op
+ :children [:left :right]
:left l
:right r})
@@ -79,12 +85,14 @@
{:type :exp
:exp-type :assignment-exp
:assignment-operator op
+ :children [:left :right]
:left l
:right r})
(defn conditional-exp-node [l m r]
{:type :exp
:exp-type :conditional-exp
+ :children [:left :right :middle]
:left l
:middle m
:right r})
@@ -484,7 +492,7 @@
(comment
- (m/validate
+ (pretty/explain
s/Program
(parse-from-src
"int main(void) {
diff --git a/src/cljcc/schema.clj b/src/cljcc/schema.clj
index 9084435..5f86dd8 100644
--- a/src/cljcc/schema.clj
+++ b/src/cljcc/schema.clj
@@ -52,7 +52,9 @@
[:type [:= :exp]]
[:exp-type [:= :cast-exp]]
[:target-type #'Type]
+ [:typed-inner [:ref #'Exp]]
[:value [:ref #'Exp]]
+ [:children [:= [:value]]]
[:value-type {:optional true} #'Type]])
(def UnaryExp
@@ -61,6 +63,7 @@
[:exp-type [:= :unary-exp]]
[:unary-operator `[:enum ~@t/unary-ops]]
[:value [:ref #'Exp]]
+ [:children [:= [:value]]]
[:value-type {:optional true} #'Type]])
(def BinaryExp
@@ -70,6 +73,7 @@
[:binary-operator `[:enum ~@(set (keys t/bin-ops))]]
[:left [:ref #'Exp]]
[:right [:ref #'Exp]]
+ [:children [:= [:left :right]]]
[:value-type {:optional true} #'Type]])
(def AssignmentExp
@@ -77,6 +81,7 @@
[:type [:= :exp]]
[:exp-type [:= :assignment-exp]]
[:assignment-operator `[:enum ~@t/assignment-ops]]
+ [:children [:= [:left :right]]]
[:left [:ref #'Exp]]
[:right [:ref #'Exp]]
[:value-type {:optional true} #'Type]])
@@ -85,6 +90,7 @@
[:map
[:type [:= :exp]]
[:exp-type [:= :conditional-exp]]
+ [:children [:= [:left :right :middle]]]
[:left [:ref #'Exp]]
[:middle [:ref #'Exp]]
[:right [:ref #'Exp]]
@@ -96,6 +102,7 @@
[:exp-type [:= :function-call-exp]]
[:identifier string?]
[:arguments [:vector [:ref #'Exp]]]
+ [:children [:= [:arguments]]]
[:value-type {:optional true} #'Type]])
(def Exp
@@ -316,3 +323,127 @@
[:map
[:ident->symbol #'SymbolMap]
[:program #'Program]])
+
+(def TackyVar
+ [:map
+ [:type [:= :variable]]
+ [:value string?]])
+
+(def TackyConstant
+ [:map
+ [:type [:= :constant]]
+ [:value #'Const]])
+
+(def TackyVal
+ [:schema {:registry {::mtacky-var #'TackyVar
+ ::mtacky-constant #'TackyConstant}}
+ [:multi {:dispatch :type}
+ [:variable #'TackyVar]
+ [:constant #'TackyConstant]]])
+
+(def TackyReturn
+ [:map
+ [:type [:= :return]]
+ [:val #'TackyVal]])
+
+(def TackySignExtend
+ [:map
+ [:type [:= :sign-extend]]
+ [:src #'TackyVal]
+ [:dst #'TackyVal]])
+
+(def TackyTruncate
+ [:map
+ [:type [:= :truncate]]
+ [:src #'TackyVal]
+ [:dst #'TackyVal]])
+
+(def TackyUnary
+ [:map
+ [:type [:= :unary]]
+ [:unary-operator `[:enum ~@t/tacky-unary-ops]]
+ [:src #'TackyVal]
+ [:dst #'TackyVal]])
+
+(def TackyBinary
+ [:map
+ [:type [:= :binary]]
+ [:binary-operator `[:enum ~@t/tacky-binary-ops]]
+ [:src1 #'TackyVal]
+ [:src2 #'TackyVal]
+ [:dst #'TackyVal]])
+
+(def TackyCopy
+ [:map
+ [:type [:= :copy]]
+ [:src #'TackyVal]
+ [:dst #'TackyVal]])
+
+(def TackyJump
+ [:map
+ [:type [:= :jump]]
+ [:identifier string?]])
+
+(def TackyJumpIfZero
+ [:map
+ [:type [:= :jump-if-zero]]
+ [:val #'TackyVal]
+ [:identifier string?]])
+
+(def TackyJumpIfNotZero
+ [:map
+ [:type [:= :jump-if-not-zero]]
+ [:val #'TackyVal]
+ [:identifier string?]])
+
+(def TackyLabel
+ [:map
+ [:type [:= :label]]
+ [:identifier string?]])
+
+(def TackyFunCall
+ [:map
+ [:type [:= :fun-call]]
+ [:identifier string?]
+ [:arguments [:vector #'TackyVal]]
+ [:dst #'TackyVal]])
+
+(def TackyInstruction
+ [:multi {:dispatch :type}
+ [:return #'TackyReturn]
+ [:sign-extend #'TackySignExtend]
+ [:truncate #'TackyTruncate]
+ [:unary #'TackyUnary]
+ [:binary #'TackyBinary]
+ [:copy #'TackyCopy]
+ [:jump #'TackyJump]
+ [:jump-if-zero #'TackyJumpIfZero]
+ [:jump-if-not-zero #'TackyJumpIfNotZero]
+ [:label #'TackyLabel]
+ [:fun-call #'TackyFunCall]])
+
+(def TackyFunction
+ [:map
+ [:identifier string?]
+ [:global? boolean?]
+ [:type [:= :declaration]]
+ [:declaration-type [:= :function]]
+ [:parameters [:vector string?]]
+ [:instructions [:vector #'TackyInstruction]]])
+
+(def TackyStaticVariable
+ [:map
+ [:identifier string?]
+ [:global? boolean?]
+ [:variable-type #'Type]
+ [:initial #'Initial]
+ [:declaration-type [:= :static-variable]]
+ [:type [:= :declaration]]])
+
+(def TackyTopLevel
+ [:multi {:dispatch :declaration-type}
+ [:static-variable #'TackyStaticVariable]
+ [:function #'TackyFunction]])
+
+(def TackyProgram
+ [:vector #'TackyTopLevel])
diff --git a/src/cljcc/symbol.clj b/src/cljcc/symbol.clj
new file mode 100644
index 0000000..3cc4af9
--- /dev/null
+++ b/src/cljcc/symbol.clj
@@ -0,0 +1,38 @@
+(ns cljcc.symbol)
+
+;; Contains functions related to symbol table manipulation.
+
+(defn create-symbol [type attribute]
+ {:type type
+ :attribute attribute})
+
+(defn local-attribute []
+ {:type :local})
+
+(defn static-attribute [initial-value global?]
+ {:type :static
+ :initial-value initial-value
+ :global? global?})
+
+(defn fun-attribute [defined? global?]
+ {:type :fun
+ :defined? defined?
+ :global? global?})
+
+(defn no-initializer-iv []
+ {:type :no-initializer})
+
+(defn tentative-iv []
+ {:type :tentative})
+
+(defn initial-iv [static-init]
+ {:type :initial
+ :static-init static-init})
+
+(defn int-init [v]
+ {:type :int-init
+ :value v})
+
+(defn long-init [v]
+ {:type :long-init
+ :value v})
diff --git a/src/cljcc/symbols.clj b/src/cljcc/symbols.clj
deleted file mode 100644
index 1afbe47..0000000
--- a/src/cljcc/symbols.clj
+++ /dev/null
@@ -1,10 +0,0 @@
-(ns cljcc.symbols)
-
-(def symbols
- "Holds global symbol table.
-
- Maps identifiers to their types."
- (atom {}))
-
-(defn reset-symbols [new-symbols]
- (reset! symbols new-symbols))
diff --git a/src/cljcc/tacky.clj b/src/cljcc/tacky.clj
index b19dacd..8f87165 100644
--- a/src/cljcc/tacky.clj
+++ b/src/cljcc/tacky.clj
@@ -4,7 +4,14 @@
[cljcc.util :as u]
[cljcc.parser :as p]
[cljcc.exception :as exc]
- [cljcc.analyze.core :as a]))
+ [cljcc.symbol :as sym]
+ [cljcc.analyze.resolve :as r]
+ [cljcc.analyze.label-loops :as label-loop]
+ [malli.dev.pretty :as pretty]
+ [cljcc.analyze.typecheck :as tc]
+ [cljcc.analyze.core :as a]
+ [malli.core :as m]
+ [cljcc.schema :as s]))
(defn- variable
([]
@@ -17,14 +24,26 @@
{:type :variable
:value (:identifier v)})
+(defn tacky-var [identifier]
+ {:type :variable
+ :value identifier})
+
(defn- label
([] (label "label"))
([ident] (u/create-identifier! ident)))
-(defn constant [^Integer v]
- {:type :constant
+(defn- const-int [v]
+ {:type :int
+ :value v})
+
+(defn- const-long [v]
+ {:type :long
:value v})
+(defn constant [const-value]
+ {:type :constant
+ :value const-value})
+
(defn- unary-operator
"Converts parser's unary operator to tacky representation."
[op]
@@ -48,7 +67,8 @@
:assignment-bitwise-or :bitwise-or
:assignment-bitwise-xor :bitwise-xor
:assignment-bitwise-left-shift :bitwise-left-shift
- :assignment-bitwise-right-shift :bitwise-right-shift))
+ :assignment-bitwise-right-shift :bitwise-right-shift
+ (exc/tacky-error "Invalid assignment operator." op)))
(defn- binary-operator
"Converts parser's binary operator to tacky representation."
@@ -70,7 +90,7 @@
:bitwise-xor :bit-xor
:bitwise-right-shift :bit-right-shift
:bitwise-left-shift :bit-left-shift
- (throw (ex-info "Tacky Error. Invalid binary operator." {binop binop}))))
+ (exc/tacky-error "Invalid binary operator." binop)))
;;;; Instructions
@@ -91,6 +111,16 @@
{:type :return
:val val})
+(defn- sign-extend-instruction [src dst]
+ {:type :sign-extend
+ :src src
+ :dst dst})
+
+(defn- truncate-instruction [src dst]
+ {:type :truncate
+ :src src
+ :dst dst})
+
(defn- copy-instruction [src dst]
{:type :copy
:src src
@@ -122,138 +152,230 @@
;;;; Expression handlers
-(declare expression-handler)
+;; Timothy Baldridge, Data all the ASTs
+(defn postwalk [ast f]
+ (f (reduce
+ (fn [acc key]
+ (let [value (get acc key)]
+ (if (vector? value)
+ (assoc acc key (doall (map (fn [node] (postwalk node f))
+ value)))
+ (assoc acc key (postwalk value f)))))
+ ast
+ (:children ast))))
+
+(defn- add-var-to-symbol [var var-type symbols]
+ (swap! symbols assoc (:value var) {:type var-type
+ :attribute (sym/local-attribute)}))
+
+(defmulti exp-handler
+ (fn [exp _symbols]
+ (:exp-type exp)))
-(defn- constant-expr-handler [e]
- {:val (constant (:value e))})
+(comment
-(defn- unary-expr-handler [e]
- (let [inner (expression-handler (:value e))
- src (:val inner)
- op (unary-operator (:unary-operator e))
+ (exp-handler
+ {:type :exp,
+ :exp-type :function-call-exp,
+ :children [:arguments],
+ :identifier "foo",
+ :arguments [],
+ :value-type {:type :long}}
+ (atom {}))
+
+ ())
+
+(comment
+
+ (exp-handler
+ {:type :exp,
+ :exp-type :variable-exp,
+ :identifier "x.5",
+ :value-type {:type :int}}
+ (atom {}))
+
+ ())
+
+(defmethod exp-handler :default
+ [_ _]
+ {:instructions []})
+
+(defmethod exp-handler :constant-exp
+ [exp _]
+ {:val (constant (:value exp))})
+
+(defmethod exp-handler :variable-exp
+ [exp _]
+ {:val (tacky-var (:identifier exp))})
+
+(defmethod exp-handler :cast-exp
+ [{:keys [target-type value typed-inner]} symbols]
+ (if (= target-type (tc/get-type typed-inner))
+ value
+ (let [dst (variable "cast_")
+ _ (add-var-to-symbol dst target-type symbols)
+ {res :val
+ insts :instructions} value]
+ (if (= :long (:type target-type))
+ {:val dst
+ :instructions (flatten [insts
+ (sign-extend-instruction res dst)])}
+ {:val dst
+ :instructions (flatten [insts
+ (truncate-instruction res dst)])}))))
+
+(defmethod exp-handler :unary-exp
+ [exp symbols]
+ (let [{src :val
+ insts :instructions} (:value exp)
+ op (unary-operator (:unary-operator exp))
dst (variable (str "unary_result_" op))
- instruction (unary-instruction op src dst)]
+ _ (add-var-to-symbol dst (tc/get-type exp) symbols)
+ inst (unary-instruction op src dst)]
{:val dst
- :instructions (flatten [(:instructions inner) instruction])}))
-
-(defn- binary-expr-handler [e]
- (let [e1 (expression-handler (:left e))
- e2 (expression-handler (:right e))
- src1 (:val e1)
- src2 (:val e2)
- op (binary-operator (:binary-operator e))
- dst (variable (str "binary_result_" 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)
+ :instructions (flatten [insts inst])}))
+
+(defn logical-and-binary-handler
+ [exp symbols]
+ (let [{v1 :val
+ insts1 :instructions} (:left exp)
+ {v2 :val
+ insts2 :instructions} (:right exp)
res (variable "and_result")
+ _ (add-var-to-symbol res (tc/get-type exp) symbols)
false-label (label "and_false")
end-label (label "and_end")]
{:val res
- :instructions (flatten [(:instructions e1)
+ :instructions (flatten [insts1
(jump-if-zero-instruction v1 false-label)
- (:instructions e2)
+ insts2
(jump-if-zero-instruction v2 false-label)
- (copy-instruction (constant 1) res)
+ (copy-instruction (constant (const-int 1)) res)
(jump-instruction end-label)
(label-instruction false-label)
- (copy-instruction (constant 0) res)
+ (copy-instruction (constant (const-int 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)
+(defn logical-or-binary-handler
+ [exp symbols]
+ (let [{v1 :val
+ insts1 :instructions} (:left exp)
+ {v2 :val
+ insts2 :instructions} (:right exp)
res (variable "or_result")
+ _ (add-var-to-symbol res (tc/get-type exp) symbols)
false-label (label "or_false")
end-label (label "or_end")]
{:val res
- :instructions (flatten [(:instructions e1)
+ :instructions (flatten [insts1
(jump-if-not-zero-instruction v1 end-label)
- (:instructions e2)
+ insts2
(jump-if-not-zero-instruction v2 end-label)
- (copy-instruction (constant 0) res)
+ (copy-instruction (constant (const-int 0)) res)
(jump-instruction false-label)
(label-instruction end-label)
- (copy-instruction (constant 1) res)
+ (copy-instruction (constant (const-int 1)) res)
(label-instruction false-label)])}))
-(defn- assignment-exp-handler [e]
- (let [asop (:assignment-operator e)
- direct-assignment? (= asop :assignment)
- var (parsed-var->tacky-var (:left e))] ; guaranteed to be parsed variable
+(defn binary-exp-handler
+ [exp symbols]
+ (let [{v1 :val
+ insts1 :instructions} (:left exp)
+ {v2 :val
+ insts2 :instructions} (:right exp)
+ op (binary-operator (:binary-operator exp))
+ dst (variable (str "binary_result_" op))
+ _ (add-var-to-symbol dst (tc/get-type exp) symbols)
+ binary-inst (binary-instruction op v1 v2 dst)]
+ {:val dst
+ :instructions (flatten [insts1
+ insts2
+ binary-inst])}))
+
+(defmethod exp-handler :binary-exp
+ [exp symbols]
+ (let [op (:binary-operator exp)]
+ (condp = op
+ :logical-and (logical-and-binary-handler exp symbols)
+ :logical-or (logical-or-binary-handler exp symbols)
+ (binary-exp-handler exp symbols))))
+
+(defmethod exp-handler :assignment-exp
+ [exp symbols]
+ (let [op (:assignment-operator exp)
+ var (:val (:left exp)); guaranteed to be a TackyVariable
+ direct-assignment? (= op :assignment)]
(if direct-assignment?
- (let [rhs (expression-handler (:right e))]
+ (let [{dst :val
+ insts :instructions} (:right exp)]
{: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- conditional-exp-handler [e]
- (let [ce (expression-handler (:left e))
- cv (:val ce)
- then-e (expression-handler (:middle e))
- else-e (expression-handler (:right e))
- end-label (label "conditional_end")
+ :instructions (flatten [insts
+ (copy-instruction dst var)])})
+ (let [bin-op (assignment-operator->binary-operator op)
+ bin-exp (p/binary-exp-node (:left exp) (:right exp) bin-op)
+ {rhs :val
+ insts :instructions} (exp-handler bin-exp symbols)]
+ {:val rhs
+ :instructions (flatten [insts
+ (copy-instruction rhs var)])}))))
+
+(defmethod exp-handler :conditional-exp
+ [exp symbols]
+ (let [{condition-val :val
+ condition-insts :instructions} (:left exp)
+ {then-val :val
+ then-insts :instructions} (:middle exp)
+ {else-val :val
+ else-insts :instructions} (:right exp)
+ end-label (label "condition_end")
else-label (label "conditional_else")
- res (variable "conditional_result")]
+ res (variable "conditional_result")
+ _ (add-var-to-symbol res (tc/get-type exp) symbols)]
{:val res
- :instructions (flatten
- [(:instructions ce)
- (jump-if-zero-instruction cv else-label)
- (:instructions then-e)
- (copy-instruction (:val then-e) res)
- (jump-instruction end-label)
- (label-instruction else-label)
- (:instructions else-e)
- (copy-instruction (:val else-e) res)
- (label-instruction end-label)])}))
-
-(defn- function-call-exp-handler [{identifier :identifier arguments :arguments}]
- (let [arg-exps (mapv expression-handler arguments)
- dst (variable (str "function_call_result_" identifier))
- fn-instruction (fun-call-instruction identifier (mapv #(:val %) arg-exps) dst)]
+ :instructions (flatten [condition-insts
+ (jump-if-zero-instruction condition-val else-label)
+ then-insts
+ (copy-instruction then-val res)
+ (jump-instruction end-label)
+ (label-instruction else-label)
+ else-insts
+ (copy-instruction else-val res)
+ (label-instruction end-label)])}))
+
+(defmethod exp-handler :function-call-exp
+ [{identifier :identifier
+ arguments :arguments :as exp} symbols]
+ (let [dst (variable (str "function_call_result_" identifier))
+ _ (add-var-to-symbol dst (tc/get-type exp) symbols)
+ fn-instruction (fun-call-instruction identifier
+ (mapv #(:val %) arguments)
+ dst)]
{:val dst
- :instructions (flatten [(mapv #(:instructions %) arg-exps) fn-instruction])}))
-
-(defn- expression-handler [e]
- (when-let [exp-type (:exp-type e)]
- (condp = exp-type
- :constant-exp (constant-expr-handler e)
- :unary-exp (unary-expr-handler e)
- :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)))
- :variable-exp {:val (parsed-var->tacky-var e)}
- :assignment-exp (assignment-exp-handler e)
- :conditional-exp (conditional-exp-handler e)
- :function-call-exp (function-call-exp-handler e)
- (throw (ex-info "Tacky error. Invalid expression." {e e})))))
-
-(defn- exp-instructions [exp]
- (expression-handler exp))
+ :instructions (flatten [(mapv #(:instructions %) arguments)
+ fn-instruction])}))
+
+(defn run-expression-handler
+ "Transforms a expression to tacky variable and instructions.
+
+ Parameters:
+ exp: Expression to be parsed
+ symbols: Atom for symbol map"
+ [exp symbols]
+ (postwalk exp #(exp-handler % symbols)))
+
+(comment
+
+ ())
+
+;;;; Statement Handlers
(declare statement->tacky-instruction block-item->tacky-instruction)
-(defn if-statement-handler [s]
- (let [cond-exp (exp-instructions (:condition s))
+(defn if-statement-handler [s symbols]
+ (let [cond-exp (run-expression-handler (:condition s) symbols)
cond-value (:val cond-exp)
cond-instructions (:instructions cond-exp)
- then-instructions (statement->tacky-instruction (:then-statement s))
+ then-instructions (statement->tacky-instruction (:then-statement s) symbols)
end-label (label "if_end")
else-label (label "if_else")
else? (:else-statement s)]
@@ -263,29 +385,29 @@
then-instructions
(jump-instruction end-label)
(label-instruction else-label)
- (statement->tacky-instruction (:else-statement s))
+ (statement->tacky-instruction (:else-statement s) symbols)
(label-instruction end-label)]
[cond-instructions
(jump-if-zero-instruction cond-value end-label)
then-instructions
(label-instruction end-label)])))
-(defn- compound-statement-handler [s]
- (flatten (mapv block-item->tacky-instruction (:block s))))
+(defn- compound-statement-handler [s symbols]
+ (flatten (mapv #(block-item->tacky-instruction % symbols) (:block s))))
-(defn- break-statement-handler [s]
+(defn- break-statement-handler [s _]
[(jump-instruction (str "break_" (:label s)))])
-(defn- continue-statement-handler [s]
+(defn- continue-statement-handler [s _]
[(jump-instruction (str "continue_" (:label s)))])
-(defn- while-statement-handler [s]
+(defn- while-statement-handler [s symbols]
(let [continue-label (str "continue_" (:label s))
break-label (str "break_" (:label s))
- cond-exp (exp-instructions (:condition s))
+ cond-exp (run-expression-handler (:condition s) symbols)
cond-value (:val cond-exp)
cond-instructions (:instructions cond-exp)
- body-instructions (statement->tacky-instruction (:body s))]
+ body-instructions (statement->tacky-instruction (:body s) symbols)]
(flatten [(label-instruction continue-label)
cond-instructions
(jump-if-zero-instruction cond-value break-label)
@@ -293,14 +415,14 @@
(jump-instruction continue-label)
(label-instruction break-label)])))
-(defn- do-while-statement-handler [s]
+(defn- do-while-statement-handler [s symbols]
(let [start-label (label "do_while_start")
continue-label (str "continue_" (:label s))
break-label (str "break_" (:label s))
- cond-exp (exp-instructions (:condition s))
+ cond-exp (run-expression-handler (:condition s) symbols)
cond-value (:val cond-exp)
cond-instructions (:instructions cond-exp)
- body-instructions (statement->tacky-instruction (:body s))]
+ body-instructions (statement->tacky-instruction (:body s) symbols)]
(flatten [(label-instruction start-label)
body-instructions
(label-instruction continue-label)
@@ -308,20 +430,20 @@
(jump-if-not-zero-instruction cond-value start-label)
(label-instruction break-label)])))
-(defn- for-statement-handler [s]
+(defn- for-statement-handler [s symbols]
(let [init-instructions (if (= :declaration (:type (:init s)))
- (block-item->tacky-instruction (:init s))
- (:instructions (exp-instructions (:init s))))
+ (block-item->tacky-instruction (:init s) symbols)
+ (:instructions (run-expression-handler (:init s) symbols)))
start-label (label "for_start")
break-label (str "break_" (:label s))
continue-label (str "continue_" (:label s))
cond? (not (nil? (:condition s)))
- body-instructions (statement->tacky-instruction (:body s))
+ body-instructions (statement->tacky-instruction (:body s) symbols)
post-instructions (if (nil? (:post s))
[]
- (:instructions (exp-instructions (:post s))))
+ (:instructions (run-expression-handler (:post s) symbols)))
cond-instructions (if cond?
- (let [ce (exp-instructions (:condition s))
+ (let [ce (run-expression-handler (:condition s) symbols)
ce-inst (:instructions ce)
ce-v (:val ce)]
[ce-inst
@@ -337,90 +459,99 @@
(jump-instruction start-label)
(label-instruction break-label)])))
-(defn- statement->tacky-instruction [s]
+(defn- statement->tacky-instruction [s symbols]
(condp = (:statement-type s)
- :return (let [e (exp-instructions (:value s))
+ :return (let [e (run-expression-handler (:value s) symbols)
val (:val e)
instructions (:instructions e)]
(conj (vec instructions) (return-instruction val)))
- :expression [(:instructions (exp-instructions (:value s)))]
- :if (if-statement-handler s)
- :compound (compound-statement-handler s)
- :break (break-statement-handler s)
- :continue (continue-statement-handler s)
- :for (for-statement-handler s)
- :while (while-statement-handler s)
- :do-while (do-while-statement-handler s)
+ :expression [(:instructions (run-expression-handler (:value s) symbols))]
+ :if (if-statement-handler s symbols)
+ :compound (compound-statement-handler s symbols)
+ :break (break-statement-handler s symbols)
+ :continue (continue-statement-handler s symbols)
+ :for (for-statement-handler s symbols)
+ :while (while-statement-handler s symbols)
+ :do-while (do-while-statement-handler s symbols)
:empty []
- (throw (ex-info "Tacky error. Invalid statement." {:statement s}))))
+ (exc/tacky-error "Invalid statement" s)))
-(defn- declaration->tacky-instruction [d]
+(defn- declaration->tacky-instruction [d symbols]
(when (:initial d)
(let [local? (nil? (:storage-class d))
var (parsed-var->tacky-var d) ; only needs :identifier key in declaration
- rhs (exp-instructions (:initial d))]
+ rhs (run-expression-handler (:initial d) symbols)]
(if local?
(flatten [(:instructions rhs) (copy-instruction (:val rhs) var)])
[])))) ; ignoring initializers for non local variable declarations
-(defn- block-item->tacky-instruction [item]
+(defn- block-item->tacky-instruction [item symbols]
(condp = (:type item)
- :statement (statement->tacky-instruction item)
- :declaration (declaration->tacky-instruction item)
- (throw (ex-info "Tacky error. Invalid block item." {:item item}))))
+ :statement (statement->tacky-instruction item symbols)
+ :declaration (declaration->tacky-instruction item symbols)
+ (exc/tacky-error "Invalid block item." item)))
-(defn- function-definition->tacky-function [function-definition ident->symbol]
- (let [add-return (fn [xs] (conj (vec xs) (return-instruction (constant 0))))
+(defn- function-definition->tacky-function [function-definition symbols]
+ (let [add-return (fn [xs] (conj (vec xs) (return-instruction (constant {:type :int :value 0}))))
instructions (->> function-definition
:body
(remove nil?)
- (mapv block-item->tacky-instruction)
+ (mapv #(block-item->tacky-instruction % symbols))
flatten
(remove nil?)
add-return)]
(-> function-definition
(dissoc :body)
- (assoc :global? (get-in ident->symbol [(:identifier function-definition)
- :attrs
- :global?]))
+ (assoc :global? (get-in @symbols [(:identifier function-definition)
+ :attribute
+ :global?]))
(assoc :instructions instructions))))
-(defn- tacky-static-variable [identifier global? variable-type initial-value]
+(defn- tacky-static-variable [identifier global? variable-type initial]
{:identifier identifier
:global? global?
- :initial-value initial-value
+ :initial initial
:type :declaration
:variable-type variable-type
:declaration-type :static-variable})
-(defn- tacky-static-variable-instructions [ident->symbols]
- (reduce
- (fn [acc [k v]]
- (if (string? k)
- (if (= :static (get-in v [:attrs :type]))
- (condp = (get-in v [:attrs :initial-value :type])
- :initial (conj acc (tacky-static-variable k (get-in v [:attrs :global?]) (get-in v [:attrs :initial-value :value])))
- :tentative (conj acc (tacky-static-variable k (get-in v [:attrs :global?]) 0))
- acc)
- acc)
- acc))
- []
- ident->symbols))
-
-(defn- tacky-function-instructions [ast ident->symbol]
+(defn- tacky-static-variable-instructions
+ "Generates list of tacky static variable from symbol map."
+ [ident->symbol]
+ (let [rf (fn [acc [k v]]
+ (if (= :static (get-in v [:attribute :type]))
+ (let [vtype (get-in v [:type])
+ global? (get-in v [:attribute :global?])
+ initial (get-in v [:attribute :initial-value])
+ tentative-initial (if (= :int (:type vtype))
+ (sym/initial-iv (sym/int-init 0))
+ (sym/initial-iv (sym/long-init 0)))
+ itype (get-in v [:attribute :initial-value :type])]
+ (condp = itype
+ :initial (conj acc (tacky-static-variable k global? vtype initial))
+ :tentative (conj acc (tacky-static-variable k global? vtype tentative-initial))
+ acc))
+ acc))]
+ (reduce rf [] ident->symbol)))
+
+(defn- tacky-function-instructions [ast symbols]
(let [fn-defined? (fn [x] (if (= :function (:declaration-type x))
(or (= (:identifier x) "main") (seq (:body x)))
true))]
(->> ast
(filterv #(= :function (:declaration-type %)))
(filterv fn-defined?)
- (mapv #(function-definition->tacky-function % ident->symbol)))))
+ (mapv #(function-definition->tacky-function % symbols)))))
-(defn tacky-generate [{ast :block ident->symbol :ident->symbol}]
+(defn tacky-generate [{ast :program ident->symbol :ident->symbol}]
(let [variable-instructions (tacky-static-variable-instructions ident->symbol)
- function-instructions (tacky-function-instructions ast ident->symbol)]
- {:program (concat variable-instructions function-instructions)
- :ident->symbol ident->symbol}))
+ symbols (atom ident->symbol)
+ function-instructions (tacky-function-instructions ast symbols)
+ program (vec (concat variable-instructions function-instructions))
+ _ (m/coerce s/TackyProgram program)
+ _ (m/coerce s/SymbolMap @symbols)]
+ {:program program
+ :ident->symbol @symbols}))
(defn tacky-from-src [src]
(-> src
@@ -431,6 +562,55 @@
(comment
+ (def tmp
+ "
+long foo(void) {
+ return 1;
+}
+
+int bar(int x, int y) {
+ return x + y;
+}
+
+int main(void) {
+int x = 6;
+return (long) foo() + 2 + x + bar(x, 7) + (3 ? 4 : 5);
+
+}")
+
+ (-> tmp
+ l/lex
+ p/parse
+ a/validate)
+
+ (tacky-from-src tmp)
+
+ ())
+
+(comment
+
+ (def ex "
+long foo(void) {
+ return 1;
+}
+
+int bar(int x, int y) {
+ return x + y;
+}
+
+int main(void) {
+int x = 6;
+return (long) foo() + 2 + x + bar(x, 7) + (3 ? 4 : 5);
+}")
+
+ (-> ex
+ l/lex
+ p/parse
+ a/validate)
+
+ (tacky-from-src
+ "int main(void) { return 42; }")
+
(tacky-from-src
"
extern int foo;
@@ -449,4 +629,34 @@ int foo;
")
+ (def file-path "./test-programs/example.c")
+
+ (slurp "./test-programs/example.c")
+
+ (-> file-path
+ slurp
+ p/parse-from-src
+ a/validate)
+
+ (-> file-path
+ slurp
+ p/parse-from-src
+ a/validate
+ tacky-generate)
+
+ (pretty/explain
+ s/TackyProgram
+ (-> file-path
+ slurp
+ p/parse-from-src
+ a/validate
+ tacky-generate
+ :program))
+
+ (-> file-path
+ slurp
+ p/parse-from-src
+ a/validate
+ tacky-generate)
+
())
diff --git a/src/cljcc/token.clj b/src/cljcc/token.clj
index 86231b8..3eaa505 100644
--- a/src/cljcc/token.clj
+++ b/src/cljcc/token.clj
@@ -213,3 +213,24 @@
:line line
:col col
:literal literal}))
+
+(def tacky-unary-ops
+ #{:bit-not :negate :logical-not})
+
+(def tacky-binary-ops
+ #{:add
+ :sub
+ :mul
+ :div
+ :mod
+ :equal
+ :not-equal
+ :less-than
+ :greater-than
+ :less-or-equal
+ :greater-or-equal
+ :bit-and
+ :bit-or
+ :bit-xor
+ :bit-right-shift
+ :bit-left-shift})