@@ -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);
|
||||||
|
|||||||
285
src/codegen.rs
285
src/codegen.rs
@@ -1,6 +1,8 @@
|
|||||||
use crate::parser::{Program, Function, Expression, Statement, Type, BinaryOperator, UnaryOperator};
|
|
||||||
use crate::targets::Target;
|
|
||||||
use crate::error::{AleccError, Result};
|
use crate::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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
107
src/compiler.rs
107
src/compiler.rs
@@ -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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
122
src/lexer.rs
122
src/lexer.rs
@@ -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,
|
||||||
|
|||||||
12
src/lib.rs
12
src/lib.rs
@@ -1,9 +1,9 @@
|
|||||||
pub mod lexer;
|
|
||||||
pub mod parser;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod targets;
|
|
||||||
pub mod compiler;
|
|
||||||
pub mod cli;
|
pub mod 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;
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
20
src/main.rs
20
src/main.rs
@@ -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<()> {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
191
src/parser.rs
191
src/parser.rs
@@ -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,
|
||||||
|
|||||||
@@ -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",
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user