From 8a0fbac7392807973d2bbe14eb1faeca705e82fd Mon Sep 17 00:00:00 2001 From: Toni Date: Sun, 1 Jun 2025 16:12:47 +0200 Subject: [PATCH] support up to 6 args, euler --- examples/euler1.zr | 12 ++++++++++ examples/euler10.zr | 27 ++++++++++++++++++++++ examples/euler14.zr | 27 ++++++++++++++++++++++ examples/euler2.zr | 16 +++++++++++++ examples/euler3.zr | 14 +++++++++++ examples/euler5.zr | 21 +++++++++++++++++ examples/euler6.zr | 18 +++++++++++++++ examples/euler7.zr | 29 +++++++++++++++++++++++ examples/euler9.zr | 14 +++++++++++ examples/fib.zr | 2 +- src/codegen_x86_64.rs | 54 ++++++++++++++++++++++++++----------------- src/main.rs | 3 +-- 12 files changed, 213 insertions(+), 24 deletions(-) create mode 100644 examples/euler1.zr create mode 100644 examples/euler10.zr create mode 100644 examples/euler14.zr create mode 100644 examples/euler2.zr create mode 100644 examples/euler3.zr create mode 100644 examples/euler5.zr create mode 100644 examples/euler6.zr create mode 100644 examples/euler7.zr create mode 100644 examples/euler9.zr diff --git a/examples/euler1.zr b/examples/euler1.zr new file mode 100644 index 0000000..5b22afe --- /dev/null +++ b/examples/euler1.zr @@ -0,0 +1,12 @@ +func print_i64[x : I64] : I64 + printf("%ld\n", x) + +func main[] : I64 + let sum: I64 = 0 + + let i: I64 = 0 + while i < 1000 + if i % 5 == 0 || i % 3 == 0 + sum = sum + i + i = i + 1 + print_i64(sum) \ No newline at end of file diff --git a/examples/euler10.zr b/examples/euler10.zr new file mode 100644 index 0000000..bed9455 --- /dev/null +++ b/examples/euler10.zr @@ -0,0 +1,27 @@ +func print_i64[x : I64] : I64 + printf("%ld\n", x) + +func is_prime[n: I64]: I64 + if n <= 1 + return 0 + if n == 2 || n == 3 + return 1 + if n % 2 == 0 || n % 3 == 0 + return 0 + + let i: I64 = 5 + while i * i <= n + if n % i == 0 || n % (i + 2) == 0 + return 0 + i = i + 6 + return 1 + +func main[] : I64 + let sum: I64 = 0 + + let i: I64 = 0 + while i < 2000000 + if is_prime(i) + sum = sum + i + i = i + 1 + print_i64(sum) \ No newline at end of file diff --git a/examples/euler14.zr b/examples/euler14.zr new file mode 100644 index 0000000..ebdab67 --- /dev/null +++ b/examples/euler14.zr @@ -0,0 +1,27 @@ +func print_i64[x : I64] : I64 + printf("%ld\n", x) + +func collatz_num[n: I64] : I64 + if n % 2 == 0 + return n / 2 + return n * 3 + 1 + +func collatz_seq[n: I64]: I64 + let i: I64 = 1 + while n != 1 + n = collatz_num(n) + i = i + 1 + return i + +func main[] : I64 + let max: I64 = 0 + let max_index: I64 = 0 + + let i: I64 = 1 + while i < 1000000 + let seq: I64 = collatz_seq(i) + if seq > max + max = seq + max_index = i + i = i + 1 + print_i64(max_index) \ No newline at end of file diff --git a/examples/euler2.zr b/examples/euler2.zr new file mode 100644 index 0000000..42d0055 --- /dev/null +++ b/examples/euler2.zr @@ -0,0 +1,16 @@ +func print_i64[x : I64] : I64 + printf("%ld\n", x) + +func main[] : I64 + let sum: I64 = 0 + let a: I64 = 0 + let b: I64 = 1 + + while a < 4000000 + if a % 2 == 0 + sum = sum + a + let temp: I64 = b + b = a + b + a = temp + + print_i64(sum) \ No newline at end of file diff --git a/examples/euler3.zr b/examples/euler3.zr new file mode 100644 index 0000000..ebc099b --- /dev/null +++ b/examples/euler3.zr @@ -0,0 +1,14 @@ +func print_i64[x : I64] : I64 + printf("%ld\n", x) + +func main[] : I64 + let n: I64 = 600851475143 + let f: I64 = 2 + + while f * f <= n + if n % f == 0 + n = n / f + else + f = f + 1 + + print_i64(n) \ No newline at end of file diff --git a/examples/euler5.zr b/examples/euler5.zr new file mode 100644 index 0000000..3fd113b --- /dev/null +++ b/examples/euler5.zr @@ -0,0 +1,21 @@ +func print_i64[x : I64] : I64 + printf("%ld\n", x) + +func gcd[a: I64, b: I64] : I64 + while b != 0 + let tmp: I64 = b + b = a % b + a = tmp + return a + +func lcm[a: I64, b: I64] : I64 + return (a * b) / gcd(a, b) + +func main[] : I64 + let out: I64 = 1 + + let i: I64 = 1 + while i < 21 + out = lcm(out, i) + i = i + 1 + print_i64(out) \ No newline at end of file diff --git a/examples/euler6.zr b/examples/euler6.zr new file mode 100644 index 0000000..1d5d384 --- /dev/null +++ b/examples/euler6.zr @@ -0,0 +1,18 @@ +func print_i64[x : I64] : I64 + printf("%ld\n", x) + +func main[] : I64 + let sum_of_squares: I64 = 0 + let i: I64 = 1 + while i < 101 + sum_of_squares = sum_of_squares + i * i + i = i + 1 + + let square_of_sum: I64 = 0 + i = 1 + while i < 101 + square_of_sum = square_of_sum + i + i = i + 1 + square_of_sum = square_of_sum * square_of_sum + + print_i64(square_of_sum - sum_of_squares) \ No newline at end of file diff --git a/examples/euler7.zr b/examples/euler7.zr new file mode 100644 index 0000000..59d33be --- /dev/null +++ b/examples/euler7.zr @@ -0,0 +1,29 @@ +func print_i64[x : I64] : I64 + printf("%ld\n", x) + +func is_prime[n: I64]: I64 + if n <= 1 + return 0 + if n == 2 || n == 3 + return 1 + if n % 2 == 0 || n % 3 == 0 + return 0 + + let i: I64 = 5 + while i * i <= n + if n % i == 0 || n % (i + 2) == 0 + return 0 + i = i + 6 + return 1 + +func main[] : I64 + let found: I64 = 0 + + let i: I64 = 1 + while 1 + if is_prime(i) + found = found + 1 + if found == 10001 + print_i64(i) + return 0 + i = i + 1 \ No newline at end of file diff --git a/examples/euler9.zr b/examples/euler9.zr new file mode 100644 index 0000000..2588481 --- /dev/null +++ b/examples/euler9.zr @@ -0,0 +1,14 @@ +func print_i64[x : I64] : I64 + printf("%ld\n", x) + +func main[] : I64 + let a: I64 = 1 + while a < 1000 + let b: I64 = 1 + while b < 1000 + let c: I64 = 1000 - b - a + if a * a + b * b == c * c + print_i64(a * b * c) + return 0 + b = b + 1 + a = a + 1 \ No newline at end of file diff --git a/examples/fib.zr b/examples/fib.zr index ae9c4f6..527fbae 100644 --- a/examples/fib.zr +++ b/examples/fib.zr @@ -1,5 +1,5 @@ func print_i64[x : I64] : I64 - printf("%d\n", x) + printf("%ld\n", x) func main[] : I64 let a: I64 = 0 diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 4c88cd5..0538b8b 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -68,6 +68,18 @@ impl CodegenX86_64 { } } + fn nth_register(n: usize) -> &'static str { + match n { + 0 => "rdi", + 1 => "rsi", + 2 => "rdx", + 3 => "rcx", + 4 => "r8", + 5 => "r9", + _ => todo!("only up to 6 arguments supported"), + } + } + fn label(&mut self) -> String { self.label_counter += 1; format!(".L{}", self.label_counter) @@ -158,8 +170,7 @@ print equ puts return_type, body, } => { - assert!(params.len() <= 1); // TODO - assert!(return_type.lexeme == "I64"); + assert!(return_type.lexeme == "I64"); // TODO writeln!(&mut self.output, "global {}", name.lexeme)?; writeln!(&mut self.output, "{}:", name.lexeme)?; @@ -167,17 +178,20 @@ print equ puts writeln!(&mut self.output, " mov rbp, rsp")?; writeln!(&mut self.output, " sub rsp, 256")?; // TODO - if params.len() == 1 { - let offset = env.define_var( - params.first().unwrap().var_name.lexeme.clone(), - params.first().unwrap().var_type.lexeme.clone(), - ); - writeln!(&mut self.output, " mov QWORD [rbp-{}], rdi", offset)?; + for (i, param) in params.iter().enumerate() { + let offset = env + .define_var(param.var_name.lexeme.clone(), param.var_type.lexeme.clone()); + writeln!( + &mut self.output, + " mov QWORD [rbp-{}], {}", + offset, + CodegenX86_64::nth_register(i) + )?; } self.compile_stmt(env, *body)?; - writeln!(&mut self.output, " mov rax, 0")?; + writeln!(&mut self.output, " mov rax, 0")?; // TODO: remove default return value writeln!(&mut self.output, " mov rsp, rbp")?; writeln!(&mut self.output, " pop rbp")?; writeln!(&mut self.output, " ret")?; @@ -215,8 +229,8 @@ print equ puts writeln!(&mut self.output, " mov rax, rdx")?; } TokenType::Xor => writeln!(&mut self.output, " xor rax, rbx")?, - TokenType::And => todo!(), - TokenType::Or => todo!(), + TokenType::And => writeln!(&mut self.output, " and rax, rbx")?, + TokenType::Or => writeln!(&mut self.output, " or rax, rbx")?, TokenType::DoubleEqual => { writeln!(&mut self.output, " cmp rax, rbx")?; writeln!(&mut self.output, " sete al")?; @@ -254,6 +268,7 @@ print equ puts Expr::Literal(token) => match token.token_type { TokenType::Number => writeln!(&mut self.output, " mov rax, {}", token.lexeme)?, TokenType::String => { + // TODO: actual string parsing in the tokenizer let value = &token.lexeme[1..token.lexeme.len() - 1].replace("\\n", "\n"); let charcodes = value .chars() @@ -320,16 +335,13 @@ print equ puts _ => todo!(), }; - // TODO - assert!(args.len() <= 2); - if args.len() == 1 { - self.compile_expr(env, args.first().unwrap().clone())?; - writeln!(&mut self.output, " mov rdi, rax")?; - } else if args.len() == 2 { - self.compile_expr(env, args.first().unwrap().clone())?; - writeln!(&mut self.output, " mov rdi, rax")?; - self.compile_expr(env, args.get(1).unwrap().clone())?; - writeln!(&mut self.output, " mov rsi, rax")?; + for (i, arg) in args.iter().enumerate() { + self.compile_expr(env, arg.clone())?; + writeln!( + &mut self.output, + " mov {}, rax", + CodegenX86_64::nth_register(i) + )?; } writeln!(&mut self.output, " call {}", callee)?; diff --git a/src/main.rs b/src/main.rs index 9b5bfe4..1c04280 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,11 +22,10 @@ fn compile_file(path: String) -> Result<(), Box> { let statements = parser.parse()?; let mut codegen = codegen_x86_64::CodegenX86_64::new(); - let mut env = codegen_x86_64::Env::new(); codegen.emit_prologue()?; for stmt in statements { - codegen.compile_stmt(&mut env, stmt)?; + codegen.compile_stmt(&mut codegen_x86_64::Env::new(), stmt)?; } codegen.emit_epilogue()?;