@@ -20,6 +20,12 @@
|
||||
- **Seguridad**: Detección temprana de errores y manejo seguro de memoria
|
||||
- **Velocidad**: Compilación rápida con paralelización cuando es posible
|
||||
|
||||
## ⚠️ Limitaciones Actuales
|
||||
|
||||
- **Bibliotecas estándar**: No incluye implementación completa de la biblioteca estándar de C
|
||||
- **Headers del sistema**: Actualmente no procesa headers complejos del sistema
|
||||
- **Funciones estándar**: `printf` y otras funciones estándar requieren enlaces externos
|
||||
|
||||
## 🏗️ Arquitecturas Soportadas
|
||||
|
||||
| Arquitectura | Estado | Descripción |
|
||||
@@ -114,7 +120,7 @@ alecc --static programa.c -o programa_static
|
||||
#### Inclusión de Headers
|
||||
```bash
|
||||
# Directorios de headers adicionales
|
||||
alecc -I./include -I/usr/local/include programa.c -o programa
|
||||
alecc -I/usr/local/include programa.c -o programa
|
||||
|
||||
# Definir macros
|
||||
alecc -DDEBUG -DVERSION=1.0 programa.c -o programa
|
||||
|
||||
768
src/codegen.rs
768
src/codegen.rs
@@ -1,4 +1,4 @@
|
||||
use crate::parser::{Program, Function, Expression, Statement, Type, BinaryOperator};
|
||||
use crate::parser::{Program, Function, Expression, Statement, Type, BinaryOperator, UnaryOperator};
|
||||
use crate::targets::Target;
|
||||
use crate::error::{AleccError, Result};
|
||||
use std::collections::HashMap;
|
||||
@@ -9,6 +9,10 @@ pub struct CodeGenerator {
|
||||
label_counter: usize,
|
||||
string_literals: HashMap<String, String>,
|
||||
current_function_params: Vec<(String, i32)>, // (name, stack_offset)
|
||||
epilogue_emitted: bool,
|
||||
local_variables: HashMap<String, i32>, // (name, stack_offset)
|
||||
stack_offset: i32, // Current stack offset for local variables
|
||||
last_call_stack_cleanup: usize, // Stack bytes to clean up after last call
|
||||
}
|
||||
|
||||
impl CodeGenerator {
|
||||
@@ -19,10 +23,19 @@ impl CodeGenerator {
|
||||
label_counter: 0,
|
||||
string_literals: HashMap::new(),
|
||||
current_function_params: Vec::new(),
|
||||
epilogue_emitted: false,
|
||||
local_variables: HashMap::new(),
|
||||
stack_offset: 0,
|
||||
last_call_stack_cleanup: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate(&mut self, program: &Program) -> Result<String> {
|
||||
// First pass: collect all string literals
|
||||
for function in &program.functions {
|
||||
self.collect_string_literals_from_statement(&function.body)?;
|
||||
}
|
||||
|
||||
self.emit_header();
|
||||
|
||||
// Generate string literals section
|
||||
@@ -66,8 +79,9 @@ impl CodeGenerator {
|
||||
self.emit_line(" push rbp");
|
||||
self.emit_line(" mov rbp, rsp");
|
||||
|
||||
// Reserve space for temporary operations (prevents stack corruption)
|
||||
self.emit_line(" sub rsp, 128");
|
||||
// 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
|
||||
self.emit_line(" sub rsp, 120");
|
||||
|
||||
// Call main function
|
||||
self.emit_line(" call main");
|
||||
@@ -97,11 +111,27 @@ impl CodeGenerator {
|
||||
}
|
||||
|
||||
fn generate_function(&mut self, function: &Function) -> Result<()> {
|
||||
// Check if function has a body (implementation) or is just a declaration
|
||||
match &function.body {
|
||||
Statement::Block(statements) if statements.is_empty() => {
|
||||
// This is a forward declaration, generate an external reference
|
||||
self.emit_line(&format!(".extern {}", function.name));
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
// This is a function definition, generate the actual function
|
||||
}
|
||||
}
|
||||
|
||||
self.emit_line(&format!(".globl {}", function.name));
|
||||
self.emit_line(&format!("{}:", function.name));
|
||||
|
||||
// Set up parameter tracking
|
||||
self.current_function_params.clear();
|
||||
self.local_variables.clear();
|
||||
// Start local variables after parameters to avoid collision
|
||||
self.stack_offset = -(function.parameters.len() as i32 * 8);
|
||||
self.epilogue_emitted = false;
|
||||
|
||||
// Function prologue
|
||||
self.emit_function_prologue(&function.parameters)?;
|
||||
@@ -109,7 +139,8 @@ impl CodeGenerator {
|
||||
// Function body
|
||||
self.generate_statement(&function.body)?;
|
||||
|
||||
// Function epilogue (if no explicit return)
|
||||
// Function epilogue (always ensure we have a proper function ending)
|
||||
// This handles cases where there might not be explicit returns in all paths
|
||||
self.emit_function_epilogue()?;
|
||||
|
||||
self.emit_line("");
|
||||
@@ -122,9 +153,11 @@ impl CodeGenerator {
|
||||
self.emit_line(" push ebp");
|
||||
self.emit_line(" mov ebp, esp");
|
||||
|
||||
// Reserve space for parameters + 128 bytes for temporaries
|
||||
let stack_space = parameters.len() * 4 + 128;
|
||||
self.emit_line(&format!(" sub esp, {}", stack_space));
|
||||
// Reserve space for parameters only (no extra temporaries for now)
|
||||
let stack_space = parameters.len() * 4;
|
||||
if stack_space > 0 {
|
||||
self.emit_line(&format!(" sub esp, {}", stack_space));
|
||||
}
|
||||
|
||||
// Store parameters from stack (i386 calling convention)
|
||||
for (i, (name, _)) in parameters.iter().enumerate() {
|
||||
@@ -139,9 +172,12 @@ impl CodeGenerator {
|
||||
self.emit_line(" push rbp");
|
||||
self.emit_line(" mov rbp, rsp");
|
||||
|
||||
// Reserve space for parameters + 128 bytes for temporaries
|
||||
let stack_space = parameters.len() * 8 + 128;
|
||||
self.emit_line(&format!(" sub rsp, {}", stack_space));
|
||||
// Reserve space for parameters + ensure 16-byte alignment
|
||||
let stack_space = parameters.len() * 8;
|
||||
// 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 aligned_space = ((min_space + 15) / 16) * 16; // Round up to 16-byte boundary
|
||||
self.emit_line(&format!(" sub rsp, {}", aligned_space));
|
||||
|
||||
// Store parameters from registers (x86_64 calling convention)
|
||||
let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||
@@ -163,8 +199,11 @@ impl CodeGenerator {
|
||||
self.emit_line(" stp x29, x30, [sp, #-16]!");
|
||||
self.emit_line(" mov x29, sp");
|
||||
|
||||
let stack_space = (parameters.len() * 8 + 128 + 15) & !15; // 16-byte aligned
|
||||
self.emit_line(&format!(" sub sp, sp, #{}", stack_space));
|
||||
let stack_space = parameters.len() * 8;
|
||||
if stack_space > 0 {
|
||||
let aligned_space = (stack_space + 15) & !15; // 16-byte aligned
|
||||
self.emit_line(&format!(" sub sp, sp, #{}", aligned_space));
|
||||
}
|
||||
|
||||
// Store parameters from registers (ARM64 calling convention)
|
||||
for (i, (name, _)) in parameters.iter().enumerate() {
|
||||
@@ -186,6 +225,10 @@ impl CodeGenerator {
|
||||
}
|
||||
|
||||
fn emit_function_epilogue(&mut self) -> Result<()> {
|
||||
if self.epilogue_emitted {
|
||||
return Ok(()); // Don't emit duplicate epilogues
|
||||
}
|
||||
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(" mov esp, ebp");
|
||||
@@ -203,6 +246,32 @@ impl CodeGenerator {
|
||||
self.emit_line(" ret");
|
||||
}
|
||||
}
|
||||
|
||||
self.epilogue_emitted = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_function_epilogue_force(&mut self) -> Result<()> {
|
||||
// Force emit epilogue regardless of epilogue_emitted flag
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(" mov esp, ebp");
|
||||
self.emit_line(" pop ebp");
|
||||
self.emit_line(" ret");
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(" mov rsp, rbp");
|
||||
self.emit_line(" pop rbp");
|
||||
self.emit_line(" ret");
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(" mov sp, x29");
|
||||
self.emit_line(" ldp x29, x30, [sp], #16");
|
||||
self.emit_line(" ret");
|
||||
}
|
||||
}
|
||||
|
||||
self.epilogue_emitted = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -211,6 +280,37 @@ impl CodeGenerator {
|
||||
Statement::Expression(expr) => {
|
||||
self.generate_expression(expr)?;
|
||||
}
|
||||
Statement::Declaration { name, var_type, initializer } => {
|
||||
// Calculate space needed based on type
|
||||
let size = match var_type {
|
||||
Type::Array(_, Some(length)) => length * 8, // Assuming 8-byte elements
|
||||
Type::Array(_, None) => 80, // Default size for unsized arrays
|
||||
_ => 8, // Default 8 bytes for simple types
|
||||
};
|
||||
|
||||
// Allocate space for variable/array
|
||||
self.stack_offset -= size as i32;
|
||||
let var_offset = self.stack_offset;
|
||||
|
||||
// Store variable name and offset for later reference
|
||||
self.local_variables.insert(name.clone(), var_offset);
|
||||
|
||||
if let Some(init_expr) = initializer {
|
||||
self.generate_expression(init_expr)?;
|
||||
// Store the value in the local variable slot
|
||||
match self.target {
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov QWORD PTR [rbp + {}], rax", var_offset));
|
||||
}
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov DWORD PTR [ebp + {}], eax", var_offset));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" str x0, [x29, #{}]", var_offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::Return(expr) => {
|
||||
if let Some(expr) = expr {
|
||||
self.generate_expression(expr)?;
|
||||
@@ -227,7 +327,8 @@ impl CodeGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.emit_function_epilogue()?;
|
||||
// Force emit epilogue for each return statement
|
||||
self.emit_function_epilogue_force()?;
|
||||
}
|
||||
Statement::Block(statements) => {
|
||||
for stmt in statements {
|
||||
@@ -246,7 +347,14 @@ impl CodeGenerator {
|
||||
|
||||
self.emit_line(&format!("{}:", else_label));
|
||||
if let Some(else_stmt) = else_stmt {
|
||||
// Reset epilogue flag for else branch in case it contains a return
|
||||
let saved_epilogue_state = self.epilogue_emitted;
|
||||
self.epilogue_emitted = false;
|
||||
self.generate_statement(else_stmt)?;
|
||||
// If else branch didn't emit epilogue, restore the saved state
|
||||
if !self.epilogue_emitted {
|
||||
self.epilogue_emitted = saved_epilogue_state;
|
||||
}
|
||||
}
|
||||
|
||||
self.emit_line(&format!("{}:", end_label));
|
||||
@@ -264,6 +372,34 @@ impl CodeGenerator {
|
||||
|
||||
self.emit_line(&format!("{}:", end_label));
|
||||
}
|
||||
Statement::For { init, condition, increment, body } => {
|
||||
// Generate initialization
|
||||
if let Some(init_stmt) = init {
|
||||
self.generate_statement(init_stmt)?;
|
||||
}
|
||||
|
||||
let loop_label = self.new_label("forloop");
|
||||
let end_label = self.new_label("endfor");
|
||||
|
||||
self.emit_line(&format!("{}:", loop_label));
|
||||
|
||||
// Generate condition check
|
||||
if let Some(cond_expr) = condition {
|
||||
self.generate_expression(cond_expr)?;
|
||||
self.emit_conditional_jump(false, &end_label)?;
|
||||
}
|
||||
|
||||
// Generate body
|
||||
self.generate_statement(body)?;
|
||||
|
||||
// Generate increment
|
||||
if let Some(inc_expr) = increment {
|
||||
self.generate_expression(inc_expr)?;
|
||||
}
|
||||
|
||||
self.emit_jump(&loop_label)?;
|
||||
self.emit_line(&format!("{}:", end_label));
|
||||
}
|
||||
_ => {
|
||||
// Other statements not implemented yet
|
||||
return Err(AleccError::CodegenError {
|
||||
@@ -319,6 +455,19 @@ impl CodeGenerator {
|
||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||
}
|
||||
}
|
||||
} else if let Some(offset) = self.local_variables.get(name) {
|
||||
// Load local variable from stack
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Load global variable
|
||||
match self.target {
|
||||
@@ -350,31 +499,61 @@ impl CodeGenerator {
|
||||
// x86_64: first 6 args in registers, rest on stack
|
||||
let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||
|
||||
// Generate arguments and store in registers/stack
|
||||
for (i, arg) in arguments.iter().enumerate() {
|
||||
self.generate_expression(arg)?;
|
||||
if i < param_registers.len() {
|
||||
// Move to parameter register
|
||||
self.emit_line(&format!(" mov {}, rax", param_registers[i]));
|
||||
} else {
|
||||
// Push to stack (reverse order for stack args)
|
||||
// Ensure stack alignment before function call
|
||||
// Stack must be 16-byte aligned before 'call' instruction
|
||||
// Since 'call' pushes 8 bytes (return address), we need stack to be 8 bytes off 16-byte boundary
|
||||
let stack_args = if arguments.len() > param_registers.len() { arguments.len() - param_registers.len() } else { 0 };
|
||||
let mut stack_cleanup_size = 0;
|
||||
|
||||
// Handle stack arguments if any
|
||||
if stack_args > 0 {
|
||||
let total_stack_bytes = stack_args * 8;
|
||||
// Ensure alignment: if total_stack_bytes is odd multiple of 8, add 8 bytes for alignment
|
||||
if (total_stack_bytes / 8) % 2 != 0 {
|
||||
self.emit_line(" sub rsp, 8 # Stack alignment");
|
||||
stack_cleanup_size += 8;
|
||||
}
|
||||
stack_cleanup_size += stack_args * 8;
|
||||
}
|
||||
// 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)
|
||||
if arguments.len() > param_registers.len() {
|
||||
for arg in arguments.iter().skip(param_registers.len()).rev() {
|
||||
self.generate_expression(arg)?;
|
||||
self.emit_line(" push rax");
|
||||
}
|
||||
}
|
||||
|
||||
// Then handle register arguments in reverse order to avoid overwriting
|
||||
let reg_args: Vec<_> = arguments.iter().take(param_registers.len()).collect();
|
||||
for (i, arg) in reg_args.iter().enumerate().rev() {
|
||||
self.generate_expression(arg)?;
|
||||
self.emit_line(&format!(" mov {}, rax", param_registers[i]));
|
||||
}
|
||||
|
||||
// Store cleanup size for later use
|
||||
self.last_call_stack_cleanup = stack_cleanup_size;
|
||||
}
|
||||
Target::Arm64 => {
|
||||
// ARM64: first 8 args in x0-x7, rest on stack
|
||||
for (i, arg) in arguments.iter().enumerate() {
|
||||
self.generate_expression(arg)?;
|
||||
if i < 8 {
|
||||
if i > 0 {
|
||||
self.emit_line(&format!(" mov x{}, x0", i));
|
||||
}
|
||||
// x0 already has the result for first argument
|
||||
} else {
|
||||
// Save stack arguments first
|
||||
if arguments.len() > 8 {
|
||||
for arg in arguments.iter().skip(8).rev() {
|
||||
self.generate_expression(arg)?;
|
||||
self.emit_line(" str x0, [sp, #-16]!");
|
||||
}
|
||||
}
|
||||
|
||||
// Then handle register arguments in reverse order
|
||||
let reg_args: Vec<_> = arguments.iter().take(8).collect();
|
||||
for (i, arg) in reg_args.iter().enumerate().rev() {
|
||||
self.generate_expression(arg)?;
|
||||
if i > 0 {
|
||||
self.emit_line(&format!(" mov x{}, x0", i));
|
||||
}
|
||||
// x0 already has the result for first argument
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,10 +574,9 @@ impl CodeGenerator {
|
||||
}
|
||||
}
|
||||
Target::Amd64 => {
|
||||
// Clean up stack arguments (if any)
|
||||
let stack_args = if arguments.len() > 6 { arguments.len() - 6 } else { 0 };
|
||||
if stack_args > 0 {
|
||||
self.emit_line(&format!(" add rsp, {}", stack_args * 8));
|
||||
// Clean up stack using stored cleanup size
|
||||
if self.last_call_stack_cleanup > 0 {
|
||||
self.emit_line(&format!(" add rsp, {}", self.last_call_stack_cleanup));
|
||||
}
|
||||
}
|
||||
Target::Arm64 => {
|
||||
@@ -441,6 +619,11 @@ impl CodeGenerator {
|
||||
self.emit_line(" cdq"); // Sign extend eax to edx:eax
|
||||
self.emit_line(" idiv ebx");
|
||||
}
|
||||
BinaryOperator::Modulo => {
|
||||
self.emit_line(" cdq"); // Sign extend eax to edx:eax
|
||||
self.emit_line(" idiv ebx");
|
||||
self.emit_line(" mov eax, edx"); // Remainder is in edx
|
||||
}
|
||||
_ => {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: format!("Binary operator {:?} not implemented for i386", operator),
|
||||
@@ -458,6 +641,11 @@ impl CodeGenerator {
|
||||
self.emit_line(" cqo"); // Sign extend rax to rdx:rax
|
||||
self.emit_line(" idiv rbx");
|
||||
}
|
||||
BinaryOperator::Modulo => {
|
||||
self.emit_line(" cqo"); // Sign extend rax to rdx:rax
|
||||
self.emit_line(" idiv rbx");
|
||||
self.emit_line(" mov rax, rdx"); // Remainder is in rdx
|
||||
}
|
||||
// Comparison operators
|
||||
BinaryOperator::Equal => {
|
||||
self.emit_line(" cmp rax, rbx");
|
||||
@@ -489,10 +677,35 @@ impl CodeGenerator {
|
||||
self.emit_line(" setge al");
|
||||
self.emit_line(" movzx rax, al");
|
||||
}
|
||||
_ => {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: format!("Binary operator {:?} not implemented for amd64", operator),
|
||||
});
|
||||
// Logical operators
|
||||
BinaryOperator::LogicalAnd => {
|
||||
self.emit_line(" test rax, rax");
|
||||
self.emit_line(" setne al");
|
||||
self.emit_line(" test rbx, rbx");
|
||||
self.emit_line(" setne bl");
|
||||
self.emit_line(" and al, bl");
|
||||
self.emit_line(" movzx rax, al");
|
||||
}
|
||||
BinaryOperator::LogicalOr => {
|
||||
self.emit_line(" test rax, rax");
|
||||
self.emit_line(" setne al");
|
||||
self.emit_line(" test rbx, rbx");
|
||||
self.emit_line(" setne bl");
|
||||
self.emit_line(" or al, bl");
|
||||
self.emit_line(" movzx rax, al");
|
||||
}
|
||||
// Bitwise operators
|
||||
BinaryOperator::BitwiseAnd => self.emit_line(" and rax, rbx"),
|
||||
BinaryOperator::BitwiseOr => self.emit_line(" or rax, rbx"),
|
||||
BinaryOperator::BitwiseXor => self.emit_line(" xor rax, rbx"),
|
||||
// Shift operators
|
||||
BinaryOperator::LeftShift => {
|
||||
self.emit_line(" mov rcx, rbx"); // Shift count in rcx
|
||||
self.emit_line(" shl rax, cl");
|
||||
}
|
||||
BinaryOperator::RightShift => {
|
||||
self.emit_line(" mov rcx, rbx"); // Shift count in rcx
|
||||
self.emit_line(" sar rax, cl"); // Arithmetic right shift
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -503,6 +716,10 @@ impl CodeGenerator {
|
||||
BinaryOperator::Subtract => self.emit_line(" sub x0, x0, x1"),
|
||||
BinaryOperator::Multiply => self.emit_line(" mul x0, x0, x1"),
|
||||
BinaryOperator::Divide => self.emit_line(" sdiv x0, x0, x1"),
|
||||
BinaryOperator::Modulo => {
|
||||
self.emit_line(" sdiv x2, x0, x1"); // x2 = x0 / x1
|
||||
self.emit_line(" msub x0, x2, x1, x0"); // x0 = x0 - (x2 * x1)
|
||||
}
|
||||
_ => {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: format!("Binary operator {:?} not implemented for arm64", operator),
|
||||
@@ -512,6 +729,322 @@ impl CodeGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::Unary { operator, operand } => {
|
||||
match operator {
|
||||
UnaryOperator::Minus => {
|
||||
self.generate_expression(operand)?;
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(" neg eax");
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(" neg rax");
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(" neg x0, x0");
|
||||
}
|
||||
}
|
||||
}
|
||||
UnaryOperator::Plus => {
|
||||
// Plus is a no-op, just generate the operand
|
||||
self.generate_expression(operand)?;
|
||||
}
|
||||
UnaryOperator::LogicalNot => {
|
||||
self.generate_expression(operand)?;
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(" test eax, eax");
|
||||
self.emit_line(" setz al");
|
||||
self.emit_line(" movzx eax, al");
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(" test rax, rax");
|
||||
self.emit_line(" setz al");
|
||||
self.emit_line(" movzx rax, al");
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(" cmp x0, #0");
|
||||
self.emit_line(" cset x0, eq");
|
||||
}
|
||||
}
|
||||
}
|
||||
UnaryOperator::BitwiseNot => {
|
||||
self.generate_expression(operand)?;
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(" not eax");
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(" not rax");
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(" mvn x0, x0");
|
||||
}
|
||||
}
|
||||
}
|
||||
UnaryOperator::PreIncrement => {
|
||||
// Load variable, increment, store back, and leave incremented value in register
|
||||
if let Expression::Identifier(name) = operand.as_ref() {
|
||||
if let Some(&offset) = self.local_variables.get(name) {
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" inc DWORD PTR [ebp + {}]", offset));
|
||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" inc QWORD PTR [rbp + {}]", offset));
|
||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||
self.emit_line(" add x0, x0, #1");
|
||||
self.emit_line(&format!(" str x0, [x29, #{}]", offset));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: format!("Undefined variable: {}", name),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Pre-increment can only be applied to variables".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
UnaryOperator::PostIncrement => {
|
||||
// Load variable, store incremented value, but leave original value in register
|
||||
if let Expression::Identifier(name) = operand.as_ref() {
|
||||
if let Some(&offset) = self.local_variables.get(name) {
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
||||
self.emit_line(&format!(" inc DWORD PTR [ebp + {}]", offset));
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
||||
self.emit_line(&format!(" inc QWORD PTR [rbp + {}]", offset));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||
self.emit_line(&format!(" ldr x1, [x29, #{}]", offset));
|
||||
self.emit_line(" add x1, x1, #1");
|
||||
self.emit_line(&format!(" str x1, [x29, #{}]", offset));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: format!("Undefined variable: {}", name),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Post-increment can only be applied to variables".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
UnaryOperator::PreDecrement => {
|
||||
// Similar to PreIncrement but with decrement
|
||||
if let Expression::Identifier(name) = operand.as_ref() {
|
||||
if let Some(&offset) = self.local_variables.get(name) {
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" dec DWORD PTR [ebp + {}]", offset));
|
||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" dec QWORD PTR [rbp + {}]", offset));
|
||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||
self.emit_line(" sub x0, x0, #1");
|
||||
self.emit_line(&format!(" str x0, [x29, #{}]", offset));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: format!("Undefined variable: {}", name),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Pre-decrement can only be applied to variables".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
UnaryOperator::PostDecrement => {
|
||||
// Similar to PostIncrement but with decrement
|
||||
if let Expression::Identifier(name) = operand.as_ref() {
|
||||
if let Some(&offset) = self.local_variables.get(name) {
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
||||
self.emit_line(&format!(" dec DWORD PTR [ebp + {}]", offset));
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
||||
self.emit_line(&format!(" dec QWORD PTR [rbp + {}]", offset));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||
self.emit_line(&format!(" ldr x1, [x29, #{}]", offset));
|
||||
self.emit_line(" sub x1, x1, #1");
|
||||
self.emit_line(&format!(" str x1, [x29, #{}]", offset));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: format!("Undefined variable: {}", name),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Post-decrement can only be applied to variables".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
UnaryOperator::AddressOf => {
|
||||
// Get address of a variable
|
||||
if let Expression::Identifier(name) = operand.as_ref() {
|
||||
if let Some(&offset) = self.local_variables.get(name) {
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" lea eax, [ebp + {}]", offset));
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" lea rax, [rbp + {}]", offset));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" add x0, x29, #{}", offset));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: format!("Undefined variable: {}", name),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Address-of can only be applied to variables".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
UnaryOperator::Dereference => {
|
||||
// Dereference a pointer (load value from address)
|
||||
self.generate_expression(operand)?; // Get the address
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
self.emit_line(" mov eax, DWORD PTR [eax]");
|
||||
}
|
||||
Target::Amd64 => {
|
||||
self.emit_line(" mov rax, QWORD PTR [rax]");
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(" ldr x0, [x0]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::Index { array, index } => {
|
||||
// Generate the array base address
|
||||
if let Expression::Identifier(array_name) = array.as_ref() {
|
||||
if let Some(&base_offset) = self.local_variables.get(array_name) {
|
||||
// Generate the index expression
|
||||
self.generate_expression(index)?;
|
||||
|
||||
// Calculate the array element address: base + index * element_size
|
||||
match self.target {
|
||||
Target::Amd64 => {
|
||||
// Multiply index by 8 (assuming int is 8 bytes for simplicity)
|
||||
self.emit_line(" imul rax, 8"); // Use imul instead of mul
|
||||
// Add base address
|
||||
self.emit_line(&format!(" lea rbx, [rbp + {}]", base_offset));
|
||||
self.emit_line(" add rax, rbx");
|
||||
// Load the value at that address
|
||||
self.emit_line(" mov rax, QWORD PTR [rax]");
|
||||
}
|
||||
Target::I386 => {
|
||||
// Similar for 32-bit
|
||||
self.emit_line(" imul eax, 4"); // Use imul instead of mul
|
||||
self.emit_line(&format!(" lea ebx, [ebp + {}]", base_offset));
|
||||
self.emit_line(" add eax, ebx");
|
||||
self.emit_line(" mov eax, DWORD PTR [eax]");
|
||||
}
|
||||
Target::Arm64 => {
|
||||
// ARM64 implementation
|
||||
self.emit_line(" lsl x0, x0, #3"); // multiply by 8
|
||||
self.emit_line(&format!(" add x1, x29, #{}", base_offset));
|
||||
self.emit_line(" add x0, x0, x1");
|
||||
self.emit_line(" ldr x0, [x0]");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: format!("Array '{}' not found", array_name),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Complex array expressions not yet supported".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Expression::Assignment { target, operator, value } => {
|
||||
// Handle compound assignment operators
|
||||
match operator {
|
||||
crate::parser::AssignmentOperator::Assign => {
|
||||
// Simple assignment: target = value
|
||||
self.generate_expression(value)?;
|
||||
self.store_in_target(target)?;
|
||||
}
|
||||
crate::parser::AssignmentOperator::PlusAssign => {
|
||||
// target += value => target = target + value
|
||||
self.load_from_target(target)?; // Load current value
|
||||
self.emit_line(" push rax"); // Save current value
|
||||
self.generate_expression(value)?; // Generate RHS
|
||||
self.emit_line(" pop rbx"); // Restore current value
|
||||
self.emit_line(" add rax, rbx"); // target + value
|
||||
self.store_in_target(target)?; // Store result
|
||||
}
|
||||
crate::parser::AssignmentOperator::MinusAssign => {
|
||||
// target -= value => target = target - value
|
||||
self.load_from_target(target)?;
|
||||
self.emit_line(" push rax");
|
||||
self.generate_expression(value)?;
|
||||
self.emit_line(" mov rbx, rax"); // RHS in rbx
|
||||
self.emit_line(" pop rax"); // Current value in rax
|
||||
self.emit_line(" sub rax, rbx"); // target - value
|
||||
self.store_in_target(target)?;
|
||||
}
|
||||
crate::parser::AssignmentOperator::MultiplyAssign => {
|
||||
// target *= value => target = target * value
|
||||
self.load_from_target(target)?;
|
||||
self.emit_line(" push rax");
|
||||
self.generate_expression(value)?;
|
||||
self.emit_line(" pop rbx");
|
||||
self.emit_line(" imul rax, rbx"); // target * value
|
||||
self.store_in_target(target)?;
|
||||
}
|
||||
crate::parser::AssignmentOperator::DivideAssign => {
|
||||
// target /= value => target = target / value
|
||||
self.load_from_target(target)?;
|
||||
self.emit_line(" push rax");
|
||||
self.generate_expression(value)?;
|
||||
self.emit_line(" mov rbx, rax"); // RHS in rbx
|
||||
self.emit_line(" pop rax"); // Current value in rax
|
||||
self.emit_line(" cqo"); // Sign extend for division
|
||||
self.emit_line(" idiv rbx"); // target / value
|
||||
self.store_in_target(target)?;
|
||||
}
|
||||
_ => {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Assignment operator not implemented".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Expression type not implemented".to_string(),
|
||||
@@ -521,6 +1054,7 @@ impl CodeGenerator {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn push_argument(&mut self, _index: usize) -> Result<()> {
|
||||
match self.target {
|
||||
Target::I386 => {
|
||||
@@ -538,6 +1072,84 @@ impl CodeGenerator {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_from_target(&mut self, target: &Expression) -> Result<()> {
|
||||
// Load the current value of target into rax
|
||||
if let Expression::Identifier(name) = target {
|
||||
if let Some(&offset) = self.local_variables.get(name) {
|
||||
match self.target {
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
||||
}
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Global variable
|
||||
match self.target {
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov rax, QWORD PTR [{}]", name));
|
||||
}
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov eax, DWORD PTR [{}]", name));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" adrp x1, {}", name));
|
||||
self.emit_line(&format!(" add x1, x1, :lo12:{}", name));
|
||||
self.emit_line(" ldr x0, [x1]");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Complex assignment targets not supported for compound operators yet".to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn store_in_target(&mut self, target: &Expression) -> Result<()> {
|
||||
// Store rax value into target
|
||||
if let Expression::Identifier(name) = target {
|
||||
if let Some(&offset) = self.local_variables.get(name) {
|
||||
match self.target {
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov QWORD PTR [rbp + {}], rax", offset));
|
||||
}
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov DWORD PTR [ebp + {}], eax", offset));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" str x0, [x29, #{}]", offset));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Global variable
|
||||
match self.target {
|
||||
Target::Amd64 => {
|
||||
self.emit_line(&format!(" mov QWORD PTR [{}], rax", name));
|
||||
}
|
||||
Target::I386 => {
|
||||
self.emit_line(&format!(" mov DWORD PTR [{}], eax", name));
|
||||
}
|
||||
Target::Arm64 => {
|
||||
self.emit_line(&format!(" adrp x1, {}", name));
|
||||
self.emit_line(&format!(" add x1, x1, :lo12:{}", name));
|
||||
self.emit_line(" str x0, [x1]");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(AleccError::CodegenError {
|
||||
message: "Complex assignment targets not supported for compound operators yet".to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn emit_conditional_jump(&mut self, condition: bool, label: &str) -> Result<()> {
|
||||
let instruction = if condition { "jnz" } else { "jz" };
|
||||
|
||||
@@ -620,4 +1232,86 @@ impl CodeGenerator {
|
||||
.replace('\t', "\\t")
|
||||
.replace('\r', "\\r")
|
||||
}
|
||||
|
||||
fn collect_string_literals_from_statement(&mut self, stmt: &Statement) -> Result<()> {
|
||||
match stmt {
|
||||
Statement::Expression(expr) => self.collect_string_literals_from_expression(expr),
|
||||
Statement::Block(statements) => {
|
||||
for stmt in statements {
|
||||
self.collect_string_literals_from_statement(stmt)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Statement::Return(expr) => {
|
||||
if let Some(expr) = expr {
|
||||
self.collect_string_literals_from_expression(expr)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Statement::If { condition, then_stmt, else_stmt } => {
|
||||
self.collect_string_literals_from_expression(condition)?;
|
||||
self.collect_string_literals_from_statement(then_stmt)?;
|
||||
if let Some(else_statement) = else_stmt {
|
||||
self.collect_string_literals_from_statement(else_statement)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Statement::While { condition, body } => {
|
||||
self.collect_string_literals_from_expression(condition)?;
|
||||
self.collect_string_literals_from_statement(body)?;
|
||||
Ok(())
|
||||
}
|
||||
Statement::For { init, condition, increment, body } => {
|
||||
if let Some(init_stmt) = init {
|
||||
self.collect_string_literals_from_statement(init_stmt)?;
|
||||
}
|
||||
if let Some(cond_expr) = condition {
|
||||
self.collect_string_literals_from_expression(cond_expr)?;
|
||||
}
|
||||
if let Some(inc_expr) = increment {
|
||||
self.collect_string_literals_from_expression(inc_expr)?;
|
||||
}
|
||||
self.collect_string_literals_from_statement(body)?;
|
||||
Ok(())
|
||||
}
|
||||
Statement::Declaration { initializer, .. } => {
|
||||
if let Some(expr) = initializer {
|
||||
self.collect_string_literals_from_expression(expr)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => Ok(()) // Other statement types don't have expressions we need to collect
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_string_literals_from_expression(&mut self, expr: &Expression) -> Result<()> {
|
||||
match expr {
|
||||
Expression::StringLiteral(value) => {
|
||||
self.get_string_literal_label(value);
|
||||
Ok(())
|
||||
}
|
||||
Expression::Binary { left, right, .. } => {
|
||||
self.collect_string_literals_from_expression(left)?;
|
||||
self.collect_string_literals_from_expression(right)?;
|
||||
Ok(())
|
||||
}
|
||||
Expression::Unary { operand, .. } => {
|
||||
self.collect_string_literals_from_expression(operand)?;
|
||||
Ok(())
|
||||
}
|
||||
Expression::Call { function, arguments } => {
|
||||
self.collect_string_literals_from_expression(function)?;
|
||||
for arg in arguments {
|
||||
self.collect_string_literals_from_expression(arg)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Expression::Assignment { target, value, .. } => {
|
||||
self.collect_string_literals_from_expression(target)?;
|
||||
self.collect_string_literals_from_expression(value)?;
|
||||
Ok(())
|
||||
}
|
||||
_ => Ok(()) // Other expression types don't contain string literals
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ pub enum AleccError {
|
||||
message: String,
|
||||
},
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[error("Semantic error: {message}")]
|
||||
SemanticError { message: String },
|
||||
|
||||
@@ -37,6 +38,7 @@ pub enum AleccError {
|
||||
#[error("Invalid argument: {message}")]
|
||||
InvalidArgument { message: String },
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[error("Internal compiler error: {message}")]
|
||||
InternalError { message: String },
|
||||
}
|
||||
|
||||
19
src/lexer.rs
19
src/lexer.rs
@@ -38,6 +38,7 @@ pub enum TokenType {
|
||||
LeftBrace, RightBrace,
|
||||
LeftBracket, RightBracket,
|
||||
Semicolon, Comma,
|
||||
Ellipsis, // ...
|
||||
|
||||
// Preprocessor
|
||||
Hash, HashHash,
|
||||
@@ -52,6 +53,7 @@ pub struct Token {
|
||||
pub token_type: TokenType,
|
||||
pub line: usize,
|
||||
pub column: usize,
|
||||
#[allow(dead_code)]
|
||||
pub length: usize,
|
||||
}
|
||||
|
||||
@@ -249,7 +251,22 @@ impl Lexer {
|
||||
']' => Ok(Some(TokenType::RightBracket)),
|
||||
';' => Ok(Some(TokenType::Semicolon)),
|
||||
',' => Ok(Some(TokenType::Comma)),
|
||||
'.' => Ok(Some(TokenType::Dot)),
|
||||
'.' => {
|
||||
if self.match_char('.') {
|
||||
if self.match_char('.') {
|
||||
Ok(Some(TokenType::Ellipsis)) // ...
|
||||
} else {
|
||||
// Error: .. is not valid
|
||||
Err(crate::error::AleccError::ParseError {
|
||||
line: self.line,
|
||||
column: self.column,
|
||||
message: "Invalid token '..'".to_string(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Ok(Some(TokenType::Dot))
|
||||
}
|
||||
}
|
||||
'?' => Ok(Some(TokenType::Question)),
|
||||
':' => Ok(Some(TokenType::Colon)),
|
||||
'#' => {
|
||||
|
||||
9
src/lib.rs
Archivo normal
9
src/lib.rs
Archivo normal
@@ -0,0 +1,9 @@
|
||||
pub mod lexer;
|
||||
pub mod parser;
|
||||
pub mod codegen;
|
||||
pub mod targets;
|
||||
pub mod compiler;
|
||||
pub mod cli;
|
||||
pub mod error;
|
||||
pub mod optimizer;
|
||||
pub mod linker;
|
||||
@@ -210,18 +210,15 @@ impl Linker {
|
||||
command.push(lib.clone());
|
||||
}
|
||||
|
||||
// Standard libraries - skip for now to avoid conflicts
|
||||
// Our programs use custom runtime with syscalls
|
||||
/*
|
||||
// Standard libraries
|
||||
if !self.static_link {
|
||||
command.push("-lc".to_string());
|
||||
}
|
||||
*/
|
||||
|
||||
Ok(command)
|
||||
}
|
||||
|
||||
fn add_standard_startup_files(&self, command: &mut Vec<String>) -> Result<()> {
|
||||
fn add_standard_startup_files(&self, _command: &mut Vec<String>) -> Result<()> {
|
||||
// Skip startup files when we have our own _start
|
||||
// This prevents conflicts with our custom _start implementation
|
||||
Ok(())
|
||||
@@ -320,6 +317,7 @@ impl Linker {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn link_static_library(&self) -> Result<()> {
|
||||
// Use ar to create static library
|
||||
let mut command = vec!["ar".to_string(), "rcs".to_string()];
|
||||
|
||||
@@ -225,8 +225,10 @@ impl Optimizer {
|
||||
}
|
||||
|
||||
// Additional optimization passes that can be applied independently
|
||||
#[allow(dead_code)]
|
||||
pub struct OptimizationPasses;
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl OptimizationPasses {
|
||||
pub fn constant_propagation(_program: &mut Program) -> Result<()> {
|
||||
// TODO: Implement constant propagation
|
||||
|
||||
228
src/parser.rs
228
src/parser.rs
@@ -12,34 +12,44 @@ pub enum Type {
|
||||
Float,
|
||||
Double,
|
||||
Bool,
|
||||
#[allow(dead_code)]
|
||||
Pointer(Box<Type>),
|
||||
#[allow(dead_code)]
|
||||
Array(Box<Type>, Option<usize>),
|
||||
#[allow(dead_code)]
|
||||
Function {
|
||||
return_type: Box<Type>,
|
||||
parameters: Vec<Type>,
|
||||
variadic: bool,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
Struct {
|
||||
name: String,
|
||||
fields: Vec<(String, Type)>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
Union {
|
||||
name: String,
|
||||
fields: Vec<(String, Type)>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
Enum {
|
||||
name: String,
|
||||
variants: Vec<(String, i64)>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
Typedef(String, Box<Type>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Expression {
|
||||
IntegerLiteral(i64),
|
||||
#[allow(dead_code)]
|
||||
FloatLiteral(f64),
|
||||
StringLiteral(String),
|
||||
#[allow(dead_code)]
|
||||
CharLiteral(char),
|
||||
#[allow(dead_code)]
|
||||
BooleanLiteral(bool),
|
||||
Identifier(String),
|
||||
Binary {
|
||||
@@ -55,6 +65,7 @@ pub enum Expression {
|
||||
function: Box<Expression>,
|
||||
arguments: Vec<Expression>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
Member {
|
||||
object: Box<Expression>,
|
||||
member: String,
|
||||
@@ -64,16 +75,19 @@ pub enum Expression {
|
||||
array: Box<Expression>,
|
||||
index: Box<Expression>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
Cast {
|
||||
target_type: Type,
|
||||
expression: Box<Expression>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
Sizeof(Type),
|
||||
Assignment {
|
||||
target: Box<Expression>,
|
||||
operator: AssignmentOperator,
|
||||
value: Box<Expression>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
Conditional {
|
||||
condition: Box<Expression>,
|
||||
then_expr: Box<Expression>,
|
||||
@@ -100,9 +114,13 @@ pub enum UnaryOperator {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AssignmentOperator {
|
||||
Assign, PlusAssign, MinusAssign, MultiplyAssign, DivideAssign, ModuloAssign,
|
||||
BitwiseAndAssign, BitwiseOrAssign, BitwiseXorAssign,
|
||||
LeftShiftAssign, RightShiftAssign,
|
||||
Assign, PlusAssign, MinusAssign, MultiplyAssign, DivideAssign,
|
||||
#[allow(dead_code)] ModuloAssign,
|
||||
#[allow(dead_code)] BitwiseAndAssign,
|
||||
#[allow(dead_code)] BitwiseOrAssign,
|
||||
#[allow(dead_code)] BitwiseXorAssign,
|
||||
#[allow(dead_code)] LeftShiftAssign,
|
||||
#[allow(dead_code)] RightShiftAssign,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -129,36 +147,49 @@ pub enum Statement {
|
||||
increment: Option<Expression>,
|
||||
body: Box<Statement>,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
DoWhile {
|
||||
body: Box<Statement>,
|
||||
condition: Expression,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
Switch {
|
||||
expression: Expression,
|
||||
cases: Vec<(Option<Expression>, Vec<Statement>)>,
|
||||
},
|
||||
Return(Option<Expression>),
|
||||
#[allow(dead_code)]
|
||||
Break,
|
||||
#[allow(dead_code)]
|
||||
Continue,
|
||||
#[allow(dead_code)]
|
||||
Goto(String),
|
||||
#[allow(dead_code)]
|
||||
Label(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Function {
|
||||
pub name: String,
|
||||
#[allow(dead_code)]
|
||||
pub return_type: Type,
|
||||
pub parameters: Vec<(String, Type)>,
|
||||
pub body: Statement,
|
||||
#[allow(dead_code)]
|
||||
pub is_inline: bool,
|
||||
#[allow(dead_code)]
|
||||
pub is_static: bool,
|
||||
#[allow(dead_code)]
|
||||
pub is_extern: bool,
|
||||
#[allow(dead_code)]
|
||||
pub is_variadic: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Program {
|
||||
pub functions: Vec<Function>,
|
||||
pub global_variables: Vec<(String, Type, Option<Expression>)>,
|
||||
#[allow(dead_code)]
|
||||
pub type_definitions: HashMap<String, Type>,
|
||||
}
|
||||
|
||||
@@ -215,6 +246,11 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn parse_type(&mut self) -> Result<Type> {
|
||||
// Skip type qualifiers like const, volatile
|
||||
while self.match_token(&TokenType::Const) || self.match_token(&TokenType::Volatile) {
|
||||
// Just consume the qualifier for now
|
||||
}
|
||||
|
||||
let mut base_type = match &self.advance()?.token_type {
|
||||
TokenType::Void => Type::Void,
|
||||
TokenType::Char => Type::Char,
|
||||
@@ -242,6 +278,10 @@ impl Parser {
|
||||
|
||||
// Handle pointer declarators
|
||||
while self.match_token(&TokenType::Multiply) {
|
||||
// Skip const after *
|
||||
while self.match_token(&TokenType::Const) || self.match_token(&TokenType::Volatile) {
|
||||
// Just consume the qualifier for now
|
||||
}
|
||||
base_type = Type::Pointer(Box::new(base_type));
|
||||
}
|
||||
|
||||
@@ -500,7 +540,14 @@ impl Parser {
|
||||
self.consume(&TokenType::LeftParen, "Expected '(' after function name")?;
|
||||
|
||||
let mut parameters = Vec::new();
|
||||
let mut is_variadic = false;
|
||||
|
||||
while !self.check(&TokenType::RightParen) && !self.is_at_end() {
|
||||
if self.match_token(&TokenType::Ellipsis) {
|
||||
is_variadic = true;
|
||||
break;
|
||||
}
|
||||
|
||||
let param_type = self.parse_type()?;
|
||||
let param_name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
|
||||
name.clone()
|
||||
@@ -537,6 +584,7 @@ impl Parser {
|
||||
is_inline: false,
|
||||
is_static: false,
|
||||
is_extern: false,
|
||||
is_variadic,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -593,7 +641,7 @@ impl Parser {
|
||||
self.parse_block_statement()
|
||||
} else if self.is_type(&self.current_token()?.token_type) {
|
||||
// Variable declaration - convert to Statement format
|
||||
let var_type = self.parse_type()?;
|
||||
let mut var_type = self.parse_type()?;
|
||||
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
|
||||
name.clone()
|
||||
} else {
|
||||
@@ -604,6 +652,24 @@ impl Parser {
|
||||
});
|
||||
};
|
||||
|
||||
// Check for array declaration
|
||||
if self.match_token(&TokenType::LeftBracket) {
|
||||
let size = if self.check(&TokenType::RightBracket) {
|
||||
None
|
||||
} else {
|
||||
// Parse array size (should be a constant expression)
|
||||
let size_expr = self.parse_expression()?;
|
||||
if let Expression::IntegerLiteral(size) = size_expr {
|
||||
Some(size as usize)
|
||||
} else {
|
||||
// For now, just use a default size if not a simple integer
|
||||
Some(10)
|
||||
}
|
||||
};
|
||||
self.consume(&TokenType::RightBracket, "Expected ']' after array size")?;
|
||||
var_type = Type::Array(Box::new(var_type), size);
|
||||
}
|
||||
|
||||
let initializer = if self.match_token(&TokenType::Assign) {
|
||||
Some(self.parse_expression()?)
|
||||
} else {
|
||||
@@ -698,7 +764,50 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn parse_expression(&mut self) -> Result<Expression> {
|
||||
self.parse_logical_or()
|
||||
self.parse_assignment()
|
||||
}
|
||||
|
||||
fn parse_assignment(&mut self) -> Result<Expression> {
|
||||
let expr = self.parse_logical_or()?;
|
||||
|
||||
if self.match_token(&TokenType::Assign) {
|
||||
let value = self.parse_assignment()?; // Right associative
|
||||
return Ok(Expression::Assignment {
|
||||
target: Box::new(expr),
|
||||
operator: AssignmentOperator::Assign,
|
||||
value: Box::new(value),
|
||||
});
|
||||
} else if self.match_token(&TokenType::PlusAssign) {
|
||||
let value = self.parse_assignment()?;
|
||||
return Ok(Expression::Assignment {
|
||||
target: Box::new(expr),
|
||||
operator: AssignmentOperator::PlusAssign,
|
||||
value: Box::new(value),
|
||||
});
|
||||
} else if self.match_token(&TokenType::MinusAssign) {
|
||||
let value = self.parse_assignment()?;
|
||||
return Ok(Expression::Assignment {
|
||||
target: Box::new(expr),
|
||||
operator: AssignmentOperator::MinusAssign,
|
||||
value: Box::new(value),
|
||||
});
|
||||
} else if self.match_token(&TokenType::MultiplyAssign) {
|
||||
let value = self.parse_assignment()?;
|
||||
return Ok(Expression::Assignment {
|
||||
target: Box::new(expr),
|
||||
operator: AssignmentOperator::MultiplyAssign,
|
||||
value: Box::new(value),
|
||||
});
|
||||
} else if self.match_token(&TokenType::DivideAssign) {
|
||||
let value = self.parse_assignment()?;
|
||||
return Ok(Expression::Assignment {
|
||||
target: Box::new(expr),
|
||||
operator: AssignmentOperator::DivideAssign,
|
||||
value: Box::new(value),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn parse_logical_or(&mut self) -> Result<Expression> {
|
||||
@@ -718,10 +827,58 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn parse_logical_and(&mut self) -> Result<Expression> {
|
||||
let mut expr = self.parse_equality()?;
|
||||
let mut expr = self.parse_bitwise_or()?;
|
||||
|
||||
while self.match_token(&TokenType::LogicalAnd) {
|
||||
let operator = BinaryOperator::LogicalAnd;
|
||||
let right = self.parse_bitwise_or()?;
|
||||
expr = Expression::Binary {
|
||||
left: Box::new(expr),
|
||||
operator,
|
||||
right: Box::new(right),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn parse_bitwise_or(&mut self) -> Result<Expression> {
|
||||
let mut expr = self.parse_bitwise_xor()?;
|
||||
|
||||
while self.match_token(&TokenType::BitwiseOr) {
|
||||
let operator = BinaryOperator::BitwiseOr;
|
||||
let right = self.parse_bitwise_xor()?;
|
||||
expr = Expression::Binary {
|
||||
left: Box::new(expr),
|
||||
operator,
|
||||
right: Box::new(right),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn parse_bitwise_xor(&mut self) -> Result<Expression> {
|
||||
let mut expr = self.parse_bitwise_and()?;
|
||||
|
||||
while self.match_token(&TokenType::BitwiseXor) {
|
||||
let operator = BinaryOperator::BitwiseXor;
|
||||
let right = self.parse_bitwise_and()?;
|
||||
expr = Expression::Binary {
|
||||
left: Box::new(expr),
|
||||
operator,
|
||||
right: Box::new(right),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn parse_bitwise_and(&mut self) -> Result<Expression> {
|
||||
let mut expr = self.parse_equality()?;
|
||||
|
||||
while self.match_token(&TokenType::BitwiseAnd) {
|
||||
let operator = BinaryOperator::BitwiseAnd;
|
||||
let right = self.parse_equality()?;
|
||||
expr = Expression::Binary {
|
||||
left: Box::new(expr),
|
||||
@@ -754,7 +911,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn parse_comparison(&mut self) -> Result<Expression> {
|
||||
let mut expr = self.parse_term()?;
|
||||
let mut expr = self.parse_shift()?;
|
||||
|
||||
while self.match_tokens(&[TokenType::Greater, TokenType::GreaterEqual,
|
||||
TokenType::Less, TokenType::LessEqual]) {
|
||||
@@ -765,6 +922,26 @@ impl Parser {
|
||||
TokenType::LessEqual => BinaryOperator::LessEqual,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let right = self.parse_shift()?;
|
||||
expr = Expression::Binary {
|
||||
left: Box::new(expr),
|
||||
operator,
|
||||
right: Box::new(right),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
fn parse_shift(&mut self) -> Result<Expression> {
|
||||
let mut expr = self.parse_term()?;
|
||||
|
||||
while self.match_tokens(&[TokenType::LeftShift, TokenType::RightShift]) {
|
||||
let operator = match self.previous()?.token_type {
|
||||
TokenType::LeftShift => BinaryOperator::LeftShift,
|
||||
TokenType::RightShift => BinaryOperator::RightShift,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let right = self.parse_term()?;
|
||||
expr = Expression::Binary {
|
||||
left: Box::new(expr),
|
||||
@@ -818,11 +995,16 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn parse_unary(&mut self) -> Result<Expression> {
|
||||
if self.match_tokens(&[TokenType::LogicalNot, TokenType::Minus, TokenType::Plus]) {
|
||||
if self.match_tokens(&[TokenType::LogicalNot, TokenType::Minus, TokenType::Plus, TokenType::Increment, TokenType::Decrement, TokenType::BitwiseAnd, TokenType::Multiply, TokenType::BitwiseNot]) {
|
||||
let operator = match self.previous()?.token_type {
|
||||
TokenType::LogicalNot => UnaryOperator::LogicalNot,
|
||||
TokenType::Minus => UnaryOperator::Minus,
|
||||
TokenType::Plus => UnaryOperator::Plus,
|
||||
TokenType::Increment => UnaryOperator::PreIncrement,
|
||||
TokenType::Decrement => UnaryOperator::PreDecrement,
|
||||
TokenType::BitwiseAnd => UnaryOperator::AddressOf,
|
||||
TokenType::Multiply => UnaryOperator::Dereference,
|
||||
TokenType::BitwiseNot => UnaryOperator::BitwiseNot,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let right = self.parse_unary()?;
|
||||
@@ -838,8 +1020,30 @@ impl Parser {
|
||||
fn parse_call(&mut self) -> Result<Expression> {
|
||||
let mut expr = self.parse_primary()?;
|
||||
|
||||
while self.match_token(&TokenType::LeftParen) {
|
||||
expr = self.finish_call(expr)?;
|
||||
loop {
|
||||
if self.match_token(&TokenType::LeftParen) {
|
||||
expr = self.finish_call(expr)?;
|
||||
} else if self.match_token(&TokenType::LeftBracket) {
|
||||
// Array indexing
|
||||
let index = self.parse_expression()?;
|
||||
self.consume(&TokenType::RightBracket, "Expected ']' after array index")?;
|
||||
expr = Expression::Index {
|
||||
array: Box::new(expr),
|
||||
index: Box::new(index),
|
||||
};
|
||||
} else if self.match_token(&TokenType::Increment) {
|
||||
expr = Expression::Unary {
|
||||
operator: UnaryOperator::PostIncrement,
|
||||
operand: Box::new(expr),
|
||||
};
|
||||
} else if self.match_token(&TokenType::Decrement) {
|
||||
expr = Expression::Unary {
|
||||
operator: UnaryOperator::PostDecrement,
|
||||
operand: Box::new(expr),
|
||||
};
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
@@ -898,8 +1102,12 @@ enum Declaration {
|
||||
#[derive(Debug, Clone)]
|
||||
enum StorageClass {
|
||||
None,
|
||||
#[allow(dead_code)]
|
||||
Static,
|
||||
#[allow(dead_code)]
|
||||
Extern,
|
||||
#[allow(dead_code)]
|
||||
Auto,
|
||||
#[allow(dead_code)]
|
||||
Register,
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ impl Target {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn alignment(&self) -> usize {
|
||||
match self {
|
||||
Target::I386 => 4,
|
||||
@@ -54,6 +55,7 @@ impl Target {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn triple(&self) -> &'static str {
|
||||
match self {
|
||||
Target::I386 => "i386-unknown-linux-gnu",
|
||||
@@ -62,6 +64,7 @@ impl Target {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn assembler(&self) -> &'static str {
|
||||
match self {
|
||||
Target::I386 => "as --32",
|
||||
@@ -70,6 +73,7 @@ impl Target {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn linker(&self) -> &'static str {
|
||||
match self {
|
||||
Target::I386 => "ld -m elf_i386",
|
||||
@@ -78,6 +82,7 @@ impl Target {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn object_format(&self) -> &'static str {
|
||||
match self {
|
||||
Target::I386 => "elf32",
|
||||
@@ -86,6 +91,7 @@ impl Target {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn calling_convention(&self) -> CallingConvention {
|
||||
match self {
|
||||
Target::I386 => CallingConvention::Cdecl,
|
||||
@@ -94,6 +100,7 @@ impl Target {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn register_names(&self) -> RegisterSet {
|
||||
match self {
|
||||
Target::I386 => RegisterSet::X86_32,
|
||||
@@ -103,6 +110,7 @@ impl Target {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum CallingConvention {
|
||||
Cdecl, // x86-32
|
||||
@@ -110,6 +118,7 @@ pub enum CallingConvention {
|
||||
Aapcs64, // ARM64
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum RegisterSet {
|
||||
X86_32,
|
||||
@@ -117,6 +126,7 @@ pub enum RegisterSet {
|
||||
Aarch64,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl RegisterSet {
|
||||
pub fn general_purpose_registers(&self) -> &'static [&'static str] {
|
||||
match self {
|
||||
@@ -159,6 +169,7 @@ impl RegisterSet {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct TargetInfo {
|
||||
pub target: Target,
|
||||
pub endianness: Endianness,
|
||||
@@ -168,12 +179,14 @@ pub struct TargetInfo {
|
||||
pub supports_pie: bool,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Endianness {
|
||||
Little,
|
||||
Big,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl TargetInfo {
|
||||
pub fn new(target: Target) -> Self {
|
||||
let (word_size, max_align) = match target {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alecc::lexer::{Lexer, TokenType};
|
||||
use alecc::parser::Parser;
|
||||
use alecc::codegen::CodeGenerator;
|
||||
|
||||
Referencia en una nueva incidencia
Block a user