diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index a92935e..547587d 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -77,12 +77,14 @@ pub struct CodegenX86_64<'a> { data_counter: usize, pub symbol_table: &'a SymbolTable, pub expr_types: &'a HashMap, + emit_debug: bool, } impl<'a> CodegenX86_64<'a> { pub fn new( symbol_table: &'a SymbolTable, expr_types: &'a HashMap, + emit_debug: bool, ) -> CodegenX86_64<'a> { CodegenX86_64 { output: String::new(), @@ -91,6 +93,7 @@ impl<'a> CodegenX86_64<'a> { data_counter: 1, symbol_table, expr_types, + emit_debug, } } @@ -344,11 +347,15 @@ _builtin_environ: body, exported, } => { - if *exported || name.lexeme == "main" { - emit!(&mut self.output, "global {}", name.lexeme); + let name = &name.lexeme; + if self.emit_debug || *exported || name == "main" { + emit!( + &mut self.output, + "global {name}:function (__end_{name} - {name})", + ); } - emit!(&mut self.output, "section .text.{}", name.lexeme); - emit!(&mut self.output, "{}:", name.lexeme); + emit!(&mut self.output, "section .text.{}", name); + emit!(&mut self.output, "{}:", name); emit!(&mut self.output, " push rbp"); emit!(&mut self.output, " mov rbp, rsp"); @@ -398,6 +405,10 @@ _builtin_environ: emit!(&mut self.output, " ret"); } + if self.emit_debug || *exported || name == "main" { + emit!(&mut self.output, "__end_{}:", name); + } + // patch the stack size after we know how much we actually need let patch = format!(" sub rsp, {:<10}", (env.next_offset + 15) & !15); self.output diff --git a/src/main.rs b/src/main.rs index cc10322..161a605 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,7 +54,8 @@ fn compile_file(args: Args) -> Result<(), ZernError> { typechecker.typecheck_stmt(&mut typechecker::Env::new(), stmt)?; } - let mut codegen = codegen_x86_64::CodegenX86_64::new(&symbol_table, &typechecker.expr_types); + let mut codegen = + codegen_x86_64::CodegenX86_64::new(&symbol_table, &typechecker.expr_types, args.emit_debug); codegen.emit_prologue(args.use_crt)?; for stmt in statements { codegen.compile_stmt(&mut codegen_x86_64::Env::new(), &stmt)?; @@ -63,19 +64,18 @@ fn compile_file(args: Args) -> Result<(), ZernError> { if !args.emit_only { let out = args.out.unwrap_or_else(|| "out".into()); - fs::write(format!("{}.s", out), codegen.get_output()).unwrap(); + fs::write(format!("{out}.s"), codegen.get_output()).unwrap(); - run_command(format!("nasm -f elf64 -o {}.o {}.s", out, out)); + run_command(format!("nasm -f elf64 -o {out}.o {out}.s")); if args.use_crt { run_command(format!( - "cc -no-pie -o {} {}.o -flto -Wl,--gc-sections {}", - out, out, args.cflags + "cc -no-pie -o {out} {out}.o -flto -Wl,--gc-sections {}", + args.cflags )); } else { run_command(format!( - "ld -static -o {} {}.o --gc-sections -e _start", - out, out + "ld -static -o {out} {out}.o --gc-sections -e _start" )); } @@ -113,6 +113,7 @@ struct Args { path: String, out: Option, emit_only: bool, + emit_debug: bool, include_stdlib: bool, run_exe: bool, use_crt: bool, @@ -127,6 +128,7 @@ impl Args { path: String::new(), out: None, emit_only: false, + emit_debug: false, include_stdlib: true, run_exe: false, use_crt: false, @@ -150,6 +152,8 @@ impl Args { out.run_exe = true; } else if arg == "-m" { out.use_crt = true; + } else if arg == "-g" { + out.emit_debug = true; } else if arg == "-C" { match args.next() { Some(s) => out.cflags = s, @@ -160,16 +164,16 @@ impl Args { } } else if arg == "-h" || arg == "--help" { println!( - "Usage: zern [-o path] [-r] [-m] [-C cflags] [--emit-only] [--no-stdlib] path" + "Usage: zern [-o path] [-r] [-m] [-g] [-C cflags] [--emit-only] [--no-stdlib] path" ); process::exit(0); } else if arg.starts_with('-') { - eprintln!("\x1b[91mERROR\x1b[0m: unrecognized option: {}", arg); + eprintln!("\x1b[91mERROR\x1b[0m: unrecognized option: {arg}"); process::exit(1); } else if out.path.is_empty() { out.path = arg } else { - eprintln!("\x1b[91mERROR\x1b[0m: unrecognized argument: {}", arg); + eprintln!("\x1b[91mERROR\x1b[0m: unrecognized argument: {arg}"); process::exit(1); } } diff --git a/src/std/std.zr b/src/std/std.zr index 4073f71..286b8a7 100644 --- a/src/std/std.zr +++ b/src/std/std.zr @@ -495,9 +495,6 @@ func str.find[haystack: str, needle: str] : i64 return -1 func str.substr[s: str, start: i64, length: i64] : str - if start < 0 || length < 0 || start + length > str.len(s) - panic("str.substr out of bounds") - out := mem.alloc(length + 1) as str mem.copy(s as ptr + start, out as ptr, length) out[length] = 0 @@ -1038,6 +1035,12 @@ func os.exit[code: i64] : void func os.getpid[] : i64 return _builtin_syscall(SYS_getpid) +func os.basename[path: str] : str + i := path->len() - 1 + while i >= 0 && path[i] != '/' + i -= 1 + return path->substr(i + 1, path->len() - i - 1) + struct os.Timespec tv_sec: i64 tv_nsec: i64 diff --git a/src/tokenizer.rs b/src/tokenizer.rs index a4f3cac..a5a4322 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -260,7 +260,7 @@ impl Tokenizer { break; } else if self.peek() == '\n' { self.loc.line += 1; - self.loc.column = 1; + self.loc.column = 0; } self.advance(); }