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
let a: I64 = 0
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::{
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<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 {
output: String,
data_section: String,
@@ -14,31 +59,30 @@ pub struct CodegenX86_64 {
}
impl CodegenX86_64 {
pub fn new_boxed() -> Box<dyn Codegen> {
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)
}
pub fn get_output(&self) -> String {
format!(
"section .data
{}
{}",
self.data_section, self.output
)
}
impl Codegen for CodegenX86_64 {
fn get_output(&self) -> String {
format!("{}{}", self.data_section, self.output)
}
fn emit_prologue(&mut self) -> Result<(), Box<dyn Error>> {
pub fn emit_prologue(&mut self) -> Result<(), Box<dyn Error>> {
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<dyn Error>> {
pub fn emit_epilogue(&mut self) -> Result<(), Box<dyn Error>> {
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<dyn Error>> {
pub fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), Box<dyn Error>> {
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<dyn Error>> {
pub fn compile_expr(&mut self, env: &mut Env, expr: Expr) -> Result<(), Box<dyn Error>> {
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)?;

View File

@@ -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<dyn Error>> {
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())?;

View File

@@ -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,