Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
ale
2025-08-23 13:13:15 +02:00
padre ce4ff63d0d
commit 0bee0c799b
Se han modificado 11 ficheros con 736 adiciones y 413 borrados

Ver fichero

@@ -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::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 alecc::targets::Target;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
const SIMPLE_C_CODE: &str = r#" const SIMPLE_C_CODE: &str = r#"
int main() { 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); criterion_main!(benches);

Ver fichero

@@ -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::error::{AleccError, Result};
use crate::parser::{
BinaryOperator, Expression, Function, Program, Statement, Type, UnaryOperator,
};
use crate::targets::Target;
use std::collections::HashMap; use std::collections::HashMap;
pub struct CodeGenerator { pub struct CodeGenerator {
@@ -11,8 +13,8 @@ pub struct CodeGenerator {
current_function_params: Vec<(String, i32)>, // (name, stack_offset) current_function_params: Vec<(String, i32)>, // (name, stack_offset)
epilogue_emitted: bool, epilogue_emitted: bool,
local_variables: HashMap<String, i32>, // (name, stack_offset) local_variables: HashMap<String, i32>, // (name, stack_offset)
stack_offset: i32, // Current stack offset for local variables stack_offset: i32, // Current stack offset for local variables
last_call_stack_cleanup: usize, // Stack bytes to clean up after last call last_call_stack_cleanup: usize, // Stack bytes to clean up after last call
} }
impl CodeGenerator { impl CodeGenerator {
@@ -35,9 +37,9 @@ impl CodeGenerator {
for function in &program.functions { for function in &program.functions {
self.collect_string_literals_from_statement(&function.body)?; self.collect_string_literals_from_statement(&function.body)?;
} }
self.emit_header(); self.emit_header();
// Generate string literals section // Generate string literals section
if !self.string_literals.is_empty() { if !self.string_literals.is_empty() {
self.emit_line(".section .rodata"); self.emit_line(".section .rodata");
@@ -74,23 +76,23 @@ impl CodeGenerator {
self.emit_line(""); self.emit_line("");
self.emit_line(".globl _start"); self.emit_line(".globl _start");
self.emit_line("_start:"); self.emit_line("_start:");
// Set up stack and call main // Set up stack and call main
self.emit_line(" push rbp"); self.emit_line(" push rbp");
self.emit_line(" mov rbp, rsp"); self.emit_line(" mov rbp, rsp");
// Reserve space for temporary operations (ensures proper stack alignment) // Reserve space for temporary operations (ensures proper stack alignment)
// 120 bytes = 15*8, so after rbp push (8 bytes), total is 128 bytes = multiple of 16 // 120 bytes = 15*8, so after rbp push (8 bytes), total is 128 bytes = multiple of 16
self.emit_line(" sub rsp, 120"); self.emit_line(" sub rsp, 120");
// Call main function // Call main function
self.emit_line(" call main"); self.emit_line(" call main");
// Exit syscall with main's return value // Exit syscall with main's return value
self.emit_line(" mov rdi, rax"); // exit status = 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(" mov rax, 60"); // sys_exit syscall number
self.emit_line(" syscall"); // invoke syscall self.emit_line(" syscall"); // invoke syscall
Ok(()) Ok(())
} }
@@ -122,27 +124,27 @@ impl CodeGenerator {
// This is a function definition, generate the actual function // This is a function definition, generate the actual function
} }
} }
self.emit_line(&format!(".globl {}", function.name)); self.emit_line(&format!(".globl {}", function.name));
self.emit_line(&format!("{}:", function.name)); self.emit_line(&format!("{}:", function.name));
// Set up parameter tracking // Set up parameter tracking
self.current_function_params.clear(); self.current_function_params.clear();
self.local_variables.clear(); self.local_variables.clear();
// Start local variables after parameters to avoid collision // Start local variables after parameters to avoid collision
self.stack_offset = -(function.parameters.len() as i32 * 8); self.stack_offset = -(function.parameters.len() as i32 * 8);
self.epilogue_emitted = false; self.epilogue_emitted = false;
// Function prologue // Function prologue
self.emit_function_prologue(&function.parameters)?; self.emit_function_prologue(&function.parameters)?;
// Function body // Function body
self.generate_statement(&function.body)?; self.generate_statement(&function.body)?;
// Function epilogue (always ensure we have a proper function ending) // Function epilogue (always ensure we have a proper function ending)
// This handles cases where there might not be explicit returns in all paths // This handles cases where there might not be explicit returns in all paths
self.emit_function_epilogue()?; self.emit_function_epilogue()?;
self.emit_line(""); self.emit_line("");
Ok(()) Ok(())
} }
@@ -152,59 +154,64 @@ impl CodeGenerator {
Target::I386 => { Target::I386 => {
self.emit_line(" push ebp"); self.emit_line(" push ebp");
self.emit_line(" mov ebp, esp"); self.emit_line(" mov ebp, esp");
// Reserve space for parameters only (no extra temporaries for now) // Reserve space for parameters only (no extra temporaries for now)
let stack_space = parameters.len() * 4; let stack_space = parameters.len() * 4;
if stack_space > 0 { if stack_space > 0 {
self.emit_line(&format!(" sub esp, {}", stack_space)); self.emit_line(&format!(" sub esp, {}", stack_space));
} }
// Store parameters from stack (i386 calling convention) // Store parameters from stack (i386 calling convention)
for (i, (name, _)) in parameters.iter().enumerate() { for (i, (name, _)) in parameters.iter().enumerate() {
let param_offset = -(i as i32 + 1) * 4; let param_offset = -(i as i32 + 1) * 4;
let stack_offset = 8 + i as i32 * 4; // ebp + 8 + offset 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 eax, DWORD PTR [ebp + {}]", stack_offset));
self.emit_line(&format!(" mov DWORD PTR [ebp + {}], eax", param_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 => { Target::Amd64 => {
self.emit_line(" push rbp"); self.emit_line(" push rbp");
self.emit_line(" mov rbp, rsp"); self.emit_line(" mov rbp, rsp");
// Reserve space for parameters + ensure 16-byte alignment // Reserve space for parameters + ensure 16-byte alignment
let stack_space = parameters.len() * 8; let stack_space = parameters.len() * 8;
// Always reserve at least 8 bytes to maintain 16-byte alignment after rbp push // Always reserve at least 8 bytes to maintain 16-byte alignment after rbp push
let min_space = if stack_space == 0 { 8 } else { stack_space }; let min_space = if stack_space == 0 { 8 } else { stack_space };
let aligned_space = ((min_space + 15) / 16) * 16; // Round up to 16-byte boundary let aligned_space = ((min_space + 15) / 16) * 16; // Round up to 16-byte boundary
self.emit_line(&format!(" sub rsp, {}", aligned_space)); self.emit_line(&format!(" sub rsp, {}", aligned_space));
// Store parameters from registers (x86_64 calling convention) // Store parameters from registers (x86_64 calling convention)
let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
for (i, (name, _)) in parameters.iter().enumerate() { for (i, (name, _)) in parameters.iter().enumerate() {
let param_offset = -(i as i32 + 1) * 8; let param_offset = -(i as i32 + 1) * 8;
if i < param_registers.len() { if i < param_registers.len() {
// Parameter passed in register // 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 { } else {
// Parameter passed on stack // Parameter passed on stack
let stack_offset = 16 + (i - param_registers.len()) as i32 * 8; 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 rax, QWORD PTR [rbp + {}]", stack_offset));
self.emit_line(&format!(" mov QWORD PTR [rbp + {}], rax", param_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 => { Target::Arm64 => {
self.emit_line(" stp x29, x30, [sp, #-16]!"); self.emit_line(" stp x29, x30, [sp, #-16]!");
self.emit_line(" mov x29, sp"); self.emit_line(" mov x29, sp");
let stack_space = parameters.len() * 8; let stack_space = parameters.len() * 8;
if stack_space > 0 { if stack_space > 0 {
let aligned_space = (stack_space + 15) & !15; // 16-byte aligned let aligned_space = (stack_space + 15) & !15; // 16-byte aligned
self.emit_line(&format!(" sub sp, sp, #{}", aligned_space)); self.emit_line(&format!(" sub sp, sp, #{}", aligned_space));
} }
// Store parameters from registers (ARM64 calling convention) // Store parameters from registers (ARM64 calling convention)
for (i, (name, _)) in parameters.iter().enumerate() { for (i, (name, _)) in parameters.iter().enumerate() {
let param_offset = -(i as i32 + 1) * 8; let param_offset = -(i as i32 + 1) * 8;
@@ -217,7 +224,8 @@ impl CodeGenerator {
self.emit_line(&format!(" ldr x9, [x29, #{}]", stack_offset)); self.emit_line(&format!(" ldr x9, [x29, #{}]", stack_offset));
self.emit_line(&format!(" str x9, [x29, #{}]", param_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));
} }
} }
} }
@@ -228,7 +236,7 @@ impl CodeGenerator {
if self.epilogue_emitted { if self.epilogue_emitted {
return Ok(()); // Don't emit duplicate epilogues return Ok(()); // Don't emit duplicate epilogues
} }
match self.target { match self.target {
Target::I386 => { Target::I386 => {
self.emit_line(" mov esp, ebp"); self.emit_line(" mov esp, ebp");
@@ -246,7 +254,7 @@ impl CodeGenerator {
self.emit_line(" ret"); self.emit_line(" ret");
} }
} }
self.epilogue_emitted = true; self.epilogue_emitted = true;
Ok(()) Ok(())
} }
@@ -270,7 +278,7 @@ impl CodeGenerator {
self.emit_line(" ret"); self.emit_line(" ret");
} }
} }
self.epilogue_emitted = true; self.epilogue_emitted = true;
Ok(()) Ok(())
} }
@@ -280,30 +288,40 @@ impl CodeGenerator {
Statement::Expression(expr) => { Statement::Expression(expr) => {
self.generate_expression(expr)?; self.generate_expression(expr)?;
} }
Statement::Declaration { name, var_type, initializer } => { Statement::Declaration {
name,
var_type,
initializer,
} => {
// Calculate space needed based on type // Calculate space needed based on type
let size = match var_type { let size = match var_type {
Type::Array(_, Some(length)) => length * 8, // Assuming 8-byte elements Type::Array(_, Some(length)) => length * 8, // Assuming 8-byte elements
Type::Array(_, None) => 80, // Default size for unsized arrays Type::Array(_, None) => 80, // Default size for unsized arrays
_ => 8, // Default 8 bytes for simple types _ => 8, // Default 8 bytes for simple types
}; };
// Allocate space for variable/array // Allocate space for variable/array
self.stack_offset -= size as i32; self.stack_offset -= size as i32;
let var_offset = self.stack_offset; let var_offset = self.stack_offset;
// Store variable name and offset for later reference // Store variable name and offset for later reference
self.local_variables.insert(name.clone(), var_offset); self.local_variables.insert(name.clone(), var_offset);
if let Some(init_expr) = initializer { if let Some(init_expr) = initializer {
self.generate_expression(init_expr)?; self.generate_expression(init_expr)?;
// Store the value in the local variable slot // Store the value in the local variable slot
match self.target { match self.target {
Target::Amd64 => { 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 => { 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 => { Target::Arm64 => {
self.emit_line(&format!(" str x0, [x29, #{}]", var_offset)); self.emit_line(&format!(" str x0, [x29, #{}]", var_offset));
@@ -335,16 +353,20 @@ impl CodeGenerator {
self.generate_statement(stmt)?; 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 else_label = self.new_label("else");
let end_label = self.new_label("endif"); let end_label = self.new_label("endif");
self.generate_expression(condition)?; self.generate_expression(condition)?;
self.emit_conditional_jump(false, &else_label)?; self.emit_conditional_jump(false, &else_label)?;
self.generate_statement(then_stmt)?; self.generate_statement(then_stmt)?;
self.emit_jump(&end_label)?; self.emit_jump(&end_label)?;
self.emit_line(&format!("{}:", else_label)); self.emit_line(&format!("{}:", else_label));
if let Some(else_stmt) = else_stmt { if let Some(else_stmt) = else_stmt {
// Reset epilogue flag for else branch in case it contains a return // Reset epilogue flag for else branch in case it contains a return
@@ -356,47 +378,52 @@ impl CodeGenerator {
self.epilogue_emitted = saved_epilogue_state; self.epilogue_emitted = saved_epilogue_state;
} }
} }
self.emit_line(&format!("{}:", end_label)); self.emit_line(&format!("{}:", end_label));
} }
Statement::While { condition, body } => { Statement::While { condition, body } => {
let loop_label = self.new_label("loop"); let loop_label = self.new_label("loop");
let end_label = self.new_label("endloop"); let end_label = self.new_label("endloop");
self.emit_line(&format!("{}:", loop_label)); self.emit_line(&format!("{}:", loop_label));
self.generate_expression(condition)?; self.generate_expression(condition)?;
self.emit_conditional_jump(false, &end_label)?; self.emit_conditional_jump(false, &end_label)?;
self.generate_statement(body)?; self.generate_statement(body)?;
self.emit_jump(&loop_label)?; self.emit_jump(&loop_label)?;
self.emit_line(&format!("{}:", end_label)); self.emit_line(&format!("{}:", end_label));
} }
Statement::For { init, condition, increment, body } => { Statement::For {
init,
condition,
increment,
body,
} => {
// Generate initialization // Generate initialization
if let Some(init_stmt) = init { if let Some(init_stmt) = init {
self.generate_statement(init_stmt)?; self.generate_statement(init_stmt)?;
} }
let loop_label = self.new_label("forloop"); let loop_label = self.new_label("forloop");
let end_label = self.new_label("endfor"); let end_label = self.new_label("endfor");
self.emit_line(&format!("{}:", loop_label)); self.emit_line(&format!("{}:", loop_label));
// Generate condition check // Generate condition check
if let Some(cond_expr) = condition { if let Some(cond_expr) = condition {
self.generate_expression(cond_expr)?; self.generate_expression(cond_expr)?;
self.emit_conditional_jump(false, &end_label)?; self.emit_conditional_jump(false, &end_label)?;
} }
// Generate body // Generate body
self.generate_statement(body)?; self.generate_statement(body)?;
// Generate increment // Generate increment
if let Some(inc_expr) = increment { if let Some(inc_expr) = increment {
self.generate_expression(inc_expr)?; self.generate_expression(inc_expr)?;
} }
self.emit_jump(&loop_label)?; self.emit_jump(&loop_label)?;
self.emit_line(&format!("{}:", end_label)); self.emit_line(&format!("{}:", end_label));
} }
@@ -412,19 +439,17 @@ impl CodeGenerator {
fn generate_expression(&mut self, expression: &Expression) -> Result<()> { fn generate_expression(&mut self, expression: &Expression) -> Result<()> {
match expression { match expression {
Expression::IntegerLiteral(value) => { Expression::IntegerLiteral(value) => match self.target {
match self.target { Target::I386 => {
Target::I386 => { self.emit_line(&format!(" mov eax, {}", value));
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));
}
} }
} Target::Amd64 => {
self.emit_line(&format!(" mov rax, {}", value));
}
Target::Arm64 => {
self.emit_line(&format!(" mov x0, #{}", value));
}
},
Expression::StringLiteral(value) => { Expression::StringLiteral(value) => {
let label = self.get_string_literal_label(value); let label = self.get_string_literal_label(value);
match self.target { match self.target {
@@ -442,7 +467,11 @@ impl CodeGenerator {
} }
Expression::Identifier(name) => { Expression::Identifier(name) => {
// Check if it's a function parameter first // 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 // Load parameter from stack
match self.target { match self.target {
Target::I386 => { 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 // Generate arguments and place in calling convention registers/stack
match self.target { match self.target {
Target::I386 => { Target::I386 => {
@@ -498,13 +530,17 @@ impl CodeGenerator {
Target::Amd64 => { Target::Amd64 => {
// x86_64: first 6 args in registers, rest on stack // x86_64: first 6 args in registers, rest on stack
let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
// Ensure stack alignment before function call // Ensure stack alignment before function call
// Stack must be 16-byte aligned before 'call' instruction // 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 // 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; let mut stack_cleanup_size = 0;
// Handle stack arguments if any // Handle stack arguments if any
if stack_args > 0 { if stack_args > 0 {
let total_stack_bytes = stack_args * 8; let total_stack_bytes = stack_args * 8;
@@ -516,7 +552,7 @@ impl CodeGenerator {
stack_cleanup_size += stack_args * 8; stack_cleanup_size += stack_args * 8;
} }
// Note: No additional alignment for register-only calls since function prologue handles it // Note: No additional alignment for register-only calls since function prologue handles it
// First, save any arguments that go on the stack (in reverse order) // First, save any arguments that go on the stack (in reverse order)
if arguments.len() > param_registers.len() { if arguments.len() > param_registers.len() {
for arg in arguments.iter().skip(param_registers.len()).rev() { for arg in arguments.iter().skip(param_registers.len()).rev() {
@@ -524,14 +560,15 @@ impl CodeGenerator {
self.emit_line(" push rax"); self.emit_line(" push rax");
} }
} }
// Then handle register arguments in reverse order to avoid overwriting // 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() { for (i, arg) in reg_args.iter().enumerate().rev() {
self.generate_expression(arg)?; self.generate_expression(arg)?;
self.emit_line(&format!(" mov {}, rax", param_registers[i])); self.emit_line(&format!(" mov {}, rax", param_registers[i]));
} }
// Store cleanup size for later use // Store cleanup size for later use
self.last_call_stack_cleanup = stack_cleanup_size; self.last_call_stack_cleanup = stack_cleanup_size;
} }
@@ -544,7 +581,7 @@ impl CodeGenerator {
self.emit_line(" str x0, [sp, #-16]!"); self.emit_line(" str x0, [sp, #-16]!");
} }
} }
// Then handle register arguments in reverse order // Then handle register arguments in reverse order
let reg_args: Vec<_> = arguments.iter().take(8).collect(); let reg_args: Vec<_> = arguments.iter().take(8).collect();
for (i, arg) in reg_args.iter().enumerate().rev() { for (i, arg) in reg_args.iter().enumerate().rev() {
@@ -556,7 +593,7 @@ impl CodeGenerator {
} }
} }
} }
if let Expression::Identifier(func_name) = function.as_ref() { if let Expression::Identifier(func_name) = function.as_ref() {
self.emit_line(&format!(" call {}", func_name)); self.emit_line(&format!(" call {}", func_name));
} else { } else {
@@ -564,7 +601,7 @@ impl CodeGenerator {
message: "Indirect function calls not implemented".to_string(), message: "Indirect function calls not implemented".to_string(),
}); });
} }
// Clean up stack for arguments that were pushed // Clean up stack for arguments that were pushed
match self.target { match self.target {
Target::I386 => { Target::I386 => {
@@ -576,73 +613,87 @@ impl CodeGenerator {
Target::Amd64 => { Target::Amd64 => {
// Clean up stack using stored cleanup size // Clean up stack using stored cleanup size
if self.last_call_stack_cleanup > 0 { 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 => { Target::Arm64 => {
// Clean up stack arguments (if any) // 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 { if stack_args > 0 {
self.emit_line(&format!(" add sp, sp, #{}", stack_args * 16)); self.emit_line(&format!(" add sp, sp, #{}", stack_args * 16));
} }
} }
} }
} }
Expression::Binary { left, operator, right } => { Expression::Binary {
left,
operator,
right,
} => {
// Generate binary operations // Generate binary operations
// First generate right operand and save it // First generate right operand and save it
self.generate_expression(right)?; self.generate_expression(right)?;
match self.target { match self.target {
Target::I386 => { Target::I386 => {
self.emit_line(" push eax"); // Save right operand self.emit_line(" push eax"); // Save right operand
} }
Target::Amd64 => { Target::Amd64 => {
self.emit_line(" push rax"); // Save right operand self.emit_line(" push rax"); // Save right operand
} }
Target::Arm64 => { Target::Arm64 => {
self.emit_line(" str x0, [sp, #-16]!"); // Save right operand self.emit_line(" str x0, [sp, #-16]!"); // Save right operand
} }
} }
// Generate left operand // Generate left operand
self.generate_expression(left)?; self.generate_expression(left)?;
// Pop right operand and perform operation // Pop right operand and perform operation
match self.target { match self.target {
Target::I386 => { Target::I386 => {
self.emit_line(" pop ebx"); // Right operand in ebx self.emit_line(" pop ebx"); // Right operand in ebx
match operator { match operator {
BinaryOperator::Add => self.emit_line(" add eax, ebx"), BinaryOperator::Add => self.emit_line(" add eax, ebx"),
BinaryOperator::Subtract => self.emit_line(" sub eax, ebx"), BinaryOperator::Subtract => self.emit_line(" sub eax, ebx"),
BinaryOperator::Multiply => self.emit_line(" imul eax, ebx"), BinaryOperator::Multiply => self.emit_line(" imul eax, ebx"),
BinaryOperator::Divide => { 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"); self.emit_line(" idiv ebx");
} }
BinaryOperator::Modulo => { 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(" idiv ebx");
self.emit_line(" mov eax, edx"); // Remainder is in edx self.emit_line(" mov eax, edx"); // Remainder is in edx
} }
_ => { _ => {
return Err(AleccError::CodegenError { return Err(AleccError::CodegenError {
message: format!("Binary operator {:?} not implemented for i386", operator), message: format!(
"Binary operator {:?} not implemented for i386",
operator
),
}); });
} }
} }
} }
Target::Amd64 => { Target::Amd64 => {
self.emit_line(" pop rbx"); // Right operand in rbx self.emit_line(" pop rbx"); // Right operand in rbx
match operator { match operator {
BinaryOperator::Add => self.emit_line(" add rax, rbx"), BinaryOperator::Add => self.emit_line(" add rax, rbx"),
BinaryOperator::Subtract => self.emit_line(" sub rax, rbx"), BinaryOperator::Subtract => self.emit_line(" sub rax, rbx"),
BinaryOperator::Multiply => self.emit_line(" imul rax, rbx"), BinaryOperator::Multiply => self.emit_line(" imul rax, rbx"),
BinaryOperator::Divide => { 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"); self.emit_line(" idiv rbx");
} }
BinaryOperator::Modulo => { 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(" idiv rbx");
self.emit_line(" mov rax, rdx"); // Remainder is in rdx self.emit_line(" mov rax, rdx"); // Remainder is in rdx
} }
@@ -710,19 +761,22 @@ impl CodeGenerator {
} }
} }
Target::Arm64 => { 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 { match operator {
BinaryOperator::Add => self.emit_line(" add x0, x0, x1"), BinaryOperator::Add => self.emit_line(" add x0, x0, x1"),
BinaryOperator::Subtract => self.emit_line(" sub x0, x0, x1"), BinaryOperator::Subtract => self.emit_line(" sub x0, x0, x1"),
BinaryOperator::Multiply => self.emit_line(" mul x0, x0, x1"), BinaryOperator::Multiply => self.emit_line(" mul x0, x0, x1"),
BinaryOperator::Divide => self.emit_line(" sdiv x0, x0, x1"), BinaryOperator::Divide => self.emit_line(" sdiv x0, x0, x1"),
BinaryOperator::Modulo => { 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) self.emit_line(" msub x0, x2, x1, x0"); // x0 = x0 - (x2 * x1)
} }
_ => { _ => {
return Err(AleccError::CodegenError { 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) { if let Some(&offset) = self.local_variables.get(name) {
match self.target { match self.target {
Target::I386 => { Target::I386 => {
self.emit_line(&format!(" inc DWORD PTR [ebp + {}]", offset)); self.emit_line(&format!(
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset)); " inc DWORD PTR [ebp + {}]",
offset
));
self.emit_line(&format!(
" mov eax, DWORD PTR [ebp + {}]",
offset
));
} }
Target::Amd64 => { Target::Amd64 => {
self.emit_line(&format!(" inc QWORD PTR [rbp + {}]", offset)); self.emit_line(&format!(
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset)); " inc QWORD PTR [rbp + {}]",
offset
));
self.emit_line(&format!(
" mov rax, QWORD PTR [rbp + {}]",
offset
));
} }
Target::Arm64 => { Target::Arm64 => {
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset)); self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
@@ -808,7 +874,8 @@ impl CodeGenerator {
} }
} else { } else {
return Err(AleccError::CodegenError { 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) { if let Some(&offset) = self.local_variables.get(name) {
match self.target { match self.target {
Target::I386 => { Target::I386 => {
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset)); self.emit_line(&format!(
self.emit_line(&format!(" inc DWORD PTR [ebp + {}]", offset)); " mov eax, DWORD PTR [ebp + {}]",
offset
));
self.emit_line(&format!(
" inc DWORD PTR [ebp + {}]",
offset
));
} }
Target::Amd64 => { Target::Amd64 => {
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset)); self.emit_line(&format!(
self.emit_line(&format!(" inc QWORD PTR [rbp + {}]", offset)); " mov rax, QWORD PTR [rbp + {}]",
offset
));
self.emit_line(&format!(
" inc QWORD PTR [rbp + {}]",
offset
));
} }
Target::Arm64 => { Target::Arm64 => {
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset)); self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
@@ -839,7 +918,8 @@ impl CodeGenerator {
} }
} else { } else {
return Err(AleccError::CodegenError { 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) { if let Some(&offset) = self.local_variables.get(name) {
match self.target { match self.target {
Target::I386 => { Target::I386 => {
self.emit_line(&format!(" dec DWORD PTR [ebp + {}]", offset)); self.emit_line(&format!(
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset)); " dec DWORD PTR [ebp + {}]",
offset
));
self.emit_line(&format!(
" mov eax, DWORD PTR [ebp + {}]",
offset
));
} }
Target::Amd64 => { Target::Amd64 => {
self.emit_line(&format!(" dec QWORD PTR [rbp + {}]", offset)); self.emit_line(&format!(
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset)); " dec QWORD PTR [rbp + {}]",
offset
));
self.emit_line(&format!(
" mov rax, QWORD PTR [rbp + {}]",
offset
));
} }
Target::Arm64 => { Target::Arm64 => {
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset)); self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
@@ -869,7 +961,8 @@ impl CodeGenerator {
} }
} else { } else {
return Err(AleccError::CodegenError { 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) { if let Some(&offset) = self.local_variables.get(name) {
match self.target { match self.target {
Target::I386 => { Target::I386 => {
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset)); self.emit_line(&format!(
self.emit_line(&format!(" dec DWORD PTR [ebp + {}]", offset)); " mov eax, DWORD PTR [ebp + {}]",
offset
));
self.emit_line(&format!(
" dec DWORD PTR [ebp + {}]",
offset
));
} }
Target::Amd64 => { Target::Amd64 => {
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset)); self.emit_line(&format!(
self.emit_line(&format!(" dec QWORD PTR [rbp + {}]", offset)); " mov rax, QWORD PTR [rbp + {}]",
offset
));
self.emit_line(&format!(
" dec QWORD PTR [rbp + {}]",
offset
));
} }
Target::Arm64 => { Target::Arm64 => {
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset)); self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
@@ -900,7 +1005,8 @@ impl CodeGenerator {
} }
} else { } else {
return Err(AleccError::CodegenError { 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(),
}); });
} }
} }
@@ -953,13 +1059,13 @@ impl CodeGenerator {
if let Some(&base_offset) = self.local_variables.get(array_name) { if let Some(&base_offset) = self.local_variables.get(array_name) {
// Generate the index expression // Generate the index expression
self.generate_expression(index)?; self.generate_expression(index)?;
// Calculate the array element address: base + index * element_size // Calculate the array element address: base + index * element_size
match self.target { match self.target {
Target::Amd64 => { Target::Amd64 => {
// Multiply index by 8 (assuming int is 8 bytes for simplicity) // Multiply index by 8 (assuming int is 8 bytes for simplicity)
self.emit_line(" imul rax, 8"); // Use imul instead of mul 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(&format!(" lea rbx, [rbp + {}]", base_offset));
self.emit_line(" add rax, rbx"); self.emit_line(" add rax, rbx");
// Load the value at that address // 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 // Handle compound assignment operators
match operator { match operator {
crate::parser::AssignmentOperator::Assign => { crate::parser::AssignmentOperator::Assign => {
@@ -1105,7 +1215,8 @@ impl CodeGenerator {
} }
} else { } else {
return Err(AleccError::CodegenError { 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(()) Ok(())
@@ -1144,7 +1255,8 @@ impl CodeGenerator {
} }
} else { } else {
return Err(AleccError::CodegenError { 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(()) Ok(())
@@ -1152,7 +1264,7 @@ impl CodeGenerator {
fn emit_conditional_jump(&mut self, condition: bool, label: &str) -> Result<()> { fn emit_conditional_jump(&mut self, condition: bool, label: &str) -> Result<()> {
let instruction = if condition { "jnz" } else { "jz" }; let instruction = if condition { "jnz" } else { "jz" };
match self.target { match self.target {
Target::I386 | Target::Amd64 => { Target::I386 | Target::Amd64 => {
self.emit_line(&format!(" test eax, eax")); self.emit_line(&format!(" test eax, eax"));
@@ -1209,7 +1321,8 @@ impl CodeGenerator {
label.clone() label.clone()
} else { } else {
let label = format!(".LC{}", self.string_literals.len()); 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 label
} }
} }
@@ -1248,7 +1361,11 @@ impl CodeGenerator {
} }
Ok(()) 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_expression(condition)?;
self.collect_string_literals_from_statement(then_stmt)?; self.collect_string_literals_from_statement(then_stmt)?;
if let Some(else_statement) = else_stmt { if let Some(else_statement) = else_stmt {
@@ -1261,7 +1378,12 @@ impl CodeGenerator {
self.collect_string_literals_from_statement(body)?; self.collect_string_literals_from_statement(body)?;
Ok(()) Ok(())
} }
Statement::For { init, condition, increment, body } => { Statement::For {
init,
condition,
increment,
body,
} => {
if let Some(init_stmt) = init { if let Some(init_stmt) = init {
self.collect_string_literals_from_statement(init_stmt)?; self.collect_string_literals_from_statement(init_stmt)?;
} }
@@ -1280,7 +1402,7 @@ impl CodeGenerator {
} }
Ok(()) 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)?; self.collect_string_literals_from_expression(operand)?;
Ok(()) Ok(())
} }
Expression::Call { function, arguments } => { Expression::Call {
function,
arguments,
} => {
self.collect_string_literals_from_expression(function)?; self.collect_string_literals_from_expression(function)?;
for arg in arguments { for arg in arguments {
self.collect_string_literals_from_expression(arg)?; self.collect_string_literals_from_expression(arg)?;
@@ -1311,7 +1436,7 @@ impl CodeGenerator {
self.collect_string_literals_from_expression(value)?; self.collect_string_literals_from_expression(value)?;
Ok(()) Ok(())
} }
_ => Ok(()) // Other expression types don't contain string literals _ => Ok(()), // Other expression types don't contain string literals
} }
} }
} }

Ver fichero

@@ -1,15 +1,15 @@
use crate::cli::Args; use crate::cli::Args;
use crate::lexer::Lexer;
use crate::parser::Parser;
use crate::codegen::CodeGenerator; use crate::codegen::CodeGenerator;
use crate::optimizer::{Optimizer, OptimizationLevel};
use crate::linker::Linker;
use crate::targets::Target;
use crate::error::{AleccError, Result}; 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::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use tokio::fs; use tokio::fs;
use tracing::{info, debug, warn}; use tracing::{debug, info, warn};
pub struct Compiler { pub struct Compiler {
args: Args, args: Args,
@@ -19,11 +19,10 @@ pub struct Compiler {
impl Compiler { impl Compiler {
pub fn new(args: Args) -> Result<Self> { pub fn new(args: Args) -> Result<Self> {
let target = Target::from_string(&args.target).ok_or_else(|| { let target =
AleccError::UnsupportedTarget { Target::from_string(&args.target).ok_or_else(|| AleccError::UnsupportedTarget {
target: args.target.clone(), target: args.target.clone(),
} })?;
})?;
Ok(Self { Ok(Self {
args, args,
@@ -39,9 +38,11 @@ impl Compiler {
}); });
} }
info!("Compiling {} files for target {}", info!(
self.args.input_files.len(), "Compiling {} files for target {}",
self.target.as_str()); self.args.input_files.len(),
self.target.as_str()
);
let mut object_files = Vec::new(); let mut object_files = Vec::new();
let input_files = self.args.input_files.clone(); // Clone to avoid borrow issues let input_files = self.args.input_files.clone(); // Clone to avoid borrow issues
@@ -49,15 +50,19 @@ impl Compiler {
// Process each input file // Process each input file
for input_file in &input_files { for input_file in &input_files {
debug!("Processing file: {}", input_file.display()); debug!("Processing file: {}", input_file.display());
let extension = input_file.extension() let extension = input_file
.extension()
.and_then(|ext| ext.to_str()) .and_then(|ext| ext.to_str())
.unwrap_or(""); .unwrap_or("");
match extension { match extension {
"c" | "cpp" | "cxx" | "cc" | "C" => { "c" | "cpp" | "cxx" | "cc" | "C" => {
let obj_file = self.compile_source_file(input_file).await?; 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); object_files.push(obj_file);
} }
} }
@@ -71,10 +76,15 @@ impl Compiler {
object_files.push(input_file.clone()); object_files.push(input_file.clone());
} }
_ => { _ => {
warn!("Unknown file extension for {}, treating as C source", warn!(
input_file.display()); "Unknown file extension for {}, treating as C source",
input_file.display()
);
let obj_file = self.compile_source_file(input_file).await?; 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); object_files.push(obj_file);
} }
} }
@@ -96,19 +106,20 @@ impl Compiler {
info!("Compiling source file: {}", input_file.display()); info!("Compiling source file: {}", input_file.display());
// Read source file // Read source file
let source = fs::read_to_string(input_file).await.map_err(|_e| { let source =
AleccError::FileNotFound { fs::read_to_string(input_file)
path: input_file.to_string_lossy().to_string(), .await
} .map_err(|_e| AleccError::FileNotFound {
})?; path: input_file.to_string_lossy().to_string(),
})?;
// Preprocessing // Preprocessing
let preprocessed = if self.args.preprocess_only { let preprocessed = if self.args.preprocess_only {
let output_path = self.get_output_path(input_file, "i")?; let output_path = self.get_output_path(input_file, "i")?;
let preprocessed = self.preprocess(&source, input_file).await?; let preprocessed = self.preprocess(&source, input_file).await?;
fs::write(&output_path, preprocessed).await.map_err(|e| { fs::write(&output_path, preprocessed)
AleccError::IoError(e) .await
})?; .map_err(|e| AleccError::IoError(e))?;
return Ok(output_path); return Ok(output_path);
} else { } else {
self.preprocess(&source, input_file).await? self.preprocess(&source, input_file).await?
@@ -136,17 +147,17 @@ impl Compiler {
if self.args.assembly_only { if self.args.assembly_only {
let output_path = self.get_output_path(input_file, "s")?; let output_path = self.get_output_path(input_file, "s")?;
fs::write(&output_path, assembly).await.map_err(|e| { fs::write(&output_path, assembly)
AleccError::IoError(e) .await
})?; .map_err(|e| AleccError::IoError(e))?;
return Ok(output_path); return Ok(output_path);
} }
// Write assembly to temporary file // Write assembly to temporary file
let asm_path = self.create_temp_file("s")?; let asm_path = self.create_temp_file("s")?;
fs::write(&asm_path, assembly).await.map_err(|e| { fs::write(&asm_path, assembly)
AleccError::IoError(e) .await
})?; .map_err(|e| AleccError::IoError(e))?;
// Assemble // Assemble
let obj_path = self.assemble_file(&asm_path).await?; let obj_path = self.assemble_file(&asm_path).await?;
@@ -156,7 +167,7 @@ impl Compiler {
async fn preprocess(&self, source: &str, input_file: &Path) -> Result<String> { async fn preprocess(&self, source: &str, input_file: &Path) -> Result<String> {
debug!("Preprocessing {}", input_file.display()); debug!("Preprocessing {}", input_file.display());
// Simple preprocessing - just handle basic #include and #define // Simple preprocessing - just handle basic #include and #define
let mut preprocessed = String::new(); let mut preprocessed = String::new();
let mut defines = std::collections::HashMap::new(); let mut defines = std::collections::HashMap::new();
@@ -175,7 +186,7 @@ impl Compiler {
// Process source line by line // Process source line by line
for line in source.lines() { for line in source.lines() {
let trimmed = line.trim(); let trimmed = line.trim();
if trimmed.starts_with("#include") { if trimmed.starts_with("#include") {
// Handle #include (simplified) // Handle #include (simplified)
match self.extract_include_file(trimmed) { match self.extract_include_file(trimmed) {
@@ -238,7 +249,7 @@ impl Compiler {
} }
} }
} }
if let Some(start) = line.find('<') { if let Some(start) = line.find('<') {
if let Some(end) = line.rfind('>') { if let Some(end) = line.rfind('>') {
if start != end { if start != end {
@@ -278,7 +289,7 @@ impl Compiler {
], ],
Target::Amd64 => vec![ Target::Amd64 => vec![
"/usr/include", "/usr/include",
"/usr/local/include", "/usr/local/include",
"/usr/include/x86_64-linux-gnu", "/usr/include/x86_64-linux-gnu",
], ],
Target::Arm64 => vec![ Target::Arm64 => vec![
@@ -311,12 +322,12 @@ impl Compiler {
let assembler = match self.target { let assembler = match self.target {
Target::I386 => "as", Target::I386 => "as",
Target::Amd64 => "as", Target::Amd64 => "as",
Target::Arm64 => "aarch64-linux-gnu-as", Target::Arm64 => "aarch64-linux-gnu-as",
}; };
let mut command = Command::new(assembler); let mut command = Command::new(assembler);
match self.target { match self.target {
Target::I386 => { Target::I386 => {
command.args(&["--32"]); command.args(&["--32"]);
@@ -330,8 +341,9 @@ impl Compiler {
} }
command.args(&[ command.args(&[
"-o", &obj_path.to_string_lossy(), "-o",
&asm_file.to_string_lossy() &obj_path.to_string_lossy(),
&asm_file.to_string_lossy(),
]); ]);
let output = command.output().map_err(|e| AleccError::CodegenError { let output = command.output().map_err(|e| AleccError::CodegenError {
@@ -352,7 +364,7 @@ impl Compiler {
info!("Linking {} object files", object_files.len()); info!("Linking {} object files", object_files.len());
let mut linker = Linker::new(self.target); let mut linker = Linker::new(self.target);
// Set output path // Set output path
let output_path = self.args.output.clone().unwrap_or_else(|| { let output_path = self.args.output.clone().unwrap_or_else(|| {
if self.args.shared { if self.args.shared {
@@ -401,20 +413,26 @@ impl Compiler {
if let Some(ref output) = self.args.output { if let Some(ref output) = self.args.output {
Ok(output.clone()) Ok(output.clone())
} else { } else {
let stem = input_file.file_stem() let stem = input_file
.file_stem()
.ok_or_else(|| AleccError::InvalidArgument { .ok_or_else(|| AleccError::InvalidArgument {
message: "Invalid input file name".to_string(), 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> { fn create_temp_file(&mut self, extension: &str) -> Result<PathBuf> {
let temp_path = std::env::temp_dir() let temp_path = std::env::temp_dir().join(format!(
.join(format!("alecc_{}_{}.{}", "alecc_{}_{}.{}",
std::process::id(), std::process::id(),
self.temp_files.len(), self.temp_files.len(),
extension)); extension
));
self.temp_files.push(temp_path.clone()); self.temp_files.push(temp_path.clone());
Ok(temp_path) Ok(temp_path)
} }
@@ -423,8 +441,11 @@ impl Compiler {
for temp_file in &self.temp_files { for temp_file in &self.temp_files {
if temp_file.exists() { if temp_file.exists() {
if let Err(e) = fs::remove_file(temp_file).await { if let Err(e) = fs::remove_file(temp_file).await {
warn!("Failed to remove temporary file {}: {}", warn!(
temp_file.display(), e); "Failed to remove temporary file {}: {}",
temp_file.display(),
e
);
} }
} }
} }

Ver fichero

@@ -12,36 +12,116 @@ pub enum TokenType {
Identifier(String), Identifier(String),
// Keywords // Keywords
Auto, Break, Case, Char, Const, Continue, Default, Do, Auto,
Double, Else, Enum, Extern, Float, For, Goto, If, Break,
Int, Long, Register, Return, Short, Signed, Sizeof, Static, Case,
Struct, Switch, Typedef, Union, Unsigned, Void, Volatile, While, 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 // C++ Keywords
Bool, Class, Explicit, Export, False, Friend, Inline, Mutable, Bool,
Namespace, New, Operator, Private, Protected, Public, Template, Class,
This, Throw, True, Try, Typename, Using, Virtual, Explicit,
Export,
False,
Friend,
Inline,
Mutable,
Namespace,
New,
Operator,
Private,
Protected,
Public,
Template,
This,
Throw,
True,
Try,
Typename,
Using,
Virtual,
// Operators // Operators
Plus, Minus, Multiply, Divide, Modulo, Plus,
Assign, PlusAssign, MinusAssign, MultiplyAssign, DivideAssign, ModuloAssign, Minus,
Equal, NotEqual, Less, Greater, LessEqual, GreaterEqual, Multiply,
LogicalAnd, LogicalOr, LogicalNot, Divide,
BitwiseAnd, BitwiseOr, BitwiseXor, BitwiseNot, Modulo,
LeftShift, RightShift, LeftShiftAssign, RightShiftAssign, Assign,
BitwiseAndAssign, BitwiseOrAssign, BitwiseXorAssign, PlusAssign,
Increment, Decrement, MinusAssign,
Arrow, Dot, Question, Colon, 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 // Delimiters
LeftParen, RightParen, LeftParen,
LeftBrace, RightBrace, RightParen,
LeftBracket, RightBracket, LeftBrace,
Semicolon, Comma, RightBrace,
LeftBracket,
RightBracket,
Semicolon,
Comma,
Ellipsis, // ... Ellipsis, // ...
// Preprocessor // Preprocessor
Hash, HashHash, Hash,
HashHash,
// Special // Special
Eof, Eof,
@@ -100,10 +180,10 @@ impl Lexer {
pub fn tokenize(&mut self) -> crate::error::Result<Vec<Token>> { pub fn tokenize(&mut self) -> crate::error::Result<Vec<Token>> {
let mut tokens = Vec::new(); let mut tokens = Vec::new();
while !self.is_at_end() { while !self.is_at_end() {
self.skip_whitespace(); self.skip_whitespace();
if self.is_at_end() { if self.is_at_end() {
break; break;
} }
@@ -128,7 +208,7 @@ impl Lexer {
fn scan_token(&mut self) -> crate::error::Result<Option<TokenType>> { fn scan_token(&mut self) -> crate::error::Result<Option<TokenType>> {
let c = self.advance(); let c = self.advance();
match c { match c {
'+' => { '+' => {
if self.match_char('=') { if self.match_char('=') {
@@ -365,7 +445,7 @@ impl Lexer {
} }
self.advance(); self.advance();
} }
Err(crate::error::AleccError::LexError { Err(crate::error::AleccError::LexError {
line: self.line, line: self.line,
column: self.column, column: self.column,
@@ -375,13 +455,13 @@ impl Lexer {
fn scan_string(&mut self) -> crate::error::Result<Option<TokenType>> { fn scan_string(&mut self) -> crate::error::Result<Option<TokenType>> {
let mut value = String::new(); let mut value = String::new();
while !self.is_at_end() && self.current_char() != '"' { while !self.is_at_end() && self.current_char() != '"' {
if self.current_char() == '\n' { if self.current_char() == '\n' {
self.line += 1; self.line += 1;
self.column = 1; self.column = 1;
} }
if self.current_char() == '\\' { if self.current_char() == '\\' {
self.advance(); self.advance();
if !self.is_at_end() { if !self.is_at_end() {
@@ -402,7 +482,7 @@ impl Lexer {
self.advance(); self.advance();
} }
} }
if self.is_at_end() { if self.is_at_end() {
return Err(crate::error::AleccError::LexError { return Err(crate::error::AleccError::LexError {
line: self.line, line: self.line,
@@ -410,7 +490,7 @@ impl Lexer {
message: "Unterminated string literal".to_string(), message: "Unterminated string literal".to_string(),
}); });
} }
self.advance(); // consume closing '"' self.advance(); // consume closing '"'
Ok(Some(TokenType::StringLiteral(value))) Ok(Some(TokenType::StringLiteral(value)))
} }
@@ -423,7 +503,7 @@ impl Lexer {
message: "Unterminated character literal".to_string(), message: "Unterminated character literal".to_string(),
}); });
} }
let c = if self.current_char() == '\\' { let c = if self.current_char() == '\\' {
self.advance(); self.advance();
if self.is_at_end() { if self.is_at_end() {
@@ -445,9 +525,9 @@ impl Lexer {
} else { } else {
self.current_char() self.current_char()
}; };
self.advance(); self.advance();
if self.is_at_end() || self.current_char() != '\'' { if self.is_at_end() || self.current_char() != '\'' {
return Err(crate::error::AleccError::LexError { return Err(crate::error::AleccError::LexError {
line: self.line, line: self.line,
@@ -455,30 +535,30 @@ impl Lexer {
message: "Unterminated character literal".to_string(), message: "Unterminated character literal".to_string(),
}); });
} }
self.advance(); // consume closing '\'' self.advance(); // consume closing '\''
Ok(Some(TokenType::CharLiteral(c))) Ok(Some(TokenType::CharLiteral(c)))
} }
fn scan_number(&mut self) -> crate::error::Result<Option<TokenType>> { fn scan_number(&mut self) -> crate::error::Result<Option<TokenType>> {
let start = self.position - 1; let start = self.position - 1;
while !self.is_at_end() && self.current_char().is_ascii_digit() { while !self.is_at_end() && self.current_char().is_ascii_digit() {
self.advance(); self.advance();
} }
let mut is_float = false; let mut is_float = false;
if !self.is_at_end() && self.current_char() == '.' && self.peek().is_ascii_digit() { if !self.is_at_end() && self.current_char() == '.' && self.peek().is_ascii_digit() {
is_float = true; is_float = true;
self.advance(); // consume '.' self.advance(); // consume '.'
while !self.is_at_end() && self.current_char().is_ascii_digit() { while !self.is_at_end() && self.current_char().is_ascii_digit() {
self.advance(); self.advance();
} }
} }
let text = &self.input[start..self.position]; let text = &self.input[start..self.position];
if is_float { if is_float {
match text.parse::<f64>() { match text.parse::<f64>() {
Ok(value) => Ok(Some(TokenType::FloatLiteral(value))), Ok(value) => Ok(Some(TokenType::FloatLiteral(value))),
@@ -502,7 +582,7 @@ impl Lexer {
fn scan_identifier(&mut self) -> crate::error::Result<Option<TokenType>> { fn scan_identifier(&mut self) -> crate::error::Result<Option<TokenType>> {
let start = self.position - 1; let start = self.position - 1;
while !self.is_at_end() { while !self.is_at_end() {
let c = self.current_char(); let c = self.current_char();
if c.is_ascii_alphanumeric() || c == '_' { if c.is_ascii_alphanumeric() || c == '_' {
@@ -511,7 +591,7 @@ impl Lexer {
break; break;
} }
} }
let text = &self.input[start..self.position]; let text = &self.input[start..self.position];
let token_type = match text { let token_type = match text {
"auto" => TokenType::Auto, "auto" => TokenType::Auto,
@@ -571,7 +651,7 @@ impl Lexer {
"virtual" => TokenType::Virtual, "virtual" => TokenType::Virtual,
_ => TokenType::Identifier(text.to_string()), _ => TokenType::Identifier(text.to_string()),
}; };
Ok(Some(token_type)) Ok(Some(token_type))
} }
} }

Ver fichero

@@ -1,9 +1,9 @@
pub mod lexer;
pub mod parser;
pub mod codegen;
pub mod targets;
pub mod compiler;
pub mod cli; pub mod cli;
pub mod codegen;
pub mod compiler;
pub mod error; pub mod error;
pub mod optimizer; pub mod lexer;
pub mod linker; pub mod linker;
pub mod optimizer;
pub mod parser;
pub mod targets;

Ver fichero

@@ -1,5 +1,5 @@
use crate::targets::Target;
use crate::error::{AleccError, Result}; use crate::error::{AleccError, Result};
use crate::targets::Target;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
@@ -88,7 +88,7 @@ impl Linker {
} }
let linker_command = self.build_linker_command()?; let linker_command = self.build_linker_command()?;
let output = Command::new(&linker_command[0]) let output = Command::new(&linker_command[0])
.args(&linker_command[1..]) .args(&linker_command[1..])
.output() .output()
@@ -108,14 +108,14 @@ impl Linker {
fn build_linker_command(&self) -> Result<Vec<String>> { fn build_linker_command(&self) -> Result<Vec<String>> {
let mut command = Vec::new(); let mut command = Vec::new();
// Choose linker based on target // Choose linker based on target
let linker = match self.target { let linker = match self.target {
Target::I386 => "ld", Target::I386 => "ld",
Target::Amd64 => "ld", Target::Amd64 => "ld",
Target::Arm64 => "aarch64-linux-gnu-ld", Target::Arm64 => "aarch64-linux-gnu-ld",
}; };
command.push(linker.to_string()); command.push(linker.to_string());
// Target-specific flags // Target-specific flags
@@ -238,10 +238,7 @@ impl Linker {
"/usr/lib64", "/usr/lib64",
"/lib64", "/lib64",
], ],
Target::Arm64 => vec![ Target::Arm64 => vec!["/usr/lib/aarch64-linux-gnu", "/lib/aarch64-linux-gnu"],
"/usr/lib/aarch64-linux-gnu",
"/lib/aarch64-linux-gnu",
],
}; };
for path in lib_paths { for path in lib_paths {
@@ -274,7 +271,7 @@ impl Linker {
let libgcc_path = String::from_utf8_lossy(&output.stdout); let libgcc_path = String::from_utf8_lossy(&output.stdout);
let libgcc_path = libgcc_path.trim(); let libgcc_path = libgcc_path.trim();
if let Some(parent) = Path::new(libgcc_path).parent() { if let Some(parent) = Path::new(libgcc_path).parent() {
Ok(parent.to_string_lossy().to_string()) Ok(parent.to_string_lossy().to_string())
} else { } else {
@@ -286,15 +283,15 @@ impl Linker {
pub async fn link_shared_library(&self, soname: Option<&str>) -> Result<()> { pub async fn link_shared_library(&self, soname: Option<&str>) -> Result<()> {
let mut command = self.build_linker_command()?; let mut command = self.build_linker_command()?;
// Remove executable-specific flags // Remove executable-specific flags
command.retain(|arg| arg != "-pie" && !arg.starts_with("-dynamic-linker")); command.retain(|arg| arg != "-pie" && !arg.starts_with("-dynamic-linker"));
// Add shared library flags // Add shared library flags
if !command.contains(&"-shared".to_string()) { if !command.contains(&"-shared".to_string()) {
command.push("-shared".to_string()); command.push("-shared".to_string());
} }
if let Some(soname) = soname { if let Some(soname) = soname {
command.push("-soname".to_string()); command.push("-soname".to_string());
command.push(soname.to_string()); command.push(soname.to_string());
@@ -322,7 +319,7 @@ impl Linker {
// Use ar to create static library // Use ar to create static library
let mut command = vec!["ar".to_string(), "rcs".to_string()]; let mut command = vec!["ar".to_string(), "rcs".to_string()];
command.push(self.output_path.to_string_lossy().to_string()); command.push(self.output_path.to_string_lossy().to_string());
for obj in &self.object_files { for obj in &self.object_files {
command.push(obj.to_string_lossy().to_string()); command.push(obj.to_string_lossy().to_string());
} }

Ver fichero

@@ -1,19 +1,19 @@
use clap::Parser;
use anyhow::Result; 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 cli;
mod codegen;
mod compiler;
mod error; mod error;
mod lexer;
mod linker;
mod optimizer;
mod parser;
mod targets;
use compiler::Compiler;
use cli::Args; use cli::Args;
use compiler::Compiler;
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
@@ -21,11 +21,11 @@ async fn main() -> Result<()> {
tracing_subscriber::fmt::init(); tracing_subscriber::fmt::init();
let args = Args::parse(); let args = Args::parse();
info!("Starting ALECC compiler v{}", env!("CARGO_PKG_VERSION")); info!("Starting ALECC compiler v{}", env!("CARGO_PKG_VERSION"));
let mut compiler = Compiler::new(args.clone())?; let mut compiler = Compiler::new(args.clone())?;
match compiler.compile().await { match compiler.compile().await {
Ok(()) => { Ok(()) => {
info!("Compilation completed successfully"); info!("Compilation completed successfully");

Ver fichero

@@ -1,5 +1,5 @@
use crate::parser::Program;
use crate::error::Result; use crate::error::Result;
use crate::parser::Program;
pub struct Optimizer { pub struct Optimizer {
level: OptimizationLevel, level: OptimizationLevel,
@@ -40,9 +40,7 @@ impl Optimizer {
// No optimization // No optimization
Ok(()) Ok(())
} }
OptimizationLevel::Basic => { OptimizationLevel::Basic => self.basic_optimizations(program),
self.basic_optimizations(program)
}
OptimizationLevel::Moderate => { OptimizationLevel::Moderate => {
self.basic_optimizations(program)?; self.basic_optimizations(program)?;
self.moderate_optimizations(program) self.moderate_optimizations(program)
@@ -67,59 +65,59 @@ impl Optimizer {
fn basic_optimizations(&mut self, program: &mut Program) -> Result<()> { fn basic_optimizations(&mut self, program: &mut Program) -> Result<()> {
// Dead code elimination // Dead code elimination
self.eliminate_dead_code(program)?; self.eliminate_dead_code(program)?;
// Constant folding // Constant folding
self.fold_constants(program)?; self.fold_constants(program)?;
// Basic strength reduction // Basic strength reduction
self.basic_strength_reduction(program)?; self.basic_strength_reduction(program)?;
Ok(()) Ok(())
} }
fn moderate_optimizations(&mut self, program: &mut Program) -> Result<()> { fn moderate_optimizations(&mut self, program: &mut Program) -> Result<()> {
// Loop optimizations // Loop optimizations
self.optimize_loops(program)?; self.optimize_loops(program)?;
// Function inlining (basic) // Function inlining (basic)
self.inline_small_functions(program)?; self.inline_small_functions(program)?;
// Common subexpression elimination // Common subexpression elimination
self.eliminate_common_subexpressions(program)?; self.eliminate_common_subexpressions(program)?;
Ok(()) Ok(())
} }
fn aggressive_optimizations(&mut self, program: &mut Program) -> Result<()> { fn aggressive_optimizations(&mut self, program: &mut Program) -> Result<()> {
// Advanced loop optimizations // Advanced loop optimizations
self.advanced_loop_optimizations(program)?; self.advanced_loop_optimizations(program)?;
// Aggressive function inlining // Aggressive function inlining
self.aggressive_inlining(program)?; self.aggressive_inlining(program)?;
// Inter-procedural optimizations // Inter-procedural optimizations
self.interprocedural_optimizations(program)?; self.interprocedural_optimizations(program)?;
// Vectorization // Vectorization
self.auto_vectorization(program)?; self.auto_vectorization(program)?;
Ok(()) Ok(())
} }
fn size_optimizations(&mut self, program: &mut Program) -> Result<()> { fn size_optimizations(&mut self, program: &mut Program) -> Result<()> {
// Prefer smaller code sequences // Prefer smaller code sequences
self.optimize_for_size(program)?; self.optimize_for_size(program)?;
// Merge identical functions // Merge identical functions
self.merge_identical_functions(program)?; self.merge_identical_functions(program)?;
Ok(()) Ok(())
} }
fn aggressive_size_optimizations(&mut self, program: &mut Program) -> Result<()> { fn aggressive_size_optimizations(&mut self, program: &mut Program) -> Result<()> {
// More aggressive size optimizations that might impact performance // More aggressive size optimizations that might impact performance
self.ultra_size_optimizations(program)?; self.ultra_size_optimizations(program)?;
Ok(()) Ok(())
} }

Ver fichero

@@ -1,5 +1,5 @@
use crate::lexer::{Token, TokenType};
use crate::error::{AleccError, Result}; use crate::error::{AleccError, Result};
use crate::lexer::{Token, TokenType};
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -97,30 +97,59 @@ pub enum Expression {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum BinaryOperator { pub enum BinaryOperator {
Add, Subtract, Multiply, Divide, Modulo, Add,
Equal, NotEqual, Less, Greater, LessEqual, GreaterEqual, Subtract,
LogicalAnd, LogicalOr, Multiply,
BitwiseAnd, BitwiseOr, BitwiseXor, Divide,
LeftShift, RightShift, Modulo,
Equal,
NotEqual,
Less,
Greater,
LessEqual,
GreaterEqual,
LogicalAnd,
LogicalOr,
BitwiseAnd,
BitwiseOr,
BitwiseXor,
LeftShift,
RightShift,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum UnaryOperator { pub enum UnaryOperator {
Plus, Minus, LogicalNot, BitwiseNot, Plus,
PreIncrement, PostIncrement, Minus,
PreDecrement, PostDecrement, LogicalNot,
AddressOf, Dereference, BitwiseNot,
PreIncrement,
PostIncrement,
PreDecrement,
PostDecrement,
AddressOf,
Dereference,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum AssignmentOperator { pub enum AssignmentOperator {
Assign, PlusAssign, MinusAssign, MultiplyAssign, DivideAssign, Assign,
#[allow(dead_code)] ModuloAssign, PlusAssign,
#[allow(dead_code)] BitwiseAndAssign, MinusAssign,
#[allow(dead_code)] BitwiseOrAssign, MultiplyAssign,
#[allow(dead_code)] BitwiseXorAssign, DivideAssign,
#[allow(dead_code)] LeftShiftAssign, #[allow(dead_code)]
#[allow(dead_code)] RightShiftAssign, ModuloAssign,
#[allow(dead_code)]
BitwiseAndAssign,
#[allow(dead_code)]
BitwiseOrAssign,
#[allow(dead_code)]
BitwiseXorAssign,
#[allow(dead_code)]
LeftShiftAssign,
#[allow(dead_code)]
RightShiftAssign,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -235,9 +264,11 @@ impl Parser {
} else { } else {
let storage_class = self.parse_storage_class(); let storage_class = self.parse_storage_class();
let base_type = self.parse_type()?; let base_type = self.parse_type()?;
if self.check(&TokenType::LeftParen) || if self.check(&TokenType::LeftParen)
(self.check(&TokenType::Identifier("".to_string())) && self.peek_ahead(1)?.token_type == TokenType::LeftParen) { || (self.check(&TokenType::Identifier("".to_string()))
&& self.peek_ahead(1)?.token_type == TokenType::LeftParen)
{
self.parse_function_declaration(storage_class, base_type) self.parse_function_declaration(storage_class, base_type)
} else { } else {
self.parse_variable_declaration(storage_class, base_type) self.parse_variable_declaration(storage_class, base_type)
@@ -300,7 +331,7 @@ impl Parser {
}; };
let mut fields = Vec::new(); let mut fields = Vec::new();
if self.match_token(&TokenType::LeftBrace) { if self.match_token(&TokenType::LeftBrace) {
while !self.check(&TokenType::RightBrace) && !self.is_at_end() { while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
let field_type = self.parse_type()?; let field_type = self.parse_type()?;
@@ -313,11 +344,14 @@ impl Parser {
message: "Expected field name".to_string(), message: "Expected field name".to_string(),
}); });
}; };
self.consume(&TokenType::Semicolon, "Expected ';' after field declaration")?; self.consume(
&TokenType::Semicolon,
"Expected ';' after field declaration",
)?;
fields.push((field_name, field_type)); fields.push((field_name, field_type));
} }
self.consume(&TokenType::RightBrace, "Expected '}' after struct body")?; self.consume(&TokenType::RightBrace, "Expected '}' after struct body")?;
} }
@@ -337,7 +371,7 @@ impl Parser {
}; };
let mut fields = Vec::new(); let mut fields = Vec::new();
if self.match_token(&TokenType::LeftBrace) { if self.match_token(&TokenType::LeftBrace) {
while !self.check(&TokenType::RightBrace) && !self.is_at_end() { while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
let field_type = self.parse_type()?; let field_type = self.parse_type()?;
@@ -350,11 +384,14 @@ impl Parser {
message: "Expected field name".to_string(), message: "Expected field name".to_string(),
}); });
}; };
self.consume(&TokenType::Semicolon, "Expected ';' after field declaration")?; self.consume(
&TokenType::Semicolon,
"Expected ';' after field declaration",
)?;
fields.push((field_name, field_type)); fields.push((field_name, field_type));
} }
self.consume(&TokenType::RightBrace, "Expected '}' after union body")?; self.consume(&TokenType::RightBrace, "Expected '}' after union body")?;
} }
@@ -374,10 +411,11 @@ impl Parser {
let mut variants = Vec::new(); let mut variants = Vec::new();
let mut current_value = 0i64; let mut current_value = 0i64;
if self.match_token(&TokenType::LeftBrace) { if self.match_token(&TokenType::LeftBrace) {
while !self.check(&TokenType::RightBrace) && !self.is_at_end() { 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() name.clone()
} else { } else {
return Err(AleccError::ParseError { return Err(AleccError::ParseError {
@@ -386,7 +424,7 @@ impl Parser {
message: "Expected enum variant name".to_string(), message: "Expected enum variant name".to_string(),
}); });
}; };
if self.match_token(&TokenType::Assign) { if self.match_token(&TokenType::Assign) {
if let TokenType::IntegerLiteral(value) = &self.advance()?.token_type { if let TokenType::IntegerLiteral(value) = &self.advance()?.token_type {
current_value = *value; current_value = *value;
@@ -398,15 +436,15 @@ impl Parser {
}); });
} }
} }
variants.push((variant_name, current_value)); variants.push((variant_name, current_value));
current_value += 1; current_value += 1;
if !self.check(&TokenType::RightBrace) { if !self.check(&TokenType::RightBrace) {
self.consume(&TokenType::Comma, "Expected ',' between enum variants")?; self.consume(&TokenType::Comma, "Expected ',' between enum variants")?;
} }
} }
self.consume(&TokenType::RightBrace, "Expected '}' after enum body")?; self.consume(&TokenType::RightBrace, "Expected '}' after enum body")?;
} }
@@ -415,11 +453,13 @@ impl Parser {
// Helper methods // Helper methods
fn current_token(&self) -> Result<&Token> { fn current_token(&self) -> Result<&Token> {
self.tokens.get(self.current).ok_or_else(|| AleccError::ParseError { self.tokens
line: 0, .get(self.current)
column: 0, .ok_or_else(|| AleccError::ParseError {
message: "Unexpected end of input".to_string(), line: 0,
}) column: 0,
message: "Unexpected end of input".to_string(),
})
} }
fn advance(&mut self) -> Result<&Token> { fn advance(&mut self) -> Result<&Token> {
@@ -445,32 +485,39 @@ impl Parser {
} }
fn previous(&self) -> Result<&Token> { fn previous(&self) -> Result<&Token> {
self.tokens.get(self.current - 1).ok_or_else(|| AleccError::ParseError { self.tokens
line: 0, .get(self.current - 1)
column: 0, .ok_or_else(|| AleccError::ParseError {
message: "No previous token".to_string(), line: 0,
}) column: 0,
message: "No previous token".to_string(),
})
} }
fn peek_ahead(&self, offset: usize) -> Result<&Token> { fn peek_ahead(&self, offset: usize) -> Result<&Token> {
self.tokens.get(self.current + offset).ok_or_else(|| AleccError::ParseError { self.tokens
line: 0, .get(self.current + offset)
column: 0, .ok_or_else(|| AleccError::ParseError {
message: "Unexpected end of input".to_string(), line: 0,
}) column: 0,
message: "Unexpected end of input".to_string(),
})
} }
fn is_at_end(&self) -> bool { fn is_at_end(&self) -> bool {
self.current >= self.tokens.len() || self.current >= self.tokens.len()
matches!(self.tokens.get(self.current).map(|t| &t.token_type), Some(TokenType::Eof)) || matches!(
self.tokens.get(self.current).map(|t| &t.token_type),
Some(TokenType::Eof)
)
} }
fn check(&self, token_type: &TokenType) -> bool { fn check(&self, token_type: &TokenType) -> bool {
if self.is_at_end() { if self.is_at_end() {
false false
} else { } else {
std::mem::discriminant(&self.current_token().unwrap().token_type) == std::mem::discriminant(&self.current_token().unwrap().token_type)
std::mem::discriminant(token_type) == std::mem::discriminant(token_type)
} }
} }
@@ -521,12 +568,16 @@ impl Parser {
message: "Expected typedef name".to_string(), message: "Expected typedef name".to_string(),
}); });
}; };
self.consume(&TokenType::Semicolon, "Expected ';' after typedef")?; self.consume(&TokenType::Semicolon, "Expected ';' after typedef")?;
Ok(Declaration::TypeDef(name, base_type)) 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 { let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone() name.clone()
} else { } else {
@@ -538,16 +589,16 @@ impl Parser {
}; };
self.consume(&TokenType::LeftParen, "Expected '(' after function name")?; self.consume(&TokenType::LeftParen, "Expected '(' after function name")?;
let mut parameters = Vec::new(); let mut parameters = Vec::new();
let mut is_variadic = false; let mut is_variadic = false;
while !self.check(&TokenType::RightParen) && !self.is_at_end() { while !self.check(&TokenType::RightParen) && !self.is_at_end() {
if self.match_token(&TokenType::Ellipsis) { if self.match_token(&TokenType::Ellipsis) {
is_variadic = true; is_variadic = true;
break; break;
} }
let param_type = self.parse_type()?; let param_type = self.parse_type()?;
let param_name = if let TokenType::Identifier(name) = &self.advance()?.token_type { let param_name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone() name.clone()
@@ -558,21 +609,24 @@ impl Parser {
message: "Expected parameter name".to_string(), message: "Expected parameter name".to_string(),
}); });
}; };
parameters.push((param_name, param_type)); parameters.push((param_name, param_type));
if !self.check(&TokenType::RightParen) { if !self.check(&TokenType::RightParen) {
self.consume(&TokenType::Comma, "Expected ',' between parameters")?; self.consume(&TokenType::Comma, "Expected ',' between parameters")?;
} }
} }
self.consume(&TokenType::RightParen, "Expected ')' after parameters")?; self.consume(&TokenType::RightParen, "Expected ')' after parameters")?;
let body = if self.check(&TokenType::LeftBrace) { let body = if self.check(&TokenType::LeftBrace) {
self.advance()?; // Consume the LeftBrace self.advance()?; // Consume the LeftBrace
self.parse_block_statement()? self.parse_block_statement()?
} else { } else {
self.consume(&TokenType::Semicolon, "Expected ';' after function declaration")?; self.consume(
&TokenType::Semicolon,
"Expected ';' after function declaration",
)?;
Statement::Block(Vec::new()) // Forward 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 { let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone() name.clone()
} else { } else {
@@ -605,8 +663,11 @@ impl Parser {
None None
}; };
self.consume(&TokenType::Semicolon, "Expected ';' after variable declaration")?; self.consume(
&TokenType::Semicolon,
"Expected ';' after variable declaration",
)?;
Ok(Declaration::Variable(name, var_type, initializer)) Ok(Declaration::Variable(name, var_type, initializer))
} }
@@ -616,7 +677,7 @@ impl Parser {
while !self.check(&TokenType::RightBrace) && !self.is_at_end() { while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
statements.push(self.parse_statement()?); statements.push(self.parse_statement()?);
} }
self.consume(&TokenType::RightBrace, "Expected '}'")?; self.consume(&TokenType::RightBrace, "Expected '}'")?;
Ok(Statement::Block(statements)) Ok(Statement::Block(statements))
} }
@@ -676,8 +737,11 @@ impl Parser {
None None
}; };
self.consume(&TokenType::Semicolon, "Expected ';' after variable declaration")?; self.consume(
&TokenType::Semicolon,
"Expected ';' after variable declaration",
)?;
Ok(Statement::Declaration { Ok(Statement::Declaration {
name, name,
var_type, var_type,
@@ -695,14 +759,14 @@ impl Parser {
self.consume(&TokenType::LeftParen, "Expected '(' after 'if'")?; self.consume(&TokenType::LeftParen, "Expected '(' after 'if'")?;
let condition = self.parse_expression()?; let condition = self.parse_expression()?;
self.consume(&TokenType::RightParen, "Expected ')' after if condition")?; self.consume(&TokenType::RightParen, "Expected ')' after if condition")?;
let then_stmt = Box::new(self.parse_statement()?); let then_stmt = Box::new(self.parse_statement()?);
let else_stmt = if self.match_token(&TokenType::Else) { let else_stmt = if self.match_token(&TokenType::Else) {
Some(Box::new(self.parse_statement()?)) Some(Box::new(self.parse_statement()?))
} else { } else {
None None
}; };
Ok(Statement::If { Ok(Statement::If {
condition, condition,
then_stmt, then_stmt,
@@ -715,39 +779,39 @@ impl Parser {
let condition = self.parse_expression()?; let condition = self.parse_expression()?;
self.consume(&TokenType::RightParen, "Expected ')' after while condition")?; self.consume(&TokenType::RightParen, "Expected ')' after while condition")?;
let body = Box::new(self.parse_statement()?); let body = Box::new(self.parse_statement()?);
Ok(Statement::While { condition, body }) Ok(Statement::While { condition, body })
} }
fn parse_for_statement(&mut self) -> Result<Statement> { fn parse_for_statement(&mut self) -> Result<Statement> {
self.consume(&TokenType::LeftParen, "Expected '(' after 'for'")?; self.consume(&TokenType::LeftParen, "Expected '(' after 'for'")?;
let init = if self.check(&TokenType::Semicolon) { let init = if self.check(&TokenType::Semicolon) {
None None
} else { } else {
Some(Box::new(self.parse_statement()?)) Some(Box::new(self.parse_statement()?))
}; };
if init.is_none() { if init.is_none() {
self.advance()?; // consume semicolon self.advance()?; // consume semicolon
} }
let condition = if self.check(&TokenType::Semicolon) { let condition = if self.check(&TokenType::Semicolon) {
None None
} else { } else {
Some(self.parse_expression()?) Some(self.parse_expression()?)
}; };
self.consume(&TokenType::Semicolon, "Expected ';' after for condition")?; self.consume(&TokenType::Semicolon, "Expected ';' after for condition")?;
let increment = if self.check(&TokenType::RightParen) { let increment = if self.check(&TokenType::RightParen) {
None None
} else { } else {
Some(self.parse_expression()?) Some(self.parse_expression()?)
}; };
self.consume(&TokenType::RightParen, "Expected ')' after for clauses")?; self.consume(&TokenType::RightParen, "Expected ')' after for clauses")?;
let body = Box::new(self.parse_statement()?); let body = Box::new(self.parse_statement()?);
Ok(Statement::For { Ok(Statement::For {
init, init,
condition, condition,
@@ -757,10 +821,18 @@ impl Parser {
} }
fn is_type(&self, token_type: &TokenType) -> bool { fn is_type(&self, token_type: &TokenType) -> bool {
matches!(token_type, matches!(
TokenType::Int | TokenType::Float | TokenType::Double | token_type,
TokenType::Char | TokenType::Void | TokenType::Short | TokenType::Int
TokenType::Long | TokenType::Signed | TokenType::Unsigned) | TokenType::Float
| TokenType::Double
| TokenType::Char
| TokenType::Void
| TokenType::Short
| TokenType::Long
| TokenType::Signed
| TokenType::Unsigned
)
} }
fn parse_expression(&mut self) -> Result<Expression> { fn parse_expression(&mut self) -> Result<Expression> {
@@ -769,7 +841,7 @@ impl Parser {
fn parse_assignment(&mut self) -> Result<Expression> { fn parse_assignment(&mut self) -> Result<Expression> {
let expr = self.parse_logical_or()?; let expr = self.parse_logical_or()?;
if self.match_token(&TokenType::Assign) { if self.match_token(&TokenType::Assign) {
let value = self.parse_assignment()?; // Right associative let value = self.parse_assignment()?; // Right associative
return Ok(Expression::Assignment { return Ok(Expression::Assignment {
@@ -806,13 +878,13 @@ impl Parser {
value: Box::new(value), value: Box::new(value),
}); });
} }
Ok(expr) Ok(expr)
} }
fn parse_logical_or(&mut self) -> Result<Expression> { fn parse_logical_or(&mut self) -> Result<Expression> {
let mut expr = self.parse_logical_and()?; let mut expr = self.parse_logical_and()?;
while self.match_token(&TokenType::LogicalOr) { while self.match_token(&TokenType::LogicalOr) {
let operator = BinaryOperator::LogicalOr; let operator = BinaryOperator::LogicalOr;
let right = self.parse_logical_and()?; let right = self.parse_logical_and()?;
@@ -822,13 +894,13 @@ impl Parser {
right: Box::new(right), right: Box::new(right),
}; };
} }
Ok(expr) Ok(expr)
} }
fn parse_logical_and(&mut self) -> Result<Expression> { fn parse_logical_and(&mut self) -> Result<Expression> {
let mut expr = self.parse_bitwise_or()?; let mut expr = self.parse_bitwise_or()?;
while self.match_token(&TokenType::LogicalAnd) { while self.match_token(&TokenType::LogicalAnd) {
let operator = BinaryOperator::LogicalAnd; let operator = BinaryOperator::LogicalAnd;
let right = self.parse_bitwise_or()?; let right = self.parse_bitwise_or()?;
@@ -838,13 +910,13 @@ impl Parser {
right: Box::new(right), right: Box::new(right),
}; };
} }
Ok(expr) Ok(expr)
} }
fn parse_bitwise_or(&mut self) -> Result<Expression> { fn parse_bitwise_or(&mut self) -> Result<Expression> {
let mut expr = self.parse_bitwise_xor()?; let mut expr = self.parse_bitwise_xor()?;
while self.match_token(&TokenType::BitwiseOr) { while self.match_token(&TokenType::BitwiseOr) {
let operator = BinaryOperator::BitwiseOr; let operator = BinaryOperator::BitwiseOr;
let right = self.parse_bitwise_xor()?; let right = self.parse_bitwise_xor()?;
@@ -854,13 +926,13 @@ impl Parser {
right: Box::new(right), right: Box::new(right),
}; };
} }
Ok(expr) Ok(expr)
} }
fn parse_bitwise_xor(&mut self) -> Result<Expression> { fn parse_bitwise_xor(&mut self) -> Result<Expression> {
let mut expr = self.parse_bitwise_and()?; let mut expr = self.parse_bitwise_and()?;
while self.match_token(&TokenType::BitwiseXor) { while self.match_token(&TokenType::BitwiseXor) {
let operator = BinaryOperator::BitwiseXor; let operator = BinaryOperator::BitwiseXor;
let right = self.parse_bitwise_and()?; let right = self.parse_bitwise_and()?;
@@ -870,13 +942,13 @@ impl Parser {
right: Box::new(right), right: Box::new(right),
}; };
} }
Ok(expr) Ok(expr)
} }
fn parse_bitwise_and(&mut self) -> Result<Expression> { fn parse_bitwise_and(&mut self) -> Result<Expression> {
let mut expr = self.parse_equality()?; let mut expr = self.parse_equality()?;
while self.match_token(&TokenType::BitwiseAnd) { while self.match_token(&TokenType::BitwiseAnd) {
let operator = BinaryOperator::BitwiseAnd; let operator = BinaryOperator::BitwiseAnd;
let right = self.parse_equality()?; let right = self.parse_equality()?;
@@ -886,13 +958,13 @@ impl Parser {
right: Box::new(right), right: Box::new(right),
}; };
} }
Ok(expr) Ok(expr)
} }
fn parse_equality(&mut self) -> Result<Expression> { fn parse_equality(&mut self) -> Result<Expression> {
let mut expr = self.parse_comparison()?; let mut expr = self.parse_comparison()?;
while self.match_tokens(&[TokenType::Equal, TokenType::NotEqual]) { while self.match_tokens(&[TokenType::Equal, TokenType::NotEqual]) {
let operator = match self.previous()?.token_type { let operator = match self.previous()?.token_type {
TokenType::Equal => BinaryOperator::Equal, TokenType::Equal => BinaryOperator::Equal,
@@ -906,15 +978,19 @@ impl Parser {
right: Box::new(right), right: Box::new(right),
}; };
} }
Ok(expr) Ok(expr)
} }
fn parse_comparison(&mut self) -> Result<Expression> { fn parse_comparison(&mut self) -> Result<Expression> {
let mut expr = self.parse_shift()?; let mut expr = self.parse_shift()?;
while self.match_tokens(&[TokenType::Greater, TokenType::GreaterEqual, while self.match_tokens(&[
TokenType::Less, TokenType::LessEqual]) { TokenType::Greater,
TokenType::GreaterEqual,
TokenType::Less,
TokenType::LessEqual,
]) {
let operator = match self.previous()?.token_type { let operator = match self.previous()?.token_type {
TokenType::Greater => BinaryOperator::Greater, TokenType::Greater => BinaryOperator::Greater,
TokenType::GreaterEqual => BinaryOperator::GreaterEqual, TokenType::GreaterEqual => BinaryOperator::GreaterEqual,
@@ -929,13 +1005,13 @@ impl Parser {
right: Box::new(right), right: Box::new(right),
}; };
} }
Ok(expr) Ok(expr)
} }
fn parse_shift(&mut self) -> Result<Expression> { fn parse_shift(&mut self) -> Result<Expression> {
let mut expr = self.parse_term()?; let mut expr = self.parse_term()?;
while self.match_tokens(&[TokenType::LeftShift, TokenType::RightShift]) { while self.match_tokens(&[TokenType::LeftShift, TokenType::RightShift]) {
let operator = match self.previous()?.token_type { let operator = match self.previous()?.token_type {
TokenType::LeftShift => BinaryOperator::LeftShift, TokenType::LeftShift => BinaryOperator::LeftShift,
@@ -949,13 +1025,13 @@ impl Parser {
right: Box::new(right), right: Box::new(right),
}; };
} }
Ok(expr) Ok(expr)
} }
fn parse_term(&mut self) -> Result<Expression> { fn parse_term(&mut self) -> Result<Expression> {
let mut expr = self.parse_factor()?; let mut expr = self.parse_factor()?;
while self.match_tokens(&[TokenType::Minus, TokenType::Plus]) { while self.match_tokens(&[TokenType::Minus, TokenType::Plus]) {
let operator = match self.previous()?.token_type { let operator = match self.previous()?.token_type {
TokenType::Minus => BinaryOperator::Subtract, TokenType::Minus => BinaryOperator::Subtract,
@@ -969,13 +1045,13 @@ impl Parser {
right: Box::new(right), right: Box::new(right),
}; };
} }
Ok(expr) Ok(expr)
} }
fn parse_factor(&mut self) -> Result<Expression> { fn parse_factor(&mut self) -> Result<Expression> {
let mut expr = self.parse_unary()?; let mut expr = self.parse_unary()?;
while self.match_tokens(&[TokenType::Divide, TokenType::Multiply, TokenType::Modulo]) { while self.match_tokens(&[TokenType::Divide, TokenType::Multiply, TokenType::Modulo]) {
let operator = match self.previous()?.token_type { let operator = match self.previous()?.token_type {
TokenType::Divide => BinaryOperator::Divide, TokenType::Divide => BinaryOperator::Divide,
@@ -990,12 +1066,21 @@ impl Parser {
right: Box::new(right), right: Box::new(right),
}; };
} }
Ok(expr) Ok(expr)
} }
fn parse_unary(&mut self) -> Result<Expression> { 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 { let operator = match self.previous()?.token_type {
TokenType::LogicalNot => UnaryOperator::LogicalNot, TokenType::LogicalNot => UnaryOperator::LogicalNot,
TokenType::Minus => UnaryOperator::Minus, TokenType::Minus => UnaryOperator::Minus,
@@ -1013,13 +1098,13 @@ impl Parser {
operand: Box::new(right), operand: Box::new(right),
}); });
} }
self.parse_call() self.parse_call()
} }
fn parse_call(&mut self) -> Result<Expression> { fn parse_call(&mut self) -> Result<Expression> {
let mut expr = self.parse_primary()?; let mut expr = self.parse_primary()?;
loop { loop {
if self.match_token(&TokenType::LeftParen) { if self.match_token(&TokenType::LeftParen) {
expr = self.finish_call(expr)?; expr = self.finish_call(expr)?;
@@ -1045,13 +1130,13 @@ impl Parser {
break; break;
} }
} }
Ok(expr) Ok(expr)
} }
fn finish_call(&mut self, callee: Expression) -> Result<Expression> { fn finish_call(&mut self, callee: Expression) -> Result<Expression> {
let mut arguments = Vec::new(); let mut arguments = Vec::new();
if !self.check(&TokenType::RightParen) { if !self.check(&TokenType::RightParen) {
loop { loop {
arguments.push(self.parse_expression()?); arguments.push(self.parse_expression()?);
@@ -1060,9 +1145,9 @@ impl Parser {
} }
} }
} }
self.consume(&TokenType::RightParen, "Expected ')' after arguments")?; self.consume(&TokenType::RightParen, "Expected ')' after arguments")?;
Ok(Expression::Call { Ok(Expression::Call {
function: Box::new(callee), function: Box::new(callee),
arguments, arguments,
@@ -1075,7 +1160,7 @@ impl Parser {
self.consume(&TokenType::RightParen, "Expected ')' after expression")?; self.consume(&TokenType::RightParen, "Expected ')' after expression")?;
return Ok(expr); return Ok(expr);
} }
let token = self.advance()?; let token = self.advance()?;
match &token.token_type { match &token.token_type {
TokenType::IntegerLiteral(value) => Ok(Expression::IntegerLiteral(*value)), TokenType::IntegerLiteral(value) => Ok(Expression::IntegerLiteral(*value)),

Ver fichero

@@ -19,13 +19,13 @@ impl Target {
pub fn native() -> Self { pub fn native() -> Self {
#[cfg(target_arch = "x86")] #[cfg(target_arch = "x86")]
return Target::I386; return Target::I386;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
return Target::Amd64; return Target::Amd64;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
return Target::Arm64; return Target::Arm64;
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))] #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
return Target::Amd64; // Default fallback return Target::Amd64; // Default fallback
} }
@@ -77,7 +77,7 @@ impl Target {
pub fn linker(&self) -> &'static str { pub fn linker(&self) -> &'static str {
match self { match self {
Target::I386 => "ld -m elf_i386", Target::I386 => "ld -m elf_i386",
Target::Amd64 => "ld -m elf_x86_64", Target::Amd64 => "ld -m elf_x86_64",
Target::Arm64 => "aarch64-linux-gnu-ld", Target::Arm64 => "aarch64-linux-gnu-ld",
} }
} }
@@ -113,9 +113,9 @@ impl Target {
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum CallingConvention { pub enum CallingConvention {
Cdecl, // x86-32 Cdecl, // x86-32
SystemV, // x86-64 SystemV, // x86-64
Aapcs64, // ARM64 Aapcs64, // ARM64
} }
#[allow(dead_code)] #[allow(dead_code)]
@@ -131,8 +131,15 @@ impl RegisterSet {
pub fn general_purpose_registers(&self) -> &'static [&'static str] { pub fn general_purpose_registers(&self) -> &'static [&'static str] {
match self { match self {
RegisterSet::X86_32 => &["eax", "ebx", "ecx", "edx", "esi", "edi"], 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::X86_64 => &[
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"], "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",
],
} }
} }

Ver fichero

@@ -1,11 +1,11 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use alecc::cli::Args;
use alecc::codegen::CodeGenerator;
use alecc::compiler::Compiler;
use alecc::lexer::{Lexer, TokenType}; use alecc::lexer::{Lexer, TokenType};
use alecc::parser::Parser; use alecc::parser::Parser;
use alecc::codegen::CodeGenerator;
use alecc::targets::Target; use alecc::targets::Target;
use alecc::compiler::Compiler;
use alecc::cli::Args;
use std::path::PathBuf; use std::path::PathBuf;
#[test] #[test]
@@ -13,7 +13,7 @@ mod tests {
let input = "int main() { return 0; }".to_string(); let input = "int main() { return 0; }".to_string();
let mut lexer = Lexer::new(input); let mut lexer = Lexer::new(input);
let tokens = lexer.tokenize().unwrap(); let tokens = lexer.tokenize().unwrap();
assert!(!tokens.is_empty()); assert!(!tokens.is_empty());
assert!(matches!(tokens[0].token_type, TokenType::Int)); assert!(matches!(tokens[0].token_type, TokenType::Int));
} }
@@ -23,8 +23,11 @@ mod tests {
let input = "42 3.14 'a' \"hello\"".to_string(); let input = "42 3.14 'a' \"hello\"".to_string();
let mut lexer = Lexer::new(input); let mut lexer = Lexer::new(input);
let tokens = lexer.tokenize().unwrap(); 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[1].token_type, TokenType::FloatLiteral(_)));
assert!(matches!(tokens[2].token_type, TokenType::CharLiteral('a'))); assert!(matches!(tokens[2].token_type, TokenType::CharLiteral('a')));
assert!(matches!(tokens[3].token_type, TokenType::StringLiteral(_))); assert!(matches!(tokens[3].token_type, TokenType::StringLiteral(_)));
@@ -35,7 +38,7 @@ mod tests {
let input = "+ - * / == != < > <= >=".to_string(); let input = "+ - * / == != < > <= >=".to_string();
let mut lexer = Lexer::new(input); let mut lexer = Lexer::new(input);
let tokens = lexer.tokenize().unwrap(); let tokens = lexer.tokenize().unwrap();
assert!(matches!(tokens[0].token_type, TokenType::Plus)); assert!(matches!(tokens[0].token_type, TokenType::Plus));
assert!(matches!(tokens[1].token_type, TokenType::Minus)); assert!(matches!(tokens[1].token_type, TokenType::Minus));
assert!(matches!(tokens[2].token_type, TokenType::Multiply)); assert!(matches!(tokens[2].token_type, TokenType::Multiply));
@@ -49,9 +52,10 @@ mod tests {
let input = "int x; // comment\n/* block comment */ int y;".to_string(); let input = "int x; // comment\n/* block comment */ int y;".to_string();
let mut lexer = Lexer::new(input); let mut lexer = Lexer::new(input);
let tokens = lexer.tokenize().unwrap(); let tokens = lexer.tokenize().unwrap();
// Comments should be filtered out // Comments should be filtered out
let identifier_count = tokens.iter() let identifier_count = tokens
.iter()
.filter(|t| matches!(t.token_type, TokenType::Identifier(_))) .filter(|t| matches!(t.token_type, TokenType::Identifier(_)))
.count(); .count();
assert_eq!(identifier_count, 2); // x and y assert_eq!(identifier_count, 2); // x and y
@@ -64,7 +68,7 @@ mod tests {
let tokens = lexer.tokenize().unwrap(); let tokens = lexer.tokenize().unwrap();
let mut parser = Parser::new(tokens); let mut parser = Parser::new(tokens);
let program = parser.parse().unwrap(); let program = parser.parse().unwrap();
assert_eq!(program.functions.len(), 1); assert_eq!(program.functions.len(), 1);
assert_eq!(program.functions[0].name, "main"); assert_eq!(program.functions[0].name, "main");
} }
@@ -92,10 +96,10 @@ mod tests {
let tokens = lexer.tokenize().unwrap(); let tokens = lexer.tokenize().unwrap();
let mut parser = Parser::new(tokens); let mut parser = Parser::new(tokens);
let program = parser.parse().unwrap(); let program = parser.parse().unwrap();
let mut codegen = CodeGenerator::new(Target::Amd64); let mut codegen = CodeGenerator::new(Target::Amd64);
let assembly = codegen.generate(&program).unwrap(); let assembly = codegen.generate(&program).unwrap();
assert!(assembly.contains("main:")); assert!(assembly.contains("main:"));
assert!(assembly.contains("ret")); assert!(assembly.contains("ret"));
} }
@@ -136,13 +140,13 @@ mod tests {
#[test] #[test]
fn test_error_types() { fn test_error_types() {
use alecc::error::AleccError; use alecc::error::AleccError;
let lex_error = AleccError::LexError { let lex_error = AleccError::LexError {
line: 1, line: 1,
column: 5, column: 5,
message: "Unexpected character".to_string(), message: "Unexpected character".to_string(),
}; };
assert!(format!("{}", lex_error).contains("line 1")); assert!(format!("{}", lex_error).contains("line 1"));
assert!(format!("{}", lex_error).contains("column 5")); assert!(format!("{}", lex_error).contains("column 5"));
} }