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

View File

@@ -5,10 +5,22 @@ mod parser;
mod tokenizer; mod tokenizer;
use clap::Parser; use clap::Parser;
use compiler::Compiler;
use parser::Parser as ASTParser; use parser::Parser as ASTParser;
use std::io::Read; use std::{
fs::File,
io::{BufWriter, Read, Write},
};
use tokenizer::{Tokenizer, TokenizerError}; 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)] #[derive(Debug, thiserror::Error)]
enum StationlangError { enum StationlangError {
#[error(transparent)] #[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()?; let compiler = Compiler::new(parser, args.stack_size, &mut writer);
println!("{}", output);
compiler.compile()?;
writer.flush()?;
Ok(()) Ok(())
} }

View File

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

View File

@@ -2,6 +2,22 @@ use super::{Literal, LiteralOrVariable};
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum Math { 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. /// Gets the absolute value of a number.
/// ## In Game /// ## In Game
/// `abs r? a(r?|num)` /// `abs r? a(r?|num)`
@@ -10,6 +26,10 @@ pub enum Math {
/// ## In Game /// ## In Game
/// `ceil r? a(r?|num)` /// `ceil r? a(r?|num)`
Ceil(LiteralOrVariable), 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. /// Rounds a number down to the nearest whole number.
/// ## In Game /// ## In Game
/// `floor r? a(r?|num)` /// `floor r? a(r?|num)`
@@ -26,53 +46,26 @@ pub enum Math {
/// ## In Game /// ## In Game
/// `min r? a(r?|num) b(r?|num)` /// `min r? a(r?|num) b(r?|num)`
Min(LiteralOrVariable, LiteralOrVariable), 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. /// Gets a random number between 0 and 1.
/// ## In Game /// ## In Game
/// `rand r?` /// `rand r?`
Rand, 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. /// Returns the sine of the specified angle in radians.
/// ## In Game /// ## In Game
/// `sin r? a(r?|num)` /// `sin r? a(r?|num)`
Sin(LiteralOrVariable), 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. /// Returns the tangent of the specified angle in radians.
/// ## In Game /// ## In Game
/// `tan r? a(r?|num)` /// `tan r? a(r?|num)`
Tan(LiteralOrVariable), Tan(LiteralOrVariable),
/// Truncates a number by removing the decimal portion.
/// ## In Game
/// `trunc r? a(r?|num)`
Trunc(LiteralOrVariable),
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]

View File

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