compiler wip

This commit is contained in:
2024-11-26 20:53:08 -07:00
parent e32c778acb
commit 51109ee4bb
5 changed files with 112 additions and 72 deletions

View File

@@ -3,6 +3,8 @@ use thiserror::Error;
use crate::parser::tree_node::*;
use crate::parser::Parser as ASTParser;
use std::collections::HashMap;
use std::io::BufWriter;
use std::io::Write;
/// Represents the return keyword. Used as a variable name for the register.
const RETURN: &'static str = "ret";
@@ -13,14 +15,15 @@ pub enum CompileError {
ParseError(#[from] crate::parser::ParseError),
#[error("A fatal error has occurred with the compiler. Scope could not be found.")]
ScopeError,
#[error(transparent)]
WriteError(#[from] std::io::Error),
}
pub struct Compiler {
pub struct Compiler<'a> {
parser: ASTParser,
/// Max stack size for the program is by default 512.
variable_scope: Vec<HashMap<String, usize>>,
function_scope: Vec<HashMap<String, usize>>,
output: String,
output: &'a mut BufWriter<Box<dyn Write>>,
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: HashMap<String, u8>,
@@ -28,13 +31,16 @@ pub struct Compiler {
current_line: usize,
}
impl Compiler {
pub fn new(parser: ASTParser, max_stack_size: usize) -> Self {
impl<'a> Compiler<'a> {
pub fn new(
parser: ASTParser,
max_stack_size: usize,
writer: &'a mut BufWriter<Box<dyn Write>>,
) -> Self {
Self {
parser,
variable_scope: Vec::new(),
function_scope: Vec::new(),
output: String::new(),
output: writer,
stack_pointer: 0,
register: HashMap::new(),
max_stack_size,
@@ -42,16 +48,16 @@ impl Compiler {
}
}
pub fn compile(mut self) -> Result<String, CompileError> {
pub fn compile(mut self) -> Result<(), CompileError> {
let ast = self.parser.parse_all()?;
let Some(ast) = ast else {
return Ok(String::new());
return Ok(());
};
self.expression(ast)?;
Ok(self.output)
Ok(())
}
fn expression(&mut self, expression: Expression) -> Result<(), CompileError> {
@@ -61,16 +67,35 @@ impl Compiler {
self.declaration_expression(name, expr)?
}
Expression::ReturnExpression(expr) => self.return_expression(*expr)?,
_ => todo!(),
Expression::FunctionExpression(func) => self.function_expression(func)?,
_ => 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(())
}
fn return_expression(&mut self, expression: Expression) -> Result<(), CompileError> {
// pop last var off the stack and push it into the first available register
let register = self.register.len() as u8;
self.output.push_str(&format!("pop r{}\n", register));
self.output
.write(&format!("pop r{}\n", register).as_bytes())?;
self.stack_pointer
.checked_sub(1)
.ok_or(CompileError::ScopeError)?;

View File

@@ -5,10 +5,22 @@ mod parser;
mod tokenizer;
use clap::Parser;
use compiler::Compiler;
use parser::Parser as ASTParser;
use std::io::Read;
use std::{
fs::File,
io::{BufWriter, Read, Write},
};
use tokenizer::{Tokenizer, TokenizerError};
#[macro_export]
/// A macro to create a boxed value.
macro_rules! boxed {
($e:expr) => {
Box::new($e)
};
}
#[derive(Debug, thiserror::Error)]
enum StationlangError {
#[error(transparent)]
@@ -55,13 +67,18 @@ fn run_logic() -> Result<(), StationlangError> {
}
};
let mut parser = ASTParser::new(tokenizer);
let parser = ASTParser::new(tokenizer);
let compiler = compiler::Compiler::new(parser, args.stack_size);
let mut writer: BufWriter<Box<dyn Write>> = match args.output_file {
Some(output_file) => BufWriter::new(boxed!(File::create(output_file)?)),
None => BufWriter::new(boxed!(std::io::stdout())),
};
let output = compiler.compile()?;
println!("{}", output);
let compiler = Compiler::new(parser, args.stack_size, &mut writer);
compiler.compile()?;
writer.flush()?;
Ok(())
}

View File

@@ -1,9 +1,12 @@
pub mod tree_node;
pub mod sys_call;
pub mod tree_node;
use crate::tokenizer::{
use crate::{
boxed,
tokenizer::{
token::{Keyword, Symbol, Token, TokenType},
Tokenizer, TokenizerBuffer, TokenizerError,
},
};
use std::{
backtrace::{self, Backtrace},
@@ -289,7 +292,7 @@ impl Parser {
Ok(AssignmentExpression {
identifier,
expression: Box::new(expression),
expression: boxed!(expression),
})
}
@@ -355,8 +358,8 @@ impl Parser {
expressions.insert(
index,
Expression::BinaryExpression(BinaryExpression::Exponent(
Box::new(left),
Box::new(right),
boxed!(left),
boxed!(right),
)),
);
current_iteration += 1;
@@ -378,15 +381,15 @@ impl Parser {
Symbol::Asterisk => expressions.insert(
index,
Expression::BinaryExpression(BinaryExpression::Multiply(
Box::new(left),
Box::new(right),
boxed!(left),
boxed!(right),
)),
),
Symbol::Slash => expressions.insert(
index,
Expression::BinaryExpression(BinaryExpression::Divide(
Box::new(left),
Box::new(right),
boxed!(left),
boxed!(right),
)),
),
// safety: we have already checked for the operator
@@ -411,15 +414,15 @@ impl Parser {
Symbol::Plus => expressions.insert(
index,
Expression::BinaryExpression(BinaryExpression::Add(
Box::new(left),
Box::new(right),
boxed!(left),
boxed!(right),
)),
),
Symbol::Minus => expressions.insert(
index,
Expression::BinaryExpression(BinaryExpression::Subtract(
Box::new(left),
Box::new(right),
boxed!(left),
boxed!(right),
)),
),
// safety: we have already checked for the operator
@@ -475,7 +478,7 @@ impl Parser {
});
}
Ok(Box::new(expression))
Ok(boxed!(expression))
}
fn invocation(&mut self) -> Result<InvocationExpression, ParseError> {
@@ -564,7 +567,7 @@ impl Parser {
if token_matches!(current_token, TokenType::Keyword(Keyword::Return)) {
self.assign_next()?;
let expression = self.expression()?.ok_or(ParseError::UnexpectedEOF)?;
let return_expr = Expression::ReturnExpression(Box::new(expression));
let return_expr = Expression::ReturnExpression(boxed!(expression));
expressions.push(return_expr);
self.assign_next()?;
}
@@ -611,7 +614,7 @@ impl Parser {
Ok(Expression::DeclarationExpression(
identifier,
Box::new(assignment_expression),
boxed!(assignment_expression),
))
}

View File

@@ -2,6 +2,22 @@ use super::{Literal, LiteralOrVariable};
#[derive(Debug, PartialEq, Eq)]
pub enum Math {
/// Returns the angle in radians whose cosine is the specified number.
/// ## In Game
/// `acos r? a(r?|num)`
Acos(LiteralOrVariable),
/// Returns the angle in radians whose sine is the specified number.
/// ## In Game
/// `asin r? a(r?|num)`
Asin(LiteralOrVariable),
/// Returns the angle in radians whose tangent is the specified number.
/// ## In Game
/// `atan r? a(r?|num)`
Atan(LiteralOrVariable),
/// Returns the angle in radians whose tangent is the quotient of the specified numbers.
/// ## In Game
/// `atan2 r? a(r?|num) b(r?|num)`
Atan2(LiteralOrVariable, LiteralOrVariable),
/// Gets the absolute value of a number.
/// ## In Game
/// `abs r? a(r?|num)`
@@ -10,6 +26,10 @@ pub enum Math {
/// ## In Game
/// `ceil r? a(r?|num)`
Ceil(LiteralOrVariable),
/// Returns the cosine of the specified angle in radians.
/// ## In Game
/// cos r? a(r?|num)
Cos(LiteralOrVariable),
/// Rounds a number down to the nearest whole number.
/// ## In Game
/// `floor r? a(r?|num)`
@@ -26,53 +46,26 @@ pub enum Math {
/// ## In Game
/// `min r? a(r?|num) b(r?|num)`
Min(LiteralOrVariable, LiteralOrVariable),
/// Computes the square root of a number.
/// ## In Game
/// `sqrt r? a(r?|num)`
Sqrt(LiteralOrVariable),
/// Gets a random number between 0 and 1.
/// ## In Game
/// `rand r?`
Rand,
/// Truncates a number by removing the decimal portion.
/// ## In Game
/// `trunc r? a(r?|num)`
Trunc(LiteralOrVariable),
/// Returns the angle in radians whose cosine is the specified number.
/// ## In Game
/// `acos r? a(r?|num)`
Acos(LiteralOrVariable),
/// Returns the angle in radians whose sine is the specified number.
/// ## In Game
/// `asin r? a(r?|num)`
Asin(LiteralOrVariable),
/// Returns the angle in radians whose tangent is the specified number.
/// ## In Game
/// `atan r? a(r?|num)`
Atan(LiteralOrVariable),
/// Returns the angle in radians whose tangent is the quotient of the specified numbers.
/// ## In Game
/// `atan2 r? a(r?|num) b(r?|num)`
Atan2(LiteralOrVariable, LiteralOrVariable),
/// Returns the cosine of the specified angle in radians.
/// ## In Game
/// cos r? a(r?|num)
Cos(LiteralOrVariable),
/// Returns the sine of the specified angle in radians.
/// ## In Game
/// `sin r? a(r?|num)`
Sin(LiteralOrVariable),
/// Computes the square root of a number.
/// ## In Game
/// `sqrt r? a(r?|num)`
Sqrt(LiteralOrVariable),
/// Returns the tangent of the specified angle in radians.
/// ## In Game
/// `tan r? a(r?|num)`
Tan(LiteralOrVariable),
/// Truncates a number by removing the decimal portion.
/// ## In Game
/// `trunc r? a(r?|num)`
Trunc(LiteralOrVariable),
}
#[derive(Debug, PartialEq, Eq)]

View File

@@ -10,6 +10,8 @@ use std::{
use thiserror::Error;
use token::{Keyword, Number, Symbol, Token, TokenType};
use crate::boxed;
#[derive(Error, Debug)]
pub enum TokenizerError {
#[error("IO Error: {0}")]
@@ -39,7 +41,7 @@ pub(crate) struct Tokenizer {
impl Tokenizer {
pub fn from_path(input_file: impl Into<PathBuf>) -> Result<Self, TokenizerError> {
let file = std::fs::File::open(input_file.into())?;
let reader = BufReader::new(Box::new(file) as Box<dyn Tokenize>);
let reader = BufReader::new(boxed!(file) as Box<dyn Tokenize>);
Ok(Self {
reader,
@@ -53,7 +55,7 @@ impl Tokenizer {
impl From<String> for Tokenizer {
fn from(input: String) -> Self {
let reader = BufReader::new(Box::new(Cursor::new(input)) as Box<dyn Tokenize>);
let reader = BufReader::new(boxed!(Cursor::new(input)) as Box<dyn Tokenize>);
Self {
reader,