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 {
@@ -87,9 +89,9 @@ impl CodeGenerator {
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(())
} }
@@ -165,7 +167,8 @@ impl CodeGenerator {
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 => {
@@ -185,14 +188,18 @@ impl CodeGenerator {
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 => {
@@ -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));
} }
} }
} }
@@ -280,12 +288,16 @@ 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
@@ -300,10 +312,16 @@ impl CodeGenerator {
// 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,7 +353,11 @@ 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");
@@ -372,7 +394,12 @@ impl CodeGenerator {
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)?;
@@ -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 => {
@@ -502,7 +534,11 @@ impl CodeGenerator {
// 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
@@ -526,7 +562,8 @@ impl CodeGenerator {
} }
// 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]));
@@ -576,31 +613,42 @@ 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
} }
} }
@@ -610,39 +658,42 @@ impl CodeGenerator {
// 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(),
}); });
} }
} }
@@ -959,7 +1065,7 @@ impl CodeGenerator {
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(())
@@ -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
@@ -50,14 +51,18 @@ impl Compiler {
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?;
@@ -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 {
@@ -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,

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;
@@ -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 {

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<()> {

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)

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)]
@@ -236,8 +265,10 @@ impl Parser {
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)
@@ -314,7 +345,10 @@ impl Parser {
}); });
}; };
self.consume(&TokenType::Semicolon, "Expected ';' after field declaration")?; self.consume(
&TokenType::Semicolon,
"Expected ';' after field declaration",
)?;
fields.push((field_name, field_type)); fields.push((field_name, field_type));
} }
@@ -351,7 +385,10 @@ impl Parser {
}); });
}; };
self.consume(&TokenType::Semicolon, "Expected ';' after field declaration")?; self.consume(
&TokenType::Semicolon,
"Expected ';' after field declaration",
)?;
fields.push((field_name, field_type)); fields.push((field_name, field_type));
} }
@@ -377,7 +414,8 @@ impl Parser {
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 {
@@ -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)
} }
} }
@@ -526,7 +573,11 @@ impl Parser {
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 {
@@ -572,7 +623,10 @@ impl Parser {
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,7 +663,10 @@ 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))
} }
@@ -676,7 +737,10 @@ 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,
@@ -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> {
@@ -913,8 +985,12 @@ impl Parser {
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,
@@ -995,7 +1071,16 @@ impl Parser {
} }
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,

Ver fichero

@@ -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]
@@ -24,7 +24,10 @@ mod tests {
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(_)));
@@ -51,7 +54,8 @@ mod tests {
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