This commit is contained in:
2025-06-01 21:48:47 +02:00
parent 437697b287
commit e647e7f508
20 changed files with 167 additions and 147 deletions

View File

@@ -101,11 +101,14 @@ extern printf
extern sprintf
extern strlen
extern strcmp
extern strcat
extern strcpy
extern strdup
extern puts
extern system
print equ puts
extern exit
copystr equ strdup
; generated with clang
strrev:
push r14
push rbx
@@ -118,15 +121,15 @@ strrev:
mov rcx, rax
mov rsi, r14
mov rdx, r14
.LBB0_1:
.strrev.1:
sub rdx, 1
jb .LBB0_2
jb .strrev.2
mov sil, byte [rbx + rsi - 1]
mov byte [rcx], sil
inc rcx
mov rsi, rdx
jmp .LBB0_1
.LBB0_2:
jmp .strrev.1
.strrev.2:
mov byte [rax + r14], 0
add rsp, 8
pop rbx
@@ -138,30 +141,30 @@ isqrt:
mov rcx, 1
mov rbx, rdi
shl rcx, 62
.LBB0_3:
.isqrt.1:
cmp rcx, 0
je .LBB0_5
je .isqrt.5
cmp rcx, rbx
jbe .LBB0_4
jbe .isqrt.2
shr rcx, 2
jmp .LBB0_3
.LBB0_4:
jmp .isqrt.1
.isqrt.2:
cmp rcx, 0
je .LBB0_5
je .isqrt.5
mov rdx, rax
add rdx, rcx
cmp rbx, rdx
jb .LBB0_7
jb .isqrt.3
sub rbx, rdx
shr rax, 1
add rax, rcx
jmp .LBB0_6
.LBB0_7:
jmp .isqrt.4
.isqrt.3:
shr rax, 1
.LBB0_6:
.isqrt.4:
shr rcx, 2
jmp .LBB0_4
.LBB0_5:
jmp .isqrt.2
.isqrt.5:
ret
nth:
@@ -259,10 +262,8 @@ nth:
self.compile_stmt(env, *body)?;
if name.lexeme == "main" {
// default exit code
emit!(&mut self.output, " mov rax, 0");
}
// TODO: default exit code only for main
emit!(&mut self.output, " mov rax, 0");
emit!(&mut self.output, " mov rsp, rbp");
emit!(&mut self.output, " pop rbp");
@@ -356,17 +357,22 @@ nth:
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()
.map(|x| (x as u8).to_string())
.collect::<Vec<String>>()
.join(",");
emit!(
&mut self.data_section,
" S{} db {},0",
self.data_counter,
charcodes,
);
if value.is_empty() {
emit!(&mut self.data_section, " S{} db 0", self.data_counter);
} else {
let charcodes = value
.chars()
.map(|x| (x as u8).to_string())
.collect::<Vec<String>>()
.join(",");
emit!(
&mut self.data_section,
" S{} db {},0",
self.data_counter,
charcodes,
);
}
emit!(&mut self.output, " mov rax, S{}", self.data_counter);
self.data_counter += 1;
}

View File

@@ -10,6 +10,23 @@ use std::{
use tokenizer::ZernError;
fn compile_file_to(
codegen: &mut codegen_x86_64::CodegenX86_64,
filename: &str,
source: String,
) -> Result<(), ZernError> {
let tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source);
let tokens = tokenizer.tokenize()?;
let parser = parser::Parser::new(tokens);
let statements = parser.parse()?;
for stmt in statements {
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), stmt)?;
}
Ok(())
}
fn compile_file(path: String) -> Result<(), ZernError> {
let source = match fs::read_to_string(path.clone()) {
Ok(x) => x,
@@ -21,18 +38,10 @@ fn compile_file(path: String) -> Result<(), ZernError> {
let filename = Path::new(&path).file_name().unwrap().to_str().unwrap();
let tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source);
let tokens = tokenizer.tokenize()?;
let parser = parser::Parser::new(tokens);
let statements = parser.parse()?;
let mut codegen = codegen_x86_64::CodegenX86_64::new();
codegen.emit_prologue()?;
for stmt in statements {
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), stmt)?;
}
compile_file_to(&mut codegen, "std.zr", include_str!("std.zr").into())?;
compile_file_to(&mut codegen, filename, source)?;
codegen.emit_epilogue()?;
if fs::write("out.s", codegen.get_output()).is_err() {

67
src/std.zr Normal file
View File

@@ -0,0 +1,67 @@
func print[x: String] : I64
printf("%s\n", x)
func print_i64[x: I64] : I64
printf("%ld\n", x)
func concat[a: String, b: String] : String
let c: String = malloc(strlen(a) + strlen(b) + 1)
strcpy(c, a)
strcat(c, b)
return c
func Char.to_i64[c: I64]: I64
return c - 48
func I64.to_string[n: I64] : String
let x: I64 = malloc(21)
sprintf(x, "%ld", n)
return x
func Math.gcd[a: I64, b: I64] : I64
while b != 0
let tmp: I64 = b
b = a % b
a = tmp
return a
func Math.min[a: I64, b: I64] : I64
if a < b
return a
return b
func Math.max[a: I64, b: I64] : I64
if a > b
return a
return b
func Math.abs[n: I64] : I64
if n < 0
return -n
return n
func Math.pow[b: I64, e: I64] : I64
let out: I64 = 1
let i: I64 = 0
while i < e
out = out * b
i = i + 1
return out
func Math.lcm[a: I64, b: I64] : I64
return (a * b) / Math.gcd(a, b)
func Math.is_prime[n: I64]: I64
if n <= 1
return false
if n == 2 || n == 3
return true
if n % 2 == 0 || n % 3 == 0
return false
let i: I64 = 5
while i * i <= n
if n % i == 0 || n % (i + 2) == 0
return false
i = i + 6
return true

View File

@@ -220,7 +220,7 @@ impl Tokenizer {
self.handle_indentation()?;
}
'0'..='9' => self.scan_number(),
'A'..='Z' | 'a'..='z' | '_' => self.scan_identifier(),
'A'..='Z' | 'a'..='z' | '_' | '.' => self.scan_identifier(),
_ => return error!(self.loc, "unexpected character"),
}
Ok(())
@@ -295,7 +295,11 @@ impl Tokenizer {
}
fn scan_identifier(&mut self) {
while self.peek().is_alphanumeric() || self.peek() == '_' || self.peek() == '.' {
while self.peek().is_alphanumeric()
|| self.peek() == '_'
|| self.peek() == '.'
|| self.peek() == '!'
{
self.advance();
}