function params
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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>>;
|
|
||||||
}
|
|
||||||
@@ -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)?;
|
||||||
|
|||||||
@@ -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())?;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user