Compare commits
4 Commits
9f35fc9415
...
22241a5633
| Author | SHA1 | Date | |
|---|---|---|---|
| 22241a5633 | |||
| e2be83414b | |||
| f7ed764e96 | |||
| 328741eb51 |
@@ -223,19 +223,31 @@ fn build_shift_instruction(
|
|||||||
opcode: Opcode,
|
opcode: Opcode,
|
||||||
args: &[crate::assembler::model::Token],
|
args: &[crate::assembler::model::Token],
|
||||||
) -> Result<Instruction, AssembleError> {
|
) -> Result<Instruction, AssembleError> {
|
||||||
let Some(reg_token) = args.first() else {
|
let Some(src_reg) = args.first() else {
|
||||||
return Err(AssembleError::MissingArgument(0));
|
return Err(AssembleError::MissingArgument(0));
|
||||||
};
|
};
|
||||||
let Some(amount_token) = args.get(1) else {
|
let Some(r_shamt) = args.get(1) else {
|
||||||
|
return Err(AssembleError::MissingArgument(0));
|
||||||
|
};
|
||||||
|
let Some(i_shamt) = args.get(2) else {
|
||||||
|
return Err(AssembleError::MissingArgument(1));
|
||||||
|
};
|
||||||
|
let Some(dest_reg) = args.get(3) else {
|
||||||
return Err(AssembleError::MissingArgument(1));
|
return Err(AssembleError::MissingArgument(1));
|
||||||
};
|
};
|
||||||
|
|
||||||
let reg = expect_token!(reg_token, Register)?;
|
let src = expect_token!(src_reg, Register)?;
|
||||||
let amount = expect_token!(amount_token, Immediate)? as u8;
|
let r_shamt = expect_token!(r_shamt, Register)?;
|
||||||
|
let i_shamt = expect_token!(i_shamt, Immediate)? as u8;
|
||||||
|
let dest = expect_token!(dest_reg, Register)?;
|
||||||
|
|
||||||
match opcode {
|
match opcode {
|
||||||
Opcode::Shl => Ok(Instruction::ShiftLeft(args!(R, sr1: reg, shamt: amount))),
|
Opcode::Shl => Ok(Instruction::ShiftLeft(
|
||||||
Opcode::Shr => Ok(Instruction::ShiftRight(args!(R, sr1: reg, shamt: amount))),
|
args!(R, sr1: src, sr2: r_shamt, shamt: i_shamt, dr: dest),
|
||||||
|
)),
|
||||||
|
Opcode::Shr => Ok(Instruction::ShiftRight(
|
||||||
|
args!(R, sr1: src, sr2: r_shamt, shamt: i_shamt, dr: dest),
|
||||||
|
)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use crate::assembler::TokenType;
|
||||||
use crate::{assembler::AssembleError, expect_token, expect_type, node};
|
use crate::{assembler::AssembleError, expect_token, expect_type, node};
|
||||||
|
|
||||||
use crate::assembler::model::{Node, Opcode, Token};
|
use crate::assembler::model::{Node, Opcode, Token};
|
||||||
@@ -114,7 +115,8 @@ impl Parser {
|
|||||||
|
|
||||||
let mut offset = Token::Immediate(0);
|
let mut offset = Token::Immediate(0);
|
||||||
if let Ok(next) = self.peek_next()
|
if let Ok(next) = self.peek_next()
|
||||||
&& expect_type!(next, Immediate).is_ok() {
|
&& expect_type!(next, Immediate).is_ok()
|
||||||
|
{
|
||||||
offset = self.next()?;
|
offset = self.next()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +127,8 @@ impl Parser {
|
|||||||
let dest = expect_type!(self.next()?, Register, Symbol)?;
|
let dest = expect_type!(self.next()?, Register, Symbol)?;
|
||||||
let mut offset = Token::Immediate(0);
|
let mut offset = Token::Immediate(0);
|
||||||
if let Ok(next) = self.peek_next()
|
if let Ok(next) = self.peek_next()
|
||||||
&& expect_type!(next, Immediate).is_ok() {
|
&& expect_type!(next, Immediate).is_ok()
|
||||||
|
{
|
||||||
offset = self.next()?;
|
offset = self.next()?;
|
||||||
}
|
}
|
||||||
args = vec![base, dest, offset];
|
args = vec![base, dest, offset];
|
||||||
@@ -146,15 +149,49 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Opcode::Not | Opcode::Cmp => {
|
Opcode::Not | Opcode::Cmp => {
|
||||||
let reg1 = expect_type!(self.next()?, Register, Symbol)?;
|
let src = expect_type!(self.next()?, Register, Symbol)?;
|
||||||
let reg2 = expect_type!(self.next()?, Register, Symbol)?;
|
let dest = expect_type!(self.next()?, Register, Symbol)?;
|
||||||
args = vec![reg1, reg2];
|
args = vec![src, dest];
|
||||||
}
|
}
|
||||||
|
|
||||||
Opcode::Shl | Opcode::Shr => {
|
Opcode::Shl | Opcode::Shr => {
|
||||||
let reg = expect_type!(self.next()?, Register, Symbol)?;
|
let src = expect_type!(self.next()?, Register, Symbol)?;
|
||||||
let num = expect_type!(self.next()?, Immediate)?;
|
|
||||||
args = vec![reg, num];
|
// First operand after src: could be immediate or register
|
||||||
|
let first = self.next()?;
|
||||||
|
|
||||||
|
let (r_shamt, i_shamt) = match first {
|
||||||
|
Token::Register(_) => (
|
||||||
|
first,
|
||||||
|
if let Ok(tok) = self.peek_next() {
|
||||||
|
if expect_type!(tok, Immediate).is_ok() {
|
||||||
|
self.next()?
|
||||||
|
} else {
|
||||||
|
Token::Immediate(0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Token::Immediate(0)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Token::Immediate(_) => (Token::Register(Register::Zero), first),
|
||||||
|
_ => {
|
||||||
|
return Err(AssembleError::UnexpectedToken(
|
||||||
|
first,
|
||||||
|
TokenType::Immediate,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let dest = if let Ok(tok) = self.peek_next() {
|
||||||
|
if expect_type!(tok, Register).is_ok() {
|
||||||
|
self.next()?
|
||||||
|
} else {
|
||||||
|
src.clone() // Default to src if no dest specified
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
src.clone() // Default to src if no dest specified
|
||||||
|
};
|
||||||
|
|
||||||
|
args = vec![src, r_shamt, i_shamt, dest];
|
||||||
}
|
}
|
||||||
|
|
||||||
Opcode::Inc | Opcode::Dec => {
|
Opcode::Inc | Opcode::Dec => {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ pub enum Register {
|
|||||||
Idr,
|
Idr,
|
||||||
Mmr,
|
Mmr,
|
||||||
Zero,
|
Zero,
|
||||||
NoReg,
|
Null, // Invalid - Triggers a fault if accessed
|
||||||
|
|
||||||
// system registers - can't be written to by instructions.
|
// system registers - can't be written to by instructions.
|
||||||
Mar,
|
Mar,
|
||||||
@@ -106,7 +106,7 @@ impl Register {
|
|||||||
|
|
||||||
impl Default for Register {
|
impl Default for Register {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::NoReg
|
Self::Null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ impl TryFrom<u8> for Register {
|
|||||||
0x14 => Self::Idr,
|
0x14 => Self::Idr,
|
||||||
0x15 => Self::Mmr,
|
0x15 => Self::Mmr,
|
||||||
0x16 => Self::Zero,
|
0x16 => Self::Zero,
|
||||||
0x17 => Self::NoReg,
|
0x17 => Self::Null,
|
||||||
0x18 => Self::Mar,
|
0x18 => Self::Mar,
|
||||||
0x19 => Self::Mdr,
|
0x19 => Self::Mdr,
|
||||||
0x1A => Self::Sts,
|
0x1A => Self::Sts,
|
||||||
@@ -183,7 +183,7 @@ impl TryFrom<&str> for Register {
|
|||||||
"idr" => Ok(Self::Idr),
|
"idr" => Ok(Self::Idr),
|
||||||
"mmr" => Ok(Self::Mmr),
|
"mmr" => Ok(Self::Mmr),
|
||||||
"zero" => Ok(Self::Zero),
|
"zero" => Ok(Self::Zero),
|
||||||
"null" => Ok(Self::NoReg),
|
"null" => Ok(Self::Null),
|
||||||
"pcx" => Ok(Self::Pcx),
|
"pcx" => Ok(Self::Pcx),
|
||||||
_ => Err(RegisterParseError::InvalidName(value.to_string())),
|
_ => Err(RegisterParseError::InvalidName(value.to_string())),
|
||||||
}
|
}
|
||||||
@@ -216,7 +216,7 @@ impl std::fmt::Display for Register {
|
|||||||
Self::Idr => write!(f, "idr"),
|
Self::Idr => write!(f, "idr"),
|
||||||
Self::Mmr => write!(f, "mmr"),
|
Self::Mmr => write!(f, "mmr"),
|
||||||
Self::Zero => write!(f, "zero"),
|
Self::Zero => write!(f, "zero"),
|
||||||
Self::NoReg => write!(f, "noreg"),
|
Self::Null => write!(f, "null"),
|
||||||
Self::Mar => write!(f, "mar"),
|
Self::Mar => write!(f, "mar"),
|
||||||
Self::Mdr => write!(f, "mdr"),
|
Self::Mdr => write!(f, "mdr"),
|
||||||
Self::Sts => write!(f, "sts"),
|
Self::Sts => write!(f, "sts"),
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ pub trait Encode {
|
|||||||
/// Encodes a zero argument instruction.
|
/// Encodes a zero argument instruction.
|
||||||
fn encode_no_args(opcode: u8) -> u32 {
|
fn encode_no_args(opcode: u8) -> u32 {
|
||||||
let opcode = u32::from(opcode);
|
let opcode = u32::from(opcode);
|
||||||
let sr1 = Register::NoReg as u32;
|
let sr1 = Register::Null as u32;
|
||||||
let sr2 = Register::NoReg as u32;
|
let sr2 = Register::Null as u32;
|
||||||
let dr = Register::NoReg as u32;
|
let dr = Register::Null as u32;
|
||||||
let shamt = 0;
|
let shamt = 0;
|
||||||
|
|
||||||
(opcode << 26) | (sr1 << 21) | (sr2 << 16) | (dr << 11) | (shamt << 6)
|
(opcode << 26) | (sr1 << 21) | (sr2 << 16) | (dr << 11) | (shamt << 6)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_encode_nop() {
|
fn test_encode_nop() {
|
||||||
let no_reg = Register::NoReg as u32;
|
let no_reg = Register::Null as u32;
|
||||||
let no_op = u32::from(Instruction::Nop.opcode());
|
let no_op = u32::from(Instruction::Nop.opcode());
|
||||||
|
|
||||||
let expected = (no_op << 26) | (no_reg << 21) | (no_reg << 16) | (no_reg << 11);
|
let expected = (no_op << 26) | (no_reg << 21) | (no_reg << 16) | (no_reg << 11);
|
||||||
@@ -15,7 +15,7 @@ fn test_encode_nop() {
|
|||||||
fn test_encode_mov() {
|
fn test_encode_mov() {
|
||||||
let rg0 = Register::Rg0 as u32;
|
let rg0 = Register::Rg0 as u32;
|
||||||
let rg1 = Register::Rg1 as u32;
|
let rg1 = Register::Rg1 as u32;
|
||||||
let no_reg = Register::NoReg as u32;
|
let no_reg = Register::Null as u32;
|
||||||
|
|
||||||
let instruction = Instruction::Mov(RTypeArgs::new(
|
let instruction = Instruction::Mov(RTypeArgs::new(
|
||||||
Some(Register::Rg0),
|
Some(Register::Rg0),
|
||||||
@@ -53,7 +53,7 @@ fn test_encode_load_byte() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_encode_shift_left_shamt() {
|
fn test_encode_shift_left_shamt() {
|
||||||
let rg0 = Register::Rg0 as u32;
|
let rg0 = Register::Rg0 as u32;
|
||||||
let no_reg = Register::NoReg as u32;
|
let no_reg = Register::Null as u32;
|
||||||
|
|
||||||
let shift_amount = 5;
|
let shift_amount = 5;
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ fn test_encode_shift_left_shamt() {
|
|||||||
fn test_encode_shift_left_reg() {
|
fn test_encode_shift_left_reg() {
|
||||||
let rg0 = Register::Rg0 as u32;
|
let rg0 = Register::Rg0 as u32;
|
||||||
let rg1 = Register::Rg1 as u32;
|
let rg1 = Register::Rg1 as u32;
|
||||||
let no_reg = Register::NoReg as u32;
|
let no_reg = Register::Null as u32;
|
||||||
|
|
||||||
let instruction = Instruction::ShiftLeft(RTypeArgs::new(
|
let instruction = Instruction::ShiftLeft(RTypeArgs::new(
|
||||||
Some(Register::Rg0),
|
Some(Register::Rg0),
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ use crate::backend::dsa::registers::Register;
|
|||||||
use crate::{block, comment, dsa};
|
use crate::{block, comment, dsa};
|
||||||
|
|
||||||
use crate::model::{
|
use crate::model::{
|
||||||
BinaryOperator, Call, CompilerError, ConstExpr, Declaration, Dependency, Expression,
|
AssignmentOperator, BinaryOperator, Call, CompilerError, ConstExpr, Declaration,
|
||||||
Program, Statement, TypeId, UnaryOperator, Variable,
|
Dependency, Expression, Program, Statement, TypeId, UnaryOperator, Variable,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct CodeGenerator {
|
pub struct CodeGenerator {
|
||||||
@@ -271,12 +271,17 @@ impl CodeGenerator {
|
|||||||
self.allocator.free_temp(ptr_reg);
|
self.allocator.free_temp(ptr_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::Assign { varname, value } => {
|
Statement::Assign {
|
||||||
|
varname,
|
||||||
|
value,
|
||||||
|
operator,
|
||||||
|
} => {
|
||||||
// Evaluate expression
|
// Evaluate expression
|
||||||
let (result_reg, expr_code) =
|
let (result_reg, expr_code) =
|
||||||
self.generate_expression(value, true, func_body)?;
|
self.generate_expression(value, true, func_body)?;
|
||||||
code.extend(expr_code);
|
code.extend(expr_code);
|
||||||
|
|
||||||
|
if *operator == AssignmentOperator::Assign {
|
||||||
// Check if this is a global variable
|
// Check if this is a global variable
|
||||||
if self.is_global(varname) {
|
if self.is_global(varname) {
|
||||||
// Store to global label
|
// Store to global label
|
||||||
@@ -289,6 +294,83 @@ impl CodeGenerator {
|
|||||||
|
|
||||||
// Free temporary register
|
// Free temporary register
|
||||||
self.allocator.free_temp(result_reg);
|
self.allocator.free_temp(result_reg);
|
||||||
|
|
||||||
|
return Ok(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for more complex assignment cases we need an intermediate register.
|
||||||
|
let (temp_reg, temp_code) = self.allocator.alloc_temp()?;
|
||||||
|
code.extend(temp_code);
|
||||||
|
|
||||||
|
// fetch the value of the variable
|
||||||
|
let (var_reg, var_code) = if self.is_global(varname) {
|
||||||
|
(temp_reg, vec![format!("\tldw {}, {}", varname, temp_reg)])
|
||||||
|
} else {
|
||||||
|
self.allocator.load_var(varname)?
|
||||||
|
};
|
||||||
|
code.extend(var_code);
|
||||||
|
|
||||||
|
let assign_code = match operator {
|
||||||
|
AssignmentOperator::Assign => {
|
||||||
|
unreachable!("assignment was already checked earlier.")
|
||||||
|
}
|
||||||
|
AssignmentOperator::AddAssign => {
|
||||||
|
format!("\tadd {var_reg}, {result_reg}, {temp_reg}")
|
||||||
|
}
|
||||||
|
AssignmentOperator::SubAssign => {
|
||||||
|
format!("\tsub {var_reg}, {result_reg}, {temp_reg}")
|
||||||
|
}
|
||||||
|
AssignmentOperator::MulAssign => {
|
||||||
|
return Err(CompilerError::Unimplemented(format!(
|
||||||
|
"TODO: implement multiplication for assignment"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
AssignmentOperator::DivAssign => {
|
||||||
|
return Err(CompilerError::Unimplemented(format!(
|
||||||
|
"TODO: write proper div function for DSA"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
AssignmentOperator::ModAssign => {
|
||||||
|
format!("\tmod {var_reg}, {result_reg}, {temp_reg}")
|
||||||
|
}
|
||||||
|
AssignmentOperator::AndAssign => {
|
||||||
|
format!("\tand {var_reg}, {result_reg}, {temp_reg}")
|
||||||
|
}
|
||||||
|
AssignmentOperator::OrAssign => {
|
||||||
|
format!("\tor {var_reg}, {result_reg}, {temp_reg}")
|
||||||
|
}
|
||||||
|
AssignmentOperator::XorAssign => {
|
||||||
|
format!("\txor {var_reg}, {result_reg}, {temp_reg}")
|
||||||
|
}
|
||||||
|
AssignmentOperator::LeftShiftAssign => {
|
||||||
|
// this is only useful if we optimise out the register allocation
|
||||||
|
// inside value. if let Expression::Number
|
||||||
|
// { value, .. } = *value { format!("\
|
||||||
|
// tshl {var_reg}, {value}, {temp_reg}") }
|
||||||
|
format!("\tshl {var_reg}, {result_reg}, 0, {temp_reg}")
|
||||||
|
}
|
||||||
|
AssignmentOperator::RightShiftAssign => {
|
||||||
|
// this is only useful if we optimise out the register allocation
|
||||||
|
// if let Expression::Number { value, .. } = *value {
|
||||||
|
// format!("\tshr {var_reg}, {value}, {temp_reg}")
|
||||||
|
// }
|
||||||
|
format!("\tshr {var_reg}, {result_reg}, 0, {temp_reg}")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
code.push(assign_code);
|
||||||
|
|
||||||
|
// Check if this is a global variable
|
||||||
|
if self.is_global(varname) {
|
||||||
|
// Store to global label
|
||||||
|
code.push(format!("\tstw {}, {}", temp_reg, varname));
|
||||||
|
} else {
|
||||||
|
// Store result in local variable
|
||||||
|
let store_code = self.allocator.store_var(varname, &temp_reg);
|
||||||
|
code.extend(store_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.allocator.free_temp(result_reg);
|
||||||
|
self.allocator.free_temp(temp_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::Return(expr) => {
|
Statement::Return(expr) => {
|
||||||
@@ -414,16 +496,17 @@ impl CodeGenerator {
|
|||||||
let mut code = Vec::new();
|
let mut code = Vec::new();
|
||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
Expression::StringLiteral(value) => {
|
Expression::Empty => Ok((Register::Null, code)),
|
||||||
|
|
||||||
|
Expression::Number { value, .. } => {
|
||||||
let (reg, alloc_code) = self.allocator.alloc_temp()?;
|
let (reg, alloc_code) = self.allocator.alloc_temp()?;
|
||||||
code.extend(alloc_code);
|
code.extend(alloc_code);
|
||||||
|
|
||||||
// write string into memory
|
// Load immediate value
|
||||||
let uuid = self.get_unique_label();
|
code.push(format!("\tlli {}, {}", value & 0xFFFF, reg));
|
||||||
func_body.insert(0, format!("db str_{uuid}: \"{value}\""));
|
if *value > 0xFFFF || *value < 0 {
|
||||||
|
code.push(format!("\tlui {}, {}", (value >> 16) & 0xFFFF, reg));
|
||||||
// Load pointer to string
|
}
|
||||||
code.push(format!("\tlwi str_{uuid}, {reg}"));
|
|
||||||
|
|
||||||
Ok((reg, code))
|
Ok((reg, code))
|
||||||
}
|
}
|
||||||
@@ -438,19 +521,22 @@ impl CodeGenerator {
|
|||||||
Ok((reg, code))
|
Ok((reg, code))
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression::Number { value, .. } => {
|
Expression::StringLiteral(value) => {
|
||||||
let (reg, alloc_code) = self.allocator.alloc_temp()?;
|
let (reg, alloc_code) = self.allocator.alloc_temp()?;
|
||||||
code.extend(alloc_code);
|
code.extend(alloc_code);
|
||||||
|
|
||||||
// Load immediate value
|
// write string into memory
|
||||||
code.push(format!("\tlli {}, {}", value & 0xFFFF, reg));
|
let uuid = self.get_unique_label();
|
||||||
if *value > 0xFFFF || *value < 0 {
|
func_body.insert(0, format!("db str_{uuid}: \"{value}\""));
|
||||||
code.push(format!("\tlui {}, {}", (value >> 16) & 0xFFFF, reg));
|
|
||||||
}
|
// Load pointer to string
|
||||||
|
code.push(format!("\tlwi str_{uuid}, {reg}"));
|
||||||
|
|
||||||
Ok((reg, code))
|
Ok((reg, code))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expression::ArrayLiteral { elements, type_id } => todo!(),
|
||||||
|
|
||||||
Expression::Variable { name, .. } => {
|
Expression::Variable { name, .. } => {
|
||||||
if self.is_global(&name.name) {
|
if self.is_global(&name.name) {
|
||||||
// Allocate a temporary register for the global
|
// Allocate a temporary register for the global
|
||||||
@@ -489,16 +575,14 @@ impl CodeGenerator {
|
|||||||
// Generate operation
|
// Generate operation
|
||||||
match op {
|
match op {
|
||||||
BinaryOperator::Add => {
|
BinaryOperator::Add => {
|
||||||
code.push(format!(
|
code.push(
|
||||||
"\tadd {}, {}, {}",
|
format!("\tadd {left_reg}, {right_reg}, {result_reg}",),
|
||||||
left_reg, right_reg, result_reg
|
);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
BinaryOperator::Sub => {
|
BinaryOperator::Sub => {
|
||||||
code.push(format!(
|
code.push(
|
||||||
"\tsub {}, {}, {}",
|
format!("\tsub {left_reg}, {right_reg}, {result_reg}",),
|
||||||
left_reg, right_reg, result_reg
|
);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
BinaryOperator::Mul => {
|
BinaryOperator::Mul => {
|
||||||
self.include("maths", "./lib/maths/core.dsa");
|
self.include("maths", "./lib/maths/core.dsa");
|
||||||
@@ -509,8 +593,55 @@ impl CodeGenerator {
|
|||||||
code.push(format!("\tpop {}", result_reg));
|
code.push(format!("\tpop {}", result_reg));
|
||||||
code.push("\tpop zero".to_string());
|
code.push("\tpop zero".to_string());
|
||||||
}
|
}
|
||||||
|
BinaryOperator::Div => {
|
||||||
|
return Err(CompilerError::Unimplemented(format!(
|
||||||
|
"TODO: write proper div function for DSA"
|
||||||
|
)));
|
||||||
|
// self.include("maths", "./lib/maths/core.dsa");
|
||||||
|
// // Call divide function
|
||||||
|
// code.push(format!("\tpush {}", right_reg));
|
||||||
|
// code.push(format!("\tpush {}", left_reg));
|
||||||
|
// code.push("\tcall maths::divide".to_string());
|
||||||
|
// code.push(format!("\tpop {}", result_reg));
|
||||||
|
// code.push("\tpop zero".to_string());
|
||||||
|
}
|
||||||
|
BinaryOperator::Mod => {
|
||||||
|
return Err(CompilerError::Unimplemented(format!(
|
||||||
|
"TODO: write proper mod function for DSA"
|
||||||
|
)));
|
||||||
|
// self.include("maths", "./lib/maths/core.dsa");
|
||||||
|
// // Call modulo function
|
||||||
|
// code.push(format!("\tpush {}", right_reg));
|
||||||
|
// code.push(format!("\tpush {}", left_reg));
|
||||||
|
// code.push("\tcall maths::modulo".to_string());
|
||||||
|
// code.push(format!("\tpop {}", result_reg));
|
||||||
|
// code.push("\tpop zero".to_string());
|
||||||
|
}
|
||||||
|
BinaryOperator::BitwiseAnd => {
|
||||||
|
code.push(format!("\tand {left_reg}, {right_reg}, {result_reg}"));
|
||||||
|
}
|
||||||
|
BinaryOperator::BitwiseOr => {
|
||||||
|
code.push(format!("\tor {left_reg}, {right_reg}, {result_reg}"));
|
||||||
|
}
|
||||||
|
BinaryOperator::BitwiseXor => {
|
||||||
|
code.push(format!("\txor {left_reg}, {right_reg}, {result_reg}"));
|
||||||
|
}
|
||||||
|
BinaryOperator::LogicalAnd => {
|
||||||
|
return Err(CompilerError::Unimplemented(format!(
|
||||||
|
"assembler/ISA does not yet support logical and!"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
BinaryOperator::LogicalOr => {
|
||||||
|
return Err(CompilerError::Unimplemented(format!(
|
||||||
|
"assembler/ISA does not yet support logical or!"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
BinaryOperator::LeftShift => code
|
||||||
|
.push(format!("\tshl {left_reg}, {right_reg}, 0, {result_reg}")),
|
||||||
|
BinaryOperator::RightShift => code
|
||||||
|
.push(format!("\tshr {left_reg}, {right_reg}, 0, {result_reg}")),
|
||||||
// Comparison operators - return 1 (true) or 0 (false)
|
// Comparison operators - return 1 (true) or 0 (false)
|
||||||
BinaryOperator::Eq => {
|
BinaryOperator::Equal => {
|
||||||
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
||||||
code.push(format!("\tlli 1, {}", result_reg));
|
code.push(format!("\tlli 1, {}", result_reg));
|
||||||
let end_label = format!("_cmp_end_{}", self.get_unique_label());
|
let end_label = format!("_cmp_end_{}", self.get_unique_label());
|
||||||
@@ -518,7 +649,7 @@ impl CodeGenerator {
|
|||||||
code.push(format!("\tlli 0, {}", result_reg));
|
code.push(format!("\tlli 0, {}", result_reg));
|
||||||
code.push(format!("{}:", end_label));
|
code.push(format!("{}:", end_label));
|
||||||
}
|
}
|
||||||
BinaryOperator::Ne => {
|
BinaryOperator::NotEqual => {
|
||||||
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
||||||
code.push(format!("\tlli 1, {}", result_reg));
|
code.push(format!("\tlli 1, {}", result_reg));
|
||||||
let end_label = format!("_cmp_end_{}", self.get_unique_label());
|
let end_label = format!("_cmp_end_{}", self.get_unique_label());
|
||||||
@@ -526,7 +657,7 @@ impl CodeGenerator {
|
|||||||
code.push(format!("\tlli 0, {}", result_reg));
|
code.push(format!("\tlli 0, {}", result_reg));
|
||||||
code.push(format!("{}:", end_label));
|
code.push(format!("{}:", end_label));
|
||||||
}
|
}
|
||||||
BinaryOperator::Lt => {
|
BinaryOperator::LessThan => {
|
||||||
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
||||||
code.push(format!("\tlli 1, {}", result_reg));
|
code.push(format!("\tlli 1, {}", result_reg));
|
||||||
let end_label = format!("_cmp_end_{}", self.get_unique_label());
|
let end_label = format!("_cmp_end_{}", self.get_unique_label());
|
||||||
@@ -534,7 +665,7 @@ impl CodeGenerator {
|
|||||||
code.push(format!("\tlli 0, {}", result_reg));
|
code.push(format!("\tlli 0, {}", result_reg));
|
||||||
code.push(format!("{}:", end_label));
|
code.push(format!("{}:", end_label));
|
||||||
}
|
}
|
||||||
BinaryOperator::Le => {
|
BinaryOperator::LessOrEqual => {
|
||||||
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
||||||
code.push(format!("\tlli 1, {}", result_reg));
|
code.push(format!("\tlli 1, {}", result_reg));
|
||||||
let end_label = format!("_cmp_end_{}", self.get_unique_label());
|
let end_label = format!("_cmp_end_{}", self.get_unique_label());
|
||||||
@@ -542,7 +673,7 @@ impl CodeGenerator {
|
|||||||
code.push(format!("\tlli 0, {}", result_reg));
|
code.push(format!("\tlli 0, {}", result_reg));
|
||||||
code.push(format!("{}:", end_label));
|
code.push(format!("{}:", end_label));
|
||||||
}
|
}
|
||||||
BinaryOperator::Gt => {
|
BinaryOperator::GreaterThan => {
|
||||||
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
||||||
code.push(format!("\tlli 1, {}", result_reg));
|
code.push(format!("\tlli 1, {}", result_reg));
|
||||||
let end_label = format!("_cmp_end_{}", self.get_unique_label());
|
let end_label = format!("_cmp_end_{}", self.get_unique_label());
|
||||||
@@ -550,15 +681,14 @@ impl CodeGenerator {
|
|||||||
code.push(format!("\tlli 0, {}", result_reg));
|
code.push(format!("\tlli 0, {}", result_reg));
|
||||||
code.push(format!("{}:", end_label));
|
code.push(format!("{}:", end_label));
|
||||||
}
|
}
|
||||||
BinaryOperator::Ge => {
|
BinaryOperator::GreaterOrEqual => {
|
||||||
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
code.push(format!("\tcmp {}, {}", left_reg, right_reg));
|
||||||
code.push(format!("\tlli 1, {}", result_reg));
|
code.push(format!("\tlli 1, {}", result_reg));
|
||||||
let end_label = format!("_cmp_end_{}", self.get_unique_label());
|
let end_label = format!("_cmp_end_{}", self.get_unique_label());
|
||||||
code.push(format!("\tjge {}", end_label));
|
code.push(format!("\tjge {}", end_label));
|
||||||
code.push(format!("\tlli 8, {}", result_reg));
|
code.push(format!("\tlli 8, {}", result_reg));
|
||||||
code.push(format!("{}:", end_label));
|
code.push(format!("{}:", end_label));
|
||||||
}
|
} // _ => unimplemented!(),
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free operand registers (allocator will protect variables)
|
// Free operand registers (allocator will protect variables)
|
||||||
@@ -568,6 +698,105 @@ impl CodeGenerator {
|
|||||||
Ok((result_reg, code))
|
Ok((result_reg, code))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expression::UnaryPostfix { op, operand, .. } => {
|
||||||
|
let (operand_reg, operand_code) =
|
||||||
|
self.generate_expression(operand, true, func_body)?;
|
||||||
|
code.extend(operand_code);
|
||||||
|
|
||||||
|
let (result_reg, result_alloc) = self.allocator.alloc_temp()?;
|
||||||
|
code.extend(result_alloc);
|
||||||
|
|
||||||
|
match op {
|
||||||
|
UnaryOperator::Increment => {
|
||||||
|
// prefix increment
|
||||||
|
// code.push(format!("\taddi {}, 1, {}", operand_reg,
|
||||||
|
// operand_reg));
|
||||||
|
code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||||
|
}
|
||||||
|
UnaryOperator::Decrement => {
|
||||||
|
// prefix decrement
|
||||||
|
// code.push(format!("\tsubi {}, 1, {}", operand_reg,
|
||||||
|
// operand_reg));
|
||||||
|
code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CompilerError::Generic(format!(
|
||||||
|
"{op} is prefix only!"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.allocator.free_temp(operand_reg);
|
||||||
|
Ok((result_reg, code))
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression::Unary { op, operand, .. } => {
|
||||||
|
let (operand_reg, operand_code) =
|
||||||
|
self.generate_expression(operand, true, func_body)?;
|
||||||
|
code.extend(operand_code);
|
||||||
|
|
||||||
|
let (result_reg, result_alloc) = self.allocator.alloc_temp()?;
|
||||||
|
code.extend(result_alloc);
|
||||||
|
|
||||||
|
match op {
|
||||||
|
UnaryOperator::Minus => {
|
||||||
|
// Negate: result = 0 - operand
|
||||||
|
code.push(format!("\tsub zero, {}, {}", operand_reg, result_reg));
|
||||||
|
}
|
||||||
|
UnaryOperator::Plus => {
|
||||||
|
// Just move
|
||||||
|
code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||||
|
}
|
||||||
|
UnaryOperator::Dereference => {
|
||||||
|
code.push(format!("\tldw {}, {}", operand_reg, result_reg));
|
||||||
|
}
|
||||||
|
UnaryOperator::AddressOf => {
|
||||||
|
// ensure the referenced variable is on the stack and return its
|
||||||
|
// address.
|
||||||
|
let (offset, alloc_code) =
|
||||||
|
self.allocator.free_register(&operand_reg)?;
|
||||||
|
code.extend(alloc_code);
|
||||||
|
code.push(format!(
|
||||||
|
"\taddi spr, {}, {}",
|
||||||
|
offset - self.allocator.get_stack_offset(),
|
||||||
|
result_reg
|
||||||
|
));
|
||||||
|
}
|
||||||
|
UnaryOperator::SizeOf => {
|
||||||
|
if let Ok(id) = operand.type_id() {
|
||||||
|
let size = id.size();
|
||||||
|
code.push(format!("\tmov {}, {}", size, result_reg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UnaryOperator::Increment => {
|
||||||
|
// prefix increment
|
||||||
|
// code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||||
|
code.push(format!("\taddi {}, 1, {}", operand_reg, result_reg));
|
||||||
|
}
|
||||||
|
UnaryOperator::Decrement => {
|
||||||
|
// prefix decrement
|
||||||
|
// code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
||||||
|
code.push(format!("\tsubi {}, 1, {}", operand_reg, result_reg));
|
||||||
|
}
|
||||||
|
UnaryOperator::BitwiseNot => {
|
||||||
|
code.push(format!("\tnot {}, {}", operand_reg, result_reg));
|
||||||
|
}
|
||||||
|
UnaryOperator::LogicalNot => {
|
||||||
|
return Err(CompilerError::Unimplemented(format!(
|
||||||
|
"Assembler/ISA does not yet support logical not"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CompilerError::Generic(format!(
|
||||||
|
"{op} is postfix only!"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.allocator.free_temp(operand_reg);
|
||||||
|
Ok((result_reg, code))
|
||||||
|
}
|
||||||
|
|
||||||
Expression::Call {
|
Expression::Call {
|
||||||
func: Call { name, args },
|
func: Call { name, args },
|
||||||
..
|
..
|
||||||
@@ -581,13 +810,6 @@ impl CodeGenerator {
|
|||||||
arg_regs.push(arg_reg);
|
arg_regs.push(arg_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save caller-saved registers and track which ones we saved
|
|
||||||
// old method, inefficient.
|
|
||||||
// let saved_regs = self.allocator.get_caller_saved_registers();
|
|
||||||
// for reg in &saved_regs {
|
|
||||||
// code.push(format!("\tpush {}", reg));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Save caller-saved registers and track which ones we saved
|
// Save caller-saved registers and track which ones we saved
|
||||||
let saved_regs = self.allocator.get_caller_saved_registers();
|
let saved_regs = self.allocator.get_caller_saved_registers();
|
||||||
for reg in &saved_regs {
|
for reg in &saved_regs {
|
||||||
@@ -604,9 +826,6 @@ impl CodeGenerator {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if GLOBAL_METHODS.contains_key(name.name.as_str()) {
|
|
||||||
// code.push(format!("\tcall {}",
|
|
||||||
// GLOBAL_METHODS[name.name.as_str()])); } else
|
|
||||||
if self.symbols.contains(&name.name) {
|
if self.symbols.contains(&name.name) {
|
||||||
// Call local function
|
// Call local function
|
||||||
code.push(format!("\tcall {}", name));
|
code.push(format!("\tcall {}", name));
|
||||||
@@ -644,11 +863,6 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore caller-saved registers in reverse order (LIFO)
|
|
||||||
// for reg in saved_regs.iter().rev() {
|
|
||||||
// code.push(format!("\tpop {}", reg));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Free argument registers
|
// Free argument registers
|
||||||
for reg in arg_regs {
|
for reg in arg_regs {
|
||||||
self.allocator.free_temp(reg);
|
self.allocator.free_temp(reg);
|
||||||
@@ -657,43 +871,52 @@ impl CodeGenerator {
|
|||||||
Ok((result_reg, code))
|
Ok((result_reg, code))
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression::Unary { op, operand, .. } => {
|
Expression::IndexAccess {
|
||||||
let (operand_reg, operand_code) =
|
expr,
|
||||||
self.generate_expression(operand, true, func_body)?;
|
index,
|
||||||
code.extend(operand_code);
|
type_id,
|
||||||
|
} => {
|
||||||
|
let (expr_reg, expr_alloc) =
|
||||||
|
self.generate_expression(expr, true, func_body)?;
|
||||||
|
code.extend(expr_alloc);
|
||||||
|
|
||||||
|
let (index_reg, index_alloc) =
|
||||||
|
self.generate_expression(index, true, func_body)?;
|
||||||
|
code.extend(index_alloc);
|
||||||
|
|
||||||
let (result_reg, result_alloc) = self.allocator.alloc_temp()?;
|
let (result_reg, result_alloc) = self.allocator.alloc_temp()?;
|
||||||
code.extend(result_alloc);
|
code.extend(result_alloc);
|
||||||
|
|
||||||
match op {
|
// add the expr pointer to the index to get the final address.
|
||||||
UnaryOperator::Minus => {
|
code.push(format!("\tadd {expr_reg} {index_reg} {result_reg}"));
|
||||||
// Negate: result = 0 - operand
|
// load the value at the address.
|
||||||
code.push(format!("\tsub zero, {}, {}", operand_reg, result_reg));
|
code.push(format!("\tldw {result_reg} {result_reg}"));
|
||||||
}
|
|
||||||
UnaryOperator::Plus => {
|
self.allocator.free_temp(expr_reg);
|
||||||
// Just move
|
self.allocator.free_temp(index_reg);
|
||||||
code.push(format!("\tmov {}, {}", operand_reg, result_reg));
|
|
||||||
}
|
|
||||||
UnaryOperator::Dereference => {
|
|
||||||
code.push(format!("\tldw {}, {}", operand_reg, result_reg));
|
|
||||||
}
|
|
||||||
UnaryOperator::Reference => {
|
|
||||||
let (offset, alloc_code) =
|
|
||||||
self.allocator.free_register(&operand_reg)?;
|
|
||||||
code.extend(alloc_code);
|
|
||||||
code.push(format!(
|
|
||||||
"\taddi spr, {}, {}",
|
|
||||||
offset - self.allocator.get_stack_offset(),
|
|
||||||
result_reg
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.allocator.free_temp(operand_reg);
|
|
||||||
Ok((result_reg, code))
|
Ok((result_reg, code))
|
||||||
}
|
}
|
||||||
|
Expression::MemberAccess {
|
||||||
|
expr,
|
||||||
|
field_name,
|
||||||
|
type_id,
|
||||||
|
} => Err(CompilerError::Unimplemented(format!(
|
||||||
|
"Structs are not yet implemented!"
|
||||||
|
))),
|
||||||
|
|
||||||
Expression::Empty => Ok((Register::Null, code)),
|
Expression::TypeCast {
|
||||||
|
expr,
|
||||||
|
target_type,
|
||||||
|
type_id,
|
||||||
|
} => {
|
||||||
|
let (expr_reg, expr_code) =
|
||||||
|
self.generate_expression(expr, true, func_body)?;
|
||||||
|
|
||||||
|
// not sure if we actually need to do anything here.
|
||||||
|
// for now we just return the previous expression.
|
||||||
|
Ok((expr_reg, expr_code))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ impl RegisterAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is a true temporary - safe to free
|
// This is a true temporary - safe to free
|
||||||
if reg != Register::Zero {
|
if !matches!(reg, Register::Zero | Register::Null) {
|
||||||
self.in_use.insert(reg, false);
|
self.in_use.insert(reg, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,7 +141,7 @@ impl RegisterAllocator {
|
|||||||
// Check if this variable is in a register
|
// Check if this variable is in a register
|
||||||
if let Some(location) = self.variable_locations.get(var).cloned() {
|
if let Some(location) = self.variable_locations.get(var).cloned() {
|
||||||
if let Some(reg) = location.register
|
if let Some(reg) = location.register
|
||||||
&& reg != Register::Zero
|
&& !matches!(reg, Register::Zero | Register::Null)
|
||||||
{
|
{
|
||||||
self.register_contents.remove(®);
|
self.register_contents.remove(®);
|
||||||
self.in_use.insert(reg, false);
|
self.in_use.insert(reg, false);
|
||||||
|
|||||||
+503
-223
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
|||||||
use super::lexer::Token;
|
use super::lexer::Token;
|
||||||
use crate::model::{
|
use crate::model::{
|
||||||
BinaryOperator, Block, Call, CompilerError, ConstExpr, Declaration, Dependency,
|
AssignmentOperator, BinaryOperator, Block, Call, CompilerError, ConstExpr,
|
||||||
Expression, Program, Statement, TypeId, UnaryOperator, Variable,
|
Declaration, Dependency, Expression, Program, Statement, TypeId, UnaryOperator,
|
||||||
|
Variable,
|
||||||
};
|
};
|
||||||
use crate::{expect_tt, expect_value};
|
use crate::{expect_tt, expect_value};
|
||||||
use std::ops::{ControlFlow, FromResidual, Try};
|
use std::ops::{ControlFlow, FromResidual, Try};
|
||||||
@@ -328,7 +329,26 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.next()?;
|
self.next()?;
|
||||||
let _ = expect_tt!(self.next()?, Assign)?;
|
let operator = match self.peek_next()? {
|
||||||
|
Token::Assign => AssignmentOperator::Assign,
|
||||||
|
Token::PlusEqual => AssignmentOperator::AddAssign,
|
||||||
|
Token::MinusEqual => AssignmentOperator::SubAssign,
|
||||||
|
Token::StarEqual => AssignmentOperator::MulAssign,
|
||||||
|
Token::SlashEqual => AssignmentOperator::DivAssign,
|
||||||
|
Token::PercentEqual => AssignmentOperator::ModAssign,
|
||||||
|
Token::AndEqual => AssignmentOperator::AndAssign,
|
||||||
|
Token::OrEqual => AssignmentOperator::OrAssign,
|
||||||
|
Token::XorEqual => AssignmentOperator::XorAssign,
|
||||||
|
Token::ShlEqual => AssignmentOperator::LeftShiftAssign,
|
||||||
|
Token::ShrEqual => AssignmentOperator::RightShiftAssign,
|
||||||
|
_ => {
|
||||||
|
return ParseResult::Reject(CompilerError::UnexpectedToken(
|
||||||
|
self.peek_next()?.tt().to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.next()?;
|
||||||
|
|
||||||
let value = self.parse_expression()?;
|
let value = self.parse_expression()?;
|
||||||
|
|
||||||
@@ -336,6 +356,7 @@ impl Parser {
|
|||||||
|
|
||||||
return ParseResult::Accept(Statement::Assign {
|
return ParseResult::Accept(Statement::Assign {
|
||||||
varname: varname.name,
|
varname: varname.name,
|
||||||
|
operator,
|
||||||
value,
|
value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -346,32 +367,132 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expression(&mut self) -> ParseResult<Expression, CompilerError> {
|
fn parse_expression(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||||
self.parse_comparison()
|
self.parse_logical_or()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_logical_or(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||||
|
let left = self.parse_logical_and()?;
|
||||||
|
|
||||||
|
let op = match self.peek_next()? {
|
||||||
|
Token::Ampersand => BinaryOperator::LogicalOr,
|
||||||
|
_ => return ParseResult::Accept(left),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.next()?;
|
||||||
|
ParseResult::Accept(Expression::Binary {
|
||||||
|
op,
|
||||||
|
left: Box::new(left),
|
||||||
|
right: Box::new(self.parse_logical_or()?),
|
||||||
|
type_id: Some(TypeId::U32),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_logical_and(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||||
|
let left = self.parse_bitwise_or()?;
|
||||||
|
|
||||||
|
let op = match self.peek_next()? {
|
||||||
|
Token::Ampersand => BinaryOperator::LogicalAnd,
|
||||||
|
_ => return ParseResult::Accept(left),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.next()?;
|
||||||
|
ParseResult::Accept(Expression::Binary {
|
||||||
|
op,
|
||||||
|
left: Box::new(left),
|
||||||
|
right: Box::new(self.parse_logical_and()?),
|
||||||
|
type_id: Some(TypeId::U32),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_bitwise_or(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||||
|
let left = self.parse_bitwise_xor()?;
|
||||||
|
|
||||||
|
let op = match self.peek_next()? {
|
||||||
|
Token::Ampersand => BinaryOperator::BitwiseOr,
|
||||||
|
_ => return ParseResult::Accept(left),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.next()?;
|
||||||
|
ParseResult::Accept(Expression::Binary {
|
||||||
|
op,
|
||||||
|
left: Box::new(left),
|
||||||
|
right: Box::new(self.parse_bitwise_or()?),
|
||||||
|
type_id: Some(TypeId::U32),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_bitwise_xor(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||||
|
let left = self.parse_bitwise_and()?;
|
||||||
|
|
||||||
|
let op = match self.peek_next()? {
|
||||||
|
Token::Ampersand => BinaryOperator::BitwiseXor,
|
||||||
|
_ => return ParseResult::Accept(left),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.next()?;
|
||||||
|
ParseResult::Accept(Expression::Binary {
|
||||||
|
op,
|
||||||
|
left: Box::new(left),
|
||||||
|
right: Box::new(self.parse_bitwise_xor()?),
|
||||||
|
type_id: Some(TypeId::U32),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_bitwise_and(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||||
|
let left = self.parse_comparison()?;
|
||||||
|
|
||||||
|
let op = match self.peek_next()? {
|
||||||
|
Token::Ampersand => BinaryOperator::BitwiseAnd,
|
||||||
|
_ => return ParseResult::Accept(left),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.next()?;
|
||||||
|
ParseResult::Accept(Expression::Binary {
|
||||||
|
op,
|
||||||
|
left: Box::new(left),
|
||||||
|
right: Box::new(self.parse_bitwise_and()?),
|
||||||
|
type_id: Some(TypeId::U32),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_comparison(&mut self) -> ParseResult<Expression, CompilerError> {
|
fn parse_comparison(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||||
let mut expr = self.parse_additive()?;
|
let left = self.parse_shift()?;
|
||||||
|
|
||||||
while let Some(op) = match self.peek_next()? {
|
let op = match self.peek_next()? {
|
||||||
Token::EqualEqual => Some(BinaryOperator::Eq),
|
Token::EqualEqual => BinaryOperator::Equal,
|
||||||
Token::BangEqual => Some(BinaryOperator::Ne),
|
Token::BangEqual => BinaryOperator::NotEqual,
|
||||||
Token::Less => Some(BinaryOperator::Lt),
|
Token::Less => BinaryOperator::LessThan,
|
||||||
Token::Greater => Some(BinaryOperator::Gt),
|
Token::Greater => BinaryOperator::GreaterThan,
|
||||||
Token::LessEqual => Some(BinaryOperator::Le),
|
Token::LessEqual => BinaryOperator::LessOrEqual,
|
||||||
Token::GreaterEqual => Some(BinaryOperator::Ge),
|
Token::GreaterEqual => BinaryOperator::GreaterOrEqual,
|
||||||
_ => None,
|
_ => return ParseResult::Accept(left),
|
||||||
} {
|
|
||||||
self.next()?;
|
|
||||||
let right = Box::new(self.parse_additive()?);
|
|
||||||
expr = Expression::Binary {
|
|
||||||
op,
|
|
||||||
left: Box::new(expr),
|
|
||||||
right,
|
|
||||||
type_id: Some(TypeId::Bool),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.next()?;
|
||||||
|
ParseResult::Accept(Expression::Binary {
|
||||||
|
op,
|
||||||
|
left: Box::new(left),
|
||||||
|
right: Box::new(self.parse_comparison()?),
|
||||||
|
type_id: Some(TypeId::Bool),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseResult::Accept(expr)
|
fn parse_shift(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||||
|
let left = self.parse_additive()?;
|
||||||
|
|
||||||
|
let op = match self.peek_next()? {
|
||||||
|
Token::LeftShift => BinaryOperator::LeftShift,
|
||||||
|
Token::RightShift => BinaryOperator::RightShift,
|
||||||
|
_ => return ParseResult::Accept(left),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.next()?;
|
||||||
|
ParseResult::Accept(Expression::Binary {
|
||||||
|
op,
|
||||||
|
left: Box::new(left),
|
||||||
|
right: Box::new(self.parse_shift()?),
|
||||||
|
type_id: Some(TypeId::U32),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_additive(&mut self) -> ParseResult<Expression, CompilerError> {
|
fn parse_additive(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||||
@@ -412,11 +533,27 @@ impl Parser {
|
|||||||
|
|
||||||
fn parse_unary(&mut self) -> ParseResult<Expression, CompilerError> {
|
fn parse_unary(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||||
let op = match self.peek_next()? {
|
let op = match self.peek_next()? {
|
||||||
|
// prefix inc/dec
|
||||||
|
Token::PlusPlus => UnaryOperator::Increment,
|
||||||
|
Token::MinusMinus => UnaryOperator::Decrement,
|
||||||
|
|
||||||
|
// arithmetic
|
||||||
Token::Plus => UnaryOperator::Plus,
|
Token::Plus => UnaryOperator::Plus,
|
||||||
Token::Minus => UnaryOperator::Minus,
|
Token::Minus => UnaryOperator::Minus,
|
||||||
|
|
||||||
|
// pointer
|
||||||
Token::Star => UnaryOperator::Dereference,
|
Token::Star => UnaryOperator::Dereference,
|
||||||
Token::Amphersand => UnaryOperator::Reference,
|
Token::Ampersand => UnaryOperator::AddressOf,
|
||||||
_ => return ParseResult::Accept(self.parse_primary()?),
|
|
||||||
|
// boolean
|
||||||
|
Token::Bang => UnaryOperator::LogicalNot,
|
||||||
|
Token::Tilde => UnaryOperator::BitwiseNot,
|
||||||
|
|
||||||
|
Token::SizeOf => UnaryOperator::SizeOf,
|
||||||
|
_ => {
|
||||||
|
let expr = self.parse_primary()?;
|
||||||
|
return self.parse_postfix(expr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.next()?;
|
self.next()?;
|
||||||
@@ -428,6 +565,99 @@ impl Parser {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_postfix(
|
||||||
|
&mut self,
|
||||||
|
mut expr: Expression,
|
||||||
|
) -> ParseResult<Expression, CompilerError> {
|
||||||
|
loop {
|
||||||
|
match self.peek_next()? {
|
||||||
|
// Type cast: expr as Type
|
||||||
|
Token::As => {
|
||||||
|
self.next()?; // consume 'as'
|
||||||
|
let target_type = self.parse_type()?;
|
||||||
|
expr = Expression::TypeCast {
|
||||||
|
expr: Box::new(expr),
|
||||||
|
target_type,
|
||||||
|
type_id: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Postfix increment/decrement
|
||||||
|
Token::PlusPlus => {
|
||||||
|
self.next()?;
|
||||||
|
expr = Expression::UnaryPostfix {
|
||||||
|
op: UnaryOperator::Increment,
|
||||||
|
operand: Box::new(expr),
|
||||||
|
type_id: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Token::MinusMinus => {
|
||||||
|
self.next()?;
|
||||||
|
expr = Expression::UnaryPostfix {
|
||||||
|
op: UnaryOperator::Decrement,
|
||||||
|
operand: Box::new(expr),
|
||||||
|
type_id: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array indexing: expr[index]
|
||||||
|
Token::LeftBracket => {
|
||||||
|
self.next()?; // consume '['
|
||||||
|
let index = Box::new(self.parse_expression()?);
|
||||||
|
|
||||||
|
let _ = expect_tt!(self.next()?, RightBracket)?;
|
||||||
|
|
||||||
|
expr = Expression::IndexAccess {
|
||||||
|
expr: Box::new(expr),
|
||||||
|
index,
|
||||||
|
type_id: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function call: expr(args...)
|
||||||
|
Token::LeftParen => {
|
||||||
|
self.next()?; // consume '('
|
||||||
|
let mut args = Vec::new();
|
||||||
|
|
||||||
|
if !matches!(self.peek_next()?, Token::RightParen) {
|
||||||
|
loop {
|
||||||
|
args.push(self.parse_expression()?);
|
||||||
|
if !matches!(self.peek_next()?, Token::Comma) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.next()?; // consume comma
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = expect_tt!(self.next()?, RightParen)?;
|
||||||
|
|
||||||
|
if let Expression::Variable { name, .. } = expr {
|
||||||
|
expr = Expression::Call {
|
||||||
|
func: Call { name, args },
|
||||||
|
type_id: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Member access: expr.member (if you support structs)
|
||||||
|
Token::Dot => {
|
||||||
|
self.next()?;
|
||||||
|
let field_name = expect_value!(self.next()?, Identifier)?;
|
||||||
|
expr = Expression::MemberAccess {
|
||||||
|
expr: Box::new(expr),
|
||||||
|
field_name,
|
||||||
|
type_id: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// No more postfix operations
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseResult::Accept(expr)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_primary(&mut self) -> ParseResult<Expression, CompilerError> {
|
fn parse_primary(&mut self) -> ParseResult<Expression, CompilerError> {
|
||||||
match self.peek_next()? {
|
match self.peek_next()? {
|
||||||
Token::Integer(value) => {
|
Token::Integer(value) => {
|
||||||
@@ -441,39 +671,37 @@ impl Parser {
|
|||||||
self.next()?;
|
self.next()?;
|
||||||
ParseResult::Accept(Expression::StringLiteral(value))
|
ParseResult::Accept(Expression::StringLiteral(value))
|
||||||
}
|
}
|
||||||
Token::Identifier(_) => {
|
Token::Char(value) => {
|
||||||
let name = expect_value!(self.next()?, Identifier)?;
|
|
||||||
|
|
||||||
if matches!(self.peek_next()?, Token::LeftParen) {
|
|
||||||
// Function call
|
|
||||||
self.next()?;
|
self.next()?;
|
||||||
let mut args = Vec::new();
|
ParseResult::Accept(Expression::CharLiteral(value))
|
||||||
|
|
||||||
if !matches!(self.peek_next()?, Token::RightParen) {
|
|
||||||
args.push(self.parse_expression()?);
|
|
||||||
|
|
||||||
while matches!(self.peek_next()?, Token::Comma) {
|
|
||||||
self.next()?;
|
|
||||||
args.push(self.parse_expression()?);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = expect_tt!(self.next()?, RightParen)?;
|
Token::Identifier(name) => {
|
||||||
|
self.next()?;
|
||||||
ParseResult::Accept(Expression::Call {
|
|
||||||
func: Call {
|
|
||||||
name: name.clone(),
|
|
||||||
args,
|
|
||||||
},
|
|
||||||
|
|
||||||
type_id: None,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
ParseResult::Accept(Expression::Variable {
|
ParseResult::Accept(Expression::Variable {
|
||||||
name,
|
name,
|
||||||
expr_type: None,
|
expr_type: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Token::LeftBracket => {
|
||||||
|
self.next()?; // consume '['
|
||||||
|
let mut elements = Vec::new();
|
||||||
|
|
||||||
|
if !matches!(self.peek_next()?, Token::RightBracket) {
|
||||||
|
loop {
|
||||||
|
elements.push(self.parse_expression()?);
|
||||||
|
if !matches!(self.peek_next()?, Token::Comma) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.next()?; // consume comma
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_tt!(self.next()?, RightBracket)?;
|
||||||
|
ParseResult::Accept(Expression::ArrayLiteral {
|
||||||
|
elements,
|
||||||
|
type_id: None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Token::LeftParen => {
|
Token::LeftParen => {
|
||||||
self.next()?;
|
self.next()?;
|
||||||
|
|||||||
+148
-21
@@ -11,6 +11,7 @@ pub enum CompilerError {
|
|||||||
Generic(String),
|
Generic(String),
|
||||||
UnknownType,
|
UnknownType,
|
||||||
TypeMismatch(TypeId, TypeId),
|
TypeMismatch(TypeId, TypeId),
|
||||||
|
Unimplemented(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
@@ -65,6 +66,26 @@ pub enum TypeId {
|
|||||||
Struct { name: Name, fields: Vec<TypeId> },
|
Struct { name: Name, fields: Vec<TypeId> },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TypeId {
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Self::U8 => 1,
|
||||||
|
Self::U16 => 2,
|
||||||
|
Self::U32 => 4,
|
||||||
|
Self::I8 => 1,
|
||||||
|
Self::I16 => 2,
|
||||||
|
Self::I32 => 4,
|
||||||
|
Self::Bool => 1,
|
||||||
|
Self::Char => 1,
|
||||||
|
Self::Void => 0,
|
||||||
|
Self::Ptr(t) => t.size(),
|
||||||
|
Self::Ref(t) => t.size(),
|
||||||
|
Self::Array(t, size) => t.size() * size,
|
||||||
|
Self::Struct { fields, .. } => fields.iter().map(|t| t.size()).sum(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for TypeId {
|
impl fmt::Display for TypeId {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@@ -110,6 +131,7 @@ pub enum Statement {
|
|||||||
},
|
},
|
||||||
Assign {
|
Assign {
|
||||||
varname: String,
|
varname: String,
|
||||||
|
operator: AssignmentOperator,
|
||||||
value: Expression,
|
value: Expression,
|
||||||
},
|
},
|
||||||
PtrWrite {
|
PtrWrite {
|
||||||
@@ -169,10 +191,38 @@ pub enum Expression {
|
|||||||
// Post-Semantic Analysis
|
// Post-Semantic Analysis
|
||||||
type_id: Option<TypeId>,
|
type_id: Option<TypeId>,
|
||||||
},
|
},
|
||||||
|
UnaryPostfix {
|
||||||
|
op: UnaryOperator,
|
||||||
|
operand: Box<Expression>,
|
||||||
|
|
||||||
|
// Post-Semantic Analysis
|
||||||
|
type_id: Option<TypeId>,
|
||||||
|
},
|
||||||
Variable {
|
Variable {
|
||||||
name: Name,
|
name: Name,
|
||||||
expr_type: Option<TypeId>,
|
expr_type: Option<TypeId>,
|
||||||
},
|
},
|
||||||
|
TypeCast {
|
||||||
|
expr: Box<Expression>,
|
||||||
|
target_type: TypeId,
|
||||||
|
|
||||||
|
// Post-Semantic Analysis
|
||||||
|
type_id: Option<TypeId>,
|
||||||
|
},
|
||||||
|
IndexAccess {
|
||||||
|
expr: Box<Expression>,
|
||||||
|
index: Box<Expression>,
|
||||||
|
|
||||||
|
// Post-Semantic Analysis
|
||||||
|
type_id: Option<TypeId>,
|
||||||
|
},
|
||||||
|
MemberAccess {
|
||||||
|
expr: Box<Expression>,
|
||||||
|
field_name: Name,
|
||||||
|
|
||||||
|
// Post-Semantic Analysis
|
||||||
|
type_id: Option<TypeId>,
|
||||||
|
},
|
||||||
Call {
|
Call {
|
||||||
func: Call,
|
func: Call,
|
||||||
|
|
||||||
@@ -187,6 +237,10 @@ pub enum Expression {
|
|||||||
},
|
},
|
||||||
StringLiteral(String),
|
StringLiteral(String),
|
||||||
CharLiteral(char),
|
CharLiteral(char),
|
||||||
|
ArrayLiteral {
|
||||||
|
elements: Vec<Expression>,
|
||||||
|
type_id: Option<TypeId>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -204,8 +258,17 @@ impl Expression {
|
|||||||
Expression::Call { .. } => false,
|
Expression::Call { .. } => false,
|
||||||
Expression::Binary { left, right, .. } => left.is_pure() && right.is_pure(),
|
Expression::Binary { left, right, .. } => left.is_pure() && right.is_pure(),
|
||||||
Expression::Unary { operand, .. } => operand.is_pure(),
|
Expression::Unary { operand, .. } => operand.is_pure(),
|
||||||
|
Expression::UnaryPostfix { operand, .. } => operand.is_pure(),
|
||||||
Expression::Empty => true,
|
Expression::Empty => true,
|
||||||
Expression::Variable { .. } => true,
|
Expression::Variable { .. } => true,
|
||||||
|
Expression::TypeCast { expr, .. } => expr.is_pure(),
|
||||||
|
Expression::IndexAccess { expr, index, .. } => {
|
||||||
|
expr.is_pure() && index.is_pure()
|
||||||
|
}
|
||||||
|
Expression::MemberAccess { expr, .. } => expr.is_pure(),
|
||||||
|
Expression::ArrayLiteral { elements, type_id } => {
|
||||||
|
elements.iter().all(|element| element.is_pure())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,42 +288,96 @@ impl Expression {
|
|||||||
Expression::Unary { type_id, .. } => {
|
Expression::Unary { type_id, .. } => {
|
||||||
type_id.clone().ok_or(CompilerError::UnknownType)
|
type_id.clone().ok_or(CompilerError::UnknownType)
|
||||||
}
|
}
|
||||||
|
Expression::UnaryPostfix { type_id, .. } => {
|
||||||
|
type_id.clone().ok_or(CompilerError::UnknownType)
|
||||||
|
}
|
||||||
Expression::Empty => Ok(TypeId::Void),
|
Expression::Empty => Ok(TypeId::Void),
|
||||||
Expression::Variable { expr_type, .. } => {
|
Expression::Variable { expr_type, .. } => {
|
||||||
expr_type.clone().ok_or(CompilerError::UnknownType)
|
expr_type.clone().ok_or(CompilerError::UnknownType)
|
||||||
}
|
}
|
||||||
|
Expression::TypeCast { type_id, .. } => {
|
||||||
|
type_id.clone().ok_or(CompilerError::UnknownType)
|
||||||
|
}
|
||||||
|
Expression::IndexAccess { expr, .. } => expr.type_id(),
|
||||||
|
Expression::MemberAccess { expr, .. } => expr.type_id(),
|
||||||
|
Expression::ArrayLiteral { elements, .. } => {
|
||||||
|
let element_type = elements
|
||||||
|
.first()
|
||||||
|
.map_or(TypeId::Void, |e| e.type_id().unwrap_or(TypeId::Void));
|
||||||
|
Ok(TypeId::Array(Box::new(element_type), elements.len()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum AssignmentOperator {
|
||||||
|
Assign,
|
||||||
|
AddAssign,
|
||||||
|
SubAssign,
|
||||||
|
MulAssign,
|
||||||
|
DivAssign,
|
||||||
|
ModAssign,
|
||||||
|
AndAssign,
|
||||||
|
OrAssign,
|
||||||
|
XorAssign,
|
||||||
|
LeftShiftAssign,
|
||||||
|
RightShiftAssign,
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum BinaryOperator {
|
pub enum BinaryOperator {
|
||||||
|
// arithmetic
|
||||||
Add,
|
Add,
|
||||||
Sub,
|
Sub,
|
||||||
Mul,
|
Mul,
|
||||||
Div,
|
Div,
|
||||||
Eq,
|
Mod,
|
||||||
Ne,
|
|
||||||
Lt,
|
// comparison
|
||||||
Gt,
|
Equal,
|
||||||
Le,
|
NotEqual,
|
||||||
Ge,
|
LessThan,
|
||||||
|
GreaterThan,
|
||||||
|
LessOrEqual,
|
||||||
|
GreaterOrEqual,
|
||||||
|
|
||||||
|
// bitwise
|
||||||
|
BitwiseAnd,
|
||||||
|
BitwiseOr,
|
||||||
|
BitwiseXor,
|
||||||
|
|
||||||
|
// logical
|
||||||
|
LogicalAnd,
|
||||||
|
LogicalOr,
|
||||||
|
|
||||||
|
// shift
|
||||||
|
LeftShift,
|
||||||
|
RightShift,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for BinaryOperator {
|
impl fmt::Display for BinaryOperator {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
BinaryOperator::Add => write!(f, "+"),
|
Self::Add => write!(f, "+"),
|
||||||
BinaryOperator::Sub => write!(f, "-"),
|
Self::Sub => write!(f, "-"),
|
||||||
BinaryOperator::Mul => write!(f, "*"),
|
Self::Mul => write!(f, "*"),
|
||||||
BinaryOperator::Div => write!(f, "/"),
|
Self::Div => write!(f, "/"),
|
||||||
BinaryOperator::Eq => write!(f, "=="),
|
Self::Mod => write!(f, "%"),
|
||||||
BinaryOperator::Ne => write!(f, "!="),
|
Self::Equal => write!(f, "=="),
|
||||||
BinaryOperator::Lt => write!(f, "<"),
|
Self::NotEqual => write!(f, "!="),
|
||||||
BinaryOperator::Gt => write!(f, ">"),
|
Self::LessThan => write!(f, "<"),
|
||||||
BinaryOperator::Le => write!(f, "<="),
|
Self::GreaterThan => write!(f, ">"),
|
||||||
BinaryOperator::Ge => write!(f, ">="),
|
Self::LessOrEqual => write!(f, "<="),
|
||||||
|
Self::GreaterOrEqual => write!(f, ">="),
|
||||||
|
Self::BitwiseAnd => write!(f, "&"),
|
||||||
|
Self::BitwiseOr => write!(f, "|"),
|
||||||
|
Self::BitwiseXor => write!(f, "^"),
|
||||||
|
Self::LogicalAnd => write!(f, "&&"),
|
||||||
|
Self::LogicalOr => write!(f, "||"),
|
||||||
|
Self::LeftShift => write!(f, "<<"),
|
||||||
|
Self::RightShift => write!(f, ">>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,17 +386,27 @@ impl fmt::Display for BinaryOperator {
|
|||||||
pub enum UnaryOperator {
|
pub enum UnaryOperator {
|
||||||
Plus,
|
Plus,
|
||||||
Minus,
|
Minus,
|
||||||
Reference,
|
AddressOf,
|
||||||
Dereference,
|
Dereference,
|
||||||
|
BitwiseNot,
|
||||||
|
LogicalNot,
|
||||||
|
Increment,
|
||||||
|
Decrement,
|
||||||
|
SizeOf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for UnaryOperator {
|
impl fmt::Display for UnaryOperator {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
UnaryOperator::Plus => write!(f, "+"),
|
Self::Increment => write!(f, "++"),
|
||||||
UnaryOperator::Minus => write!(f, "-"),
|
Self::Decrement => write!(f, "--"),
|
||||||
UnaryOperator::Dereference => write!(f, "*"),
|
Self::Plus => write!(f, "+"),
|
||||||
UnaryOperator::Reference => write!(f, "&"),
|
Self::Minus => write!(f, "-"),
|
||||||
|
Self::Dereference => write!(f, "*"),
|
||||||
|
Self::AddressOf => write!(f, "&"),
|
||||||
|
Self::BitwiseNot => write!(f, "~"),
|
||||||
|
Self::LogicalNot => write!(f, "!"),
|
||||||
|
Self::SizeOf => write!(f, "sizeof"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ impl RegFile {
|
|||||||
Register::Sts => &mut self.sts,
|
Register::Sts => &mut self.sts,
|
||||||
Register::Cir => &mut self.cir,
|
Register::Cir => &mut self.cir,
|
||||||
Register::Pcx => &mut self.pcx,
|
Register::Pcx => &mut self.pcx,
|
||||||
_ => return Err(ProcessorError::InvalidRegister(Register::NoReg as u8)),
|
_ => return Err(ProcessorError::InvalidRegister(Register::Null as u8)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,7 +321,7 @@ impl RegFile {
|
|||||||
Register::Cir => self.cir,
|
Register::Cir => self.cir,
|
||||||
Register::Pcx => self.pcx,
|
Register::Pcx => self.pcx,
|
||||||
Register::Zero => 0,
|
Register::Zero => 0,
|
||||||
_ => return Err(ProcessorError::InvalidRegister(Register::NoReg as u8)),
|
_ => return Err(ProcessorError::InvalidRegister(Register::Null as u8)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -349,17 +349,13 @@ impl Executable for Instruction {
|
|||||||
// Left shifts the value in Reg by the given amount (either a register, or a
|
// Left shifts the value in Reg by the given amount (either a register, or a
|
||||||
// literal value)
|
// literal value)
|
||||||
Self::ShiftLeft(a) => {
|
Self::ShiftLeft(a) => {
|
||||||
let reg = cpu.get(a.sr1)?;
|
*cpu.reg(a.dr)? = shl(cpu.get(a.sr1)?, a.shamt + cpu.get(a.sr2)? as u8);
|
||||||
let val = a.shamt;
|
|
||||||
*cpu.reg(a.sr1)? = shl(reg, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right shifts the value in Reg by the given amount (either a register, or a
|
// Right shifts the value in Reg by the given amount (either a register, or a
|
||||||
// literal value).
|
// literal value).
|
||||||
Self::ShiftRight(a) => {
|
Self::ShiftRight(a) => {
|
||||||
let regval = cpu.get(a.sr1)?;
|
*cpu.reg(a.dr)? = shr(cpu.get(a.sr1)?, a.shamt + cpu.get(a.sr2)? as u8);
|
||||||
let val = a.shamt;
|
|
||||||
*cpu.reg(a.sr1)? = shr(regval, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds the value of Src2 to Src1 and writes the result to a.dr
|
// Adds the value of Src2 to Src1 and writes the result to a.dr
|
||||||
|
|||||||
Reference in New Issue
Block a user