diff --git a/examples/euler1.zr b/examples/euler1.zr index a8a12a3..7bee2e8 100644 --- a/examples/euler1.zr +++ b/examples/euler1.zr @@ -1,9 +1,7 @@ func main[] : I64 let sum: I64 = 0 - let i: I64 = 0 - while i < 1000 + for i in 0: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 index 6ca0106..743fe77 100644 --- a/examples/euler10.zr +++ b/examples/euler10.zr @@ -1,9 +1,7 @@ func main[] : I64 let sum: I64 = 0 - let i: I64 = 0 - while i < 2000000 + for i in 0:2000000 if Math.is_prime(i) sum = sum + i - i = i + 1 print_i64(sum) \ No newline at end of file diff --git a/examples/euler12.zr b/examples/euler12.zr index b703de1..988c239 100644 --- a/examples/euler12.zr +++ b/examples/euler12.zr @@ -2,11 +2,9 @@ func num_divisors[n: I64] : I64 let end: I64 = isqrt(n) let result: I64 = 0 - let i: I64 = 1 - while i < end + 1 + for i in 1:end+1 if n % i == 0 result = result + 2 - i = i + 1 if end * end == n result = result - 1 diff --git a/examples/euler14.zr b/examples/euler14.zr index fc53f97..4f7f7a4 100644 --- a/examples/euler14.zr +++ b/examples/euler14.zr @@ -14,11 +14,9 @@ func main[] : I64 let max: I64 = 0 let max_index: I64 = 0 - let i: I64 = 1 - while i < 1000000 + for i in 1: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/euler15.zr b/examples/euler15.zr index 79b8276..835c336 100644 --- a/examples/euler15.zr +++ b/examples/euler15.zr @@ -3,9 +3,7 @@ func main[] : I64 let r: I64 = 20 let out: I64 = 1 - let i: I64 = 1 - while i < r + 1 + for i in 1:r+1 out = out * (n - (r - i)) / i - i = i + 1 print_i64(out) \ No newline at end of file diff --git a/examples/euler4.zr b/examples/euler4.zr index 2d187b5..2a32079 100644 --- a/examples/euler4.zr +++ b/examples/euler4.zr @@ -1,15 +1,13 @@ func main[] : I64 let out: I64 = 0 - let a: I64 = 500 - while a < 1000 - let b: I64 = 500 - while b < 1000 + for a in 500:1000 + for b in 500:1000 if a * b > out let s: String = I64.to_string(a * b) let s_rev: String = strrev(s) if strcmp(s, s_rev) == 0 out = a * b - b = b + 1 - a = a + 1 + free(s) + free(s_rev) print_i64(out) \ No newline at end of file diff --git a/examples/euler5.zr b/examples/euler5.zr index c7d7e8e..60dc55a 100644 --- a/examples/euler5.zr +++ b/examples/euler5.zr @@ -1,8 +1,6 @@ func main[] : I64 let out: I64 = 1 - let i: I64 = 1 - while i < 21 + for i in 1:21 out = Math.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 index eded52f..b380cf6 100644 --- a/examples/euler6.zr +++ b/examples/euler6.zr @@ -1,15 +1,11 @@ func main[] : I64 let sum_of_squares: I64 = 0 - let i: I64 = 1 - while i < 101 + for i in 1:101 sum_of_squares = sum_of_squares + i * i - i = i + 1 let square_of_sum: I64 = 0 - i = 1 - while i < 101 + for i in 1: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/euler8.zr b/examples/euler8.zr index 9f5871e..bf0f024 100644 --- a/examples/euler8.zr +++ b/examples/euler8.zr @@ -2,9 +2,8 @@ func main[] : I64 let n: String = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450" let out: I64 = 0 - let i: I64 = 0 let max: I64 = strlen(n) - 13 - while i < max + for i in 0:max let s: I64 = 1 let j: I64 = 0 while j < 13 @@ -12,5 +11,4 @@ func main[] : I64 j = j + 1 if s > out out = s - i = i + 1 print_i64(out) \ No newline at end of file diff --git a/examples/euler9.zr b/examples/euler9.zr index b37c2a7..0da5dac 100644 --- a/examples/euler9.zr +++ b/examples/euler9.zr @@ -1,11 +1,7 @@ func main[] : I64 - let a: I64 = 1 - while a < 1000 - let b: I64 = 1 - while b < 1000 + for a in 1:1000 + for b in 1: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 + return 0 \ No newline at end of file diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 9019f66..38c84de 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -228,7 +228,10 @@ set: return error!(&name.loc, format!("unknown type: {}", return_type.lexeme)); } - emit!(&mut self.output, "global {}", name.lexeme); + // TODO + if name.lexeme == "main" { + emit!(&mut self.output, "global {}", name.lexeme); + } emit!(&mut self.output, "{}:", name.lexeme); emit!(&mut self.output, " push rbp"); emit!(&mut self.output, " mov rbp, rsp"); @@ -271,6 +274,33 @@ set: emit!(&mut self.output, " call exit"); emit!(&mut self.output, "{}:", skip_label); } + Stmt::For { + var, + start, + end, + body, + } => { + let begin_label = self.label(); + let end_label = self.label(); + + let offset = env.define_var(var.lexeme, "I64".into()); + + self.compile_expr(env, start)?; + emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); + emit!(&mut self.output, "{}:", begin_label); + emit!(&mut self.output, " mov rax, QWORD [rbp-{}]", offset); + emit!(&mut self.output, " push rax"); + self.compile_expr(env, end)?; + emit!(&mut self.output, " pop rcx"); + emit!(&mut self.output, " cmp rcx, rax"); + emit!(&mut self.output, " jge {}", end_label); + self.compile_stmt(env, *body)?; + emit!(&mut self.output, " mov rax, QWORD [rbp-{}]", offset); + emit!(&mut self.output, " add rax, 1"); + emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); + emit!(&mut self.output, " jmp {}", begin_label); + emit!(&mut self.output, "{}:", end_label); + } } Ok(()) } diff --git a/src/main.rs b/src/main.rs index fb9e012..db946c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,7 +50,7 @@ fn compile_file(path: String) -> Result<(), ZernError> { } if !Command::new("nasm") - .args(["-f", "elf64", "-o", "out.o", "out.s"]) + .args(["-f", "elf64", "-w+all", "-o", "out.o", "out.s"]) .status() .unwrap() .success() diff --git a/src/parser.rs b/src/parser.rs index 914bfae..268d04f 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -24,6 +24,12 @@ pub enum Stmt { condition: Expr, body: Box, }, + For { + var: Token, + start: Expr, + end: Expr, + body: Box, + }, Function { name: Token, params: Vec, @@ -167,6 +173,8 @@ impl Parser { self.if_statement() } else if self.match_token(&[TokenType::KeywordWhile]) { self.while_statement() + } else if self.match_token(&[TokenType::KeywordFor]) { + self.for_statement() } else if self.match_token(&[TokenType::KeywordReturn]) { Ok(Stmt::Return(self.expression()?)) } else if self.match_token(&[TokenType::KeywordAssert]) { @@ -207,6 +215,22 @@ impl Parser { }) } + fn for_statement(&mut self) -> Result { + let var = self.consume(TokenType::Identifier, "expected variable name after 'for'")?; + self.consume(TokenType::KeywordIn, "expected 'in' after variable name")?; + let start = self.expression()?; + self.consume(TokenType::Colon, "expected ':' after the number")?; + let end = self.expression()?; + + let body = self.block()?; + Ok(Stmt::For { + var, + start, + end, + body: Box::new(body), + }) + } + fn expression(&mut self) -> Result { self.assignment() } diff --git a/src/tokenizer.rs b/src/tokenizer.rs index cf50c1f..e0e502b 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -37,6 +37,8 @@ pub enum TokenType { KeywordIf, KeywordElse, KeywordWhile, + KeywordFor, + KeywordIn, KeywordFunc, KeywordReturn, KeywordAssert, @@ -310,6 +312,8 @@ impl Tokenizer { "if" => TokenType::KeywordIf, "else" => TokenType::KeywordElse, "while" => TokenType::KeywordWhile, + "for" => TokenType::KeywordFor, + "in" => TokenType::KeywordIn, "func" => TokenType::KeywordFunc, "return" => TokenType::KeywordReturn, "assert" => TokenType::KeywordAssert,