function params

This commit is contained in:
2025-05-31 17:06:27 +02:00
parent 16431b2ea2
commit 7fa08d8b37
5 changed files with 91 additions and 100 deletions

View File

@@ -1,3 +1,6 @@
func print_i64[x : I64] : I64
printf("%d\n", x)
func main[] : I64 func main[] : I64
let a: I64 = 0 let a: I64 = 0
let b: I64 = 1 let b: I64 = 1

View File

@@ -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<HashMap<String, Var>>,
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<dyn Error>>;
fn emit_epilogue(&mut self) -> Result<(), Box<dyn Error>>;
fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), Box<dyn Error>>;
fn compile_expr(&mut self, env: &mut Env, expr: Expr) -> Result<(), Box<dyn Error>>;
}

View File

@@ -1,11 +1,56 @@
use std::{error::Error, fmt::Write}; use std::{collections::HashMap, error::Error, fmt::Write};
use crate::{ use crate::{
codegen::{Codegen, Env},
parser::{Expr, Stmt}, parser::{Expr, Stmt},
tokenizer::{TokenType, ZernError, error}, tokenizer::{TokenType, ZernError, error},
}; };
pub struct Var {
pub var_type: String,
pub stack_offset: usize,
}
pub struct Env {
scopes: Vec<HashMap<String, Var>>,
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 { pub struct CodegenX86_64 {
output: String, output: String,
data_section: String, data_section: String,
@@ -14,31 +59,30 @@ pub struct CodegenX86_64 {
} }
impl CodegenX86_64 { impl CodegenX86_64 {
pub fn new_boxed() -> Box<dyn Codegen> { pub fn new() -> CodegenX86_64 {
Box::new(CodegenX86_64 { CodegenX86_64 {
output: String::new(), output: String::new(),
data_section: String::from( data_section: String::new(),
"section .data label_counter: 0,
format db \"%ld\\n\\0\" data_counter: 0,
", }
),
label_counter: 1,
data_counter: 1,
})
} }
fn label(&mut self) -> String { fn label(&mut self) -> String {
self.label_counter += 1; self.label_counter += 1;
format!(".L{}", self.label_counter) format!(".L{}", self.label_counter)
} }
pub fn get_output(&self) -> String {
format!(
"section .data
{}
{}",
self.data_section, self.output
)
} }
impl Codegen for CodegenX86_64 { pub fn emit_prologue(&mut self) -> Result<(), Box<dyn Error>> {
fn get_output(&self) -> String {
format!("{}{}", self.data_section, self.output)
}
fn emit_prologue(&mut self) -> Result<(), Box<dyn Error>> {
writeln!( writeln!(
&mut self.output, &mut self.output,
" "
@@ -46,31 +90,21 @@ section .text
extern printf extern printf
extern puts extern puts
print equ 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(()) Ok(())
} }
fn emit_epilogue(&mut self) -> Result<(), Box<dyn Error>> { pub fn emit_epilogue(&mut self) -> Result<(), Box<dyn Error>> {
writeln!(&mut self.output, "section .note.GNU-stack")?; writeln!(&mut self.output, "section .note.GNU-stack")?;
writeln!(&mut self.output, " db 0")?; writeln!(&mut self.output, " db 0")?;
Ok(()) Ok(())
} }
fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), Box<dyn Error>> { pub fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), Box<dyn Error>> {
match stmt { match stmt {
Stmt::Expression(expr) => self.compile_expr(env, expr)?, Stmt::Expression(expr) => self.compile_expr(env, expr)?,
Stmt::Var { Stmt::Let {
name, name,
var_type, var_type,
initializer, initializer,
@@ -124,7 +158,7 @@ print_i64:
return_type, return_type,
body, body,
} => { } => {
assert!(params.is_empty()); // TODO assert!(params.len() <= 1); // TODO
assert!(return_type.lexeme == "I64"); assert!(return_type.lexeme == "I64");
writeln!(&mut self.output, "global {}", name.lexeme)?; writeln!(&mut self.output, "global {}", name.lexeme)?;
@@ -133,6 +167,14 @@ print_i64:
writeln!(&mut self.output, " mov rbp, rsp")?; writeln!(&mut self.output, " mov rbp, rsp")?;
writeln!(&mut self.output, " sub rsp, 256")?; // TODO 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)?; self.compile_stmt(env, *body)?;
writeln!(&mut self.output, " mov rax, 0")?; writeln!(&mut self.output, " mov rax, 0")?;
@@ -150,7 +192,7 @@ print_i64:
Ok(()) Ok(())
} }
fn compile_expr(&mut self, env: &mut Env, expr: Expr) -> Result<(), Box<dyn Error>> { pub fn compile_expr(&mut self, env: &mut Env, expr: Expr) -> Result<(), Box<dyn Error>> {
match expr { match expr {
Expr::Binary { left, op, right } => { Expr::Binary { left, op, right } => {
self.compile_expr(env, *left)?; self.compile_expr(env, *left)?;
@@ -212,7 +254,7 @@ print_i64:
Expr::Literal(token) => match token.token_type { Expr::Literal(token) => match token.token_type {
TokenType::Number => writeln!(&mut self.output, " mov rax, {}", token.lexeme)?, TokenType::Number => writeln!(&mut self.output, " mov rax, {}", token.lexeme)?,
TokenType::String => { 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 let charcodes = value
.chars() .chars()
.map(|x| format!("{}", x as u8)) .map(|x| format!("{}", x as u8))
@@ -279,10 +321,15 @@ print_i64:
}; };
// TODO // TODO
assert!(args.len() <= 1); assert!(args.len() <= 2);
if args.len() == 1 { if args.len() == 1 {
self.compile_expr(env, args.first().unwrap().clone())?; self.compile_expr(env, args.first().unwrap().clone())?;
writeln!(&mut self.output, " mov rdi, rax")?; 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)?; writeln!(&mut self.output, " call {}", callee)?;

View File

@@ -1,4 +1,3 @@
mod codegen;
mod codegen_x86_64; mod codegen_x86_64;
mod parser; mod parser;
mod tokenizer; mod tokenizer;
@@ -22,14 +21,13 @@ fn compile_file(path: String) -> Result<(), Box<dyn Error>> {
let parser = parser::Parser::new(tokens); let parser = parser::Parser::new(tokens);
let statements = parser.parse()?; let statements = parser.parse()?;
let mut codegen = codegen_x86_64::CodegenX86_64::new_boxed(); let mut codegen = codegen_x86_64::CodegenX86_64::new();
codegen.emit_prologue()?; let mut env = codegen_x86_64::Env::new();
let mut env = codegen::Env::new(); codegen.emit_prologue()?;
for stmt in statements { for stmt in statements {
codegen.compile_stmt(&mut env, stmt)?; codegen.compile_stmt(&mut env, stmt)?;
} }
codegen.emit_epilogue()?; codegen.emit_epilogue()?;
fs::write("out.s", codegen.get_output())?; fs::write("out.s", codegen.get_output())?;

View File

@@ -4,14 +4,14 @@ use crate::tokenizer::{Token, TokenType, ZernError, error};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Param { pub struct Param {
var_type: Token, pub var_type: Token,
var_name: Token, pub var_name: Token,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Stmt { pub enum Stmt {
Expression(Expr), Expression(Expr),
Var { Let {
name: Token, name: Token,
var_type: Token, var_type: Token,
initializer: Expr, initializer: Expr,
@@ -142,7 +142,7 @@ impl Parser {
let var_type = self.consume(TokenType::Identifier, "expected variable type")?; let var_type = self.consume(TokenType::Identifier, "expected variable type")?;
self.consume(TokenType::Equal, "expected '=' after variable type")?; self.consume(TokenType::Equal, "expected '=' after variable type")?;
let initializer = self.expression()?; let initializer = self.expression()?;
Ok(Stmt::Var { Ok(Stmt::Let {
name, name,
var_type, var_type,
initializer, initializer,