updated compiler with support for more operators.

(only the unary operators from this are implemented for now)
This commit is contained in:
2026-02-08 20:03:31 +00:00
parent 9f35fc9415
commit 328741eb51
5 changed files with 868 additions and 358 deletions
+33 -22
View File
@@ -510,7 +510,7 @@ impl CodeGenerator {
code.push("\tpop zero".to_string()); code.push("\tpop zero".to_string());
} }
// 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 +518,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 +526,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 +534,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 +542,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,7 +550,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::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());
@@ -581,13 +581,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 +597,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 +634,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);
@@ -677,7 +662,9 @@ impl CodeGenerator {
UnaryOperator::Dereference => { UnaryOperator::Dereference => {
code.push(format!("\tldw {}, {}", operand_reg, result_reg)); code.push(format!("\tldw {}, {}", operand_reg, result_reg));
} }
UnaryOperator::Reference => { UnaryOperator::AddressOf => {
// ensure the referenced variable is on the stack and return its
// address.
let (offset, alloc_code) = let (offset, alloc_code) =
self.allocator.free_register(&operand_reg)?; self.allocator.free_register(&operand_reg)?;
code.extend(alloc_code); code.extend(alloc_code);
@@ -687,6 +674,28 @@ impl CodeGenerator {
result_reg result_reg
)); ));
} }
UnaryOperator::SizeOf => {
if let Ok(id) = operand.type_id() {
let size = id.size();
code.push(format!("\tmov {}, {}", size, result_reg));
}
}
UnaryOperator::CastAs => {} /* this should be removed once the */
// semantic analyser can handle it!
UnaryOperator::Increment => {
// prefix increment
code.push(format!("\tmov {}, {}", operand_reg, result_reg));
code.push(format!("\taddi {}, {}, 1", operand_reg, operand_reg));
}
UnaryOperator::Decrement => {
// prefix decrement
code.push(format!("\tmov {}, {}", operand_reg, result_reg));
code.push(format!("\tsubi {}, {}, 1", operand_reg, operand_reg));
}
UnaryOperator::BitwiseNot => {
code.push(format!("\tnot {}, {}", operand_reg, result_reg));
}
UnaryOperator::LogicalNot => unimplemented!(),
} }
self.allocator.free_temp(operand_reg); self.allocator.free_temp(operand_reg);
@@ -694,6 +703,8 @@ impl CodeGenerator {
} }
Expression::Empty => Ok((Register::Null, code)), Expression::Empty => Ok((Register::Null, code)),
_ => unimplemented!(),
} }
} }
+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
+143 -36
View File
@@ -353,12 +353,12 @@ impl Parser {
let mut expr = self.parse_additive()?; let mut expr = self.parse_additive()?;
while let Some(op) = match self.peek_next()? { while let Some(op) = match self.peek_next()? {
Token::EqualEqual => Some(BinaryOperator::Eq), Token::EqualEqual => Some(BinaryOperator::Equal),
Token::BangEqual => Some(BinaryOperator::Ne), Token::BangEqual => Some(BinaryOperator::NotEqual),
Token::Less => Some(BinaryOperator::Lt), Token::Less => Some(BinaryOperator::LessThan),
Token::Greater => Some(BinaryOperator::Gt), Token::Greater => Some(BinaryOperator::GreaterThan),
Token::LessEqual => Some(BinaryOperator::Le), Token::LessEqual => Some(BinaryOperator::LessOrEqual),
Token::GreaterEqual => Some(BinaryOperator::Ge), Token::GreaterEqual => Some(BinaryOperator::GreaterOrEqual),
_ => None, _ => None,
} { } {
self.next()?; self.next()?;
@@ -412,11 +412,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 +444,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 +550,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)?; self.next()?;
ParseResult::Accept(Expression::CharLiteral(value))
}
if matches!(self.peek_next()?, Token::LeftParen) { Token::Identifier(name) => {
// Function call self.next()?;
self.next()?; ParseResult::Accept(Expression::Variable {
let mut args = Vec::new(); name,
expr_type: None,
})
}
Token::LeftBracket => {
self.next()?; // consume '['
let mut elements = Vec::new();
if !matches!(self.peek_next()?, Token::RightParen) { if !matches!(self.peek_next()?, Token::RightBracket) {
args.push(self.parse_expression()?); loop {
elements.push(self.parse_expression()?);
while matches!(self.peek_next()?, Token::Comma) { if !matches!(self.peek_next()?, Token::Comma) {
self.next()?; break;
args.push(self.parse_expression()?);
} }
self.next()?; // consume comma
} }
let _ = expect_tt!(self.next()?, RightParen)?;
ParseResult::Accept(Expression::Call {
func: Call {
name: name.clone(),
args,
},
type_id: None,
})
} else {
ParseResult::Accept(Expression::Variable {
name,
expr_type: None,
})
} }
expect_tt!(self.next()?, RightBracket)?;
ParseResult::Accept(Expression::ArrayLiteral {
elements,
type_id: None,
})
} }
Token::LeftParen => { Token::LeftParen => {
self.next()?; self.next()?;
+133 -21
View File
@@ -65,6 +65,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 {
@@ -169,10 +189,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 +235,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 +256,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,10 +286,24 @@ 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()))
}
} }
} }
} }
@@ -236,31 +311,56 @@ impl Expression {
#[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 +369,29 @@ impl fmt::Display for BinaryOperator {
pub enum UnaryOperator { pub enum UnaryOperator {
Plus, Plus,
Minus, Minus,
Reference, AddressOf,
Dereference, Dereference,
CastAs,
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::CastAs => write!(f, "as"),
Self::BitwiseNot => write!(f, "~"),
Self::LogicalNot => write!(f, "!"),
Self::SizeOf => write!(f, "sizeof"),
} }
} }
} }