r/Compilers • u/slothforestslothbear • 8d ago
Behold my Abomination: Written in Pascal, Single Pass(ish), No AST, No IR
Rockskunk.
Float is the only type. Everything else is QWORD. Shove an "integer" and a string into the same array if you wish.
Compiler written in Pascal. Emits NASM with regex peephole optimization before compilation. Incredibly permissive, you can do whatever you want and are only stopped if there is a syntax error. There are some sassy warnings for unwise choices but it is not the compiler's decision what you do with your code. I have had tons of fun figuring out how things work and learning assembly through a firehose. The IR is nasm source haha. Never going to implement an AST. I didn't read any book but i will need to STUDY the Dragon Book for register allocation. I did a cursory overview and understand nothing.
Backstory. I have been making half-baked transpilers for quite sometime now. Pascal or lisp compiler to C or (a very short) attempt at LLVM but I couldn't get them to behave how i wanted and kept losing interest. I ripped the lexer from one of them and have been using the parsing architecture from the others as inspiration and decided to just buckle down and make what I wanted even though I have been scared of assembly. I am learning as I go and keep making unfortunate choices like trying to track state with a record refactor (arrays only from now on), or routing token evaluation through like 8 redundant functions.
I have always wanted a language like this is because I love systems programming and like to rewrite things like coreutils or make shells and stuff. I love Pascal and dislike C but I have always wanted something that just gets out of my way and lets me do what i want, kinda like a dangerous Lisp. Not in your way, save your thinking for the real puzzle, not which type do you need. I have written cat, non-recursive cp and a (just writes no blocksize or flags) dd. I am going to get those to production quality and also write ls and such. I am about halfway done porting an init system I wrote in Pascal to rockskunk and its gonna be a glorious moment when i start my computer with my own language for the first time.
I finalized the syntax well before I wrote it and there will be no extra concepts, NO OOP, no new types, no restrictions, no guardrails nothing. This is a language that does what you tell it and nothing more. There's tons that i have specced out and not accomplished, but it will always remain like an "Assembly++" incredibly low level language.
Eventual features that will take me 3 years and most of my sanity. Register allocation and first-class vector support. I do not know near enough to even plan how to do these yet but the idea is the compiler uses tests and an IFDEF system that determines by machine (or a flag) what vector unit you want to compile for and sets width and then doing SIMD ops is as simple as a ** b or (a, b) *+ c. Do not count on this ever getting fleshed out but boy am I gonna try.
https://github.com/liam-0398/rockskunk/tree/main
**EDIT when reviewing post just realized my cp doesn't preserve permissions. whoops.
5
u/slothforestslothbear 7d ago edited 7d ago
Ladies and gentleman, this is what the sweet power of regex gets you.
i7-9750H, plugged in. Sum of squares fixed-point 100000000 iterations. Rockskunk vs gcc -O0 and -O2 cold warmup then one hot run I am not cherry picking.
/NFS/Code/rockskunk $ > time ./sumofsqaures
672921401752298880
real 0m0.216s
user 0m0.212s
sys 0m0.000s
/NFS/Code/rockskunk $ > time ./ssO0
672921401752298880
real 0m0.230s
user 0m0.224s
sys 0m0.000s
/NFS/Code/rockskunk $ > time ./ssO2
672921401752298880
real 0m0.080s
user 0m0.074s
sys 0m0.000s
I just beat gcc-O0, mother of god.
6
u/slothforestslothbear 7d ago
#include <stdio.h>
int main() {
long sum = 0;
long i = 0;
while (i <= 100000000) {
long sq = i * i;
sum = sum + sq;
i = i + 1;
}
printf("%ld\n", sum);
return 0;
}
F main() {
sum := 0
i := 0
LW (i <= 100000000) {
sq := i * i
sum := sum + sq
i := i + 1
}
printw(sum)
r := 0
}
section .bss
digitbuf: resb 32
g_argc: resq 1
g_argv: resq 1
section .data
section .text
main:
push rbp
mov rbp, rsp
sub rsp, 0000000032
mov rax, 0
mov [rbp-8], rax
mov rax, 0
mov [rbp-16], rax
LW0:
mov rax, [rbp-16]
cmp rax, 100000000
jg LW1
mov rax, [rbp-16]
imul rax, [rbp-16]
mov [rbp-24], rax
mov rax, [rbp-8]
add rax, [rbp-24]
mov [rbp-8], rax
mov rax, [rbp-16]
add rax, 1
mov [rbp-16], rax
jmp LW0
LW1:
mov rax, [rbp-8]
call print_qword
mov rax, 0
mov [rbp-32], rax
add rsp, 0000000032
pop rbp
ret
global _start
_start:
mov rax, [rsp]
mov [g_argc], rax
lea rax, [rsp + 8]
mov [g_argv], rax
call main
mov rdi, rax
mov rax, 60
syscall
13
u/FloweyTheFlower420 8d ago
the phrase "regex peephole optimization" gave me minor brain damage