blob: 80e4096c999d317291e176ea0c9c3d06949e413a (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
(ns cljcc.driver
(:require
[clojure.java.io :as io]
[cljcc.compiler :as c]
[cljcc.tacky :as t]
[clojure.pprint :as pp]
[cljcc.log :as log]
[cljcc.util :refer [get-os handle-sh mac-aarch64? make-file-name]]
[cljcc.parser :as p]))
(defn validate-os []
(let [os (get-os)]
(condp = os
:linux (log/info "Running on Linux.")
:mac (if (mac-aarch64?)
(log/info "Running on Mac ARM64.")
(log/info "Running on Mac x86_64."))
:unsupported (throw (Exception. (str os " is not currently supported."))))))
(defn remove-extension [^String filename]
(if (.contains filename ".")
(.substring filename 0 (.lastIndexOf filename "."))
filename))
(defn preprocessor-step [directory filename]
(let [input-file-path (make-file-name directory (remove-extension filename) "c")
preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
output (handle-sh "gcc" "-E" "-P" input-file-path "-o" preprocessed-file-path)]
(if (= 1 (:exit output))
(throw (Exception. ^String (:err output)))
(log/info (str "Successfully preprocessed file: " preprocessed-file-path)))))
(defn assemble-step [directory filename]
(let [file-without-ext (remove-extension filename)
assembly-file (make-file-name directory file-without-ext "s")
output-file (str directory "/" file-without-ext)
output (handle-sh "gcc" assembly-file "-o" output-file)]
(if (= 1 (:exit output))
(throw (Exception. ^String (:err output)))
(log/info (str "Successfully created executable at: " output-file)))))
(defn parser-step [directory filename]
(let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
file (io/file preprocessed-file-path)
source (slurp file)]
(if (p/parseable? (p/parse source))
(log/info "Input file is succesfully parsed.")
(throw (Exception. "Failed during parsing")))))
(defn tacky-step [directory filename]
(let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
file (io/file preprocessed-file-path)
source (slurp file)
output (t/tacky-generate (p/parse source))]
(log/info (str
"Successfully generated Tacky IR.\n"
(with-out-str (pp/pprint output))))))
(defn compiler-step [directory filename]
(let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
file (io/file preprocessed-file-path)
source (slurp file)
assembled-source (c/run-compile source)
out-file-path (make-file-name directory (remove-extension filename) "s")]
(spit out-file-path assembled-source)
(log/info (str "Succesfully generated assembly file.\n" assembled-source))))
(defn cleanup-step [directory filename]
(let [file-without-ext (remove-extension filename)]
(io/delete-file (make-file-name directory file-without-ext "i") true)
(io/delete-file (make-file-name directory file-without-ext "s") true)))
(defn create-steps [options directory filename]
(let [base-steps [(partial validate-os)
(partial preprocessor-step directory filename)]
parser-step-fn (partial parser-step directory filename)
compiler-step-fn (partial compiler-step directory filename)
assemble-step-fn (partial assemble-step directory filename)
tacky-step-fn (partial tacky-step directory filename)]
(cond
(:parse options) (concat base-steps [parser-step-fn])
(:tacky options) (concat base-steps [parser-step-fn tacky-step-fn])
(:codegen options) (concat base-steps [parser-step-fn tacky-step-fn compiler-step-fn])
:else (concat base-steps
[parser-step-fn tacky-step-fn compiler-step-fn assemble-step-fn]))))
(defn run-steps [options directory filename]
(let [steps (create-steps options directory filename)]
(run! #(apply % []) steps)))
(defn run
"Runs the compiler driver with the given input source file."
[^String file-path options]
(let [file (io/file ^String file-path)
filename (.getName file)
directory (.getParent file)]
(try
(run-steps options directory filename)
(finally
(cleanup-step directory filename)))))
(comment
(run "./test-programs/ex1.c" {}))
|