From 52443c837b5967a7712d4d9896c20488a9c65d0d Mon Sep 17 00:00:00 2001 From: Toni Date: Sat, 11 Apr 2026 23:59:15 +0200 Subject: [PATCH] --no-stdlib --- README.md | 2 +- src/codegen_x86_64.rs | 12 +++++------ src/main.rs | 47 +++++++++++++++++++++++++------------------ src/parser.rs | 8 ++++---- src/tokenizer.rs | 14 ++++++------- src/typechecker.rs | 6 +++--- test.zr | 2 -- 7 files changed, 48 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 435a8f4..8278de2 100644 --- a/README.md +++ b/README.md @@ -45,5 +45,5 @@ func main[] : i64 ## Quickstart ``` cargo install --git https://github.com/antpiasecki/zern -zern -m -r hello.zr +zern -r hello.zr ``` diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 21de96e..25679ef 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -97,7 +97,7 @@ impl<'a> CodegenX86_64<'a> { format!("section .data\n{}{}", self.data_section, self.output) } - pub fn emit_prologue(&mut self, use_gcc: bool) -> Result<(), ZernError> { + pub fn emit_prologue(&mut self, use_crt: bool) -> Result<(), ZernError> { emit!( &mut self.output, "section .note.GNU-stack @@ -154,7 +154,7 @@ _builtin_syscall: " ); - if !use_gcc { + if !use_crt { emit!( &mut self.output, " @@ -220,7 +220,7 @@ _builtin_environ: Some(t) => t.lexeme.clone(), None => match &initializer { Expr::Literal(token) => { - if token.token_type == TokenType::Number { + if token.token_type == TokenType::IntLiteral { "i64".into() } else { return error!(&name.loc, "unable to infer variable type"); @@ -504,17 +504,17 @@ _builtin_environ: } Expr::Grouping(expr) => self.compile_expr(env, expr)?, Expr::Literal(token) => match token.token_type { - TokenType::Number => { + TokenType::IntLiteral => { emit!(&mut self.output, " mov rax, {}", token.lexeme); } - TokenType::Char => { + TokenType::CharLiteral => { emit!( &mut self.output, " mov rax, {}", token.lexeme.chars().nth(1).unwrap() as u8 ); } - TokenType::String => { + TokenType::StringLiteral => { // TODO: actual string parsing in the tokenizer let value = &token.lexeme[1..token.lexeme.len() - 1]; diff --git a/src/main.rs b/src/main.rs index 24c969c..ecbc00e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,9 +34,11 @@ fn compile_file(args: Args) -> Result<(), ZernError> { let mut statements = Vec::new(); - parse_std_file!(statements, "std/syscalls.zr"); - parse_std_file!(statements, "std/std.zr"); - parse_std_file!(statements, "std/net.zr"); + if args.include_stdlib { + parse_std_file!(statements, "std/syscalls.zr"); + parse_std_file!(statements, "std/std.zr"); + parse_std_file!(statements, "std/net.zr"); + } let tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source); let parser = parser::Parser::new(tokenizer.tokenize()?); @@ -53,21 +55,21 @@ fn compile_file(args: Args) -> Result<(), ZernError> { } let mut codegen = codegen_x86_64::CodegenX86_64::new(&symbol_table); - codegen.emit_prologue(args.use_gcc)?; + codegen.emit_prologue(args.use_crt)?; for stmt in statements { codegen.compile_stmt(&mut codegen_x86_64::Env::new(), &stmt)?; } - if !args.output_asm { + if !args.emit_only { let out = args.out.unwrap_or_else(|| "out".into()); fs::write(format!("{}.s", out), codegen.get_output()).unwrap(); run_command(format!("nasm -f elf64 -o {}.o {}.s", out, out)); - if args.use_gcc { + if args.use_crt { run_command(format!( - "gcc -no-pie -o {} {}.o -flto -Wl,--gc-sections {}", + "cc -no-pie -o {} {}.o -flto -Wl,--gc-sections {}", out, out, args.cflags )); } else { @@ -110,9 +112,10 @@ fn run_command(cmd: String) { struct Args { path: String, out: Option, - output_asm: bool, + emit_only: bool, + include_stdlib: bool, run_exe: bool, - use_gcc: bool, + use_crt: bool, cflags: String, } @@ -121,9 +124,10 @@ impl Args { let mut out = Args { path: String::new(), out: None, - output_asm: false, + emit_only: false, + include_stdlib: true, run_exe: false, - use_gcc: false, + use_crt: false, cflags: String::new(), }; @@ -132,26 +136,30 @@ impl Args { match args.next() { Some(s) => out.out = Some(s), None => { - eprintln!("\x1b[91mERROR\x1b[0m: -o option requires a name"); + eprintln!("\x1b[91mERROR\x1b[0m: -o option requires a path"); process::exit(1); } } - } else if arg == "-S" { - out.output_asm = true; + } else if arg == "--emit-only" { + out.emit_only = true; + } else if arg == "--no-stdlib" { + out.include_stdlib = false; } else if arg == "-r" { out.run_exe = true; } else if arg == "-m" { - out.use_gcc = true; + out.use_crt = true; } else if arg == "-C" { match args.next() { Some(s) => out.cflags = s, None => { - eprintln!("\x1b[91mERROR\x1b[0m: -C option requires a name"); + eprintln!("\x1b[91mERROR\x1b[0m: -C option requires a value"); process::exit(1); } } } else if arg == "-h" || arg == "--help" { - println!("Usage: zern [-o path] [-S] [-r] [-m] [-C cflags] path"); + println!( + "Usage: zern [-o path] [-r] [-m] [-C cflags] [--emit-only] [--no-stdlib] path" + ); process::exit(0); } else if arg.starts_with('-') { eprintln!("\x1b[91mERROR\x1b[0m: unrecognized option: {}", arg); @@ -169,9 +177,8 @@ impl Args { process::exit(1); } - if !out.use_gcc && !out.cflags.is_empty() { - // no "ERROR:" since its not an error - eprintln!("You can't set CFLAGS if you're not using gcc. Add the -m flag."); + if !out.use_crt && !out.cflags.is_empty() { + eprintln!("You can't set CFLAGS if you're not using the C runtime. Add the -m flag."); process::exit(1); } diff --git a/src/parser.rs b/src/parser.rs index 3c96b89..7f8a375 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -255,7 +255,7 @@ impl Parser { fn const_declaration(&mut self) -> Result { let name = self.consume(TokenType::Identifier, "expected const name")?; self.consume(TokenType::Equal, "expected '=' after const name")?; - let value = self.consume(TokenType::Number, "expected a number after '='")?; + let value = self.consume(TokenType::IntLiteral, "expected a number after '='")?; Ok(Stmt::Const { name, value }) } @@ -576,9 +576,9 @@ impl Parser { fn primary(&mut self) -> Result { if self.match_token(&[ - TokenType::Number, - TokenType::Char, - TokenType::String, + TokenType::IntLiteral, + TokenType::CharLiteral, + TokenType::StringLiteral, TokenType::True, TokenType::False, ]) { diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 445c93d..b2162b0 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -34,9 +34,9 @@ pub enum TokenType { LessEqual, Identifier, - String, - Char, - Number, + StringLiteral, + CharLiteral, + IntLiteral, True, False, @@ -240,7 +240,7 @@ impl Tokenizer { if !self.match_char('\'') { return error!(self.loc, "expected ' after char literal"); } - self.add_token(TokenType::Char)? + self.add_token(TokenType::CharLiteral)? } '"' => { let start_loc = self.loc.clone(); @@ -265,7 +265,7 @@ impl Tokenizer { } self.advance(); - self.add_token(TokenType::String)? + self.add_token(TokenType::StringLiteral)? } ' ' | '\r' => {} '\n' => { @@ -343,7 +343,7 @@ impl Tokenizer { } } - self.add_token(TokenType::Number) + self.add_token(TokenType::IntLiteral) } fn scan_identifier(&mut self) -> Result<(), ZernError> { @@ -392,7 +392,7 @@ impl Tokenizer { fn add_token(&mut self, token_type: TokenType) -> Result<(), ZernError> { let mut lexeme: String = self.source[self.start..self.current].iter().collect(); - if token_type == TokenType::Char || token_type == TokenType::String { + if token_type == TokenType::CharLiteral || token_type == TokenType::StringLiteral { lexeme = self.unescape(&lexeme)?; } diff --git a/src/typechecker.rs b/src/typechecker.rs index e9f9494..f07c634 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -321,9 +321,9 @@ impl<'a> TypeChecker<'a> { } Expr::Grouping(expr) => self.typecheck_expr(env, expr), Expr::Literal(token) => match token.token_type { - TokenType::Number => Ok("i64".into()), - TokenType::Char => Ok("u8".into()), - TokenType::String => Ok("str".into()), + TokenType::IntLiteral => Ok("i64".into()), + TokenType::CharLiteral => Ok("u8".into()), + TokenType::StringLiteral => Ok("str".into()), TokenType::True => Ok("bool".into()), TokenType::False => Ok("bool".into()), _ => unreachable!(), diff --git a/test.zr b/test.zr index de7f608..3c3f06e 100644 --- a/test.zr +++ b/test.zr @@ -28,8 +28,6 @@ func run_test[x: str] : void let run_cmd: str = "./out" if str.equal(x, "examples/curl.zr") run_cmd = str.concat(run_cmd, " http://example.com") - else if str.equal(x, "examples/tokenizer.zr") - run_cmd = str.concat(run_cmd, " test.zr") let run_start_time: i64 = os.time() if must(os.run_shell_command?(run_cmd)) != 0