compiler wip
This commit is contained in:
@@ -3,6 +3,10 @@ name = "stationlang"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "slang"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "^4.5", features = ["derive"] }
|
clap = { version = "^4.5", features = ["derive"] }
|
||||||
quick-error = "2.0.1"
|
quick-error = "2.0.1"
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use crate::parser::tree_node::*;
|
use crate::parser::tree_node::*;
|
||||||
use crate::parser::Parser as ASTParser;
|
use crate::parser::Parser as ASTParser;
|
||||||
|
use std::borrow::BorrowMut;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::collections::VecDeque;
|
||||||
use std::io::BufWriter;
|
use std::io::BufWriter;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
@@ -24,14 +26,27 @@ quick_error! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> {
|
pub struct Compiler<'a> {
|
||||||
parser: ASTParser,
|
parser: ASTParser,
|
||||||
/// Max stack size for the program is by default 512.
|
/// Max stack size for the program is by default 512.
|
||||||
variable_scope: Vec<HashMap<String, usize>>,
|
variable_scope: Vec<HashMap<String, usize>>,
|
||||||
|
function_locations: HashMap<String, usize>,
|
||||||
output: &'a mut BufWriter<Box<dyn Write>>,
|
output: &'a mut BufWriter<Box<dyn Write>>,
|
||||||
stack_pointer: usize,
|
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
|
/// 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: HashMap<String, u8>,
|
register: VecDeque<u8>,
|
||||||
max_stack_size: usize,
|
max_stack_size: usize,
|
||||||
current_line: usize,
|
current_line: usize,
|
||||||
}
|
}
|
||||||
@@ -45,14 +60,34 @@ impl<'a> Compiler<'a> {
|
|||||||
Self {
|
Self {
|
||||||
parser,
|
parser,
|
||||||
variable_scope: Vec::new(),
|
variable_scope: Vec::new(),
|
||||||
|
function_locations: HashMap::new(),
|
||||||
output: writer,
|
output: writer,
|
||||||
stack_pointer: 0,
|
stack_pointer: 0,
|
||||||
register: HashMap::new(),
|
register: VecDeque::new(),
|
||||||
max_stack_size,
|
max_stack_size,
|
||||||
current_line: 0,
|
current_line: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_output(&mut self, output: impl Into<String>) -> Result<(), CompileError> {
|
||||||
|
self.output.write(output.into().as_bytes())?;
|
||||||
|
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<u8, CompileError> {
|
||||||
|
self.register.pop_back().ok_or(CompileError::ScopeError)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn compile(mut self) -> Result<(), CompileError> {
|
pub fn compile(mut self) -> Result<(), CompileError> {
|
||||||
let ast = self.parser.parse_all()?;
|
let ast = self.parser.parse_all()?;
|
||||||
|
|
||||||
@@ -67,71 +102,136 @@ impl<'a> Compiler<'a> {
|
|||||||
|
|
||||||
fn expression(&mut self, expression: Expression) -> Result<(), CompileError> {
|
fn expression(&mut self, expression: Expression) -> Result<(), CompileError> {
|
||||||
match expression {
|
match expression {
|
||||||
Expression::BlockExpression(block) => self.block_expression(block)?,
|
Expression::BinaryExpression(expr) => self.binary_expression(expr)?,
|
||||||
Expression::DeclarationExpression(name, expr) => {
|
Expression::BlockExpression(expr) => self.block_expression(expr)?,
|
||||||
self.declaration_expression(name, expr)?
|
Expression::DeclarationExpression(ident, expr) => {
|
||||||
|
self.declaration_expression(ident, *expr)?
|
||||||
}
|
}
|
||||||
Expression::ReturnExpression(expr) => self.return_expression(*expr)?,
|
Expression::FunctionExpression(expr) => self.function_expression(expr)?,
|
||||||
Expression::FunctionExpression(func) => self.function_expression(func)?,
|
|
||||||
_ => todo!("{:?}", expression),
|
_ => todo!("{:?}", expression),
|
||||||
};
|
};
|
||||||
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn function_expression(&mut self, func: FunctionExpression) -> Result<(), CompileError> {
|
|
||||||
for arg in func.arguments {
|
|
||||||
self.variable_scope
|
|
||||||
.last_mut()
|
|
||||||
.ok_or(CompileError::ScopeError)?
|
|
||||||
.insert(arg, self.stack_pointer);
|
|
||||||
self.stack_pointer += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for expr in func.body.0 {
|
|
||||||
self.expression(expr)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_expression(&mut self, expression: Expression) -> Result<(), CompileError> {
|
fn function_expression(&mut self, expr: FunctionExpression) -> Result<(), CompileError> {
|
||||||
// pop last var off the stack and push it into the first available register
|
// in stack order: return address, arguments
|
||||||
let register = self.register.len() as u8;
|
|
||||||
self.output
|
self.function_locations
|
||||||
.write(&format!("pop r{}\n", register).as_bytes())?;
|
.insert(expr.name.clone(), self.current_line);
|
||||||
|
|
||||||
|
self.variable_scope.push(HashMap::new());
|
||||||
|
let total_args = expr.arguments.len();
|
||||||
|
for (index, arg) in expr.arguments.iter().enumerate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
self.stack_pointer
|
|
||||||
.checked_sub(1)
|
|
||||||
.ok_or(CompileError::ScopeError)?;
|
|
||||||
self.current_line += 1;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declaration_expression(
|
fn declaration_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: String,
|
ident: String,
|
||||||
expression: Box<Expression>,
|
expression: Expression,
|
||||||
) -> Result<(), CompileError> {
|
) -> Result<(), CompileError> {
|
||||||
self.expression(*expression)?;
|
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
|
self.variable_scope
|
||||||
.last_mut()
|
.last_mut()
|
||||||
.ok_or(CompileError::ScopeError)?
|
.ok_or(CompileError::ScopeError)?
|
||||||
.insert(name, self.stack_pointer);
|
.insert(ident, stack_index);
|
||||||
self.stack_pointer += 1;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_expression(&mut self, expression: BlockExpression) -> Result<(), CompileError> {
|
fn block_expression(&mut self, expression: BlockExpression) -> Result<(), CompileError> {
|
||||||
// Push a new scope. This will be read from all the child expressions
|
|
||||||
self.variable_scope.push(HashMap::new());
|
self.variable_scope.push(HashMap::new());
|
||||||
|
|
||||||
for expr in expression.0 {
|
for expr in expression.0 {
|
||||||
self.expression(expr)?;
|
self.expression(expr)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the scope we just added, all variables are now out of scope
|
|
||||||
self.variable_scope.pop();
|
self.variable_scope.pop();
|
||||||
|
|
||||||
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
fn doStuff() {
|
let i = 234 + 432;
|
||||||
let i = {
|
|
||||||
return 234.5;
|
|
||||||
};
|
|
||||||
|
|
||||||
i = 5;
|
let y = i / 432.54;
|
||||||
|
|
||||||
// This comment is going to be ignored.
|
let z = i / y;
|
||||||
return i; // we returned here
|
|
||||||
}
|
|
||||||
|
|
||||||
doStuff();
|
|
||||||
Reference in New Issue
Block a user