--no-stdlib

This commit is contained in:
2026-04-11 23:59:15 +02:00
parent 3fd4fcd062
commit 52443c837b
7 changed files with 48 additions and 43 deletions

View File

@@ -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];

View File

@@ -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<String>,
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);
}

View File

@@ -255,7 +255,7 @@ impl Parser {
fn const_declaration(&mut self) -> Result<Stmt, ZernError> {
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<Expr, ZernError> {
if self.match_token(&[
TokenType::Number,
TokenType::Char,
TokenType::String,
TokenType::IntLiteral,
TokenType::CharLiteral,
TokenType::StringLiteral,
TokenType::True,
TokenType::False,
]) {

View File

@@ -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)?;
}

View File

@@ -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!(),