Compare commits

4 Commits

Author SHA1 Message Date
zxq5 22241a5633 - implementation of <var> <op> = <expr> type statements such as `x +=
5`
- implementation of logical and shift operations in parser and codegen.
- implementation of sizeof keyword as unary operator

in progress (non functional)
- implementation of prefix and postfix inc/dec operators

- array access by index (implemented, untested as arrays aren't
  implemented yet). essentially just a pointer write with offset.
- struct/member access (parsing implemented, untested.)
2026-02-09 00:10:37 +00:00
zxq5 e2be83414b - updated assembler to support new shift implementation
- updated emulator to support new shift implementation
- updated emulator to rename NoReg to Null as in the common lib
2026-02-09 00:05:45 +00:00
zxq5 f7ed764e96 renamed NoReg to Null in common 2026-02-09 00:04:19 +00:00
zxq5 328741eb51 updated compiler with support for more operators.
(only the unary operators from this are implemented for now)
2026-02-08 20:03:31 +00:00
12 changed files with 1375 additions and 472 deletions
+18 -6
View File
@@ -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!(),
} }
} }
+46 -9
View File
@@ -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 => {
+5 -5
View File
@@ -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"),
+3 -3
View File
@@ -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)
+4 -4
View File
@@ -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),
+299 -76
View File
@@ -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))
}
} }
} }
+2 -2
View File
@@ -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(&reg); self.register_contents.remove(&reg);
self.in_use.insert(reg, false); self.in_use.insert(reg, false);
File diff suppressed because it is too large Load Diff
+277 -49
View File
@@ -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
View File
@@ -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"),
} }
} }
} }
+2 -2
View File
@@ -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