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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>cljcc: C compiler in Clojure</title>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script type="module" src="js/cljcc-lib-wasm.js"></script>
</head>
<body class="bg-gray-50 text-gray-800 font-sans">
<div class="max-w-6xl mx-auto px-4 py-8">
<header class="mb-6">
<h1 class="text-2xl font-semibold">cljcc </h1>
<p class="text-gray-600 text-sm">C compiler implemented in Clojure.</p>
</header>
<div class="mb-4">
<p class="text-gray-700">C compiler implemented in Clojure. Based on <a href="https://nostarch.com/writing-c-compiler" class="underline text-blue-600 hover:text-blue-800 visited:text-purple-600">Writing a C Compiler by Nora Sandler</a> </p>
<p class="text-gray-700">
Clojure codebase is compiled to WASM using <a href="https://graalvm.github.io/graalvm-demos/native-image/wasm-javac/" class="underline text-blue-600 hover:text-blue-800 visited:text-purple-600">GraalVM native image.</a>
</p>
</div>
<div class="mb-4">
<p class="text-gray-700">
I have only implemented the first 12 chapters of the book. Refer the supported syntax section below.
</p>
<p class="text-gray-700">
Wrote about how I approached implementing this in Clojure. <a class = "underline text-blue-600 hover:text-blue-800 visited:text-purple-600" href="agrawal.me/posts/writing-a-c-compiler-in-clojure/">Writing a C Compiler in Clojure</a>
</p>
</div>
<div class="mb-4">
<p class="text-gray-700">
<a href="https://github.com/kaepr/cljcc" class="underline text-blue-600 hover:text-blue-800 visited:text-purple-600">Github Source: kaepr/cljcc</a>
</p>
</div>
<div class="flex flex-col md:flex-row space-y-4 md:space-y-0 md:space-x-4 mb-4">
<div class="w-full md:w-1/2">
<label for="input" class="block text-sm font-medium mb-1">Input (C code)</label>
<textarea id="input" class="w-full h-80 p-3 border border-gray-300 rounded font-mono text-sm" placeholder="Enter your C code here..."></textarea>
</div>
<div class="w-full md:w-1/2">
<label for="output" class="block text-sm font-medium mb-1">Output</label>
<textarea id="output" class="w-full h-80 p-3 border border-gray-300 bg-gray-50 rounded font-mono text-sm" placeholder="Compiler output will appear here..." readonly></textarea>
</div>
</div>
<div class="mb-6">
<p class="text-sm font-medium text-gray-700 mb-2">Compilation Stage:</p>
<div class="flex flex-wrap gap-4">
<label class="inline-flex items-center">
<input type="radio" name="compilationStage" value="lex" class="form-radio text-gray-800">
<span class="ml-2 text-sm">Tokenize</span>
</label>
<label class="inline-flex items-center">
<input type="radio" name="compilationStage" value="parse" class="form-radio text-gray-800">
<span class="ml-2 text-sm">Parse</span>
</label>
<label class="inline-flex items-center">
<input type="radio" name="compilationStage" value="validate" class="form-radio text-gray-800">
<span class="ml-2 text-sm">Type Check</span>
</label>
<label class="inline-flex items-center">
<input type="radio" name="compilationStage" value="tacky" class="form-radio text-gray-800">
<span class="ml-2 text-sm">Tacky IR</span>
</label>
<label class="inline-flex items-center">
<input type="radio" name="compilationStage" value="codegen" class="form-radio text-gray-800">
<span class="ml-2 text-sm">Codegen</span>
</label>
<label class="inline-flex items-center">
<input type="radio" name="compilationStage" value="emit" class="form-radio text-gray-800" checked>
<span class="ml-2 text-sm">Generate Assembly</span>
</label>
</div>
</div>
<div class="mb-6">
<button onclick="runSelectedCompilerStage()" class="px-4 py-2 bg-blue-700 text-white rounded hover:bg-blue-600 transition-colors text-sm font-medium">Compile</button>
</div>
<!-- Supported Syntax Section -->
<div class="mt-12 pt-6 border-t border-gray-200">
<h2 class="text-xl font-semibold mb-4">Supported Syntax</h2>
<div class="space-y-6">
<div>
<h3 class="text-md font-medium mb-2">Basic Features</h3>
<pre class="bg-gray-100 p-3 rounded border border-gray-300 text-sm font-mono overflow-auto">
<code>// Types
int, long
// Variables
int x; // Local variables
static long count = 0; // Static variables
extern long count2 = 0; // Extern variables
// Control Flow
if (x > 0) { ... } else { ... }
for (int i = 0; i < n; i++) { ... }
while (condition) { ... }
do { ... } while (condition);
// Functions
int main(void);
int add(int a, int b) { return a + b; }
// Operators
+, -, *, /, %, =, ==, !=, >, <, >=, <=, &&, ||, !</code></pre>
</div>
<div>
<h3 class="text-md font-medium mb-2">Example Code</h3>
<pre class="mb-2 bg-gray-100 p-3 rounded border border-gray-300 text-sm font-mono overflow-auto">
<code>int main(void) {
return 42;
}
</code></pre>
<pre class="mb-2 bg-gray-100 p-3 rounded border border-gray-300 text-sm font-mono overflow-auto">
<code>int main(void) {
static int x = 1;
if (x == 42)
return x;
x = x + 1;
return main();
}</code></pre>
<pre class="mb-2 bg-gray-100 p-3 rounded border border-gray-300 text-sm font-mono overflow-auto">
<code>static int x = 20;
int main(void) {
int y = 22;
return x + y;
}</code></pre>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// You can call initialization functions from your compiler.js here
if (typeof initCompiler === 'function') {
initCompiler();
}
document.getElementById('input').value = 'int main(void) {\n return 0;\n}';
});
// Store original console methods
var originalConsoleLog = console.log;
var originalConsoleError = console.error;
// Variables to store captured output
var capturedLogs = [];
var capturedErrors = [];
// Override console.log
console.log = function() {
// Capture the arguments
var args = Array.from(arguments).map(arg =>
typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
);
var message = args.join(' ');
// Add to our captured logs array
capturedLogs.push(message);
// Call original method
originalConsoleLog.apply(console, arguments);
};
// Override console.error
console.error = function() {
// Capture the arguments
var args = Array.from(arguments).map(arg =>
typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
);
var message = args.join(' ');
// Add to our captured errors array
capturedErrors.push(message);
// Call original method
originalConsoleError.apply(console, arguments);
};
// Function to clear captured logs
function clearCapturedOutput() {
capturedLogs = [];
capturedErrors = [];
}
async function runCompiler(source, stage) {
// https://gist.github.com/designbyadrian/2eb329c853516cef618a
try {
const args = [source, "linux", stage];
const config = new GraalVM.Config();
await GraalVM.run(args,config).catch(console.error);
} catch (e) {
}
}
function getCompilationStage() {
const radioButtons = document.getElementsByName('compilationStage');
for (const radioButton of radioButtons) {
if (radioButton.checked) {
return radioButton.value;
}
}
return 'emit';
}
async function runSelectedCompilerStage() {
clearCapturedOutput();
const stage = getCompilationStage();
const source = document.getElementById('input').value;
const outputElement = document.getElementById('output');
try {
let result = "";
await runCompiler(source, stage);
let output = "";
// Add console logs if there are any
if (capturedLogs.length > 0) {
output += capturedLogs.join("\n");
}
// Add console errors if there are any
if (capturedErrors.length > 0) {
output += "Errors:\n" + capturedErrors.join("\n");
}
outputElement.value = output.trim();
} catch (error) {
let errorOutput = "";
// Add console logs if there are any
if (capturedLogs.length > 0) {
errorOutput += capturedLogs.join("\n");
}
if (capturedErrors.length > 0) {
errorOutput += capturedErrors.join("\n");
}
outputElement.value = errorOutput;
}
}
</script>
</body>
</html>
|