@@ -1,9 +1,9 @@
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use alecc::lexer::Lexer;
|
||||
use alecc::parser::Parser;
|
||||
use alecc::codegen::CodeGenerator;
|
||||
use alecc::optimizer::{Optimizer, OptimizationLevel};
|
||||
use alecc::lexer::Lexer;
|
||||
use alecc::optimizer::{OptimizationLevel, Optimizer};
|
||||
use alecc::parser::Parser;
|
||||
use alecc::targets::Target;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
const SIMPLE_C_CODE: &str = r#"
|
||||
int main() {
|
||||
@@ -119,5 +119,11 @@ fn bench_optimizer(c: &mut Criterion) {
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_lexer, bench_parser, bench_codegen, bench_optimizer);
|
||||
criterion_group!(
|
||||
benches,
|
||||
bench_lexer,
|
||||
bench_parser,
|
||||
bench_codegen,
|
||||
bench_optimizer
|
||||
);
|
||||
criterion_main!(benches);
|
||||
|
||||
285
src/codegen.rs
285
src/codegen.rs
@@ -1,6 +1,8 @@
|
||||
use crate::parser::{Program, Function, Expression, Statement, Type, BinaryOperator, UnaryOperator};
|
||||
use crate::targets::Target;
|
||||
use crate::error::{AleccError, Result};
|
||||
use crate::parser::{
|
||||
BinaryOperator, Expression, Function, Program, Statement, Type, UnaryOperator,
|
||||
};
|
||||
use crate::targets::Target;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct CodeGenerator {
|
||||
@@ -11,8 +13,8 @@ pub struct CodeGenerator {
|
||||
current_function_params: Vec<(String, i32)>, // (name, stack_offset)
|
||||
epilogue_emitted: bool,
|
||||
local_variables: HashMap<String, i32>, // (name, stack_offset)
|
||||
stack_offset: i32, // Current stack offset for local variables
|
||||
last_call_stack_cleanup: usize, // Stack bytes to clean up after last call
|
||||
stack_offset: i32, // Current stack offset for local variables
|
||||
last_call_stack_cleanup: usize, // Stack bytes to clean up after last call
|
||||
}
|
||||
|
||||
impl CodeGenerator {
|
||||
@@ -87,9 +89,9 @@ impl CodeGenerator {
|
||||
self.emit_line(" call main");
|
||||
|
||||
// Exit syscall with main's return value
|
||||
self.emit_line(" mov rdi, rax"); // exit status = main's return value
|
||||
self.emit_line(" mov rax, 60"); // sys_exit syscall number
|
||||
self.emit_line(" syscall"); // invoke syscall
|
||||
self.emit_line(" mov rdi, rax"); // exit status = main's return value
|
||||
self.emit_line(" mov rax, 60"); // sys_exit syscall number
|
||||
self.emit_line(" syscall"); // invoke syscall
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -165,7 +167,8 @@ impl CodeGenerator {
|
||||
let stack_offset = 8 + i as i32 * 4; // ebp + 8 + offset
|
||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", stack_offset));
|
||||
self.emit_line(&format!(" mov DWORD PTR [ebp + {}], eax", param_offset));
|
||||
self.current_function_params.push((name.clone(), param_offset));
|
||||
self.current_function_params
|
||||
.push((name.clone(), param_offset));
|
||||
}
|
||||
}
|
||||
Target::Amd64 => {
|
||||
@@ -185,14 +188,18 @@ impl CodeGenerator {
|
||||
let param_offset = -(i as i32 + 1) * 8;
|
||||
if i < param_registers.len() {
|
||||
// Parameter passed in register
|
||||
self.emit_line(&format!(" mov QWORD PTR [rbp + {}], {}", param_offset, param_registers[i]));
|
||||
self.emit_line(&format!(
|
||||
" mov QWORD PTR [rbp + {}], {}",
|
||||
param_offset, param_registers[i]
|
||||
));
|
||||
} else {
|
||||
// Parameter passed on stack
|
||||
let stack_offset = 16 + (i - param_registers.len()) as i32 * 8;
|
||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", stack_offset));
|
||||
self.emit_line(&format!(" mov QWORD PTR [rbp + {}], rax", param_offset));
|
||||
}
|
||||
self.current_function_params.push((name.clone(), param_offset));
|
||||
self.current_function_params
|
||||
.push((name.clone(), param_offset));
|
||||
}
|
||||
}
|
||||
Target::Arm64 => {
|
||||
@@ -217,7 +224,8 @@ impl CodeGenerator {
|
||||
self.emit_line(&format!(" ldr x9, [x29, #{}]", stack_offset));
|
||||
self.emit_line(&format!(" str x9, [x29, #{}]", param_offset));
|
||||
}
|
||||
self.current_function_params.push((name.clone(), param_offset));
|
||||
self.current_function_params
|
||||
.push((name.clone(), param_offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,12 +288,16 @@ impl CodeGenerator {
|
||||
Statement::Expression(expr) => {
|
||||
self.generate_expression(expr)?;
|
||||
}
|
||||
Statement::Declaration { name, var_type, initializer } => {
|
||||
Statement::Declaration {
|
||||
name,
|
||||
var_type,
|
||||
initializer,
|
||||
} => {
|
||||
// Calculate space needed based on type
|
||||
let size = match var_type {
|
||||
Type::Array(_, Some(length)) => length * 8, // Assuming 8-byte elements
|
||||
Type::Array(_, None) => 80, // Default size for unsized arrays
|
||||
_ => 8, // Default 8 bytes for simple types
|
||||
Type::Array(_, None) => 80, // Default size for unsized arrays
|
||||
_ => 8, // Default 8 bytes for simple types
|
||||
};
|
||||
|
||||
// Allocate space for variable/array
|
||||
@@ -300,10 +312,16 @@ impl CodeGenerator {
|
||||
// Store the value in the local variable slot
|
||||
match self.target {
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov QWORD PTR [rbp + {}], rax", var_offset));
|
||||
self.emit_line(&format!(
|
||||
" mov QWORD PTR [rbp + {}], rax",
|
||||
var_offset
|
||||
));
|
||||
}
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov DWORD PTR [ebp + {}], eax", var_offset));
|
||||
self.emit_line(&format!(
|
||||
" mov DWORD PTR [ebp + {}], eax",
|
||||
var_offset
|
||||
));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" str x0, [x29, #{}]", var_offset));
|
||||
@@ -335,7 +353,11 @@ impl CodeGenerator {
|
||||
self.generate_statement(stmt)?;
|
||||
}
|
||||
}
|
||||
Statement::If { condition, then_stmt, else_stmt } => {
|
||||
Statement::If {
|
||||
condition,
|
||||
then_stmt,
|
||||
else_stmt,
|
||||
} => {
|
||||
let else_label = self.new_label("else");
|
||||
let end_label = self.new_label("endif");
|
||||
|
||||
@@ -372,7 +394,12 @@ impl CodeGenerator {
|
||||
|
||||
self.emit_line(&format!("{}:", end_label));
|
||||
}
|
||||
Statement::For { init, condition, increment, body } => {
|
||||
Statement::For {
|
||||
init,
|
||||
condition,
|
||||
increment,
|
||||
body,
|
||||
} => {
|
||||
// Generate initialization
|
||||
if let Some(init_stmt) = init {
|
||||
self.generate_statement(init_stmt)?;
|
||||
@@ -412,19 +439,17 @@ impl CodeGenerator {
|
||||
|
||||
fn generate_expression(&mut self, expression: &Expression) -> Result<()> {
|
||||
match expression {
|
||||
Expression::IntegerLiteral(value) => {
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov eax, {}", value));
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov rax, {}", value));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" mov x0, #{}", value));
|
||||
}
|
||||
Expression::IntegerLiteral(value) => match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov eax, {}", value));
|
||||
}
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov rax, {}", value));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" mov x0, #{}", value));
|
||||
}
|
||||
},
|
||||
Expression::StringLiteral(value) => {
|
||||
let label = self.get_string_literal_label(value);
|
||||
match self.target {
|
||||
@@ -442,7 +467,11 @@ impl CodeGenerator {
|
||||
}
|
||||
Expression::Identifier(name) => {
|
||||
// Check if it's a function parameter first
|
||||
if let Some((_, offset)) = self.current_function_params.iter().find(|(param_name, _)| param_name == name) {
|
||||
if let Some((_, offset)) = self
|
||||
.current_function_params
|
||||
.iter()
|
||||
.find(|(param_name, _)| param_name == name)
|
||||
{
|
||||
// Load parameter from stack
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
@@ -485,7 +514,10 @@ impl CodeGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::Call { function, arguments } => {
|
||||
Expression::Call {
|
||||
function,
|
||||
arguments,
|
||||
} => {
|
||||
// Generate arguments and place in calling convention registers/stack
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
@@ -502,7 +534,11 @@ impl CodeGenerator {
|
||||
// Ensure stack alignment before function call
|
||||
// Stack must be 16-byte aligned before 'call' instruction
|
||||
// Since 'call' pushes 8 bytes (return address), we need stack to be 8 bytes off 16-byte boundary
|
||||
let stack_args = if arguments.len() > param_registers.len() { arguments.len() - param_registers.len() } else { 0 };
|
||||
let stack_args = if arguments.len() > param_registers.len() {
|
||||
arguments.len() - param_registers.len()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let mut stack_cleanup_size = 0;
|
||||
|
||||
// Handle stack arguments if any
|
||||
@@ -526,7 +562,8 @@ impl CodeGenerator {
|
||||
}
|
||||
|
||||
// Then handle register arguments in reverse order to avoid overwriting
|
||||
let reg_args: Vec<_> = arguments.iter().take(param_registers.len()).collect();
|
||||
let reg_args: Vec<_> =
|
||||
arguments.iter().take(param_registers.len()).collect();
|
||||
for (i, arg) in reg_args.iter().enumerate().rev() {
|
||||
self.generate_expression(arg)?;
|
||||
self.emit_line(&format!(" mov {}, rax", param_registers[i]));
|
||||
@@ -576,31 +613,42 @@ impl CodeGenerator {
|
||||
Target::Amd64 => {
|
||||
// Clean up stack using stored cleanup size
|
||||
if self.last_call_stack_cleanup > 0 {
|
||||
self.emit_line(&format!(" add rsp, {}", self.last_call_stack_cleanup));
|
||||
self.emit_line(&format!(
|
||||
" add rsp, {}",
|
||||
self.last_call_stack_cleanup
|
||||
));
|
||||
}
|
||||
}
|
||||
Target::Arm64 => {
|
||||
// Clean up stack arguments (if any)
|
||||
let stack_args = if arguments.len() > 8 { arguments.len() - 8 } else { 0 };
|
||||
let stack_args = if arguments.len() > 8 {
|
||||
arguments.len() - 8
|
||||
} else {
|
||||
0
|
||||
};
|
||||
if stack_args > 0 {
|
||||
self.emit_line(&format!(" add sp, sp, #{}", stack_args * 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::Binary { left, operator, right } => {
|
||||
Expression::Binary {
|
||||
left,
|
||||
operator,
|
||||
right,
|
||||
} => {
|
||||
// Generate binary operations
|
||||
// First generate right operand and save it
|
||||
self.generate_expression(right)?;
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(" push eax"); // Save right operand
|
||||
self.emit_line(" push eax"); // Save right operand
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(" push rax"); // Save right operand
|
||||
self.emit_line(" push rax"); // Save right operand
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(" str x0, [sp, #-16]!"); // Save right operand
|
||||
self.emit_line(" str x0, [sp, #-16]!"); // Save right operand
|
||||
}
|
||||
}
|
||||
|
||||
@@ -610,39 +658,42 @@ impl CodeGenerator {
|
||||
// Pop right operand and perform operation
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(" pop ebx"); // Right operand in ebx
|
||||
self.emit_line(" pop ebx"); // Right operand in ebx
|
||||
match operator {
|
||||
BinaryOperator::Add => self.emit_line(" add eax, ebx"),
|
||||
BinaryOperator::Subtract => self.emit_line(" sub eax, ebx"),
|
||||
BinaryOperator::Multiply => self.emit_line(" imul eax, ebx"),
|
||||
BinaryOperator::Divide => {
|
||||
self.emit_line(" cdq"); // Sign extend eax to edx:eax
|
||||
self.emit_line(" cdq"); // Sign extend eax to edx:eax
|
||||
self.emit_line(" idiv ebx");
|
||||
}
|
||||
BinaryOperator::Modulo => {
|
||||
self.emit_line(" cdq"); // Sign extend eax to edx:eax
|
||||
self.emit_line(" cdq"); // Sign extend eax to edx:eax
|
||||
self.emit_line(" idiv ebx");
|
||||
self.emit_line(" mov eax, edx"); // Remainder is in edx
|
||||
}
|
||||
_ => {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: format!("Binary operator {:?} not implemented for i386", operator),
|
||||
message: format!(
|
||||
"Binary operator {:?} not implemented for i386",
|
||||
operator
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(" pop rbx"); // Right operand in rbx
|
||||
self.emit_line(" pop rbx"); // Right operand in rbx
|
||||
match operator {
|
||||
BinaryOperator::Add => self.emit_line(" add rax, rbx"),
|
||||
BinaryOperator::Subtract => self.emit_line(" sub rax, rbx"),
|
||||
BinaryOperator::Multiply => self.emit_line(" imul rax, rbx"),
|
||||
BinaryOperator::Divide => {
|
||||
self.emit_line(" cqo"); // Sign extend rax to rdx:rax
|
||||
self.emit_line(" cqo"); // Sign extend rax to rdx:rax
|
||||
self.emit_line(" idiv rbx");
|
||||
}
|
||||
BinaryOperator::Modulo => {
|
||||
self.emit_line(" cqo"); // Sign extend rax to rdx:rax
|
||||
self.emit_line(" cqo"); // Sign extend rax to rdx:rax
|
||||
self.emit_line(" idiv rbx");
|
||||
self.emit_line(" mov rax, rdx"); // Remainder is in rdx
|
||||
}
|
||||
@@ -710,19 +761,22 @@ impl CodeGenerator {
|
||||
}
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(" ldr x1, [sp], #16"); // Right operand in x1
|
||||
self.emit_line(" ldr x1, [sp], #16"); // Right operand in x1
|
||||
match operator {
|
||||
BinaryOperator::Add => self.emit_line(" add x0, x0, x1"),
|
||||
BinaryOperator::Subtract => self.emit_line(" sub x0, x0, x1"),
|
||||
BinaryOperator::Multiply => self.emit_line(" mul x0, x0, x1"),
|
||||
BinaryOperator::Divide => self.emit_line(" sdiv x0, x0, x1"),
|
||||
BinaryOperator::Modulo => {
|
||||
self.emit_line(" sdiv x2, x0, x1"); // x2 = x0 / x1
|
||||
self.emit_line(" sdiv x2, x0, x1"); // x2 = x0 / x1
|
||||
self.emit_line(" msub x0, x2, x1, x0"); // x0 = x0 - (x2 * x1)
|
||||
}
|
||||
_ => {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: format!("Binary operator {:?} not implemented for arm64", operator),
|
||||
message: format!(
|
||||
"Binary operator {:?} not implemented for arm64",
|
||||
operator
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -788,12 +842,24 @@ impl CodeGenerator {
|
||||
if let Some(&offset) = self.local_variables.get(name) {
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" inc DWORD PTR [ebp + {}]", offset));
|
||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
||||
self.emit_line(&format!(
|
||||
" inc DWORD PTR [ebp + {}]",
|
||||
offset
|
||||
));
|
||||
self.emit_line(&format!(
|
||||
" mov eax, DWORD PTR [ebp + {}]",
|
||||
offset
|
||||
));
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" inc QWORD PTR [rbp + {}]", offset));
|
||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
||||
self.emit_line(&format!(
|
||||
" inc QWORD PTR [rbp + {}]",
|
||||
offset
|
||||
));
|
||||
self.emit_line(&format!(
|
||||
" mov rax, QWORD PTR [rbp + {}]",
|
||||
offset
|
||||
));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||
@@ -808,7 +874,8 @@ impl CodeGenerator {
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Pre-increment can only be applied to variables".to_string(),
|
||||
message: "Pre-increment can only be applied to variables"
|
||||
.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -818,12 +885,24 @@ impl CodeGenerator {
|
||||
if let Some(&offset) = self.local_variables.get(name) {
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
||||
self.emit_line(&format!(" inc DWORD PTR [ebp + {}]", offset));
|
||||
self.emit_line(&format!(
|
||||
" mov eax, DWORD PTR [ebp + {}]",
|
||||
offset
|
||||
));
|
||||
self.emit_line(&format!(
|
||||
" inc DWORD PTR [ebp + {}]",
|
||||
offset
|
||||
));
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
||||
self.emit_line(&format!(" inc QWORD PTR [rbp + {}]", offset));
|
||||
self.emit_line(&format!(
|
||||
" mov rax, QWORD PTR [rbp + {}]",
|
||||
offset
|
||||
));
|
||||
self.emit_line(&format!(
|
||||
" inc QWORD PTR [rbp + {}]",
|
||||
offset
|
||||
));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||
@@ -839,7 +918,8 @@ impl CodeGenerator {
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Post-increment can only be applied to variables".to_string(),
|
||||
message: "Post-increment can only be applied to variables"
|
||||
.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -849,12 +929,24 @@ impl CodeGenerator {
|
||||
if let Some(&offset) = self.local_variables.get(name) {
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" dec DWORD PTR [ebp + {}]", offset));
|
||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
||||
self.emit_line(&format!(
|
||||
" dec DWORD PTR [ebp + {}]",
|
||||
offset
|
||||
));
|
||||
self.emit_line(&format!(
|
||||
" mov eax, DWORD PTR [ebp + {}]",
|
||||
offset
|
||||
));
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" dec QWORD PTR [rbp + {}]", offset));
|
||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
||||
self.emit_line(&format!(
|
||||
" dec QWORD PTR [rbp + {}]",
|
||||
offset
|
||||
));
|
||||
self.emit_line(&format!(
|
||||
" mov rax, QWORD PTR [rbp + {}]",
|
||||
offset
|
||||
));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||
@@ -869,7 +961,8 @@ impl CodeGenerator {
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Pre-decrement can only be applied to variables".to_string(),
|
||||
message: "Pre-decrement can only be applied to variables"
|
||||
.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -879,12 +972,24 @@ impl CodeGenerator {
|
||||
if let Some(&offset) = self.local_variables.get(name) {
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
||||
self.emit_line(&format!(" dec DWORD PTR [ebp + {}]", offset));
|
||||
self.emit_line(&format!(
|
||||
" mov eax, DWORD PTR [ebp + {}]",
|
||||
offset
|
||||
));
|
||||
self.emit_line(&format!(
|
||||
" dec DWORD PTR [ebp + {}]",
|
||||
offset
|
||||
));
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
||||
self.emit_line(&format!(" dec QWORD PTR [rbp + {}]", offset));
|
||||
self.emit_line(&format!(
|
||||
" mov rax, QWORD PTR [rbp + {}]",
|
||||
offset
|
||||
));
|
||||
self.emit_line(&format!(
|
||||
" dec QWORD PTR [rbp + {}]",
|
||||
offset
|
||||
));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||
@@ -900,7 +1005,8 @@ impl CodeGenerator {
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Post-decrement can only be applied to variables".to_string(),
|
||||
message: "Post-decrement can only be applied to variables"
|
||||
.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -959,7 +1065,7 @@ impl CodeGenerator {
|
||||
Target::Amd64 => {
|
||||
// Multiply index by 8 (assuming int is 8 bytes for simplicity)
|
||||
self.emit_line(" imul rax, 8"); // Use imul instead of mul
|
||||
// Add base address
|
||||
// Add base address
|
||||
self.emit_line(&format!(" lea rbx, [rbp + {}]", base_offset));
|
||||
self.emit_line(" add rax, rbx");
|
||||
// Load the value at that address
|
||||
@@ -991,7 +1097,11 @@ impl CodeGenerator {
|
||||
});
|
||||
}
|
||||
}
|
||||
Expression::Assignment { target, operator, value } => {
|
||||
Expression::Assignment {
|
||||
target,
|
||||
operator,
|
||||
value,
|
||||
} => {
|
||||
// Handle compound assignment operators
|
||||
match operator {
|
||||
crate::parser::AssignmentOperator::Assign => {
|
||||
@@ -1105,7 +1215,8 @@ impl CodeGenerator {
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Complex assignment targets not supported for compound operators yet".to_string(),
|
||||
message: "Complex assignment targets not supported for compound operators yet"
|
||||
.to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
@@ -1144,7 +1255,8 @@ impl CodeGenerator {
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Complex assignment targets not supported for compound operators yet".to_string(),
|
||||
message: "Complex assignment targets not supported for compound operators yet"
|
||||
.to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
@@ -1209,7 +1321,8 @@ impl CodeGenerator {
|
||||
label.clone()
|
||||
} else {
|
||||
let label = format!(".LC{}", self.string_literals.len());
|
||||
self.string_literals.insert(content.to_string(), label.clone());
|
||||
self.string_literals
|
||||
.insert(content.to_string(), label.clone());
|
||||
label
|
||||
}
|
||||
}
|
||||
@@ -1248,7 +1361,11 @@ impl CodeGenerator {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Statement::If { condition, then_stmt, else_stmt } => {
|
||||
Statement::If {
|
||||
condition,
|
||||
then_stmt,
|
||||
else_stmt,
|
||||
} => {
|
||||
self.collect_string_literals_from_expression(condition)?;
|
||||
self.collect_string_literals_from_statement(then_stmt)?;
|
||||
if let Some(else_statement) = else_stmt {
|
||||
@@ -1261,7 +1378,12 @@ impl CodeGenerator {
|
||||
self.collect_string_literals_from_statement(body)?;
|
||||
Ok(())
|
||||
}
|
||||
Statement::For { init, condition, increment, body } => {
|
||||
Statement::For {
|
||||
init,
|
||||
condition,
|
||||
increment,
|
||||
body,
|
||||
} => {
|
||||
if let Some(init_stmt) = init {
|
||||
self.collect_string_literals_from_statement(init_stmt)?;
|
||||
}
|
||||
@@ -1280,7 +1402,7 @@ impl CodeGenerator {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => Ok(()) // Other statement types don't have expressions we need to collect
|
||||
_ => Ok(()), // Other statement types don't have expressions we need to collect
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1299,7 +1421,10 @@ impl CodeGenerator {
|
||||
self.collect_string_literals_from_expression(operand)?;
|
||||
Ok(())
|
||||
}
|
||||
Expression::Call { function, arguments } => {
|
||||
Expression::Call {
|
||||
function,
|
||||
arguments,
|
||||
} => {
|
||||
self.collect_string_literals_from_expression(function)?;
|
||||
for arg in arguments {
|
||||
self.collect_string_literals_from_expression(arg)?;
|
||||
@@ -1311,7 +1436,7 @@ impl CodeGenerator {
|
||||
self.collect_string_literals_from_expression(value)?;
|
||||
Ok(())
|
||||
}
|
||||
_ => Ok(()) // Other expression types don't contain string literals
|
||||
_ => Ok(()), // Other expression types don't contain string literals
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
107
src/compiler.rs
107
src/compiler.rs
@@ -1,15 +1,15 @@
|
||||
use crate::cli::Args;
|
||||
use crate::lexer::Lexer;
|
||||
use crate::parser::Parser;
|
||||
use crate::codegen::CodeGenerator;
|
||||
use crate::optimizer::{Optimizer, OptimizationLevel};
|
||||
use crate::linker::Linker;
|
||||
use crate::targets::Target;
|
||||
use crate::error::{AleccError, Result};
|
||||
use crate::lexer::Lexer;
|
||||
use crate::linker::Linker;
|
||||
use crate::optimizer::{OptimizationLevel, Optimizer};
|
||||
use crate::parser::Parser;
|
||||
use crate::targets::Target;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use tokio::fs;
|
||||
use tracing::{info, debug, warn};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
pub struct Compiler {
|
||||
args: Args,
|
||||
@@ -19,11 +19,10 @@ pub struct Compiler {
|
||||
|
||||
impl Compiler {
|
||||
pub fn new(args: Args) -> Result<Self> {
|
||||
let target = Target::from_string(&args.target).ok_or_else(|| {
|
||||
AleccError::UnsupportedTarget {
|
||||
let target =
|
||||
Target::from_string(&args.target).ok_or_else(|| AleccError::UnsupportedTarget {
|
||||
target: args.target.clone(),
|
||||
}
|
||||
})?;
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
args,
|
||||
@@ -39,9 +38,11 @@ impl Compiler {
|
||||
});
|
||||
}
|
||||
|
||||
info!("Compiling {} files for target {}",
|
||||
self.args.input_files.len(),
|
||||
self.target.as_str());
|
||||
info!(
|
||||
"Compiling {} files for target {}",
|
||||
self.args.input_files.len(),
|
||||
self.target.as_str()
|
||||
);
|
||||
|
||||
let mut object_files = Vec::new();
|
||||
let input_files = self.args.input_files.clone(); // Clone to avoid borrow issues
|
||||
@@ -50,14 +51,18 @@ impl Compiler {
|
||||
for input_file in &input_files {
|
||||
debug!("Processing file: {}", input_file.display());
|
||||
|
||||
let extension = input_file.extension()
|
||||
let extension = input_file
|
||||
.extension()
|
||||
.and_then(|ext| ext.to_str())
|
||||
.unwrap_or("");
|
||||
|
||||
match extension {
|
||||
"c" | "cpp" | "cxx" | "cc" | "C" => {
|
||||
let obj_file = self.compile_source_file(input_file).await?;
|
||||
if !self.args.compile_only && !self.args.assembly_only && !self.args.preprocess_only {
|
||||
if !self.args.compile_only
|
||||
&& !self.args.assembly_only
|
||||
&& !self.args.preprocess_only
|
||||
{
|
||||
object_files.push(obj_file);
|
||||
}
|
||||
}
|
||||
@@ -71,10 +76,15 @@ impl Compiler {
|
||||
object_files.push(input_file.clone());
|
||||
}
|
||||
_ => {
|
||||
warn!("Unknown file extension for {}, treating as C source",
|
||||
input_file.display());
|
||||
warn!(
|
||||
"Unknown file extension for {}, treating as C source",
|
||||
input_file.display()
|
||||
);
|
||||
let obj_file = self.compile_source_file(input_file).await?;
|
||||
if !self.args.compile_only && !self.args.assembly_only && !self.args.preprocess_only {
|
||||
if !self.args.compile_only
|
||||
&& !self.args.assembly_only
|
||||
&& !self.args.preprocess_only
|
||||
{
|
||||
object_files.push(obj_file);
|
||||
}
|
||||
}
|
||||
@@ -96,19 +106,20 @@ impl Compiler {
|
||||
info!("Compiling source file: {}", input_file.display());
|
||||
|
||||
// Read source file
|
||||
let source = fs::read_to_string(input_file).await.map_err(|_e| {
|
||||
AleccError::FileNotFound {
|
||||
path: input_file.to_string_lossy().to_string(),
|
||||
}
|
||||
})?;
|
||||
let source =
|
||||
fs::read_to_string(input_file)
|
||||
.await
|
||||
.map_err(|_e| AleccError::FileNotFound {
|
||||
path: input_file.to_string_lossy().to_string(),
|
||||
})?;
|
||||
|
||||
// Preprocessing
|
||||
let preprocessed = if self.args.preprocess_only {
|
||||
let output_path = self.get_output_path(input_file, "i")?;
|
||||
let preprocessed = self.preprocess(&source, input_file).await?;
|
||||
fs::write(&output_path, preprocessed).await.map_err(|e| {
|
||||
AleccError::IoError(e)
|
||||
})?;
|
||||
fs::write(&output_path, preprocessed)
|
||||
.await
|
||||
.map_err(|e| AleccError::IoError(e))?;
|
||||
return Ok(output_path);
|
||||
} else {
|
||||
self.preprocess(&source, input_file).await?
|
||||
@@ -136,17 +147,17 @@ impl Compiler {
|
||||
|
||||
if self.args.assembly_only {
|
||||
let output_path = self.get_output_path(input_file, "s")?;
|
||||
fs::write(&output_path, assembly).await.map_err(|e| {
|
||||
AleccError::IoError(e)
|
||||
})?;
|
||||
fs::write(&output_path, assembly)
|
||||
.await
|
||||
.map_err(|e| AleccError::IoError(e))?;
|
||||
return Ok(output_path);
|
||||
}
|
||||
|
||||
// Write assembly to temporary file
|
||||
let asm_path = self.create_temp_file("s")?;
|
||||
fs::write(&asm_path, assembly).await.map_err(|e| {
|
||||
AleccError::IoError(e)
|
||||
})?;
|
||||
fs::write(&asm_path, assembly)
|
||||
.await
|
||||
.map_err(|e| AleccError::IoError(e))?;
|
||||
|
||||
// Assemble
|
||||
let obj_path = self.assemble_file(&asm_path).await?;
|
||||
@@ -330,8 +341,9 @@ impl Compiler {
|
||||
}
|
||||
|
||||
command.args(&[
|
||||
"-o", &obj_path.to_string_lossy(),
|
||||
&asm_file.to_string_lossy()
|
||||
"-o",
|
||||
&obj_path.to_string_lossy(),
|
||||
&asm_file.to_string_lossy(),
|
||||
]);
|
||||
|
||||
let output = command.output().map_err(|e| AleccError::CodegenError {
|
||||
@@ -401,20 +413,26 @@ impl Compiler {
|
||||
if let Some(ref output) = self.args.output {
|
||||
Ok(output.clone())
|
||||
} else {
|
||||
let stem = input_file.file_stem()
|
||||
let stem = input_file
|
||||
.file_stem()
|
||||
.ok_or_else(|| AleccError::InvalidArgument {
|
||||
message: "Invalid input file name".to_string(),
|
||||
})?;
|
||||
Ok(PathBuf::from(format!("{}.{}", stem.to_string_lossy(), extension)))
|
||||
Ok(PathBuf::from(format!(
|
||||
"{}.{}",
|
||||
stem.to_string_lossy(),
|
||||
extension
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
fn create_temp_file(&mut self, extension: &str) -> Result<PathBuf> {
|
||||
let temp_path = std::env::temp_dir()
|
||||
.join(format!("alecc_{}_{}.{}",
|
||||
std::process::id(),
|
||||
self.temp_files.len(),
|
||||
extension));
|
||||
let temp_path = std::env::temp_dir().join(format!(
|
||||
"alecc_{}_{}.{}",
|
||||
std::process::id(),
|
||||
self.temp_files.len(),
|
||||
extension
|
||||
));
|
||||
self.temp_files.push(temp_path.clone());
|
||||
Ok(temp_path)
|
||||
}
|
||||
@@ -423,8 +441,11 @@ impl Compiler {
|
||||
for temp_file in &self.temp_files {
|
||||
if temp_file.exists() {
|
||||
if let Err(e) = fs::remove_file(temp_file).await {
|
||||
warn!("Failed to remove temporary file {}: {}",
|
||||
temp_file.display(), e);
|
||||
warn!(
|
||||
"Failed to remove temporary file {}: {}",
|
||||
temp_file.display(),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
122
src/lexer.rs
122
src/lexer.rs
@@ -12,36 +12,116 @@ pub enum TokenType {
|
||||
Identifier(String),
|
||||
|
||||
// Keywords
|
||||
Auto, Break, Case, Char, Const, Continue, Default, Do,
|
||||
Double, Else, Enum, Extern, Float, For, Goto, If,
|
||||
Int, Long, Register, Return, Short, Signed, Sizeof, Static,
|
||||
Struct, Switch, Typedef, Union, Unsigned, Void, Volatile, While,
|
||||
Auto,
|
||||
Break,
|
||||
Case,
|
||||
Char,
|
||||
Const,
|
||||
Continue,
|
||||
Default,
|
||||
Do,
|
||||
Double,
|
||||
Else,
|
||||
Enum,
|
||||
Extern,
|
||||
Float,
|
||||
For,
|
||||
Goto,
|
||||
If,
|
||||
Int,
|
||||
Long,
|
||||
Register,
|
||||
Return,
|
||||
Short,
|
||||
Signed,
|
||||
Sizeof,
|
||||
Static,
|
||||
Struct,
|
||||
Switch,
|
||||
Typedef,
|
||||
Union,
|
||||
Unsigned,
|
||||
Void,
|
||||
Volatile,
|
||||
While,
|
||||
|
||||
// C++ Keywords
|
||||
Bool, Class, Explicit, Export, False, Friend, Inline, Mutable,
|
||||
Namespace, New, Operator, Private, Protected, Public, Template,
|
||||
This, Throw, True, Try, Typename, Using, Virtual,
|
||||
Bool,
|
||||
Class,
|
||||
Explicit,
|
||||
Export,
|
||||
False,
|
||||
Friend,
|
||||
Inline,
|
||||
Mutable,
|
||||
Namespace,
|
||||
New,
|
||||
Operator,
|
||||
Private,
|
||||
Protected,
|
||||
Public,
|
||||
Template,
|
||||
This,
|
||||
Throw,
|
||||
True,
|
||||
Try,
|
||||
Typename,
|
||||
Using,
|
||||
Virtual,
|
||||
|
||||
// Operators
|
||||
Plus, Minus, Multiply, Divide, Modulo,
|
||||
Assign, PlusAssign, MinusAssign, MultiplyAssign, DivideAssign, ModuloAssign,
|
||||
Equal, NotEqual, Less, Greater, LessEqual, GreaterEqual,
|
||||
LogicalAnd, LogicalOr, LogicalNot,
|
||||
BitwiseAnd, BitwiseOr, BitwiseXor, BitwiseNot,
|
||||
LeftShift, RightShift, LeftShiftAssign, RightShiftAssign,
|
||||
BitwiseAndAssign, BitwiseOrAssign, BitwiseXorAssign,
|
||||
Increment, Decrement,
|
||||
Arrow, Dot, Question, Colon,
|
||||
Plus,
|
||||
Minus,
|
||||
Multiply,
|
||||
Divide,
|
||||
Modulo,
|
||||
Assign,
|
||||
PlusAssign,
|
||||
MinusAssign,
|
||||
MultiplyAssign,
|
||||
DivideAssign,
|
||||
ModuloAssign,
|
||||
Equal,
|
||||
NotEqual,
|
||||
Less,
|
||||
Greater,
|
||||
LessEqual,
|
||||
GreaterEqual,
|
||||
LogicalAnd,
|
||||
LogicalOr,
|
||||
LogicalNot,
|
||||
BitwiseAnd,
|
||||
BitwiseOr,
|
||||
BitwiseXor,
|
||||
BitwiseNot,
|
||||
LeftShift,
|
||||
RightShift,
|
||||
LeftShiftAssign,
|
||||
RightShiftAssign,
|
||||
BitwiseAndAssign,
|
||||
BitwiseOrAssign,
|
||||
BitwiseXorAssign,
|
||||
Increment,
|
||||
Decrement,
|
||||
Arrow,
|
||||
Dot,
|
||||
Question,
|
||||
Colon,
|
||||
|
||||
// Delimiters
|
||||
LeftParen, RightParen,
|
||||
LeftBrace, RightBrace,
|
||||
LeftBracket, RightBracket,
|
||||
Semicolon, Comma,
|
||||
LeftParen,
|
||||
RightParen,
|
||||
LeftBrace,
|
||||
RightBrace,
|
||||
LeftBracket,
|
||||
RightBracket,
|
||||
Semicolon,
|
||||
Comma,
|
||||
Ellipsis, // ...
|
||||
|
||||
// Preprocessor
|
||||
Hash, HashHash,
|
||||
Hash,
|
||||
HashHash,
|
||||
|
||||
// Special
|
||||
Eof,
|
||||
|
||||
12
src/lib.rs
12
src/lib.rs
@@ -1,9 +1,9 @@
|
||||
pub mod lexer;
|
||||
pub mod parser;
|
||||
pub mod codegen;
|
||||
pub mod targets;
|
||||
pub mod compiler;
|
||||
pub mod cli;
|
||||
pub mod codegen;
|
||||
pub mod compiler;
|
||||
pub mod error;
|
||||
pub mod optimizer;
|
||||
pub mod lexer;
|
||||
pub mod linker;
|
||||
pub mod optimizer;
|
||||
pub mod parser;
|
||||
pub mod targets;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::targets::Target;
|
||||
use crate::error::{AleccError, Result};
|
||||
use crate::targets::Target;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
@@ -238,10 +238,7 @@ impl Linker {
|
||||
"/usr/lib64",
|
||||
"/lib64",
|
||||
],
|
||||
Target::Arm64 => vec![
|
||||
"/usr/lib/aarch64-linux-gnu",
|
||||
"/lib/aarch64-linux-gnu",
|
||||
],
|
||||
Target::Arm64 => vec!["/usr/lib/aarch64-linux-gnu", "/lib/aarch64-linux-gnu"],
|
||||
};
|
||||
|
||||
for path in lib_paths {
|
||||
|
||||
20
src/main.rs
20
src/main.rs
@@ -1,19 +1,19 @@
|
||||
use clap::Parser;
|
||||
use anyhow::Result;
|
||||
use tracing::{info, error};
|
||||
use clap::Parser;
|
||||
use tracing::{error, info};
|
||||
|
||||
mod compiler;
|
||||
mod lexer;
|
||||
mod parser;
|
||||
mod codegen;
|
||||
mod optimizer;
|
||||
mod linker;
|
||||
mod targets;
|
||||
mod cli;
|
||||
mod codegen;
|
||||
mod compiler;
|
||||
mod error;
|
||||
mod lexer;
|
||||
mod linker;
|
||||
mod optimizer;
|
||||
mod parser;
|
||||
mod targets;
|
||||
|
||||
use compiler::Compiler;
|
||||
use cli::Args;
|
||||
use compiler::Compiler;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::parser::Program;
|
||||
use crate::error::Result;
|
||||
use crate::parser::Program;
|
||||
|
||||
pub struct Optimizer {
|
||||
level: OptimizationLevel,
|
||||
@@ -40,9 +40,7 @@ impl Optimizer {
|
||||
// No optimization
|
||||
Ok(())
|
||||
}
|
||||
OptimizationLevel::Basic => {
|
||||
self.basic_optimizations(program)
|
||||
}
|
||||
OptimizationLevel::Basic => self.basic_optimizations(program),
|
||||
OptimizationLevel::Moderate => {
|
||||
self.basic_optimizations(program)?;
|
||||
self.moderate_optimizations(program)
|
||||
|
||||
191
src/parser.rs
191
src/parser.rs
@@ -1,5 +1,5 @@
|
||||
use crate::lexer::{Token, TokenType};
|
||||
use crate::error::{AleccError, Result};
|
||||
use crate::lexer::{Token, TokenType};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -97,30 +97,59 @@ pub enum Expression {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum BinaryOperator {
|
||||
Add, Subtract, Multiply, Divide, Modulo,
|
||||
Equal, NotEqual, Less, Greater, LessEqual, GreaterEqual,
|
||||
LogicalAnd, LogicalOr,
|
||||
BitwiseAnd, BitwiseOr, BitwiseXor,
|
||||
LeftShift, RightShift,
|
||||
Add,
|
||||
Subtract,
|
||||
Multiply,
|
||||
Divide,
|
||||
Modulo,
|
||||
Equal,
|
||||
NotEqual,
|
||||
Less,
|
||||
Greater,
|
||||
LessEqual,
|
||||
GreaterEqual,
|
||||
LogicalAnd,
|
||||
LogicalOr,
|
||||
BitwiseAnd,
|
||||
BitwiseOr,
|
||||
BitwiseXor,
|
||||
LeftShift,
|
||||
RightShift,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum UnaryOperator {
|
||||
Plus, Minus, LogicalNot, BitwiseNot,
|
||||
PreIncrement, PostIncrement,
|
||||
PreDecrement, PostDecrement,
|
||||
AddressOf, Dereference,
|
||||
Plus,
|
||||
Minus,
|
||||
LogicalNot,
|
||||
BitwiseNot,
|
||||
PreIncrement,
|
||||
PostIncrement,
|
||||
PreDecrement,
|
||||
PostDecrement,
|
||||
AddressOf,
|
||||
Dereference,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AssignmentOperator {
|
||||
Assign, PlusAssign, MinusAssign, MultiplyAssign, DivideAssign,
|
||||
#[allow(dead_code)] ModuloAssign,
|
||||
#[allow(dead_code)] BitwiseAndAssign,
|
||||
#[allow(dead_code)] BitwiseOrAssign,
|
||||
#[allow(dead_code)] BitwiseXorAssign,
|
||||
#[allow(dead_code)] LeftShiftAssign,
|
||||
#[allow(dead_code)] RightShiftAssign,
|
||||
Assign,
|
||||
PlusAssign,
|
||||
MinusAssign,
|
||||
MultiplyAssign,
|
||||
DivideAssign,
|
||||
#[allow(dead_code)]
|
||||
ModuloAssign,
|
||||
#[allow(dead_code)]
|
||||
BitwiseAndAssign,
|
||||
#[allow(dead_code)]
|
||||
BitwiseOrAssign,
|
||||
#[allow(dead_code)]
|
||||
BitwiseXorAssign,
|
||||
#[allow(dead_code)]
|
||||
LeftShiftAssign,
|
||||
#[allow(dead_code)]
|
||||
RightShiftAssign,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -236,8 +265,10 @@ impl Parser {
|
||||
let storage_class = self.parse_storage_class();
|
||||
let base_type = self.parse_type()?;
|
||||
|
||||
if self.check(&TokenType::LeftParen) ||
|
||||
(self.check(&TokenType::Identifier("".to_string())) && self.peek_ahead(1)?.token_type == TokenType::LeftParen) {
|
||||
if self.check(&TokenType::LeftParen)
|
||||
|| (self.check(&TokenType::Identifier("".to_string()))
|
||||
&& self.peek_ahead(1)?.token_type == TokenType::LeftParen)
|
||||
{
|
||||
self.parse_function_declaration(storage_class, base_type)
|
||||
} else {
|
||||
self.parse_variable_declaration(storage_class, base_type)
|
||||
@@ -314,7 +345,10 @@ impl Parser {
|
||||
});
|
||||
};
|
||||
|
||||
self.consume(&TokenType::Semicolon, "Expected ';' after field declaration")?;
|
||||
self.consume(
|
||||
&TokenType::Semicolon,
|
||||
"Expected ';' after field declaration",
|
||||
)?;
|
||||
fields.push((field_name, field_type));
|
||||
}
|
||||
|
||||
@@ -351,7 +385,10 @@ impl Parser {
|
||||
});
|
||||
};
|
||||
|
||||
self.consume(&TokenType::Semicolon, "Expected ';' after field declaration")?;
|
||||
self.consume(
|
||||
&TokenType::Semicolon,
|
||||
"Expected ';' after field declaration",
|
||||
)?;
|
||||
fields.push((field_name, field_type));
|
||||
}
|
||||
|
||||
@@ -377,7 +414,8 @@ impl Parser {
|
||||
|
||||
if self.match_token(&TokenType::LeftBrace) {
|
||||
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
|
||||
let variant_name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
|
||||
let variant_name = if let TokenType::Identifier(name) = &self.advance()?.token_type
|
||||
{
|
||||
name.clone()
|
||||
} else {
|
||||
return Err(AleccError::ParseError {
|
||||
@@ -415,11 +453,13 @@ impl Parser {
|
||||
|
||||
// Helper methods
|
||||
fn current_token(&self) -> Result<&Token> {
|
||||
self.tokens.get(self.current).ok_or_else(|| AleccError::ParseError {
|
||||
line: 0,
|
||||
column: 0,
|
||||
message: "Unexpected end of input".to_string(),
|
||||
})
|
||||
self.tokens
|
||||
.get(self.current)
|
||||
.ok_or_else(|| AleccError::ParseError {
|
||||
line: 0,
|
||||
column: 0,
|
||||
message: "Unexpected end of input".to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
fn advance(&mut self) -> Result<&Token> {
|
||||
@@ -445,32 +485,39 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn previous(&self) -> Result<&Token> {
|
||||
self.tokens.get(self.current - 1).ok_or_else(|| AleccError::ParseError {
|
||||
line: 0,
|
||||
column: 0,
|
||||
message: "No previous token".to_string(),
|
||||
})
|
||||
self.tokens
|
||||
.get(self.current - 1)
|
||||
.ok_or_else(|| AleccError::ParseError {
|
||||
line: 0,
|
||||
column: 0,
|
||||
message: "No previous token".to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
fn peek_ahead(&self, offset: usize) -> Result<&Token> {
|
||||
self.tokens.get(self.current + offset).ok_or_else(|| AleccError::ParseError {
|
||||
line: 0,
|
||||
column: 0,
|
||||
message: "Unexpected end of input".to_string(),
|
||||
})
|
||||
self.tokens
|
||||
.get(self.current + offset)
|
||||
.ok_or_else(|| AleccError::ParseError {
|
||||
line: 0,
|
||||
column: 0,
|
||||
message: "Unexpected end of input".to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
fn is_at_end(&self) -> bool {
|
||||
self.current >= self.tokens.len() ||
|
||||
matches!(self.tokens.get(self.current).map(|t| &t.token_type), Some(TokenType::Eof))
|
||||
self.current >= self.tokens.len()
|
||||
|| matches!(
|
||||
self.tokens.get(self.current).map(|t| &t.token_type),
|
||||
Some(TokenType::Eof)
|
||||
)
|
||||
}
|
||||
|
||||
fn check(&self, token_type: &TokenType) -> bool {
|
||||
if self.is_at_end() {
|
||||
false
|
||||
} else {
|
||||
std::mem::discriminant(&self.current_token().unwrap().token_type) ==
|
||||
std::mem::discriminant(token_type)
|
||||
std::mem::discriminant(&self.current_token().unwrap().token_type)
|
||||
== std::mem::discriminant(token_type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,7 +573,11 @@ impl Parser {
|
||||
Ok(Declaration::TypeDef(name, base_type))
|
||||
}
|
||||
|
||||
fn parse_function_declaration(&mut self, _storage: StorageClass, return_type: Type) -> Result<Declaration> {
|
||||
fn parse_function_declaration(
|
||||
&mut self,
|
||||
_storage: StorageClass,
|
||||
return_type: Type,
|
||||
) -> Result<Declaration> {
|
||||
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
|
||||
name.clone()
|
||||
} else {
|
||||
@@ -572,7 +623,10 @@ impl Parser {
|
||||
self.advance()?; // Consume the LeftBrace
|
||||
self.parse_block_statement()?
|
||||
} else {
|
||||
self.consume(&TokenType::Semicolon, "Expected ';' after function declaration")?;
|
||||
self.consume(
|
||||
&TokenType::Semicolon,
|
||||
"Expected ';' after function declaration",
|
||||
)?;
|
||||
Statement::Block(Vec::new()) // Forward declaration
|
||||
};
|
||||
|
||||
@@ -588,7 +642,11 @@ impl Parser {
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_variable_declaration(&mut self, _storage: StorageClass, var_type: Type) -> Result<Declaration> {
|
||||
fn parse_variable_declaration(
|
||||
&mut self,
|
||||
_storage: StorageClass,
|
||||
var_type: Type,
|
||||
) -> Result<Declaration> {
|
||||
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
|
||||
name.clone()
|
||||
} else {
|
||||
@@ -605,7 +663,10 @@ impl Parser {
|
||||
None
|
||||
};
|
||||
|
||||
self.consume(&TokenType::Semicolon, "Expected ';' after variable declaration")?;
|
||||
self.consume(
|
||||
&TokenType::Semicolon,
|
||||
"Expected ';' after variable declaration",
|
||||
)?;
|
||||
|
||||
Ok(Declaration::Variable(name, var_type, initializer))
|
||||
}
|
||||
@@ -676,7 +737,10 @@ impl Parser {
|
||||
None
|
||||
};
|
||||
|
||||
self.consume(&TokenType::Semicolon, "Expected ';' after variable declaration")?;
|
||||
self.consume(
|
||||
&TokenType::Semicolon,
|
||||
"Expected ';' after variable declaration",
|
||||
)?;
|
||||
|
||||
Ok(Statement::Declaration {
|
||||
name,
|
||||
@@ -757,10 +821,18 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn is_type(&self, token_type: &TokenType) -> bool {
|
||||
matches!(token_type,
|
||||
TokenType::Int | TokenType::Float | TokenType::Double |
|
||||
TokenType::Char | TokenType::Void | TokenType::Short |
|
||||
TokenType::Long | TokenType::Signed | TokenType::Unsigned)
|
||||
matches!(
|
||||
token_type,
|
||||
TokenType::Int
|
||||
| TokenType::Float
|
||||
| TokenType::Double
|
||||
| TokenType::Char
|
||||
| TokenType::Void
|
||||
| TokenType::Short
|
||||
| TokenType::Long
|
||||
| TokenType::Signed
|
||||
| TokenType::Unsigned
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_expression(&mut self) -> Result<Expression> {
|
||||
@@ -913,8 +985,12 @@ impl Parser {
|
||||
fn parse_comparison(&mut self) -> Result<Expression> {
|
||||
let mut expr = self.parse_shift()?;
|
||||
|
||||
while self.match_tokens(&[TokenType::Greater, TokenType::GreaterEqual,
|
||||
TokenType::Less, TokenType::LessEqual]) {
|
||||
while self.match_tokens(&[
|
||||
TokenType::Greater,
|
||||
TokenType::GreaterEqual,
|
||||
TokenType::Less,
|
||||
TokenType::LessEqual,
|
||||
]) {
|
||||
let operator = match self.previous()?.token_type {
|
||||
TokenType::Greater => BinaryOperator::Greater,
|
||||
TokenType::GreaterEqual => BinaryOperator::GreaterEqual,
|
||||
@@ -995,7 +1071,16 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn parse_unary(&mut self) -> Result<Expression> {
|
||||
if self.match_tokens(&[TokenType::LogicalNot, TokenType::Minus, TokenType::Plus, TokenType::Increment, TokenType::Decrement, TokenType::BitwiseAnd, TokenType::Multiply, TokenType::BitwiseNot]) {
|
||||
if self.match_tokens(&[
|
||||
TokenType::LogicalNot,
|
||||
TokenType::Minus,
|
||||
TokenType::Plus,
|
||||
TokenType::Increment,
|
||||
TokenType::Decrement,
|
||||
TokenType::BitwiseAnd,
|
||||
TokenType::Multiply,
|
||||
TokenType::BitwiseNot,
|
||||
]) {
|
||||
let operator = match self.previous()?.token_type {
|
||||
TokenType::LogicalNot => UnaryOperator::LogicalNot,
|
||||
TokenType::Minus => UnaryOperator::Minus,
|
||||
|
||||
@@ -113,9 +113,9 @@ impl Target {
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum CallingConvention {
|
||||
Cdecl, // x86-32
|
||||
SystemV, // x86-64
|
||||
Aapcs64, // ARM64
|
||||
Cdecl, // x86-32
|
||||
SystemV, // x86-64
|
||||
Aapcs64, // ARM64
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@@ -131,8 +131,15 @@ impl RegisterSet {
|
||||
pub fn general_purpose_registers(&self) -> &'static [&'static str] {
|
||||
match self {
|
||||
RegisterSet::X86_32 => &["eax", "ebx", "ecx", "edx", "esi", "edi"],
|
||||
RegisterSet::X86_64 => &["rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"],
|
||||
RegisterSet::Aarch64 => &["x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28"],
|
||||
RegisterSet::X86_64 => &[
|
||||
"rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13",
|
||||
"r14", "r15",
|
||||
],
|
||||
RegisterSet::Aarch64 => &[
|
||||
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12",
|
||||
"x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24",
|
||||
"x25", "x26", "x27", "x28",
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alecc::cli::Args;
|
||||
use alecc::codegen::CodeGenerator;
|
||||
use alecc::compiler::Compiler;
|
||||
use alecc::lexer::{Lexer, TokenType};
|
||||
use alecc::parser::Parser;
|
||||
use alecc::codegen::CodeGenerator;
|
||||
use alecc::targets::Target;
|
||||
use alecc::compiler::Compiler;
|
||||
use alecc::cli::Args;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
@@ -24,7 +24,10 @@ mod tests {
|
||||
let mut lexer = Lexer::new(input);
|
||||
let tokens = lexer.tokenize().unwrap();
|
||||
|
||||
assert!(matches!(tokens[0].token_type, TokenType::IntegerLiteral(42)));
|
||||
assert!(matches!(
|
||||
tokens[0].token_type,
|
||||
TokenType::IntegerLiteral(42)
|
||||
));
|
||||
assert!(matches!(tokens[1].token_type, TokenType::FloatLiteral(_)));
|
||||
assert!(matches!(tokens[2].token_type, TokenType::CharLiteral('a')));
|
||||
assert!(matches!(tokens[3].token_type, TokenType::StringLiteral(_)));
|
||||
@@ -51,7 +54,8 @@ mod tests {
|
||||
let tokens = lexer.tokenize().unwrap();
|
||||
|
||||
// Comments should be filtered out
|
||||
let identifier_count = tokens.iter()
|
||||
let identifier_count = tokens
|
||||
.iter()
|
||||
.filter(|t| matches!(t.token_type, TokenType::Identifier(_)))
|
||||
.count();
|
||||
assert_eq!(identifier_count, 2); // x and y
|
||||
|
||||
Referencia en una nueva incidencia
Block a user