initial commit

Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
ale
2025-08-21 16:49:30 +02:00
commit 771f2d64ae
Se han modificado 21 ficheros con 3892 adiciones y 0 borrados

114
src/cli.rs Archivo normal
Ver fichero

@@ -0,0 +1,114 @@
use clap::{Parser, ValueEnum};
use std::path::PathBuf;
#[derive(Parser, Debug, Clone)]
#[command(name = "alecc")]
#[command(about = "A high-performance C/C++ compiler with GCC compatibility")]
#[command(version)]
pub struct Args {
/// Input source files
#[arg(value_name = "FILE")]
pub input_files: Vec<PathBuf>,
/// Output file name
#[arg(short = 'o', long = "output", value_name = "FILE")]
pub output: Option<PathBuf>,
/// Target architecture
#[arg(short = 't', long = "target", default_value = "native")]
pub target: String,
/// Compilation mode
#[arg(short = 'c', long = "compile")]
pub compile_only: bool,
/// Generate assembly only
#[arg(short = 'S', long = "assemble")]
pub assembly_only: bool,
/// Preprocessing only
#[arg(short = 'E', long = "preprocess")]
pub preprocess_only: bool,
/// Optimization level
#[arg(short = 'O', long = "optimize", default_value = "0")]
pub optimization: String,
/// Debug information
#[arg(short = 'g', long = "debug")]
pub debug: bool,
/// Warning level
#[arg(short = 'W', long = "warn")]
pub warnings: Vec<String>,
/// Include directories
#[arg(short = 'I', long = "include")]
pub include_dirs: Vec<PathBuf>,
/// Library directories
#[arg(short = 'L', long = "library-path")]
pub library_dirs: Vec<PathBuf>,
/// Libraries to link
#[arg(short = 'l', long = "library")]
pub libraries: Vec<String>,
/// Define preprocessor macros
#[arg(short = 'D', long = "define")]
pub defines: Vec<String>,
/// Undefine preprocessor macros
#[arg(short = 'U', long = "undefine")]
pub undefines: Vec<String>,
/// C standard version
#[arg(long = "std")]
pub standard: Option<String>,
/// Verbose output
#[arg(short = 'v', long = "verbose")]
pub verbose: bool,
/// Position independent code
#[arg(long = "pic")]
pub pic: bool,
/// Position independent executable
#[arg(long = "pie")]
pub pie: bool,
/// Static linking
#[arg(long = "static")]
pub static_link: bool,
/// Shared library creation
#[arg(long = "shared")]
pub shared: bool,
/// Thread model
#[arg(long = "thread-model", default_value = "posix")]
pub thread_model: String,
/// Enable LTO
#[arg(long = "lto")]
pub lto: bool,
/// Cross compilation sysroot
#[arg(long = "sysroot")]
pub sysroot: Option<PathBuf>,
/// Additional compiler flags
#[arg(long = "extra-flags")]
pub extra_flags: Vec<String>,
}
#[derive(Debug, Clone, ValueEnum)]
pub enum OptimizationLevel {
O0,
O1,
O2,
O3,
Os,
Oz,
}

396
src/codegen.rs Archivo normal
Ver fichero

@@ -0,0 +1,396 @@
use crate::parser::{Program, Function, Expression, Statement, Type};
use crate::targets::Target;
use crate::error::{AleccError, Result};
use std::collections::HashMap;
pub struct CodeGenerator {
target: Target,
output: String,
label_counter: usize,
string_literals: HashMap<String, String>,
}
impl CodeGenerator {
pub fn new(target: Target) -> Self {
Self {
target,
output: String::new(),
label_counter: 0,
string_literals: HashMap::new(),
}
}
pub fn generate(&mut self, program: &Program) -> Result<String> {
self.emit_header();
// Generate string literals section
if !self.string_literals.is_empty() {
self.emit_line(".section .rodata");
for (content, label) in &self.string_literals {
self.emit_line(&format!("{}:", label));
self.emit_line(&format!(" .string \"{}\"", self.escape_string(content)));
}
self.emit_line("");
}
// Generate global variables
if !program.global_variables.is_empty() {
self.emit_line(".section .data");
for (name, var_type, _initializer) in &program.global_variables {
self.emit_global_variable(name, var_type)?;
}
self.emit_line("");
}
// Generate functions
self.emit_line(".section .text");
for function in &program.functions {
self.generate_function(function)?;
}
Ok(self.output.clone())
}
fn emit_header(&mut self) {
match self.target {
Target::I386 => {
self.emit_line(".arch i386");
self.emit_line(".intel_syntax noprefix");
}
Target::Amd64 => {
self.emit_line(".arch x86_64");
self.emit_line(".intel_syntax noprefix");
}
Target::Arm64 => {
self.emit_line(".arch armv8-a");
}
}
self.emit_line("");
}
fn generate_function(&mut self, function: &Function) -> Result<()> {
self.emit_line(&format!(".globl {}", function.name));
self.emit_line(&format!("{}:", function.name));
// Function prologue
self.emit_function_prologue(&function.parameters)?;
// Function body
self.generate_statement(&function.body)?;
// Function epilogue (if no explicit return)
self.emit_function_epilogue()?;
self.emit_line("");
Ok(())
}
fn emit_function_prologue(&mut self, parameters: &[(String, Type)]) -> Result<()> {
match self.target {
Target::I386 => {
self.emit_line(" push ebp");
self.emit_line(" mov ebp, esp");
// Reserve space for local variables (simplified)
let stack_space = parameters.len() * 4; // Simplified calculation
if stack_space > 0 {
self.emit_line(&format!(" sub esp, {}", stack_space));
}
}
Target::Amd64 => {
self.emit_line(" push rbp");
self.emit_line(" mov rbp, rsp");
let stack_space = parameters.len() * 8;
if stack_space > 0 {
self.emit_line(&format!(" sub rsp, {}", stack_space));
}
}
Target::Arm64 => {
self.emit_line(" stp x29, x30, [sp, #-16]!");
self.emit_line(" mov x29, sp");
let stack_space = (parameters.len() * 8 + 15) & !15; // 16-byte aligned
if stack_space > 0 {
self.emit_line(&format!(" sub sp, sp, #{}", stack_space));
}
}
}
Ok(())
}
fn emit_function_epilogue(&mut self) -> Result<()> {
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");
}
}
Ok(())
}
fn generate_statement(&mut self, statement: &Statement) -> Result<()> {
match statement {
Statement::Expression(expr) => {
self.generate_expression(expr)?;
}
Statement::Return(expr) => {
if let Some(expr) = expr {
self.generate_expression(expr)?;
// Move result to return register
match self.target {
Target::I386 => {
// Result should already be in eax
}
Target::Amd64 => {
// Result should already be in rax
}
Target::Arm64 => {
// Result should already be in x0
}
}
}
self.emit_function_epilogue()?;
}
Statement::Block(statements) => {
for stmt in statements {
self.generate_statement(stmt)?;
}
}
Statement::If { condition, then_stmt, else_stmt } => {
let else_label = self.new_label("else");
let end_label = self.new_label("endif");
self.generate_expression(condition)?;
self.emit_conditional_jump(false, &else_label)?;
self.generate_statement(then_stmt)?;
self.emit_jump(&end_label)?;
self.emit_line(&format!("{}:", else_label));
if let Some(else_stmt) = else_stmt {
self.generate_statement(else_stmt)?;
}
self.emit_line(&format!("{}:", end_label));
}
Statement::While { condition, body } => {
let loop_label = self.new_label("loop");
let end_label = self.new_label("endloop");
self.emit_line(&format!("{}:", loop_label));
self.generate_expression(condition)?;
self.emit_conditional_jump(false, &end_label)?;
self.generate_statement(body)?;
self.emit_jump(&loop_label)?;
self.emit_line(&format!("{}:", end_label));
}
_ => {
// Other statements not implemented yet
return Err(AleccError::CodegenError {
message: "Statement type not implemented".to_string(),
});
}
}
Ok(())
}
fn generate_expression(&mut self, expression: &Expression) -> Result<()> {
match expression {
Expression::IntegerLiteral(value) => {
match self.target {
Target::I386 => {
self.emit_line(&format!(" mov eax, {}", value));
}
Target::Amd64 => {
self.emit_line(&format!(" mov rax, {}", value));
}
Target::Arm64 => {
self.emit_line(&format!(" mov x0, #{}", value));
}
}
}
Expression::StringLiteral(value) => {
let label = self.get_string_literal_label(value);
match self.target {
Target::I386 => {
self.emit_line(&format!(" mov eax, OFFSET {}", label));
}
Target::Amd64 => {
self.emit_line(&format!(" lea rax, [{}]", label));
}
Target::Arm64 => {
self.emit_line(&format!(" adrp x0, {}", label));
self.emit_line(&format!(" add x0, x0, :lo12:{}", label));
}
}
}
Expression::Identifier(name) => {
// Load variable (simplified - assumes it's a parameter or global)
match self.target {
Target::I386 => {
self.emit_line(&format!(" mov eax, DWORD PTR [{}]", name));
}
Target::Amd64 => {
self.emit_line(&format!(" mov rax, QWORD 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]");
}
}
}
Expression::Call { function, arguments } => {
// Generate arguments in reverse order
for (i, arg) in arguments.iter().enumerate().rev() {
self.generate_expression(arg)?;
self.push_argument(i)?;
}
if let Expression::Identifier(func_name) = function.as_ref() {
self.emit_line(&format!(" call {}", func_name));
} else {
return Err(AleccError::CodegenError {
message: "Indirect function calls not implemented".to_string(),
});
}
// Clean up stack
let stack_cleanup = arguments.len() * self.target.pointer_size();
if stack_cleanup > 0 {
match self.target {
Target::I386 => {
self.emit_line(&format!(" add esp, {}", stack_cleanup));
}
Target::Amd64 => {
// Arguments passed in registers, no cleanup needed
}
Target::Arm64 => {
// Arguments passed in registers, no cleanup needed
}
}
}
}
_ => {
return Err(AleccError::CodegenError {
message: "Expression type not implemented".to_string(),
});
}
}
Ok(())
}
fn push_argument(&mut self, _index: usize) -> Result<()> {
match self.target {
Target::I386 => {
self.emit_line(" push eax");
}
Target::Amd64 => {
// Use calling convention registers
self.emit_line(" push rax"); // Simplified
}
Target::Arm64 => {
// Use calling convention registers
self.emit_line(" str x0, [sp, #-16]!"); // Simplified
}
}
Ok(())
}
fn emit_conditional_jump(&mut self, condition: bool, label: &str) -> Result<()> {
let instruction = if condition { "jnz" } else { "jz" };
match self.target {
Target::I386 | Target::Amd64 => {
self.emit_line(&format!(" test eax, eax"));
self.emit_line(&format!(" {} {}", instruction, label));
}
Target::Arm64 => {
let branch_inst = if condition { "cbnz" } else { "cbz" };
self.emit_line(&format!(" {} x0, {}", branch_inst, label));
}
}
Ok(())
}
fn emit_jump(&mut self, label: &str) -> Result<()> {
match self.target {
Target::I386 | Target::Amd64 => {
self.emit_line(&format!(" jmp {}", label));
}
Target::Arm64 => {
self.emit_line(&format!(" b {}", label));
}
}
Ok(())
}
fn emit_global_variable(&mut self, name: &str, var_type: &Type) -> Result<()> {
let size = self.get_type_size(var_type);
self.emit_line(&format!("{}:", name));
match size {
1 => self.emit_line(" .byte 0"),
2 => self.emit_line(" .word 0"),
4 => self.emit_line(" .long 0"),
8 => self.emit_line(" .quad 0"),
_ => self.emit_line(&format!(" .zero {}", size)),
}
Ok(())
}
fn get_type_size(&self, var_type: &Type) -> usize {
match var_type {
Type::Char => 1,
Type::Short => 2,
Type::Int => 4,
Type::Long => self.target.pointer_size(),
Type::Float => 4,
Type::Double => 8,
Type::Pointer(_) => self.target.pointer_size(),
_ => self.target.pointer_size(), // Default
}
}
fn get_string_literal_label(&mut self, content: &str) -> String {
if let Some(label) = self.string_literals.get(content) {
label.clone()
} else {
let label = format!(".LC{}", self.string_literals.len());
self.string_literals.insert(content.to_string(), label.clone());
label
}
}
fn new_label(&mut self, prefix: &str) -> String {
let label = format!(".L{}_{}", prefix, self.label_counter);
self.label_counter += 1;
label
}
fn emit_line(&mut self, line: &str) {
self.output.push_str(line);
self.output.push('\n');
}
fn escape_string(&self, s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
.replace('\t', "\\t")
.replace('\r', "\\r")
}
}

418
src/compiler.rs Archivo normal
Ver fichero

@@ -0,0 +1,418 @@
use crate::cli::Args;
use crate::lexer::Lexer;
use crate::parser::Parser;
use crate::codegen::CodeGenerator;
use crate::optimizer::{Optimizer, OptimizationLevel};
use crate::linker::Linker;
use crate::targets::Target;
use crate::error::{AleccError, Result};
use std::path::{Path, PathBuf};
use std::process::Command;
use tokio::fs;
use tracing::{info, debug, warn, error};
pub struct Compiler {
args: Args,
target: Target,
temp_files: Vec<PathBuf>,
}
impl Compiler {
pub fn new(args: Args) -> Result<Self> {
let target = Target::from_string(&args.target).ok_or_else(|| {
AleccError::UnsupportedTarget {
target: args.target.clone(),
}
})?;
Ok(Self {
args,
target,
temp_files: Vec::new(),
})
}
pub async fn compile(&mut self) -> Result<()> {
if self.args.input_files.is_empty() {
return Err(AleccError::InvalidArgument {
message: "No input files specified".to_string(),
});
}
info!("Compiling {} files for target {}",
self.args.input_files.len(),
self.target.as_str());
let mut object_files = Vec::new();
// Process each input file
for input_file in &self.args.input_files {
debug!("Processing file: {}", input_file.display());
let extension = input_file.extension()
.and_then(|ext| ext.to_str())
.unwrap_or("");
match extension {
"c" | "cpp" | "cxx" | "cc" | "C" => {
let obj_file = self.compile_source_file(input_file).await?;
if !self.args.compile_only && !self.args.assembly_only && !self.args.preprocess_only {
object_files.push(obj_file);
}
}
"s" | "S" => {
let obj_file = self.assemble_file(input_file).await?;
if !self.args.compile_only && !self.args.assembly_only {
object_files.push(obj_file);
}
}
"o" => {
object_files.push(input_file.clone());
}
_ => {
warn!("Unknown file extension for {}, treating as C source",
input_file.display());
let obj_file = self.compile_source_file(input_file).await?;
if !self.args.compile_only && !self.args.assembly_only && !self.args.preprocess_only {
object_files.push(obj_file);
}
}
}
}
// Link if not compile-only
if !self.args.compile_only && !self.args.assembly_only && !self.args.preprocess_only {
self.link_files(object_files).await?;
}
// Cleanup temporary files
self.cleanup().await?;
Ok(())
}
async fn compile_source_file(&mut self, input_file: &Path) -> Result<PathBuf> {
info!("Compiling source file: {}", input_file.display());
// Read source file
let source = fs::read_to_string(input_file).await.map_err(|e| {
AleccError::FileNotFound {
path: input_file.to_string_lossy().to_string(),
}
})?;
// Preprocessing
let preprocessed = if self.args.preprocess_only {
let output_path = self.get_output_path(input_file, "i")?;
let preprocessed = self.preprocess(&source, input_file).await?;
fs::write(&output_path, preprocessed).await.map_err(|e| {
AleccError::IoError(e)
})?;
return Ok(output_path);
} else {
self.preprocess(&source, input_file).await?
};
// Lexical analysis
debug!("Lexical analysis for {}", input_file.display());
let mut lexer = Lexer::new(preprocessed);
let tokens = lexer.tokenize()?;
// Parsing
debug!("Parsing {}", input_file.display());
let mut parser = Parser::new(tokens);
let mut program = parser.parse()?;
// Optimization
let opt_level = OptimizationLevel::from_string(&self.args.optimization);
let mut optimizer = Optimizer::new(opt_level);
optimizer.optimize(&mut program)?;
// Code generation
debug!("Code generation for {}", input_file.display());
let mut codegen = CodeGenerator::new(self.target);
let assembly = codegen.generate(&program)?;
if self.args.assembly_only {
let output_path = self.get_output_path(input_file, "s")?;
fs::write(&output_path, assembly).await.map_err(|e| {
AleccError::IoError(e)
})?;
return Ok(output_path);
}
// Write assembly to temporary file
let asm_path = self.create_temp_file("s")?;
fs::write(&asm_path, assembly).await.map_err(|e| {
AleccError::IoError(e)
})?;
// Assemble
let obj_path = self.assemble_file(&asm_path).await?;
Ok(obj_path)
}
async fn preprocess(&self, source: &str, input_file: &Path) -> Result<String> {
debug!("Preprocessing {}", input_file.display());
// Simple preprocessing - just handle basic #include and #define
let mut preprocessed = String::new();
let mut defines = std::collections::HashMap::new();
// Add command-line defines
for define in &self.args.defines {
if let Some(eq_pos) = define.find('=') {
let key = define[..eq_pos].to_string();
let value = define[eq_pos + 1..].to_string();
defines.insert(key, value);
} else {
defines.insert(define.clone(), "1".to_string());
}
}
// Process source line by line
for line in source.lines() {
let trimmed = line.trim();
if trimmed.starts_with("#include") {
// Handle #include (simplified)
let include_file = self.extract_include_file(trimmed)?;
let include_path = self.resolve_include_path(&include_file)?;
if include_path.exists() {
let include_content = fs::read_to_string(&include_path).await.map_err(|e| {
AleccError::IoError(e)
})?;
let included = self.preprocess(&include_content, &include_path).await?;
preprocessed.push_str(&included);
preprocessed.push('\n');
}
} else if trimmed.starts_with("#define") {
// Handle #define (simplified)
let parts: Vec<&str> = trimmed[7..].split_whitespace().collect();
if parts.len() >= 1 {
let key = parts[0].to_string();
let value = if parts.len() > 1 {
parts[1..].join(" ")
} else {
"1".to_string()
};
defines.insert(key, value);
}
} else if !trimmed.starts_with('#') {
// Regular line - expand macros
let mut expanded_line = line.to_string();
for (key, value) in &defines {
expanded_line = expanded_line.replace(key, value);
}
preprocessed.push_str(&expanded_line);
preprocessed.push('\n');
}
}
Ok(preprocessed)
}
fn extract_include_file(&self, line: &str) -> Result<String> {
if let Some(start) = line.find('"') {
if let Some(end) = line.rfind('"') {
if start != end {
return Ok(line[start + 1..end].to_string());
}
}
}
if let Some(start) = line.find('<') {
if let Some(end) = line.rfind('>') {
if start != end {
return Ok(line[start + 1..end].to_string());
}
}
}
Err(AleccError::ParseError {
line: 0,
column: 0,
message: format!("Invalid #include directive: {}", line),
})
}
fn resolve_include_path(&self, include_file: &str) -> Result<PathBuf> {
// Check current directory first
let current_path = PathBuf::from(include_file);
if current_path.exists() {
return Ok(current_path);
}
// Check include directories
for include_dir in &self.args.include_dirs {
let path = include_dir.join(include_file);
if path.exists() {
return Ok(path);
}
}
// Check system include directories
let system_includes = match self.target {
Target::I386 => vec![
"/usr/include",
"/usr/local/include",
"/usr/include/i386-linux-gnu",
],
Target::Amd64 => vec![
"/usr/include",
"/usr/local/include",
"/usr/include/x86_64-linux-gnu",
],
Target::Arm64 => vec![
"/usr/include",
"/usr/local/include",
"/usr/include/aarch64-linux-gnu",
],
};
for sys_dir in system_includes {
let path = Path::new(sys_dir).join(include_file);
if path.exists() {
return Ok(path);
}
}
Err(AleccError::FileNotFound {
path: include_file.to_string(),
})
}
async fn assemble_file(&mut self, asm_file: &Path) -> Result<PathBuf> {
debug!("Assembling {}", asm_file.display());
let obj_path = if self.args.compile_only {
self.get_output_path(asm_file, "o")?
} else {
self.create_temp_file("o")?
};
let assembler = match self.target {
Target::I386 => "as",
Target::Amd64 => "as",
Target::Arm64 => "aarch64-linux-gnu-as",
};
let mut command = Command::new(assembler);
match self.target {
Target::I386 => {
command.args(&["--32"]);
}
Target::Amd64 => {
command.args(&["--64"]);
}
Target::Arm64 => {
// Default options for aarch64
}
}
command.args(&[
"-o", &obj_path.to_string_lossy(),
&asm_file.to_string_lossy()
]);
let output = command.output().map_err(|e| AleccError::CodegenError {
message: format!("Failed to execute assembler: {}", e),
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(AleccError::CodegenError {
message: format!("Assembly failed: {}", stderr),
});
}
Ok(obj_path)
}
async fn link_files(&mut self, object_files: Vec<PathBuf>) -> Result<()> {
info!("Linking {} object files", object_files.len());
let mut linker = Linker::new(self.target);
// Set output path
let output_path = self.args.output.clone().unwrap_or_else(|| {
if self.args.shared {
PathBuf::from("lib.so")
} else {
PathBuf::from("a.out")
}
});
linker.set_output_path(output_path);
// Add object files
for obj in object_files {
linker.add_object_file(obj);
}
// Add library paths
for lib_path in &self.args.library_dirs {
linker.add_library_path(lib_path.clone());
}
// Add libraries
for lib in &self.args.libraries {
linker.add_library(lib.clone());
}
// Set linker options
linker.set_static_link(self.args.static_link);
linker.set_shared(self.args.shared);
linker.set_pic(self.args.pic);
linker.set_pie(self.args.pie);
linker.set_debug(self.args.debug);
linker.set_lto(self.args.lto);
linker.set_sysroot(self.args.sysroot.clone());
// Link
if self.args.shared {
linker.link_shared_library(None).await?;
} else {
linker.link().await?;
}
Ok(())
}
fn get_output_path(&self, input_file: &Path, extension: &str) -> Result<PathBuf> {
if let Some(ref output) = self.args.output {
Ok(output.clone())
} else {
let stem = input_file.file_stem()
.ok_or_else(|| AleccError::InvalidArgument {
message: "Invalid input file name".to_string(),
})?;
Ok(PathBuf::from(format!("{}.{}", stem.to_string_lossy(), extension)))
}
}
fn create_temp_file(&mut self, extension: &str) -> Result<PathBuf> {
let temp_path = std::env::temp_dir()
.join(format!("alecc_{}_{}.{}",
std::process::id(),
self.temp_files.len(),
extension));
self.temp_files.push(temp_path.clone());
Ok(temp_path)
}
async fn cleanup(&mut self) -> Result<()> {
for temp_file in &self.temp_files {
if temp_file.exists() {
if let Err(e) = fs::remove_file(temp_file).await {
warn!("Failed to remove temporary file {}: {}",
temp_file.display(), e);
}
}
}
self.temp_files.clear();
Ok(())
}
}

44
src/error.rs Archivo normal
Ver fichero

@@ -0,0 +1,44 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AleccError {
#[error("Lexical error at line {line}, column {column}: {message}")]
LexError {
line: usize,
column: usize,
message: String,
},
#[error("Parse error at line {line}, column {column}: {message}")]
ParseError {
line: usize,
column: usize,
message: String,
},
#[error("Semantic error: {message}")]
SemanticError { message: String },
#[error("Code generation error: {message}")]
CodegenError { message: String },
#[error("Linker error: {message}")]
LinkerError { message: String },
#[error("Target not supported: {target}")]
UnsupportedTarget { target: String },
#[error("File not found: {path}")]
FileNotFound { path: String },
#[error("I/O error: {0}")]
IoError(#[from] std::io::Error),
#[error("Invalid argument: {message}")]
InvalidArgument { message: String },
#[error("Internal compiler error: {message}")]
InternalError { message: String },
}
pub type Result<T> = std::result::Result<T, AleccError>;

560
src/lexer.rs Archivo normal
Ver fichero

@@ -0,0 +1,560 @@
use std::fmt;
#[derive(Debug, Clone, PartialEq)]
pub enum TokenType {
// Literals
IntegerLiteral(i64),
FloatLiteral(f64),
StringLiteral(String),
CharLiteral(char),
// Identifiers
Identifier(String),
// Keywords
Auto, Break, Case, Char, Const, Continue, Default, Do,
Double, Else, Enum, Extern, Float, For, Goto, If,
Int, Long, Register, Return, Short, Signed, Sizeof, Static,
Struct, Switch, Typedef, Union, Unsigned, Void, Volatile, While,
// C++ Keywords
Bool, Class, Explicit, Export, False, Friend, Inline, Mutable,
Namespace, New, Operator, Private, Protected, Public, Template,
This, Throw, True, Try, Typename, Using, Virtual,
// Operators
Plus, Minus, Multiply, Divide, Modulo,
Assign, PlusAssign, MinusAssign, MultiplyAssign, DivideAssign, ModuloAssign,
Equal, NotEqual, Less, Greater, LessEqual, GreaterEqual,
LogicalAnd, LogicalOr, LogicalNot,
BitwiseAnd, BitwiseOr, BitwiseXor, BitwiseNot,
LeftShift, RightShift, LeftShiftAssign, RightShiftAssign,
BitwiseAndAssign, BitwiseOrAssign, BitwiseXorAssign,
Increment, Decrement,
Arrow, Dot, Question, Colon,
// Delimiters
LeftParen, RightParen,
LeftBrace, RightBrace,
LeftBracket, RightBracket,
Semicolon, Comma,
// Preprocessor
Hash, HashHash,
// Special
Eof,
Newline,
}
#[derive(Debug, Clone)]
pub struct Token {
pub token_type: TokenType,
pub line: usize,
pub column: usize,
pub length: usize,
}
impl Token {
pub fn new(token_type: TokenType, line: usize, column: usize, length: usize) -> Self {
Self {
token_type,
line,
column,
length,
}
}
}
impl fmt::Display for TokenType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TokenType::IntegerLiteral(n) => write!(f, "{}", n),
TokenType::FloatLiteral(n) => write!(f, "{}", n),
TokenType::StringLiteral(s) => write!(f, "\"{}\"", s),
TokenType::CharLiteral(c) => write!(f, "'{}'", c),
TokenType::Identifier(s) => write!(f, "{}", s),
_ => write!(f, "{:?}", self),
}
}
}
pub struct Lexer {
input: String,
position: usize,
line: usize,
column: usize,
}
impl Lexer {
pub fn new(input: String) -> Self {
Self {
input,
position: 0,
line: 1,
column: 1,
}
}
pub fn tokenize(&mut self) -> crate::error::Result<Vec<Token>> {
let mut tokens = Vec::new();
while !self.is_at_end() {
self.skip_whitespace();
if self.is_at_end() {
break;
}
let start_line = self.line;
let start_column = self.column;
let start_position = self.position;
match self.scan_token() {
Ok(Some(token_type)) => {
let length = self.position - start_position;
tokens.push(Token::new(token_type, start_line, start_column, length));
}
Ok(None) => {} // Skip whitespace/comments
Err(e) => return Err(e),
}
}
tokens.push(Token::new(TokenType::Eof, self.line, self.column, 0));
Ok(tokens)
}
fn scan_token(&mut self) -> crate::error::Result<Option<TokenType>> {
let c = self.advance();
match c {
'+' => {
if self.match_char('=') {
Ok(Some(TokenType::PlusAssign))
} else if self.match_char('+') {
Ok(Some(TokenType::Increment))
} else {
Ok(Some(TokenType::Plus))
}
}
'-' => {
if self.match_char('=') {
Ok(Some(TokenType::MinusAssign))
} else if self.match_char('-') {
Ok(Some(TokenType::Decrement))
} else if self.match_char('>') {
Ok(Some(TokenType::Arrow))
} else {
Ok(Some(TokenType::Minus))
}
}
'*' => {
if self.match_char('=') {
Ok(Some(TokenType::MultiplyAssign))
} else {
Ok(Some(TokenType::Multiply))
}
}
'/' => {
if self.match_char('=') {
Ok(Some(TokenType::DivideAssign))
} else if self.match_char('/') {
self.skip_line_comment();
Ok(None)
} else if self.match_char('*') {
self.skip_block_comment()?;
Ok(None)
} else {
Ok(Some(TokenType::Divide))
}
}
'=' => {
if self.match_char('=') {
Ok(Some(TokenType::Equal))
} else {
Ok(Some(TokenType::Assign))
}
}
'!' => {
if self.match_char('=') {
Ok(Some(TokenType::NotEqual))
} else {
Ok(Some(TokenType::LogicalNot))
}
}
'<' => {
if self.match_char('=') {
Ok(Some(TokenType::LessEqual))
} else if self.match_char('<') {
if self.match_char('=') {
Ok(Some(TokenType::LeftShiftAssign))
} else {
Ok(Some(TokenType::LeftShift))
}
} else {
Ok(Some(TokenType::Less))
}
}
'>' => {
if self.match_char('=') {
Ok(Some(TokenType::GreaterEqual))
} else if self.match_char('>') {
if self.match_char('=') {
Ok(Some(TokenType::RightShiftAssign))
} else {
Ok(Some(TokenType::RightShift))
}
} else {
Ok(Some(TokenType::Greater))
}
}
'&' => {
if self.match_char('&') {
Ok(Some(TokenType::LogicalAnd))
} else if self.match_char('=') {
Ok(Some(TokenType::BitwiseAndAssign))
} else {
Ok(Some(TokenType::BitwiseAnd))
}
}
'|' => {
if self.match_char('|') {
Ok(Some(TokenType::LogicalOr))
} else if self.match_char('=') {
Ok(Some(TokenType::BitwiseOrAssign))
} else {
Ok(Some(TokenType::BitwiseOr))
}
}
'^' => {
if self.match_char('=') {
Ok(Some(TokenType::BitwiseXorAssign))
} else {
Ok(Some(TokenType::BitwiseXor))
}
}
'~' => Ok(Some(TokenType::BitwiseNot)),
'%' => {
if self.match_char('=') {
Ok(Some(TokenType::ModuloAssign))
} else {
Ok(Some(TokenType::Modulo))
}
}
'(' => Ok(Some(TokenType::LeftParen)),
')' => Ok(Some(TokenType::RightParen)),
'{' => Ok(Some(TokenType::LeftBrace)),
'}' => Ok(Some(TokenType::RightBrace)),
'[' => Ok(Some(TokenType::LeftBracket)),
']' => Ok(Some(TokenType::RightBracket)),
';' => Ok(Some(TokenType::Semicolon)),
',' => Ok(Some(TokenType::Comma)),
'.' => Ok(Some(TokenType::Dot)),
'?' => Ok(Some(TokenType::Question)),
':' => Ok(Some(TokenType::Colon)),
'#' => {
if self.match_char('#') {
Ok(Some(TokenType::HashHash))
} else {
Ok(Some(TokenType::Hash))
}
}
'\n' => {
self.line += 1;
self.column = 1;
Ok(Some(TokenType::Newline))
}
'"' => self.scan_string(),
'\'' => self.scan_char(),
_ => {
if c.is_ascii_digit() {
self.scan_number()
} else if c.is_ascii_alphabetic() || c == '_' {
self.scan_identifier()
} else {
Err(crate::error::AleccError::LexError {
line: self.line,
column: self.column - 1,
message: format!("Unexpected character: '{}'", c),
})
}
}
}
}
fn advance(&mut self) -> char {
let c = self.current_char();
self.position += 1;
self.column += 1;
c
}
fn current_char(&self) -> char {
if self.is_at_end() {
'\0'
} else {
self.input.chars().nth(self.position).unwrap_or('\0')
}
}
fn peek(&self) -> char {
if self.position + 1 >= self.input.len() {
'\0'
} else {
self.input.chars().nth(self.position + 1).unwrap_or('\0')
}
}
fn match_char(&mut self, expected: char) -> bool {
if self.is_at_end() || self.current_char() != expected {
false
} else {
self.advance();
true
}
}
fn is_at_end(&self) -> bool {
self.position >= self.input.len()
}
fn skip_whitespace(&mut self) {
while !self.is_at_end() {
match self.current_char() {
' ' | '\r' | '\t' => {
self.advance();
}
_ => break,
}
}
}
fn skip_line_comment(&mut self) {
while !self.is_at_end() && self.current_char() != '\n' {
self.advance();
}
}
fn skip_block_comment(&mut self) -> crate::error::Result<()> {
while !self.is_at_end() {
if self.current_char() == '*' && self.peek() == '/' {
self.advance(); // consume '*'
self.advance(); // consume '/'
return Ok(());
}
if self.current_char() == '\n' {
self.line += 1;
self.column = 1;
}
self.advance();
}
Err(crate::error::AleccError::LexError {
line: self.line,
column: self.column,
message: "Unterminated block comment".to_string(),
})
}
fn scan_string(&mut self) -> crate::error::Result<Option<TokenType>> {
let mut value = String::new();
while !self.is_at_end() && self.current_char() != '"' {
if self.current_char() == '\n' {
self.line += 1;
self.column = 1;
}
if self.current_char() == '\\' {
self.advance();
if !self.is_at_end() {
let escaped = match self.current_char() {
'n' => '\n',
't' => '\t',
'r' => '\r',
'\\' => '\\',
'"' => '"',
'0' => '\0',
c => c,
};
value.push(escaped);
self.advance();
}
} else {
value.push(self.current_char());
self.advance();
}
}
if self.is_at_end() {
return Err(crate::error::AleccError::LexError {
line: self.line,
column: self.column,
message: "Unterminated string literal".to_string(),
});
}
self.advance(); // consume closing '"'
Ok(Some(TokenType::StringLiteral(value)))
}
fn scan_char(&mut self) -> crate::error::Result<Option<TokenType>> {
if self.is_at_end() {
return Err(crate::error::AleccError::LexError {
line: self.line,
column: self.column,
message: "Unterminated character literal".to_string(),
});
}
let c = if self.current_char() == '\\' {
self.advance();
if self.is_at_end() {
return Err(crate::error::AleccError::LexError {
line: self.line,
column: self.column,
message: "Unterminated character literal".to_string(),
});
}
match self.current_char() {
'n' => '\n',
't' => '\t',
'r' => '\r',
'\\' => '\\',
'\'' => '\'',
'0' => '\0',
c => c,
}
} else {
self.current_char()
};
self.advance();
if self.is_at_end() || self.current_char() != '\'' {
return Err(crate::error::AleccError::LexError {
line: self.line,
column: self.column,
message: "Unterminated character literal".to_string(),
});
}
self.advance(); // consume closing '\''
Ok(Some(TokenType::CharLiteral(c)))
}
fn scan_number(&mut self) -> crate::error::Result<Option<TokenType>> {
let start = self.position - 1;
while !self.is_at_end() && self.current_char().is_ascii_digit() {
self.advance();
}
let mut is_float = false;
if !self.is_at_end() && self.current_char() == '.' && self.peek().is_ascii_digit() {
is_float = true;
self.advance(); // consume '.'
while !self.is_at_end() && self.current_char().is_ascii_digit() {
self.advance();
}
}
let text = &self.input[start..self.position];
if is_float {
match text.parse::<f64>() {
Ok(value) => Ok(Some(TokenType::FloatLiteral(value))),
Err(_) => Err(crate::error::AleccError::LexError {
line: self.line,
column: self.column,
message: format!("Invalid float literal: {}", text),
}),
}
} else {
match text.parse::<i64>() {
Ok(value) => Ok(Some(TokenType::IntegerLiteral(value))),
Err(_) => Err(crate::error::AleccError::LexError {
line: self.line,
column: self.column,
message: format!("Invalid integer literal: {}", text),
}),
}
}
}
fn scan_identifier(&mut self) -> crate::error::Result<Option<TokenType>> {
let start = self.position - 1;
while !self.is_at_end() {
let c = self.current_char();
if c.is_ascii_alphanumeric() || c == '_' {
self.advance();
} else {
break;
}
}
let text = &self.input[start..self.position];
let token_type = match text {
"auto" => TokenType::Auto,
"break" => TokenType::Break,
"case" => TokenType::Case,
"char" => TokenType::Char,
"const" => TokenType::Const,
"continue" => TokenType::Continue,
"default" => TokenType::Default,
"do" => TokenType::Do,
"double" => TokenType::Double,
"else" => TokenType::Else,
"enum" => TokenType::Enum,
"extern" => TokenType::Extern,
"float" => TokenType::Float,
"for" => TokenType::For,
"goto" => TokenType::Goto,
"if" => TokenType::If,
"int" => TokenType::Int,
"long" => TokenType::Long,
"register" => TokenType::Register,
"return" => TokenType::Return,
"short" => TokenType::Short,
"signed" => TokenType::Signed,
"sizeof" => TokenType::Sizeof,
"static" => TokenType::Static,
"struct" => TokenType::Struct,
"switch" => TokenType::Switch,
"typedef" => TokenType::Typedef,
"union" => TokenType::Union,
"unsigned" => TokenType::Unsigned,
"void" => TokenType::Void,
"volatile" => TokenType::Volatile,
"while" => TokenType::While,
// C++ keywords
"bool" => TokenType::Bool,
"class" => TokenType::Class,
"explicit" => TokenType::Explicit,
"export" => TokenType::Export,
"false" => TokenType::False,
"friend" => TokenType::Friend,
"inline" => TokenType::Inline,
"mutable" => TokenType::Mutable,
"namespace" => TokenType::Namespace,
"new" => TokenType::New,
"operator" => TokenType::Operator,
"private" => TokenType::Private,
"protected" => TokenType::Protected,
"public" => TokenType::Public,
"template" => TokenType::Template,
"this" => TokenType::This,
"throw" => TokenType::Throw,
"true" => TokenType::True,
"try" => TokenType::Try,
"typename" => TokenType::Typename,
"using" => TokenType::Using,
"virtual" => TokenType::Virtual,
_ => TokenType::Identifier(text.to_string()),
};
Ok(Some(token_type))
}
}

369
src/linker.rs Archivo normal
Ver fichero

@@ -0,0 +1,369 @@
use crate::targets::Target;
use crate::error::{AleccError, Result};
use std::path::{Path, PathBuf};
use std::process::Command;
use tokio::fs;
pub struct Linker {
target: Target,
output_path: PathBuf,
object_files: Vec<PathBuf>,
library_paths: Vec<PathBuf>,
libraries: Vec<String>,
static_link: bool,
shared: bool,
pic: bool,
pie: bool,
sysroot: Option<PathBuf>,
debug: bool,
lto: bool,
}
impl Linker {
pub fn new(target: Target) -> Self {
Self {
target,
output_path: PathBuf::from("a.out"),
object_files: Vec::new(),
library_paths: Vec::new(),
libraries: Vec::new(),
static_link: false,
shared: false,
pic: false,
pie: false,
sysroot: None,
debug: false,
lto: false,
}
}
pub fn set_output_path(&mut self, path: PathBuf) {
self.output_path = path;
}
pub fn add_object_file(&mut self, path: PathBuf) {
self.object_files.push(path);
}
pub fn add_library_path(&mut self, path: PathBuf) {
self.library_paths.push(path);
}
pub fn add_library(&mut self, name: String) {
self.libraries.push(name);
}
pub fn set_static_link(&mut self, static_link: bool) {
self.static_link = static_link;
}
pub fn set_shared(&mut self, shared: bool) {
self.shared = shared;
}
pub fn set_pic(&mut self, pic: bool) {
self.pic = pic;
}
pub fn set_pie(&mut self, pie: bool) {
self.pie = pie;
}
pub fn set_sysroot(&mut self, sysroot: Option<PathBuf>) {
self.sysroot = sysroot;
}
pub fn set_debug(&mut self, debug: bool) {
self.debug = debug;
}
pub fn set_lto(&mut self, lto: bool) {
self.lto = lto;
}
pub async fn link(&self) -> Result<()> {
if self.object_files.is_empty() {
return Err(AleccError::LinkerError {
message: "No object files to link".to_string(),
});
}
let linker_command = self.build_linker_command()?;
let output = Command::new(&linker_command[0])
.args(&linker_command[1..])
.output()
.map_err(|e| AleccError::LinkerError {
message: format!("Failed to execute linker: {}", e),
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(AleccError::LinkerError {
message: format!("Linker failed: {}", stderr),
});
}
Ok(())
}
fn build_linker_command(&self) -> Result<Vec<String>> {
let mut command = Vec::new();
// Choose linker based on target
let linker = match self.target {
Target::I386 => "ld",
Target::Amd64 => "ld",
Target::Arm64 => "aarch64-linux-gnu-ld",
};
command.push(linker.to_string());
// Target-specific flags
match self.target {
Target::I386 => {
command.push("-m".to_string());
command.push("elf_i386".to_string());
}
Target::Amd64 => {
command.push("-m".to_string());
command.push("elf_x86_64".to_string());
}
Target::Arm64 => {
command.push("-m".to_string());
command.push("aarch64linux".to_string());
}
}
// Output file
command.push("-o".to_string());
command.push(self.output_path.to_string_lossy().to_string());
// Sysroot
if let Some(ref sysroot) = self.sysroot {
command.push("--sysroot".to_string());
command.push(sysroot.to_string_lossy().to_string());
}
// Position independent code
if self.pic {
command.push("-shared".to_string());
}
// Position independent executable
if self.pie {
command.push("-pie".to_string());
}
// Static linking
if self.static_link {
command.push("-static".to_string());
}
// Shared library
if self.shared {
command.push("-shared".to_string());
}
// Debug information
if self.debug {
command.push("-g".to_string());
}
// LTO
if self.lto {
command.push("--lto-O3".to_string());
}
// Dynamic linker
if !self.static_link && !self.shared {
let dynamic_linker = match self.target {
Target::I386 => "/lib/ld-linux.so.2",
Target::Amd64 => "/lib64/ld-linux-x86-64.so.2",
Target::Arm64 => "/lib/ld-linux-aarch64.so.1",
};
command.push("-dynamic-linker".to_string());
command.push(dynamic_linker.to_string());
}
// Standard library paths and startup files
if !self.static_link && !self.shared {
self.add_standard_startup_files(&mut command)?;
}
// Library search paths
for path in &self.library_paths {
command.push("-L".to_string());
command.push(path.to_string_lossy().to_string());
}
// Add standard library paths
self.add_standard_library_paths(&mut command)?;
// Object files
for obj in &self.object_files {
command.push(obj.to_string_lossy().to_string());
}
// Libraries
for lib in &self.libraries {
command.push("-l".to_string());
command.push(lib.clone());
}
// Standard libraries
if !self.static_link {
command.push("-lc".to_string());
}
Ok(command)
}
fn add_standard_startup_files(&self, command: &mut Vec<String>) -> Result<()> {
let lib_path = match self.target {
Target::I386 => "/usr/lib/i386-linux-gnu",
Target::Amd64 => "/usr/lib/x86_64-linux-gnu",
Target::Arm64 => "/usr/lib/aarch64-linux-gnu",
};
// Add crt1.o, crti.o, crtbegin.o
let startup_files = if self.pie {
vec!["Scrt1.o", "crti.o"]
} else {
vec!["crt1.o", "crti.o"]
};
for file in startup_files {
command.push(format!("{}/{}", lib_path, file));
}
// Add GCC's crtbegin.o
let gcc_lib = self.get_gcc_lib_path()?;
if self.shared {
command.push(format!("{}/crtbeginS.o", gcc_lib));
} else {
command.push(format!("{}/crtbegin.o", gcc_lib));
}
Ok(())
}
fn add_standard_library_paths(&self, command: &mut Vec<String>) -> Result<()> {
let lib_paths = match self.target {
Target::I386 => vec![
"/usr/lib/i386-linux-gnu",
"/lib/i386-linux-gnu",
"/usr/lib32",
"/lib32",
],
Target::Amd64 => vec![
"/usr/lib/x86_64-linux-gnu",
"/lib/x86_64-linux-gnu",
"/usr/lib64",
"/lib64",
],
Target::Arm64 => vec![
"/usr/lib/aarch64-linux-gnu",
"/lib/aarch64-linux-gnu",
],
};
for path in lib_paths {
command.push("-L".to_string());
command.push(path.to_string());
}
// Add GCC library path
let gcc_lib = self.get_gcc_lib_path()?;
command.push("-L".to_string());
command.push(gcc_lib);
Ok(())
}
fn get_gcc_lib_path(&self) -> Result<String> {
// Try to find GCC library path
let output = Command::new("gcc")
.args(&["-print-libgcc-file-name"])
.output()
.map_err(|e| AleccError::LinkerError {
message: format!("Failed to find GCC library path: {}", e),
})?;
if !output.status.success() {
return Err(AleccError::LinkerError {
message: "Failed to determine GCC library path".to_string(),
});
}
let libgcc_path = String::from_utf8_lossy(&output.stdout);
let libgcc_path = libgcc_path.trim();
if let Some(parent) = Path::new(libgcc_path).parent() {
Ok(parent.to_string_lossy().to_string())
} else {
Err(AleccError::LinkerError {
message: "Invalid GCC library path".to_string(),
})
}
}
pub async fn link_shared_library(&self, soname: Option<&str>) -> Result<()> {
let mut command = self.build_linker_command()?;
// Remove executable-specific flags
command.retain(|arg| arg != "-pie" && !arg.starts_with("-dynamic-linker"));
// Add shared library flags
if !command.contains(&"-shared".to_string()) {
command.push("-shared".to_string());
}
if let Some(soname) = soname {
command.push("-soname".to_string());
command.push(soname.to_string());
}
let output = Command::new(&command[0])
.args(&command[1..])
.output()
.map_err(|e| AleccError::LinkerError {
message: format!("Failed to execute linker: {}", e),
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(AleccError::LinkerError {
message: format!("Shared library linking failed: {}", stderr),
});
}
Ok(())
}
pub async fn link_static_library(&self) -> Result<()> {
// Use ar to create static library
let mut command = vec!["ar".to_string(), "rcs".to_string()];
command.push(self.output_path.to_string_lossy().to_string());
for obj in &self.object_files {
command.push(obj.to_string_lossy().to_string());
}
let output = Command::new(&command[0])
.args(&command[1..])
.output()
.map_err(|e| AleccError::LinkerError {
message: format!("Failed to execute ar: {}", e),
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(AleccError::LinkerError {
message: format!("Static library creation failed: {}", stderr),
});
}
Ok(())
}
}

39
src/main.rs Archivo normal
Ver fichero

@@ -0,0 +1,39 @@
use clap::{Parser, Subcommand};
use anyhow::Result;
use tracing::{info, error};
mod compiler;
mod lexer;
mod parser;
mod codegen;
mod optimizer;
mod linker;
mod targets;
mod cli;
mod error;
use compiler::Compiler;
use cli::Args;
#[tokio::main]
async fn main() -> Result<()> {
// Initialize tracing
tracing_subscriber::fmt::init();
let args = Args::parse();
info!("Starting ALECC compiler v{}", env!("CARGO_PKG_VERSION"));
let mut compiler = Compiler::new(args.clone())?;
match compiler.compile().await {
Ok(()) => {
info!("Compilation completed successfully");
Ok(())
}
Err(e) => {
error!("Compilation failed: {}", e);
std::process::exit(1);
}
}
}

265
src/optimizer.rs Archivo normal
Ver fichero

@@ -0,0 +1,265 @@
use crate::parser::Program;
use crate::error::{AleccError, Result};
pub struct Optimizer {
level: OptimizationLevel,
}
#[derive(Debug, Clone, Copy)]
pub enum OptimizationLevel {
None, // -O0
Basic, // -O1
Moderate, // -O2
Aggressive, // -O3
Size, // -Os
SizeZ, // -Oz
}
impl OptimizationLevel {
pub fn from_string(s: &str) -> Self {
match s {
"0" => OptimizationLevel::None,
"1" => OptimizationLevel::Basic,
"2" => OptimizationLevel::Moderate,
"3" => OptimizationLevel::Aggressive,
"s" => OptimizationLevel::Size,
"z" => OptimizationLevel::SizeZ,
_ => OptimizationLevel::None,
}
}
}
impl Optimizer {
pub fn new(level: OptimizationLevel) -> Self {
Self { level }
}
pub fn optimize(&mut self, program: &mut Program) -> Result<()> {
match self.level {
OptimizationLevel::None => {
// No optimization
Ok(())
}
OptimizationLevel::Basic => {
self.basic_optimizations(program)
}
OptimizationLevel::Moderate => {
self.basic_optimizations(program)?;
self.moderate_optimizations(program)
}
OptimizationLevel::Aggressive => {
self.basic_optimizations(program)?;
self.moderate_optimizations(program)?;
self.aggressive_optimizations(program)
}
OptimizationLevel::Size => {
self.basic_optimizations(program)?;
self.size_optimizations(program)
}
OptimizationLevel::SizeZ => {
self.basic_optimizations(program)?;
self.size_optimizations(program)?;
self.aggressive_size_optimizations(program)
}
}
}
fn basic_optimizations(&mut self, program: &mut Program) -> Result<()> {
// Dead code elimination
self.eliminate_dead_code(program)?;
// Constant folding
self.fold_constants(program)?;
// Basic strength reduction
self.basic_strength_reduction(program)?;
Ok(())
}
fn moderate_optimizations(&mut self, program: &mut Program) -> Result<()> {
// Loop optimizations
self.optimize_loops(program)?;
// Function inlining (basic)
self.inline_small_functions(program)?;
// Common subexpression elimination
self.eliminate_common_subexpressions(program)?;
Ok(())
}
fn aggressive_optimizations(&mut self, program: &mut Program) -> Result<()> {
// Advanced loop optimizations
self.advanced_loop_optimizations(program)?;
// Aggressive function inlining
self.aggressive_inlining(program)?;
// Inter-procedural optimizations
self.interprocedural_optimizations(program)?;
// Vectorization
self.auto_vectorization(program)?;
Ok(())
}
fn size_optimizations(&mut self, program: &mut Program) -> Result<()> {
// Prefer smaller code sequences
self.optimize_for_size(program)?;
// Merge identical functions
self.merge_identical_functions(program)?;
Ok(())
}
fn aggressive_size_optimizations(&mut self, program: &mut Program) -> Result<()> {
// More aggressive size optimizations that might impact performance
self.ultra_size_optimizations(program)?;
Ok(())
}
// Basic optimization implementations
fn eliminate_dead_code(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement dead code elimination
// - Remove unreachable code
// - Remove unused variables
// - Remove functions that are never called
Ok(())
}
fn fold_constants(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement constant folding
// - Evaluate constant expressions at compile time
// - Propagate constants through simple assignments
Ok(())
}
fn basic_strength_reduction(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement basic strength reduction
// - Replace multiplication by powers of 2 with shifts
// - Replace division by powers of 2 with shifts
// - Replace expensive operations with cheaper equivalents
Ok(())
}
fn optimize_loops(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement loop optimizations
// - Loop unrolling for small loops
// - Loop-invariant code motion
// - Strength reduction in loops
Ok(())
}
fn inline_small_functions(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement function inlining
// - Inline functions that are called only once
// - Inline very small functions
// - Consider call frequency and function size
Ok(())
}
fn eliminate_common_subexpressions(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement CSE
// - Identify repeated expressions
// - Store results in temporary variables
// - Reuse computed values
Ok(())
}
fn advanced_loop_optimizations(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement advanced loop optimizations
// - Loop fusion
// - Loop tiling
// - Loop interchange
Ok(())
}
fn aggressive_inlining(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement aggressive inlining
// - Inline more functions based on profiling data
// - Cross-module inlining
Ok(())
}
fn interprocedural_optimizations(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement IPO
// - Whole-program analysis
// - Cross-function optimizations
// - Global dead code elimination
Ok(())
}
fn auto_vectorization(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement auto-vectorization
// - Identify vectorizable loops
// - Generate SIMD instructions
// - Target-specific vector optimizations
Ok(())
}
fn optimize_for_size(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement size optimizations
// - Prefer smaller instruction sequences
// - Optimize for code density
Ok(())
}
fn merge_identical_functions(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement function merging
// - Identify functions with identical bodies
// - Merge them to reduce code size
Ok(())
}
fn ultra_size_optimizations(&mut self, _program: &mut Program) -> Result<()> {
// TODO: Implement ultra-aggressive size optimizations
// - Sacrifice performance for minimal size
// - Use compact calling conventions
Ok(())
}
}
// Additional optimization passes that can be applied independently
pub struct OptimizationPasses;
impl OptimizationPasses {
pub fn constant_propagation(_program: &mut Program) -> Result<()> {
// TODO: Implement constant propagation
Ok(())
}
pub fn register_allocation(_program: &mut Program) -> Result<()> {
// TODO: Implement register allocation
// - Graph coloring algorithm
// - Linear scan algorithm
// - Target-specific register constraints
Ok(())
}
pub fn peephole_optimization(_program: &mut Program) -> Result<()> {
// TODO: Implement peephole optimizations
// - Pattern matching on small instruction sequences
// - Replace with more efficient sequences
Ok(())
}
pub fn tail_call_optimization(_program: &mut Program) -> Result<()> {
// TODO: Implement tail call optimization
// - Convert tail calls to jumps
// - Eliminate stack frame overhead
Ok(())
}
pub fn branch_optimization(_program: &mut Program) -> Result<()> {
// TODO: Implement branch optimizations
// - Predict likely branches
// - Reorder code to improve branch prediction
// - Eliminate redundant branches
Ok(())
}
}

597
src/parser.rs Archivo normal
Ver fichero

@@ -0,0 +1,597 @@
use crate::lexer::{Token, TokenType};
use crate::error::{AleccError, Result};
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub enum Type {
Void,
Char,
Short,
Int,
Long,
Float,
Double,
Bool,
Pointer(Box<Type>),
Array(Box<Type>, Option<usize>),
Function {
return_type: Box<Type>,
parameters: Vec<Type>,
variadic: bool,
},
Struct {
name: String,
fields: Vec<(String, Type)>,
},
Union {
name: String,
fields: Vec<(String, Type)>,
},
Enum {
name: String,
variants: Vec<(String, i64)>,
},
Typedef(String, Box<Type>),
}
#[derive(Debug, Clone)]
pub enum Expression {
IntegerLiteral(i64),
FloatLiteral(f64),
StringLiteral(String),
CharLiteral(char),
BooleanLiteral(bool),
Identifier(String),
Binary {
left: Box<Expression>,
operator: BinaryOperator,
right: Box<Expression>,
},
Unary {
operator: UnaryOperator,
operand: Box<Expression>,
},
Call {
function: Box<Expression>,
arguments: Vec<Expression>,
},
Member {
object: Box<Expression>,
member: String,
is_arrow: bool,
},
Index {
array: Box<Expression>,
index: Box<Expression>,
},
Cast {
target_type: Type,
expression: Box<Expression>,
},
Sizeof(Type),
Assignment {
target: Box<Expression>,
operator: AssignmentOperator,
value: Box<Expression>,
},
Conditional {
condition: Box<Expression>,
then_expr: Box<Expression>,
else_expr: Box<Expression>,
},
}
#[derive(Debug, Clone)]
pub enum BinaryOperator {
Add, Subtract, Multiply, Divide, Modulo,
Equal, NotEqual, Less, Greater, LessEqual, GreaterEqual,
LogicalAnd, LogicalOr,
BitwiseAnd, BitwiseOr, BitwiseXor,
LeftShift, RightShift,
}
#[derive(Debug, Clone)]
pub enum UnaryOperator {
Plus, Minus, LogicalNot, BitwiseNot,
PreIncrement, PostIncrement,
PreDecrement, PostDecrement,
AddressOf, Dereference,
}
#[derive(Debug, Clone)]
pub enum AssignmentOperator {
Assign, PlusAssign, MinusAssign, MultiplyAssign, DivideAssign, ModuloAssign,
BitwiseAndAssign, BitwiseOrAssign, BitwiseXorAssign,
LeftShiftAssign, RightShiftAssign,
}
#[derive(Debug, Clone)]
pub enum Statement {
Expression(Expression),
Declaration {
name: String,
var_type: Type,
initializer: Option<Expression>,
},
Block(Vec<Statement>),
If {
condition: Expression,
then_stmt: Box<Statement>,
else_stmt: Option<Box<Statement>>,
},
While {
condition: Expression,
body: Box<Statement>,
},
For {
init: Option<Box<Statement>>,
condition: Option<Expression>,
increment: Option<Expression>,
body: Box<Statement>,
},
DoWhile {
body: Box<Statement>,
condition: Expression,
},
Switch {
expression: Expression,
cases: Vec<(Option<Expression>, Vec<Statement>)>,
},
Return(Option<Expression>),
Break,
Continue,
Goto(String),
Label(String),
}
#[derive(Debug, Clone)]
pub struct Function {
pub name: String,
pub return_type: Type,
pub parameters: Vec<(String, Type)>,
pub body: Statement,
pub is_inline: bool,
pub is_static: bool,
pub is_extern: bool,
}
#[derive(Debug, Clone)]
pub struct Program {
pub functions: Vec<Function>,
pub global_variables: Vec<(String, Type, Option<Expression>)>,
pub type_definitions: HashMap<String, Type>,
}
pub struct Parser {
tokens: Vec<Token>,
current: usize,
}
impl Parser {
pub fn new(tokens: Vec<Token>) -> Self {
Self { tokens, current: 0 }
}
pub fn parse(&mut self) -> Result<Program> {
let mut functions = Vec::new();
let mut global_variables = Vec::new();
let mut type_definitions = HashMap::new();
while !self.is_at_end() {
match self.parse_declaration()? {
Declaration::Function(func) => functions.push(func),
Declaration::Variable(name, var_type, init) => {
global_variables.push((name, var_type, init));
}
Declaration::TypeDef(name, type_def) => {
type_definitions.insert(name, type_def);
}
}
}
Ok(Program {
functions,
global_variables,
type_definitions,
})
}
fn parse_declaration(&mut self) -> Result<Declaration> {
if self.match_token(&TokenType::Typedef) {
self.parse_typedef()
} else {
let storage_class = self.parse_storage_class();
let base_type = self.parse_type()?;
if self.check(&TokenType::LeftParen) ||
(self.check(&TokenType::Identifier("".to_string())) && self.peek_ahead(1)?.token_type == TokenType::LeftParen) {
self.parse_function_declaration(storage_class, base_type)
} else {
self.parse_variable_declaration(storage_class, base_type)
}
}
}
fn parse_type(&mut self) -> Result<Type> {
let mut base_type = match &self.advance()?.token_type {
TokenType::Void => Type::Void,
TokenType::Char => Type::Char,
TokenType::Short => Type::Short,
TokenType::Int => Type::Int,
TokenType::Long => Type::Long,
TokenType::Float => Type::Float,
TokenType::Double => Type::Double,
TokenType::Bool => Type::Bool,
TokenType::Struct => self.parse_struct_type()?,
TokenType::Union => self.parse_union_type()?,
TokenType::Enum => self.parse_enum_type()?,
TokenType::Identifier(name) => {
// Could be a typedef name
Type::Typedef(name.clone(), Box::new(Type::Void)) // Placeholder
}
_ => {
return Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected type specifier".to_string(),
});
}
};
// Handle pointer declarators
while self.match_token(&TokenType::Multiply) {
base_type = Type::Pointer(Box::new(base_type));
}
Ok(base_type)
}
fn parse_struct_type(&mut self) -> Result<Type> {
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone()
} else {
return Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected struct name".to_string(),
});
};
let mut fields = Vec::new();
if self.match_token(&TokenType::LeftBrace) {
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
let field_type = self.parse_type()?;
let field_name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone()
} else {
return Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected field name".to_string(),
});
};
self.consume(&TokenType::Semicolon, "Expected ';' after field declaration")?;
fields.push((field_name, field_type));
}
self.consume(&TokenType::RightBrace, "Expected '}' after struct body")?;
}
Ok(Type::Struct { name, fields })
}
fn parse_union_type(&mut self) -> Result<Type> {
// Similar to struct parsing
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone()
} else {
return Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected union name".to_string(),
});
};
let mut fields = Vec::new();
if self.match_token(&TokenType::LeftBrace) {
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
let field_type = self.parse_type()?;
let field_name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone()
} else {
return Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected field name".to_string(),
});
};
self.consume(&TokenType::Semicolon, "Expected ';' after field declaration")?;
fields.push((field_name, field_type));
}
self.consume(&TokenType::RightBrace, "Expected '}' after union body")?;
}
Ok(Type::Union { name, fields })
}
fn parse_enum_type(&mut self) -> Result<Type> {
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone()
} else {
return Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected enum name".to_string(),
});
};
let mut variants = Vec::new();
let mut current_value = 0i64;
if self.match_token(&TokenType::LeftBrace) {
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
let variant_name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone()
} else {
return Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected enum variant name".to_string(),
});
};
if self.match_token(&TokenType::Assign) {
if let TokenType::IntegerLiteral(value) = &self.advance()?.token_type {
current_value = *value;
} else {
return Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected integer literal for enum value".to_string(),
});
}
}
variants.push((variant_name, current_value));
current_value += 1;
if !self.check(&TokenType::RightBrace) {
self.consume(&TokenType::Comma, "Expected ',' between enum variants")?;
}
}
self.consume(&TokenType::RightBrace, "Expected '}' after enum body")?;
}
Ok(Type::Enum { name, variants })
}
// Helper methods
fn current_token(&self) -> Result<&Token> {
self.tokens.get(self.current).ok_or_else(|| AleccError::ParseError {
line: 0,
column: 0,
message: "Unexpected end of input".to_string(),
})
}
fn advance(&mut self) -> Result<&Token> {
if !self.is_at_end() {
self.current += 1;
}
self.previous()
}
fn previous(&self) -> Result<&Token> {
self.tokens.get(self.current - 1).ok_or_else(|| AleccError::ParseError {
line: 0,
column: 0,
message: "No previous token".to_string(),
})
}
fn peek_ahead(&self, offset: usize) -> Result<&Token> {
self.tokens.get(self.current + offset).ok_or_else(|| AleccError::ParseError {
line: 0,
column: 0,
message: "Unexpected end of input".to_string(),
})
}
fn is_at_end(&self) -> bool {
self.current >= self.tokens.len() ||
matches!(self.tokens.get(self.current).map(|t| &t.token_type), Some(TokenType::Eof))
}
fn check(&self, token_type: &TokenType) -> bool {
if self.is_at_end() {
false
} else {
std::mem::discriminant(&self.current_token().unwrap().token_type) ==
std::mem::discriminant(token_type)
}
}
fn match_token(&mut self, token_type: &TokenType) -> bool {
if self.check(token_type) {
self.advance().unwrap();
true
} else {
false
}
}
fn consume(&mut self, token_type: &TokenType, message: &str) -> Result<&Token> {
if self.check(token_type) {
self.advance()
} else {
Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: message.to_string(),
})
}
}
// Placeholder implementations for missing methods
fn parse_storage_class(&mut self) -> StorageClass {
StorageClass::None // Simplified for now
}
fn parse_typedef(&mut self) -> Result<Declaration> {
let base_type = self.parse_type()?;
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone()
} else {
return Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected typedef name".to_string(),
});
};
self.consume(&TokenType::Semicolon, "Expected ';' after typedef")?;
Ok(Declaration::TypeDef(name, base_type))
}
fn parse_function_declaration(&mut self, _storage: StorageClass, return_type: Type) -> Result<Declaration> {
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone()
} else {
return Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected function name".to_string(),
});
};
self.consume(&TokenType::LeftParen, "Expected '(' after function name")?;
let mut parameters = Vec::new();
while !self.check(&TokenType::RightParen) && !self.is_at_end() {
let param_type = self.parse_type()?;
let param_name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone()
} else {
return Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected parameter name".to_string(),
});
};
parameters.push((param_name, param_type));
if !self.check(&TokenType::RightParen) {
self.consume(&TokenType::Comma, "Expected ',' between parameters")?;
}
}
self.consume(&TokenType::RightParen, "Expected ')' after parameters")?;
let body = if self.check(&TokenType::LeftBrace) {
self.parse_block_statement()?
} else {
self.consume(&TokenType::Semicolon, "Expected ';' after function declaration")?;
Statement::Block(Vec::new()) // Forward declaration
};
Ok(Declaration::Function(Function {
name,
return_type,
parameters,
body,
is_inline: false,
is_static: false,
is_extern: false,
}))
}
fn parse_variable_declaration(&mut self, _storage: StorageClass, var_type: Type) -> Result<Declaration> {
let name = if let TokenType::Identifier(name) = &self.advance()?.token_type {
name.clone()
} else {
return Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected variable name".to_string(),
});
};
let initializer = if self.match_token(&TokenType::Assign) {
Some(self.parse_expression()?)
} else {
None
};
self.consume(&TokenType::Semicolon, "Expected ';' after variable declaration")?;
Ok(Declaration::Variable(name, var_type, initializer))
}
fn parse_block_statement(&mut self) -> Result<Statement> {
self.consume(&TokenType::LeftBrace, "Expected '{'")?;
let mut statements = Vec::new();
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
statements.push(self.parse_statement()?);
}
self.consume(&TokenType::RightBrace, "Expected '}'")?;
Ok(Statement::Block(statements))
}
fn parse_statement(&mut self) -> Result<Statement> {
// Simplified statement parsing
if self.match_token(&TokenType::Return) {
let expr = if !self.check(&TokenType::Semicolon) {
Some(self.parse_expression()?)
} else {
None
};
self.consume(&TokenType::Semicolon, "Expected ';' after return")?;
Ok(Statement::Return(expr))
} else {
let expr = self.parse_expression()?;
self.consume(&TokenType::Semicolon, "Expected ';' after expression")?;
Ok(Statement::Expression(expr))
}
}
fn parse_expression(&mut self) -> Result<Expression> {
// Simplified expression parsing - just literals and identifiers for now
match &self.advance()?.token_type {
TokenType::IntegerLiteral(value) => Ok(Expression::IntegerLiteral(*value)),
TokenType::FloatLiteral(value) => Ok(Expression::FloatLiteral(*value)),
TokenType::StringLiteral(value) => Ok(Expression::StringLiteral(value.clone())),
TokenType::CharLiteral(value) => Ok(Expression::CharLiteral(*value)),
TokenType::Identifier(name) => Ok(Expression::Identifier(name.clone())),
_ => Err(AleccError::ParseError {
line: self.current_token()?.line,
column: self.current_token()?.column,
message: "Expected expression".to_string(),
}),
}
}
}
#[derive(Debug, Clone)]
enum Declaration {
Function(Function),
Variable(String, Type, Option<Expression>),
TypeDef(String, Type),
}
#[derive(Debug, Clone)]
enum StorageClass {
None,
Static,
Extern,
Auto,
Register,
}

232
src/targets.rs Archivo normal
Ver fichero

@@ -0,0 +1,232 @@
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Target {
I386,
Amd64,
Arm64,
}
impl Target {
pub fn from_string(s: &str) -> Option<Self> {
match s {
"i386" | "i686" | "x86" => Some(Target::I386),
"amd64" | "x86_64" | "x64" => Some(Target::Amd64),
"arm64" | "aarch64" => Some(Target::Arm64),
"native" => Some(Self::native()),
_ => None,
}
}
pub fn native() -> Self {
#[cfg(target_arch = "x86")]
return Target::I386;
#[cfg(target_arch = "x86_64")]
return Target::Amd64;
#[cfg(target_arch = "aarch64")]
return Target::Arm64;
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
return Target::Amd64; // Default fallback
}
pub fn pointer_size(&self) -> usize {
match self {
Target::I386 => 4,
Target::Amd64 => 8,
Target::Arm64 => 8,
}
}
pub fn alignment(&self) -> usize {
match self {
Target::I386 => 4,
Target::Amd64 => 8,
Target::Arm64 => 8,
}
}
pub fn as_str(&self) -> &'static str {
match self {
Target::I386 => "i386",
Target::Amd64 => "amd64",
Target::Arm64 => "arm64",
}
}
pub fn triple(&self) -> &'static str {
match self {
Target::I386 => "i386-unknown-linux-gnu",
Target::Amd64 => "x86_64-unknown-linux-gnu",
Target::Arm64 => "aarch64-unknown-linux-gnu",
}
}
pub fn assembler(&self) -> &'static str {
match self {
Target::I386 => "as --32",
Target::Amd64 => "as --64",
Target::Arm64 => "aarch64-linux-gnu-as",
}
}
pub fn linker(&self) -> &'static str {
match self {
Target::I386 => "ld -m elf_i386",
Target::Amd64 => "ld -m elf_x86_64",
Target::Arm64 => "aarch64-linux-gnu-ld",
}
}
pub fn object_format(&self) -> &'static str {
match self {
Target::I386 => "elf32",
Target::Amd64 => "elf64",
Target::Arm64 => "elf64",
}
}
pub fn calling_convention(&self) -> CallingConvention {
match self {
Target::I386 => CallingConvention::Cdecl,
Target::Amd64 => CallingConvention::SystemV,
Target::Arm64 => CallingConvention::Aapcs64,
}
}
pub fn register_names(&self) -> RegisterSet {
match self {
Target::I386 => RegisterSet::X86_32,
Target::Amd64 => RegisterSet::X86_64,
Target::Arm64 => RegisterSet::Aarch64,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum CallingConvention {
Cdecl, // x86-32
SystemV, // x86-64
Aapcs64, // ARM64
}
#[derive(Debug, Clone, Copy)]
pub enum RegisterSet {
X86_32,
X86_64,
Aarch64,
}
impl RegisterSet {
pub fn general_purpose_registers(&self) -> &'static [&'static str] {
match self {
RegisterSet::X86_32 => &["eax", "ebx", "ecx", "edx", "esi", "edi"],
RegisterSet::X86_64 => &["rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"],
RegisterSet::Aarch64 => &["x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28"],
}
}
pub fn parameter_registers(&self) -> &'static [&'static str] {
match self {
RegisterSet::X86_32 => &[], // Parameters passed on stack
RegisterSet::X86_64 => &["rdi", "rsi", "rdx", "rcx", "r8", "r9"],
RegisterSet::Aarch64 => &["x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7"],
}
}
pub fn return_register(&self) -> &'static str {
match self {
RegisterSet::X86_32 => "eax",
RegisterSet::X86_64 => "rax",
RegisterSet::Aarch64 => "x0",
}
}
pub fn stack_pointer(&self) -> &'static str {
match self {
RegisterSet::X86_32 => "esp",
RegisterSet::X86_64 => "rsp",
RegisterSet::Aarch64 => "sp",
}
}
pub fn frame_pointer(&self) -> &'static str {
match self {
RegisterSet::X86_32 => "ebp",
RegisterSet::X86_64 => "rbp",
RegisterSet::Aarch64 => "x29",
}
}
}
pub struct TargetInfo {
pub target: Target,
pub endianness: Endianness,
pub word_size: usize,
pub max_align: usize,
pub supports_pic: bool,
pub supports_pie: bool,
}
#[derive(Debug, Clone, Copy)]
pub enum Endianness {
Little,
Big,
}
impl TargetInfo {
pub fn new(target: Target) -> Self {
let (word_size, max_align) = match target {
Target::I386 => (4, 4),
Target::Amd64 => (8, 8),
Target::Arm64 => (8, 16),
};
Self {
target,
endianness: Endianness::Little, // All supported targets are little-endian
word_size,
max_align,
supports_pic: true,
supports_pie: true,
}
}
pub fn size_of_type(&self, type_name: &str) -> Option<usize> {
match type_name {
"char" | "signed char" | "unsigned char" => Some(1),
"short" | "unsigned short" => Some(2),
"int" | "unsigned int" => Some(4),
"long" | "unsigned long" => Some(self.word_size),
"long long" | "unsigned long long" => Some(8),
"float" => Some(4),
"double" => Some(8),
"long double" => match self.target {
Target::I386 => Some(12),
Target::Amd64 => Some(16),
Target::Arm64 => Some(16),
},
"void*" | "size_t" | "ptrdiff_t" => Some(self.word_size),
_ => None,
}
}
pub fn align_of_type(&self, type_name: &str) -> Option<usize> {
match type_name {
"char" | "signed char" | "unsigned char" => Some(1),
"short" | "unsigned short" => Some(2),
"int" | "unsigned int" => Some(4),
"long" | "unsigned long" => Some(self.word_size),
"long long" | "unsigned long long" => Some(8),
"float" => Some(4),
"double" => Some(8),
"long double" => match self.target {
Target::I386 => Some(4),
Target::Amd64 => Some(16),
Target::Arm64 => Some(16),
},
"void*" | "size_t" | "ptrdiff_t" => Some(self.word_size),
_ => None,
}
}
}