diff --git a/output.stationeers b/output.stationeers new file mode 100644 index 0000000..8120724 --- /dev/null +++ b/output.stationeers @@ -0,0 +1,18 @@ +j main +sub sp sp 3 +pop ra +j ra +push 9 +push 1 +push 2 +push 3 +j 1 +sub sp sp 3 +pop ra +j ra +main: +push 19 +push 1 +push 2 +push 3 +j 4 diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index f9ac0ec..943da9d 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -1,10 +1,8 @@ use crate::parser::tree_node::*; use crate::parser::Parser as ASTParser; -use std::borrow::BorrowMut; -use std::collections::HashMap; -use std::collections::VecDeque; -use std::io::BufWriter; -use std::io::Write; +use std::cmp::Ordering; +use std::collections::{HashMap, VecDeque}; +use std::io::{BufWriter, Write}; /// Represents the return keyword. Used as a variable name for the register. const RETURN: &'static str = "ret"; @@ -23,71 +21,90 @@ quick_error! { from() display("Write error: {}", err) } + DuplicateVariable(variable: String) { + display("A variable with the same name already exists in the current scope: {}", variable) + } + VariableNotFound(variable: String) { + display("Variable {} was not found in the current scope.", variable) + } + MissingFunction(name: String) { + display("Function {} was not found in the function table.", name) + } } } -macro_rules! variable_index { - ($compiler:expr, $name:expr) => { - $compiler - .variable_scope - .iter() - .rev() - .find(|v| v.contains_key(&$name)) - .map(|v| v[&$name]) - .ok_or(CompileError::ScopeError)? - }; -} - pub struct Compiler<'a> { parser: ASTParser, /// Max stack size for the program is by default 512. - variable_scope: Vec>, + variable_scope: Vec>, function_locations: HashMap, output: &'a mut BufWriter>, - stack_pointer: usize, /// A map of variable names to register numbers. 0-15 are reserved for variables, 16 is the stack pointer, 17 is the return address register: VecDeque, - max_stack_size: usize, current_line: usize, + declared_main: bool, } impl<'a> Compiler<'a> { - pub fn new( - parser: ASTParser, - max_stack_size: usize, - writer: &'a mut BufWriter>, - ) -> Self { + pub fn new(parser: ASTParser, writer: &'a mut BufWriter>) -> Self { Self { parser, variable_scope: Vec::new(), function_locations: HashMap::new(), output: writer, - stack_pointer: 0, register: VecDeque::new(), - max_stack_size, current_line: 0, + declared_main: false, } } + fn get_variable_index(&self, var_name: &str) -> Result { + let mut offset = 0; + + for scope in &self.variable_scope { + if let Some(index) = scope.get(var_name) { + return Ok(*index + offset); + } + + offset += scope.len() as i32; + } + + Err(CompileError::VariableNotFound(var_name.to_owned())) + } + + fn push_stack(&mut self, var_name: &str) -> Result<(), CompileError> { + // check to make sure the variable doesn't already exist in the current scope + if self + .variable_scope + .last() + .ok_or(CompileError::ScopeError)? + .contains_key(var_name) + { + return Err(CompileError::DuplicateVariable(var_name.to_string())); + } + + let scope_size = self + .variable_scope + .last() + .ok_or(CompileError::ScopeError)? + .len(); + + self.variable_scope + .last_mut() + .ok_or(CompileError::ScopeError)? + .insert(var_name.to_string(), scope_size as i32); + + Ok(()) + } + fn write_output(&mut self, output: impl Into) -> Result<(), CompileError> { self.output.write(output.into().as_bytes())?; + self.output.write(b"\n")?; self.current_line += 1; Ok(()) } - fn push_register(&mut self) -> Result<(), CompileError> { - if self.register.len() >= 15 { - return Err(CompileError::ScopeError); - } - self.register.push_back(self.register.len() as u8); - Ok(()) - } - - fn pop_register(&mut self) -> Result { - self.register.pop_back().ok_or(CompileError::ScopeError) - } - pub fn compile(mut self) -> Result<(), CompileError> { let ast = self.parser.parse_all()?; @@ -95,72 +112,119 @@ impl<'a> Compiler<'a> { return Ok(()); }; - self.expression(ast)?; + // Jump directly to the main block. This will avoid executing functions before the main block. + self.write_output(format!("j main"))?; + self.expression(ast)?; Ok(()) } fn expression(&mut self, expression: Expression) -> Result<(), CompileError> { match expression { - Expression::BinaryExpression(expr) => self.binary_expression(expr)?, - Expression::BlockExpression(expr) => self.block_expression(expr)?, - Expression::DeclarationExpression(ident, expr) => { - self.declaration_expression(ident, *expr)? - } Expression::FunctionExpression(expr) => self.function_expression(expr)?, - + Expression::BlockExpression(expr) => self.block_expression(expr)?, + Expression::InvocationExpression(expr) => self.invocation_expression(expr)?, + Expression::BinaryExpression(expr) => self.binary_expression(expr)?, _ => todo!("{:?}", expression), }; Ok(()) } - fn function_expression(&mut self, expr: FunctionExpression) -> Result<(), CompileError> { - // in stack order: return address, arguments + fn binary_expression(&mut self, expr: BinaryExpression) -> Result<(), CompileError> { + todo!() + } - self.function_locations - .insert(expr.name.clone(), self.current_line); + fn invocation_expression(&mut self, expr: InvocationExpression) -> Result<(), CompileError> { + let function_name = expr.name; - self.variable_scope.push(HashMap::new()); - let total_args = expr.arguments.len(); - for (index, arg) in expr.arguments.iter().enumerate() { - + let function_line = self + .function_locations + .get(&function_name) + .ok_or(CompileError::MissingFunction(function_name.clone()))? + .clone(); + + let mut to_write = String::new(); + + let mut iter_index = 0; + for arg in expr.arguments { + match arg { + Expression::Literal(Literal::Number(num)) => { + to_write.push_str(&format!("push {}\n", num)); + } + Expression::Variable(var_name) => { + let index = self.get_variable_index(&var_name)?; + to_write.push_str(&format!("sub r0 sp {index}\n")); + to_write.push_str("get r0 db r0\n"); + to_write.push_str("push r0\n"); + self.push_stack(&format!("{function_name}{iter_index}"))?; + } + Expression::BinaryExpression(expr) => { + self.binary_expression(expr)?; + } + _ => todo!("something is up with the arguments"), + } + + iter_index += 1; } - Ok(()) - } + // push the return address onto the stack. Current + to write + pushing the return address + let return_addr = self.current_line + to_write.lines().count() + 2; + self.write_output(format!("push {return_addr}"))?; + self.output.write(to_write.as_bytes())?; + self.current_line = return_addr; - fn declaration_expression( - &mut self, - ident: String, - expression: Expression, - ) -> Result<(), CompileError> { - let stack_index = self.stack_pointer; - self.stack_pointer += 1; - - match expression { - Expression::Literal(Literal::Number(num)) => { - self.write_output(format!("poke {stack_index} {num}\n"))?; - } - _ => { - self.expression(expression)?; - let register = self.register.len(); - self.write_output(format!("poke {stack_index} r{register}\n"))?; - self.register.pop_back(); - } - }; - self.variable_scope - .last_mut() - .ok_or(CompileError::ScopeError)? - .insert(ident, stack_index); + self.write_output(format!("j {function_line}"))?; Ok(()) } - fn block_expression(&mut self, expression: BlockExpression) -> Result<(), CompileError> { + fn function_expression(&mut self, expression: FunctionExpression) -> Result<(), CompileError> { + let func_name = expression.name; + self.variable_scope.push(HashMap::new()); + self.function_locations.insert(func_name, self.current_line); + + for arg in expression.arguments { + self.push_stack(&arg)?; + } + + for expr in expression.body.0 { + self.expression(expr)?; + } + + let scope = self.variable_scope.pop().ok_or(CompileError::ScopeError)?; + + self.write_output(format!("sub sp sp {0}", scope.len()))?; + self.write_output("pop ra")?; + self.write_output("j ra")?; + + Ok(()) + } + + fn block_expression(&mut self, mut expression: BlockExpression) -> Result<(), CompileError> { + self.variable_scope.push(HashMap::new()); + + // hoist functions to the top of the block + expression.0.sort_by(|a, b| { + if matches!(a, Expression::FunctionExpression(_)) + && matches!(b, Expression::FunctionExpression(_)) + { + Ordering::Equal + } else if matches!(a, Expression::FunctionExpression(_)) { + Ordering::Less + } else { + Ordering::Greater + } + }); + for expr in expression.0 { + // if we haven't declared main yet and we have already declared all the function expressions, declare main + if !self.declared_main && !matches!(expr, Expression::FunctionExpression(_)) { + self.write_output("main:")?; + self.declared_main = true; + } self.expression(expr)?; } @@ -168,70 +232,4 @@ impl<'a> Compiler<'a> { Ok(()) } - - fn binary_expression(&mut self, expression: BinaryExpression) -> Result<(), CompileError> { - fn handle_expression<'a>( - compiler: &'a mut Compiler, - left: Expression, - right: Expression, - operator: &'static str, - register_number: u8, - ) -> Result<(), CompileError> { - let value_left = match left { - Expression::Literal(Literal::Number(num)) => { - format!("{num}") - } - Expression::Variable(name) => { - let stack_index = variable_index!(compiler, name); - compiler.write_output(format!( - "get r{0} d0 {stack_index}\n", - register_number + 1 - ))?; - format!("r{0}", register_number + 1) - } - _ => todo!(), - }; - - let value_right = match right { - Expression::Literal(Literal::Number(num)) => { - format!("{num}") - } - Expression::Variable(name) => { - let stack_index = variable_index!(compiler, name); - compiler.write_output(format!( - "get r{0} d0 {stack_index}\n", - register_number + 2 - ))?; - format!("r{0}", register_number + 2) - } - _ => todo!(), - }; - - compiler.write_output(format!( - "{operator} r{register_number} {value_left} {value_right}\n" - ))?; - - Ok(()) - } - - let result_register = self.register.len(); - - match expression { - BinaryExpression::Add(left, right) => { - handle_expression(self, *left, *right, "add", result_register as u8)? - } - BinaryExpression::Subtract(left, right) => { - handle_expression(self, *left, *right, "sub", result_register as u8)? - } - BinaryExpression::Multiply(left, right) => { - handle_expression(self, *left, *right, "mul", result_register as u8)? - } - BinaryExpression::Divide(left, right) => { - handle_expression(self, *left, *right, "div", result_register as u8)? - } - _ => todo!("Exponents have a different instruction set. {{ exp r? a(r?|num) }}"), - } - - Ok(()) - } } diff --git a/src/main.rs b/src/main.rs index 59f1566..4c20682 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,9 +50,6 @@ struct Args { /// What file should be compiled. If not set, input will be read from stdin. #[arg(short, long)] input_file: Option, - /// The stack size for the compiled program. Compilation will fail if the compiler detects that the program will exceed this stack size. - #[arg(short, long, default_value_t = 512)] - stack_size: usize, /// The output file for the compiled program. If not set, output will go to stdout. #[arg(short, long)] output_file: Option, @@ -85,7 +82,7 @@ fn run_logic() -> Result<(), StationlangError> { None => BufWriter::new(boxed!(std::io::stdout())), }; - let compiler = Compiler::new(parser, args.stack_size, &mut writer); + let compiler = Compiler::new(parser, &mut writer); compiler.compile()?; writer.flush()?; diff --git a/tests/file.stlg b/tests/file.stlg index 6efd478..a7c6395 100644 --- a/tests/file.stlg +++ b/tests/file.stlg @@ -1,5 +1,9 @@ -let i = 234 + 432; +fn test(a, b, c) { + +}; -let y = i / 432.54; +fn test2(x, y, z) { + test(1, 2, 3); +}; -let z = i / y; \ No newline at end of file +test2(1, 2, 3); \ No newline at end of file