codegen trait
This commit is contained in:
268
src/codegen.rs
268
src/codegen.rs
@@ -1,13 +1,10 @@
|
|||||||
use std::{collections::HashMap, error::Error, fmt::Write};
|
use std::{collections::HashMap, error::Error};
|
||||||
|
|
||||||
use crate::{
|
use crate::parser::{Expr, Stmt};
|
||||||
parser::{Expr, Stmt},
|
|
||||||
tokenizer::{MotError, TokenType, error},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Var {
|
pub struct Var {
|
||||||
var_type: String,
|
pub var_type: String,
|
||||||
stack_offset: usize,
|
pub stack_offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Env {
|
pub struct Env {
|
||||||
@@ -19,9 +16,10 @@ impl Env {
|
|||||||
pub fn new() -> Env {
|
pub fn new() -> Env {
|
||||||
Env {
|
Env {
|
||||||
scopes: vec![HashMap::new()],
|
scopes: vec![HashMap::new()],
|
||||||
next_offset: 8,
|
next_offset: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_scope(&mut self) {
|
pub fn push_scope(&mut self) {
|
||||||
self.scopes.push(HashMap::new());
|
self.scopes.push(HashMap::new());
|
||||||
}
|
}
|
||||||
@@ -32,7 +30,7 @@ impl Env {
|
|||||||
|
|
||||||
pub fn define_var(&mut self, name: String, var_type: String) -> usize {
|
pub fn define_var(&mut self, name: String, var_type: String) -> usize {
|
||||||
let offset = self.next_offset;
|
let offset = self.next_offset;
|
||||||
self.next_offset += 8;
|
self.next_offset += 1;
|
||||||
self.scopes.last_mut().unwrap().insert(name, Var {
|
self.scopes.last_mut().unwrap().insert(name, Var {
|
||||||
var_type,
|
var_type,
|
||||||
stack_offset: offset,
|
stack_offset: offset,
|
||||||
@@ -50,250 +48,10 @@ impl Env {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Codegen {
|
pub trait Codegen {
|
||||||
output: String,
|
fn emit_prologue(&mut self) -> Result<(), Box<dyn Error>>;
|
||||||
label_counter: usize,
|
fn emit_epilogue(&mut self) -> Result<(), Box<dyn Error>>;
|
||||||
}
|
fn get_output(&self) -> String;
|
||||||
|
fn compile_stmt(&mut self, env: &mut Env, stmt: Stmt) -> Result<(), Box<dyn Error>>;
|
||||||
impl Codegen {
|
fn compile_expr(&mut self, env: &mut Env, expr: Expr) -> Result<(), Box<dyn Error>>;
|
||||||
pub fn new() -> Codegen {
|
|
||||||
Codegen {
|
|
||||||
output: String::new(),
|
|
||||||
label_counter: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn emit_prologue(&mut self) -> Result<(), Box<dyn Error>> {
|
|
||||||
writeln!(
|
|
||||||
&mut self.output,
|
|
||||||
"section .data
|
|
||||||
format db \"%ld\", 10, 0
|
|
||||||
|
|
||||||
section .text
|
|
||||||
extern printf
|
|
||||||
|
|
||||||
print:
|
|
||||||
push rbp
|
|
||||||
mov rbp, rsp
|
|
||||||
mov rdi, format
|
|
||||||
mov rsi, rax
|
|
||||||
xor rax, rax
|
|
||||||
call printf
|
|
||||||
pop rbp
|
|
||||||
ret
|
|
||||||
"
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
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(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_output(self) -> String {
|
|
||||||
self.output
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn label(&mut self) -> String {
|
|
||||||
self.label_counter += 1;
|
|
||||||
format!(".L{}", self.label_counter)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
name,
|
|
||||||
var_type,
|
|
||||||
initializer,
|
|
||||||
} => {
|
|
||||||
// TODO: types
|
|
||||||
assert!(var_type.lexeme == "I64");
|
|
||||||
|
|
||||||
self.compile_expr(env, initializer)?;
|
|
||||||
let offset = env.define_var(name.lexeme.clone(), var_type.lexeme);
|
|
||||||
writeln!(&mut self.output, " mov QWORD [rbp-{}], rax", offset)?;
|
|
||||||
}
|
|
||||||
Stmt::Block(statements) => {
|
|
||||||
env.push_scope();
|
|
||||||
for stmt in statements {
|
|
||||||
self.compile_stmt(env, stmt)?;
|
|
||||||
}
|
|
||||||
env.pop_scope();
|
|
||||||
}
|
|
||||||
Stmt::If {
|
|
||||||
condition,
|
|
||||||
then_branch,
|
|
||||||
else_branch,
|
|
||||||
} => {
|
|
||||||
let else_label = self.label();
|
|
||||||
let end_label = self.label();
|
|
||||||
|
|
||||||
self.compile_expr(env, condition)?;
|
|
||||||
writeln!(&mut self.output, " test rax, rax")?;
|
|
||||||
writeln!(&mut self.output, " je {}", else_label)?;
|
|
||||||
self.compile_stmt(env, *then_branch.clone())?;
|
|
||||||
writeln!(&mut self.output, " jmp {}", end_label)?;
|
|
||||||
writeln!(&mut self.output, "{}:", else_label)?;
|
|
||||||
self.compile_stmt(env, *else_branch.clone())?;
|
|
||||||
writeln!(&mut self.output, "{}:", end_label)?;
|
|
||||||
}
|
|
||||||
Stmt::While { condition, body } => {
|
|
||||||
let begin_label = self.label();
|
|
||||||
let end_label = self.label();
|
|
||||||
|
|
||||||
writeln!(&mut self.output, "{}:", begin_label)?;
|
|
||||||
self.compile_expr(env, condition)?;
|
|
||||||
writeln!(&mut self.output, " test rax, rax")?;
|
|
||||||
writeln!(&mut self.output, " je {}", end_label)?;
|
|
||||||
self.compile_stmt(env, *body.clone())?;
|
|
||||||
writeln!(&mut self.output, " jmp {}", begin_label)?;
|
|
||||||
writeln!(&mut self.output, "{}:", end_label)?;
|
|
||||||
}
|
|
||||||
Stmt::Function { name, params, body } => {
|
|
||||||
assert!(params.is_empty()); // TODO
|
|
||||||
|
|
||||||
writeln!(&mut self.output, "global {}", name.lexeme)?;
|
|
||||||
writeln!(&mut self.output, "{}:", name.lexeme)?;
|
|
||||||
writeln!(&mut self.output, " push rbp")?;
|
|
||||||
writeln!(&mut self.output, " mov rbp, rsp")?;
|
|
||||||
writeln!(&mut self.output, " sub rsp, 256")?; // TODO
|
|
||||||
|
|
||||||
self.compile_stmt(env, *body)?;
|
|
||||||
|
|
||||||
writeln!(&mut self.output, " mov rsp, rbp")?;
|
|
||||||
writeln!(&mut self.output, " pop rbp")?;
|
|
||||||
writeln!(&mut self.output, " mov rax, 0")?;
|
|
||||||
writeln!(&mut self.output, " ret")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
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)?;
|
|
||||||
writeln!(&mut self.output, " push rax")?;
|
|
||||||
self.compile_expr(env, *right)?;
|
|
||||||
writeln!(&mut self.output, " mov rbx, rax")?;
|
|
||||||
writeln!(&mut self.output, " pop rax")?;
|
|
||||||
|
|
||||||
match op.token_type {
|
|
||||||
TokenType::Plus => writeln!(&mut self.output, " add rax, rbx")?,
|
|
||||||
TokenType::Minus => writeln!(&mut self.output, " sub rax, rbx")?,
|
|
||||||
TokenType::Star => writeln!(&mut self.output, " imul rax, rbx")?,
|
|
||||||
TokenType::Slash => {
|
|
||||||
writeln!(&mut self.output, " cqo")?;
|
|
||||||
writeln!(&mut self.output, " idiv rbx")?;
|
|
||||||
}
|
|
||||||
TokenType::Mod => {
|
|
||||||
writeln!(&mut self.output, " cqo")?;
|
|
||||||
writeln!(&mut self.output, " idiv rbx")?;
|
|
||||||
writeln!(&mut self.output, " mov rax, rdx")?;
|
|
||||||
}
|
|
||||||
TokenType::Xor => writeln!(&mut self.output, " xor rax, rbx")?,
|
|
||||||
TokenType::And => todo!(),
|
|
||||||
TokenType::Or => todo!(),
|
|
||||||
TokenType::DoubleEqual => {
|
|
||||||
writeln!(&mut self.output, " cmp rax, rbx")?;
|
|
||||||
writeln!(&mut self.output, " sete al")?;
|
|
||||||
writeln!(&mut self.output, " movzx rax, al")?;
|
|
||||||
}
|
|
||||||
TokenType::NotEqual => {
|
|
||||||
writeln!(&mut self.output, " cmp rax, rbx")?;
|
|
||||||
writeln!(&mut self.output, " setne al")?;
|
|
||||||
writeln!(&mut self.output, " movzx rax, al")?;
|
|
||||||
}
|
|
||||||
TokenType::Greater => {
|
|
||||||
writeln!(&mut self.output, " cmp rax, rbx")?;
|
|
||||||
writeln!(&mut self.output, " setg al")?;
|
|
||||||
writeln!(&mut self.output, " movzx rax, al")?;
|
|
||||||
}
|
|
||||||
TokenType::GreaterEqual => {
|
|
||||||
writeln!(&mut self.output, " cmp rax, rbx")?;
|
|
||||||
writeln!(&mut self.output, " setge al")?;
|
|
||||||
writeln!(&mut self.output, " movzx rax, al")?;
|
|
||||||
}
|
|
||||||
TokenType::Less => {
|
|
||||||
writeln!(&mut self.output, " cmp rax, rbx")?;
|
|
||||||
writeln!(&mut self.output, " setl al")?;
|
|
||||||
writeln!(&mut self.output, " movzx rax, al")?;
|
|
||||||
}
|
|
||||||
TokenType::LessEqual => {
|
|
||||||
writeln!(&mut self.output, " cmp rax, rbx")?;
|
|
||||||
writeln!(&mut self.output, " setle al")?;
|
|
||||||
writeln!(&mut self.output, " movzx rax, al")?;
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expr::Grouping(expr) => self.compile_expr(env, *expr)?,
|
|
||||||
Expr::Literal(token) => match token.token_type {
|
|
||||||
TokenType::Number => writeln!(&mut self.output, " mov rax, {}", token.lexeme)?,
|
|
||||||
TokenType::String => todo!(),
|
|
||||||
_ => unreachable!(),
|
|
||||||
},
|
|
||||||
Expr::Unary { op, right } => {
|
|
||||||
self.compile_expr(env, *right)?;
|
|
||||||
match op.token_type {
|
|
||||||
TokenType::Minus => writeln!(&mut self.output, " neg rax")?,
|
|
||||||
TokenType::Bang => {
|
|
||||||
writeln!(&mut self.output, " test rax, rax")?;
|
|
||||||
writeln!(&mut self.output, " sete al")?;
|
|
||||||
writeln!(&mut self.output, " movzx rax, al")?;
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expr::Variable(name) => {
|
|
||||||
let var = match env.get_var(&name.lexeme) {
|
|
||||||
Some(x) => x,
|
|
||||||
None => {
|
|
||||||
return error!(name.loc, format!("undefined variable: {}", &name.lexeme));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
writeln!(
|
|
||||||
&mut self.output,
|
|
||||||
" mov rax, QWORD [rbp-{}]",
|
|
||||||
var.stack_offset
|
|
||||||
)?
|
|
||||||
}
|
|
||||||
Expr::Assign { name, value } => {
|
|
||||||
self.compile_expr(env, *value)?;
|
|
||||||
|
|
||||||
let var = match env.get_var(&name.lexeme) {
|
|
||||||
Some(x) => x,
|
|
||||||
None => {
|
|
||||||
return error!(name.loc, format!("undefined variable: {}", &name.lexeme));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
writeln!(
|
|
||||||
&mut self.output,
|
|
||||||
" mov QWORD [rbp-{}], rax",
|
|
||||||
var.stack_offset
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Expr::Call {
|
|
||||||
callee,
|
|
||||||
paren: _,
|
|
||||||
args,
|
|
||||||
} => {
|
|
||||||
let callee = match *callee {
|
|
||||||
Expr::Variable(name) => name.lexeme,
|
|
||||||
_ => todo!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
assert!(args.len() == 1);
|
|
||||||
|
|
||||||
self.compile_expr(env, args.first().unwrap().clone())?;
|
|
||||||
writeln!(&mut self.output, " mov rdi, rax")?;
|
|
||||||
writeln!(&mut self.output, " call {}", callee)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
257
src/codegen_x86_64.rs
Normal file
257
src/codegen_x86_64.rs
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
use std::{error::Error, fmt::Write};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
codegen::{Codegen, Env},
|
||||||
|
parser::{Expr, Stmt},
|
||||||
|
tokenizer::{MotError, TokenType, error},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct CodegenX86_64 {
|
||||||
|
output: String,
|
||||||
|
label_counter: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodegenX86_64 {
|
||||||
|
pub fn new_boxed() -> Box<dyn Codegen> {
|
||||||
|
Box::new(CodegenX86_64 {
|
||||||
|
output: String::new(),
|
||||||
|
label_counter: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn label(&mut self) -> String {
|
||||||
|
self.label_counter += 1;
|
||||||
|
format!(".L{}", self.label_counter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Codegen for CodegenX86_64 {
|
||||||
|
fn emit_prologue(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
|
writeln!(
|
||||||
|
&mut self.output,
|
||||||
|
"section .data
|
||||||
|
format db \"%ld\", 10, 0
|
||||||
|
|
||||||
|
section .text
|
||||||
|
extern printf
|
||||||
|
|
||||||
|
print:
|
||||||
|
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>> {
|
||||||
|
writeln!(&mut self.output, "section .note.GNU-stack")?;
|
||||||
|
writeln!(&mut self.output, " db 0")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_output(&self) -> String {
|
||||||
|
self.output.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
name,
|
||||||
|
var_type,
|
||||||
|
initializer,
|
||||||
|
} => {
|
||||||
|
// TODO: types
|
||||||
|
assert!(var_type.lexeme == "I64");
|
||||||
|
|
||||||
|
self.compile_expr(env, initializer)?;
|
||||||
|
let offset = env.define_var(name.lexeme.clone(), var_type.lexeme);
|
||||||
|
writeln!(&mut self.output, " mov QWORD [rbp-{}], rax", offset * 8)?;
|
||||||
|
}
|
||||||
|
Stmt::Block(statements) => {
|
||||||
|
env.push_scope();
|
||||||
|
for stmt in statements {
|
||||||
|
self.compile_stmt(env, stmt)?;
|
||||||
|
}
|
||||||
|
env.pop_scope();
|
||||||
|
}
|
||||||
|
Stmt::If {
|
||||||
|
condition,
|
||||||
|
then_branch,
|
||||||
|
else_branch,
|
||||||
|
} => {
|
||||||
|
let else_label = self.label();
|
||||||
|
let end_label = self.label();
|
||||||
|
|
||||||
|
self.compile_expr(env, condition)?;
|
||||||
|
writeln!(&mut self.output, " test rax, rax")?;
|
||||||
|
writeln!(&mut self.output, " je {}", else_label)?;
|
||||||
|
self.compile_stmt(env, *then_branch.clone())?;
|
||||||
|
writeln!(&mut self.output, " jmp {}", end_label)?;
|
||||||
|
writeln!(&mut self.output, "{}:", else_label)?;
|
||||||
|
self.compile_stmt(env, *else_branch.clone())?;
|
||||||
|
writeln!(&mut self.output, "{}:", end_label)?;
|
||||||
|
}
|
||||||
|
Stmt::While { condition, body } => {
|
||||||
|
let begin_label = self.label();
|
||||||
|
let end_label = self.label();
|
||||||
|
|
||||||
|
writeln!(&mut self.output, "{}:", begin_label)?;
|
||||||
|
self.compile_expr(env, condition)?;
|
||||||
|
writeln!(&mut self.output, " test rax, rax")?;
|
||||||
|
writeln!(&mut self.output, " je {}", end_label)?;
|
||||||
|
self.compile_stmt(env, *body.clone())?;
|
||||||
|
writeln!(&mut self.output, " jmp {}", begin_label)?;
|
||||||
|
writeln!(&mut self.output, "{}:", end_label)?;
|
||||||
|
}
|
||||||
|
Stmt::Function { name, params, body } => {
|
||||||
|
assert!(params.is_empty()); // TODO
|
||||||
|
|
||||||
|
writeln!(&mut self.output, "global {}", name.lexeme)?;
|
||||||
|
writeln!(&mut self.output, "{}:", name.lexeme)?;
|
||||||
|
writeln!(&mut self.output, " push rbp")?;
|
||||||
|
writeln!(&mut self.output, " mov rbp, rsp")?;
|
||||||
|
writeln!(&mut self.output, " sub rsp, 256")?; // TODO
|
||||||
|
|
||||||
|
self.compile_stmt(env, *body)?;
|
||||||
|
|
||||||
|
writeln!(&mut self.output, " mov rsp, rbp")?;
|
||||||
|
writeln!(&mut self.output, " pop rbp")?;
|
||||||
|
writeln!(&mut self.output, " mov rax, 0")?;
|
||||||
|
writeln!(&mut self.output, " ret")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
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)?;
|
||||||
|
writeln!(&mut self.output, " push rax")?;
|
||||||
|
self.compile_expr(env, *right)?;
|
||||||
|
writeln!(&mut self.output, " mov rbx, rax")?;
|
||||||
|
writeln!(&mut self.output, " pop rax")?;
|
||||||
|
|
||||||
|
match op.token_type {
|
||||||
|
TokenType::Plus => writeln!(&mut self.output, " add rax, rbx")?,
|
||||||
|
TokenType::Minus => writeln!(&mut self.output, " sub rax, rbx")?,
|
||||||
|
TokenType::Star => writeln!(&mut self.output, " imul rax, rbx")?,
|
||||||
|
TokenType::Slash => {
|
||||||
|
writeln!(&mut self.output, " cqo")?;
|
||||||
|
writeln!(&mut self.output, " idiv rbx")?;
|
||||||
|
}
|
||||||
|
TokenType::Mod => {
|
||||||
|
writeln!(&mut self.output, " cqo")?;
|
||||||
|
writeln!(&mut self.output, " idiv rbx")?;
|
||||||
|
writeln!(&mut self.output, " mov rax, rdx")?;
|
||||||
|
}
|
||||||
|
TokenType::Xor => writeln!(&mut self.output, " xor rax, rbx")?,
|
||||||
|
TokenType::And => todo!(),
|
||||||
|
TokenType::Or => todo!(),
|
||||||
|
TokenType::DoubleEqual => {
|
||||||
|
writeln!(&mut self.output, " cmp rax, rbx")?;
|
||||||
|
writeln!(&mut self.output, " sete al")?;
|
||||||
|
writeln!(&mut self.output, " movzx rax, al")?;
|
||||||
|
}
|
||||||
|
TokenType::NotEqual => {
|
||||||
|
writeln!(&mut self.output, " cmp rax, rbx")?;
|
||||||
|
writeln!(&mut self.output, " setne al")?;
|
||||||
|
writeln!(&mut self.output, " movzx rax, al")?;
|
||||||
|
}
|
||||||
|
TokenType::Greater => {
|
||||||
|
writeln!(&mut self.output, " cmp rax, rbx")?;
|
||||||
|
writeln!(&mut self.output, " setg al")?;
|
||||||
|
writeln!(&mut self.output, " movzx rax, al")?;
|
||||||
|
}
|
||||||
|
TokenType::GreaterEqual => {
|
||||||
|
writeln!(&mut self.output, " cmp rax, rbx")?;
|
||||||
|
writeln!(&mut self.output, " setge al")?;
|
||||||
|
writeln!(&mut self.output, " movzx rax, al")?;
|
||||||
|
}
|
||||||
|
TokenType::Less => {
|
||||||
|
writeln!(&mut self.output, " cmp rax, rbx")?;
|
||||||
|
writeln!(&mut self.output, " setl al")?;
|
||||||
|
writeln!(&mut self.output, " movzx rax, al")?;
|
||||||
|
}
|
||||||
|
TokenType::LessEqual => {
|
||||||
|
writeln!(&mut self.output, " cmp rax, rbx")?;
|
||||||
|
writeln!(&mut self.output, " setle al")?;
|
||||||
|
writeln!(&mut self.output, " movzx rax, al")?;
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Grouping(expr) => self.compile_expr(env, *expr)?,
|
||||||
|
Expr::Literal(token) => match token.token_type {
|
||||||
|
TokenType::Number => writeln!(&mut self.output, " mov rax, {}", token.lexeme)?,
|
||||||
|
TokenType::String => todo!(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
Expr::Unary { op, right } => {
|
||||||
|
self.compile_expr(env, *right)?;
|
||||||
|
match op.token_type {
|
||||||
|
TokenType::Minus => writeln!(&mut self.output, " neg rax")?,
|
||||||
|
TokenType::Bang => {
|
||||||
|
writeln!(&mut self.output, " test rax, rax")?;
|
||||||
|
writeln!(&mut self.output, " sete al")?;
|
||||||
|
writeln!(&mut self.output, " movzx rax, al")?;
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Variable(name) => {
|
||||||
|
let var = match env.get_var(&name.lexeme) {
|
||||||
|
Some(x) => x,
|
||||||
|
None => {
|
||||||
|
return error!(name.loc, format!("undefined variable: {}", &name.lexeme));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
writeln!(
|
||||||
|
&mut self.output,
|
||||||
|
" mov rax, QWORD [rbp-{}]",
|
||||||
|
var.stack_offset * 8
|
||||||
|
)?
|
||||||
|
}
|
||||||
|
Expr::Assign { name, value } => {
|
||||||
|
self.compile_expr(env, *value)?;
|
||||||
|
|
||||||
|
let var = match env.get_var(&name.lexeme) {
|
||||||
|
Some(x) => x,
|
||||||
|
None => {
|
||||||
|
return error!(name.loc, format!("undefined variable: {}", &name.lexeme));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
writeln!(
|
||||||
|
&mut self.output,
|
||||||
|
" mov QWORD [rbp-{}], rax",
|
||||||
|
var.stack_offset * 8
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Expr::Call {
|
||||||
|
callee,
|
||||||
|
paren: _,
|
||||||
|
args,
|
||||||
|
} => {
|
||||||
|
let callee = match *callee {
|
||||||
|
Expr::Variable(name) => name.lexeme,
|
||||||
|
_ => todo!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
assert!(args.len() == 1);
|
||||||
|
|
||||||
|
self.compile_expr(env, args.first().unwrap().clone())?;
|
||||||
|
writeln!(&mut self.output, " mov rdi, rax")?;
|
||||||
|
writeln!(&mut self.output, " call {}", callee)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
mod codegen;
|
mod codegen;
|
||||||
|
mod codegen_x86_64;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod tokenizer;
|
mod tokenizer;
|
||||||
|
|
||||||
@@ -21,7 +22,7 @@ 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::Codegen::new();
|
let mut codegen = codegen_x86_64::CodegenX86_64::new_boxed();
|
||||||
codegen.emit_prologue()?;
|
codegen.emit_prologue()?;
|
||||||
|
|
||||||
let mut env = codegen::Env::new();
|
let mut env = codegen::Env::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user