From 7fa08d8b37772a6fb53cada06e05299661284273 Mon Sep 17 00:00:00 2001 From: Toni Date: Sat, 31 May 2025 17:06:27 +0200 Subject: [PATCH] function params --- examples/fib.zr | 3 ++ src/codegen.rs | 57 --------------------- src/codegen_x86_64.rs | 115 +++++++++++++++++++++++++++++------------- src/main.rs | 8 ++- src/parser.rs | 8 +-- 5 files changed, 91 insertions(+), 100 deletions(-) delete mode 100644 src/codegen.rs diff --git a/examples/fib.zr b/examples/fib.zr index afe69ec..ae9c4f6 100644 --- a/examples/fib.zr +++ b/examples/fib.zr @@ -1,3 +1,6 @@ +func print_i64[x : I64] : I64 + printf("%d\n", x) + func main[] : I64 let a: I64 = 0 let b: I64 = 1 diff --git a/src/codegen.rs b/src/codegen.rs deleted file mode 100644 index 73111a1..0000000 --- a/src/codegen.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::{collections::HashMap, error::Error}; - -use crate::parser::{Expr, Stmt}; - -pub struct Var { - pub var_type: String, - pub stack_offset: usize, -} - -pub struct Env { - scopes: Vec>, - next_offset: usize, -} - -impl Env { - pub fn new() -> Env { - Env { - scopes: vec![HashMap::new()], - next_offset: 8, - } - } - - pub fn push_scope(&mut self) { - self.scopes.push(HashMap::new()); - } - - pub fn pop_scope(&mut self) { - self.scopes.pop(); - } - - pub fn define_var(&mut self, name: String, var_type: String) -> usize { - let offset = self.next_offset; - self.next_offset += 8; - self.scopes.last_mut().unwrap().insert(name, Var { - var_type, - stack_offset: offset, - }); - offset - } - - pub fn get_var(&self, name: &str) -> Option<&Var> { - for scope in self.scopes.iter().rev() { - if let Some(var) = scope.get(name) { - return Some(var); - } - } - None - } -} - -pub trait Codegen { - fn get_output(&self) -> String; - fn emit_prologue(&mut self) -> Result<(), Box>; - fn emit_epilogue(&mut self) -> Result<(), Box>; - fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), Box>; - fn compile_expr(&mut self, env: &mut Env, expr: Expr) -> Result<(), Box>; -} diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 54dab93..4c88cd5 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -1,11 +1,56 @@ -use std::{error::Error, fmt::Write}; +use std::{collections::HashMap, error::Error, fmt::Write}; use crate::{ - codegen::{Codegen, Env}, parser::{Expr, Stmt}, tokenizer::{TokenType, ZernError, error}, }; +pub struct Var { + pub var_type: String, + pub stack_offset: usize, +} + +pub struct Env { + scopes: Vec>, + next_offset: usize, +} + +impl Env { + pub fn new() -> Env { + Env { + scopes: vec![HashMap::new()], + next_offset: 8, + } + } + + pub fn push_scope(&mut self) { + self.scopes.push(HashMap::new()); + } + + pub fn pop_scope(&mut self) { + self.scopes.pop(); + } + + pub fn define_var(&mut self, name: String, var_type: String) -> usize { + let offset = self.next_offset; + self.next_offset += 8; + self.scopes.last_mut().unwrap().insert(name, Var { + var_type, + stack_offset: offset, + }); + offset + } + + pub fn get_var(&self, name: &str) -> Option<&Var> { + for scope in self.scopes.iter().rev() { + if let Some(var) = scope.get(name) { + return Some(var); + } + } + None + } +} + pub struct CodegenX86_64 { output: String, data_section: String, @@ -14,31 +59,30 @@ pub struct CodegenX86_64 { } impl CodegenX86_64 { - pub fn new_boxed() -> Box { - Box::new(CodegenX86_64 { + pub fn new() -> CodegenX86_64 { + CodegenX86_64 { output: String::new(), - data_section: String::from( - "section .data - format db \"%ld\\n\\0\" -", - ), - label_counter: 1, - data_counter: 1, - }) + data_section: String::new(), + label_counter: 0, + data_counter: 0, + } } fn label(&mut self) -> String { self.label_counter += 1; format!(".L{}", self.label_counter) } -} -impl Codegen for CodegenX86_64 { - fn get_output(&self) -> String { - format!("{}{}", self.data_section, self.output) + pub fn get_output(&self) -> String { + format!( + "section .data +{} +{}", + self.data_section, self.output + ) } - fn emit_prologue(&mut self) -> Result<(), Box> { + pub fn emit_prologue(&mut self) -> Result<(), Box> { writeln!( &mut self.output, " @@ -46,31 +90,21 @@ section .text extern printf extern puts print equ puts - -print_i64: - push rbp - mov rbp, rsp - mov rdi, format - mov rsi, rax - xor rax, rax - call printf - pop rbp - ret " )?; Ok(()) } - fn emit_epilogue(&mut self) -> Result<(), Box> { + pub fn emit_epilogue(&mut self) -> Result<(), Box> { writeln!(&mut self.output, "section .note.GNU-stack")?; writeln!(&mut self.output, " db 0")?; Ok(()) } - fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), Box> { + pub fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), Box> { match stmt { Stmt::Expression(expr) => self.compile_expr(env, expr)?, - Stmt::Var { + Stmt::Let { name, var_type, initializer, @@ -124,7 +158,7 @@ print_i64: return_type, body, } => { - assert!(params.is_empty()); // TODO + assert!(params.len() <= 1); // TODO assert!(return_type.lexeme == "I64"); writeln!(&mut self.output, "global {}", name.lexeme)?; @@ -133,6 +167,14 @@ print_i64: writeln!(&mut self.output, " mov rbp, rsp")?; writeln!(&mut self.output, " sub rsp, 256")?; // TODO + if params.len() == 1 { + let offset = env.define_var( + params.first().unwrap().var_name.lexeme.clone(), + params.first().unwrap().var_type.lexeme.clone(), + ); + writeln!(&mut self.output, " mov QWORD [rbp-{}], rdi", offset)?; + } + self.compile_stmt(env, *body)?; writeln!(&mut self.output, " mov rax, 0")?; @@ -150,7 +192,7 @@ print_i64: Ok(()) } - fn compile_expr(&mut self, env: &mut Env, expr: Expr) -> Result<(), Box> { + pub fn compile_expr(&mut self, env: &mut Env, expr: Expr) -> Result<(), Box> { match expr { Expr::Binary { left, op, right } => { self.compile_expr(env, *left)?; @@ -212,7 +254,7 @@ print_i64: Expr::Literal(token) => match token.token_type { TokenType::Number => writeln!(&mut self.output, " mov rax, {}", token.lexeme)?, TokenType::String => { - let value = &token.lexeme[1..token.lexeme.len() - 1]; + let value = &token.lexeme[1..token.lexeme.len() - 1].replace("\\n", "\n"); let charcodes = value .chars() .map(|x| format!("{}", x as u8)) @@ -279,10 +321,15 @@ print_i64: }; // TODO - assert!(args.len() <= 1); + assert!(args.len() <= 2); if args.len() == 1 { self.compile_expr(env, args.first().unwrap().clone())?; writeln!(&mut self.output, " mov rdi, rax")?; + } else if args.len() == 2 { + self.compile_expr(env, args.first().unwrap().clone())?; + writeln!(&mut self.output, " mov rdi, rax")?; + self.compile_expr(env, args.get(1).unwrap().clone())?; + writeln!(&mut self.output, " mov rsi, rax")?; } writeln!(&mut self.output, " call {}", callee)?; diff --git a/src/main.rs b/src/main.rs index 76314fb..9b5bfe4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ -mod codegen; mod codegen_x86_64; mod parser; mod tokenizer; @@ -22,14 +21,13 @@ fn compile_file(path: String) -> Result<(), Box> { let parser = parser::Parser::new(tokens); let statements = parser.parse()?; - let mut codegen = codegen_x86_64::CodegenX86_64::new_boxed(); - codegen.emit_prologue()?; + let mut codegen = codegen_x86_64::CodegenX86_64::new(); + let mut env = codegen_x86_64::Env::new(); - let mut env = codegen::Env::new(); + codegen.emit_prologue()?; for stmt in statements { codegen.compile_stmt(&mut env, stmt)?; } - codegen.emit_epilogue()?; fs::write("out.s", codegen.get_output())?; diff --git a/src/parser.rs b/src/parser.rs index 5f4b406..42abd4d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -4,14 +4,14 @@ use crate::tokenizer::{Token, TokenType, ZernError, error}; #[derive(Debug, Clone)] pub struct Param { - var_type: Token, - var_name: Token, + pub var_type: Token, + pub var_name: Token, } #[derive(Debug, Clone)] pub enum Stmt { Expression(Expr), - Var { + Let { name: Token, var_type: Token, initializer: Expr, @@ -142,7 +142,7 @@ impl Parser { let var_type = self.consume(TokenType::Identifier, "expected variable type")?; self.consume(TokenType::Equal, "expected '=' after variable type")?; let initializer = self.expression()?; - Ok(Stmt::Var { + Ok(Stmt::Let { name, var_type, initializer,