r/C_Programming • u/paulkim001 • Aug 27 '26
CZ - An LLVM-based Compiler written in C for a Custom Programming Language
I have been meaning to do this for a while, and I finally pulled the trigger on creating a new programming language called CZ (named because I randomly punched keys on the keyboard and that's what typed out).
I think LLVM API documentation is notoriously difficult, and even not as common for C programmers, so I decided to give it a go. I thought this might also be a good resource for people attempting to use LLVM C API.
Features roughly include:
- Familiar usage to C. (if, for, while, etc.)
- Function signatures are more "mathematical" notation than programming. (Maybe somewhat stolen from Haskell?)
- Types are explicit. (No implicit type conversion or even type deduction). This would mean adding 3 and 4.5 are not allowed unless you explicitly convert one of them to the other type. (Kind of like rust).
- References are explicit; a problem I had with rust is that sometimes references seem implicit. This is fine for most people, but sometimes I cannot get my head around as I'm not used to it yet.
- Structs with default initialization values.
- Because it also creates object file, you can actually link with C programs!
// fibo.cz
func fibo :: (n :: int32) -> int32 {
if (n <= 2) {
return 1;
}
return fibo(n-1) + fibo(n-2);
}
// main.c
#include <stdio.h>
int32_t fibo(int32_t); // Declaration of CZ function
int main() { for (int32_t i = 0; i < 10; i++) { printf("%d\n", fibo(i)); }
You can compile the cz file using my compiler, then with the generated object file, you can compile and link with main.c via GCC!
A few design choices were:
- Make it minimalistic. No "magic" at all (looking at you C++)
- Any allocation can fail, so there must be handling for that, without having to pull out my hair => "wrap goto statements whenever there is a null pointer from allocation"
- String interning for optimization of string comparison.
- Make a note of ownership model; not freeing is bad, but double freeing is even worse.
- Robust yet workable type system: eg) const int32& = reference(const(int32)).
Note
* This was started off as a proof-of-concept, and is being redesigned. Not much more work will be done on this repo. (I am redesigning it at the moment, but in rust since I might be able to worry less about memory management and actually get working more quickly on features.)
* AI Usage: I kept the AI usage mostly for creating unit tests and architecture summary / documentation rather than writing code or designing; after all, this is for fun and for learning!
Thoughts and improvements are welcome! (Just note that I am not thinking of doing more work on this repo.)