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

Ver fichero

@@ -1,9 +1,9 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use alecc::lexer::Lexer;
use alecc::parser::Parser;
use alecc::codegen::CodeGenerator;
use alecc::optimizer::{Optimizer, OptimizationLevel};
use alecc::lexer::Lexer;
use alecc::optimizer::{OptimizationLevel, Optimizer};
use alecc::parser::Parser;
use alecc::targets::Target;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
const SIMPLE_C_CODE: &str = r#"
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);

Ver fichero

@@ -1,6 +1,8 @@
use crate::parser::{Program, Function, Expression, Statement, Type, BinaryOperator, UnaryOperator};
use crate::targets::Target;
use crate::error::{AleccError, Result};
use crate::parser::{
BinaryOperator, Expression, Function, Program, Statement, Type, UnaryOperator,
};
use crate::targets::Target;
use std::collections::HashMap;
pub struct CodeGenerator {
@@ -165,7 +167,8 @@ impl CodeGenerator {
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 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 => {
@@ -185,14 +188,18 @@ impl CodeGenerator {
let param_offset = -(i as i32 + 1) * 8;
if i < param_registers.len() {
// 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 {
// Parameter passed on stack
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 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 => {
@@ -217,7 +224,8 @@ impl CodeGenerator {
self.emit_line(&format!(" ldr x9, [x29, #{}]", stack_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,7 +288,11 @@ impl CodeGenerator {
Statement::Expression(expr) => {
self.generate_expression(expr)?;
}
Statement::Declaration { name, var_type, initializer } => {
Statement::Declaration {
name,
var_type,
initializer,
} => {
// Calculate space needed based on type
let size = match var_type {
Type::Array(_, Some(length)) => length * 8, // Assuming 8-byte elements
@@ -300,10 +312,16 @@ impl CodeGenerator {
// Store the value in the local variable slot
match self.target {
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 => {
self.emit_line(&format!(" mov DWORD PTR [ebp + {}], eax", var_offset));
self.emit_line(&format!(
" mov DWORD PTR [ebp + {}], eax",
var_offset
));
}
Target::Arm64 => {
self.emit_line(&format!(" str x0, [x29, #{}]", var_offset));
@@ -335,7 +353,11 @@ impl CodeGenerator {
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 end_label = self.new_label("endif");
@@ -372,7 +394,12 @@ impl CodeGenerator {
self.emit_line(&format!("{}:", end_label));
}
Statement::For { init, condition, increment, body } => {
Statement::For {
init,
condition,
increment,
body,
} => {
// Generate initialization
if let Some(init_stmt) = init {
self.generate_statement(init_stmt)?;
@@ -412,8 +439,7 @@ impl CodeGenerator {
fn generate_expression(&mut self, expression: &Expression) -> Result<()> {
match expression {
Expression::IntegerLiteral(value) => {
match self.target {
Expression::IntegerLiteral(value) => match self.target {
Target::I386 => {
self.emit_line(&format!(" mov eax, {}", value));
}
@@ -423,8 +449,7 @@ impl CodeGenerator {
Target::Arm64 => {
self.emit_line(&format!(" mov x0, #{}", value));
}
}
}
},
Expression::StringLiteral(value) => {
let label = self.get_string_literal_label(value);
match self.target {
@@ -442,7 +467,11 @@ impl CodeGenerator {
}
Expression::Identifier(name) => {
// 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
match self.target {
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
match self.target {
Target::I386 => {
@@ -502,7 +534,11 @@ impl CodeGenerator {
// Ensure stack alignment before function call
// Stack must be 16-byte aligned before 'call' instruction
// Since 'call' pushes 8 bytes (return address), we need stack to be 8 bytes off 16-byte boundary
let stack_args = if arguments.len() > param_registers.len() { arguments.len() - param_registers.len() } else { 0 };
let stack_args = if arguments.len() > param_registers.len() {
arguments.len() - param_registers.len()
} else {
0
};
let mut stack_cleanup_size = 0;
// Handle stack arguments if any
@@ -526,7 +562,8 @@ impl CodeGenerator {
}
// 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() {
self.generate_expression(arg)?;
self.emit_line(&format!(" mov {}, rax", param_registers[i]));
@@ -576,19 +613,30 @@ impl CodeGenerator {
Target::Amd64 => {
// Clean up stack using stored cleanup size
if self.last_call_stack_cleanup > 0 {
self.emit_line(&format!(" add rsp, {}", self.last_call_stack_cleanup));
self.emit_line(&format!(
" add rsp, {}",
self.last_call_stack_cleanup
));
}
}
Target::Arm64 => {
// 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 {
self.emit_line(&format!(" add sp, sp, #{}", stack_args * 16));
}
}
}
}
Expression::Binary { left, operator, right } => {
Expression::Binary {
left,
operator,
right,
} => {
// Generate binary operations
// First generate right operand and save it
self.generate_expression(right)?;
@@ -626,7 +674,10 @@ impl CodeGenerator {
}
_ => {
return Err(AleccError::CodegenError {
message: format!("Binary operator {:?} not implemented for i386", operator),
message: format!(
"Binary operator {:?} not implemented for i386",
operator
),
});
}
}
@@ -722,7 +773,10 @@ impl CodeGenerator {
}
_ => {
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) {
match self.target {
Target::I386 => {
self.emit_line(&format!(" inc DWORD PTR [ebp + {}]", offset));
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
self.emit_line(&format!(
" inc DWORD PTR [ebp + {}]",
offset
));
self.emit_line(&format!(
" mov eax, DWORD PTR [ebp + {}]",
offset
));
}
Target::Amd64 => {
self.emit_line(&format!(" inc QWORD PTR [rbp + {}]", offset));
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
self.emit_line(&format!(
" inc QWORD PTR [rbp + {}]",
offset
));
self.emit_line(&format!(
" mov rax, QWORD PTR [rbp + {}]",
offset
));
}
Target::Arm64 => {
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
@@ -808,7 +874,8 @@ impl CodeGenerator {
}
} else {
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) {
match self.target {
Target::I386 => {
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
self.emit_line(&format!(" inc DWORD PTR [ebp + {}]", offset));
self.emit_line(&format!(
" mov eax, DWORD PTR [ebp + {}]",
offset
));
self.emit_line(&format!(
" inc DWORD PTR [ebp + {}]",
offset
));
}
Target::Amd64 => {
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
self.emit_line(&format!(" inc QWORD PTR [rbp + {}]", offset));
self.emit_line(&format!(
" mov rax, QWORD PTR [rbp + {}]",
offset
));
self.emit_line(&format!(
" inc QWORD PTR [rbp + {}]",
offset
));
}
Target::Arm64 => {
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
@@ -839,7 +918,8 @@ impl CodeGenerator {
}
} else {
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) {
match self.target {
Target::I386 => {
self.emit_line(&format!(" dec DWORD PTR [ebp + {}]", offset));
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
self.emit_line(&format!(
" dec DWORD PTR [ebp + {}]",
offset
));
self.emit_line(&format!(
" mov eax, DWORD PTR [ebp + {}]",
offset
));
}
Target::Amd64 => {
self.emit_line(&format!(" dec QWORD PTR [rbp + {}]", offset));
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
self.emit_line(&format!(
" dec QWORD PTR [rbp + {}]",
offset
));
self.emit_line(&format!(
" mov rax, QWORD PTR [rbp + {}]",
offset
));
}
Target::Arm64 => {
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
@@ -869,7 +961,8 @@ impl CodeGenerator {
}
} else {
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) {
match self.target {
Target::I386 => {
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
self.emit_line(&format!(" dec DWORD PTR [ebp + {}]", offset));
self.emit_line(&format!(
" mov eax, DWORD PTR [ebp + {}]",
offset
));
self.emit_line(&format!(
" dec DWORD PTR [ebp + {}]",
offset
));
}
Target::Amd64 => {
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
self.emit_line(&format!(" dec QWORD PTR [rbp + {}]", offset));
self.emit_line(&format!(
" mov rax, QWORD PTR [rbp + {}]",
offset
));
self.emit_line(&format!(
" dec QWORD PTR [rbp + {}]",
offset
));
}
Target::Arm64 => {
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
@@ -900,7 +1005,8 @@ impl CodeGenerator {
}
} else {
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(),
});
}
}
@@ -991,7 +1097,11 @@ impl CodeGenerator {
});
}
}
Expression::Assignment { target, operator, value } => {
Expression::Assignment {
target,
operator,
value,
} => {
// Handle compound assignment operators
match operator {
crate::parser::AssignmentOperator::Assign => {
@@ -1105,7 +1215,8 @@ impl CodeGenerator {
}
} else {
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(())
@@ -1144,7 +1255,8 @@ impl CodeGenerator {
}
} else {
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(())
@@ -1209,7 +1321,8 @@ impl CodeGenerator {
label.clone()
} else {
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
}
}
@@ -1248,7 +1361,11 @@ impl CodeGenerator {
}
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_statement(then_stmt)?;
if let Some(else_statement) = else_stmt {
@@ -1261,7 +1378,12 @@ impl CodeGenerator {
self.collect_string_literals_from_statement(body)?;
Ok(())
}
Statement::For { init, condition, increment, body } => {
Statement::For {
init,
condition,
increment,
body,
} => {
if let Some(init_stmt) = init {
self.collect_string_literals_from_statement(init_stmt)?;
}
@@ -1280,7 +1402,7 @@ impl CodeGenerator {
}
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)?;
Ok(())
}
Expression::Call { function, arguments } => {
Expression::Call {
function,
arguments,
} => {
self.collect_string_literals_from_expression(function)?;
for arg in arguments {
self.collect_string_literals_from_expression(arg)?;
@@ -1311,7 +1436,7 @@ impl CodeGenerator {
self.collect_string_literals_from_expression(value)?;
Ok(())
}
_ => Ok(()) // Other expression types don't contain string literals
_ => Ok(()), // Other expression types don't contain string literals
}
}
}

Ver fichero

@@ -1,15 +1,15 @@
use crate::cli::Args;
use crate::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 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::process::Command;
use tokio::fs;
use tracing::{info, debug, warn};
use tracing::{debug, info, warn};
pub struct Compiler {
args: Args,
@@ -19,10 +19,9 @@ pub struct Compiler {
impl Compiler {
pub fn new(args: Args) -> Result<Self> {
let target = Target::from_string(&args.target).ok_or_else(|| {
AleccError::UnsupportedTarget {
let target =
Target::from_string(&args.target).ok_or_else(|| AleccError::UnsupportedTarget {
target: args.target.clone(),
}
})?;
Ok(Self {
@@ -39,9 +38,11 @@ impl Compiler {
});
}
info!("Compiling {} files for target {}",
info!(
"Compiling {} files for target {}",
self.args.input_files.len(),
self.target.as_str());
self.target.as_str()
);
let mut object_files = Vec::new();
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 {
debug!("Processing file: {}", input_file.display());
let extension = input_file.extension()
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 {
if !self.args.compile_only
&& !self.args.assembly_only
&& !self.args.preprocess_only
{
object_files.push(obj_file);
}
}
@@ -71,10 +76,15 @@ impl Compiler {
object_files.push(input_file.clone());
}
_ => {
warn!("Unknown file extension for {}, treating as C source",
input_file.display());
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 {
if !self.args.compile_only
&& !self.args.assembly_only
&& !self.args.preprocess_only
{
object_files.push(obj_file);
}
}
@@ -96,19 +106,20 @@ impl Compiler {
info!("Compiling source file: {}", input_file.display());
// Read source file
let source = fs::read_to_string(input_file).await.map_err(|_e| {
AleccError::FileNotFound {
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)
})?;
fs::write(&output_path, preprocessed)
.await
.map_err(|e| AleccError::IoError(e))?;
return Ok(output_path);
} else {
self.preprocess(&source, input_file).await?
@@ -136,17 +147,17 @@ impl Compiler {
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)
})?;
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)
})?;
fs::write(&asm_path, assembly)
.await
.map_err(|e| AleccError::IoError(e))?;
// Assemble
let obj_path = self.assemble_file(&asm_path).await?;
@@ -330,8 +341,9 @@ impl Compiler {
}
command.args(&[
"-o", &obj_path.to_string_lossy(),
&asm_file.to_string_lossy()
"-o",
&obj_path.to_string_lossy(),
&asm_file.to_string_lossy(),
]);
let output = command.output().map_err(|e| AleccError::CodegenError {
@@ -401,20 +413,26 @@ impl Compiler {
if let Some(ref output) = self.args.output {
Ok(output.clone())
} else {
let stem = input_file.file_stem()
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)))
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_{}_{}.{}",
let temp_path = std::env::temp_dir().join(format!(
"alecc_{}_{}.{}",
std::process::id(),
self.temp_files.len(),
extension));
extension
));
self.temp_files.push(temp_path.clone());
Ok(temp_path)
}
@@ -423,8 +441,11 @@ impl Compiler {
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);
warn!(
"Failed to remove temporary file {}: {}",
temp_file.display(),
e
);
}
}
}

Ver fichero

@@ -12,36 +12,116 @@ pub enum TokenType {
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,
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,
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,
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,
LeftParen,
RightParen,
LeftBrace,
RightBrace,
LeftBracket,
RightBracket,
Semicolon,
Comma,
Ellipsis, // ...
// Preprocessor
Hash, HashHash,
Hash,
HashHash,
// Special
Eof,

Ver fichero

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

Ver fichero

@@ -1,5 +1,5 @@
use crate::targets::Target;
use crate::error::{AleccError, Result};
use crate::targets::Target;
use std::path::{Path, PathBuf};
use std::process::Command;
@@ -238,10 +238,7 @@ impl Linker {
"/usr/lib64",
"/lib64",
],
Target::Arm64 => vec![
"/usr/lib/aarch64-linux-gnu",
"/lib/aarch64-linux-gnu",
],
Target::Arm64 => vec!["/usr/lib/aarch64-linux-gnu", "/lib/aarch64-linux-gnu"],
};
for path in lib_paths {

Ver fichero

@@ -1,19 +1,19 @@
use clap::Parser;
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 codegen;
mod compiler;
mod error;
mod lexer;
mod linker;
mod optimizer;
mod parser;
mod targets;
use compiler::Compiler;
use cli::Args;
use compiler::Compiler;
#[tokio::main]
async fn main() -> Result<()> {

Ver fichero

@@ -1,5 +1,5 @@
use crate::parser::Program;
use crate::error::Result;
use crate::parser::Program;
pub struct Optimizer {
level: OptimizationLevel,
@@ -40,9 +40,7 @@ impl Optimizer {
// No optimization
Ok(())
}
OptimizationLevel::Basic => {
self.basic_optimizations(program)
}
OptimizationLevel::Basic => self.basic_optimizations(program),
OptimizationLevel::Moderate => {
self.basic_optimizations(program)?;
self.moderate_optimizations(program)

Ver fichero

@@ -1,5 +1,5 @@
use crate::lexer::{Token, TokenType};
use crate::error::{AleccError, Result};
use crate::lexer::{Token, TokenType};
use std::collections::HashMap;
#[derive(Debug, Clone)]
@@ -97,30 +97,59 @@ pub enum 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,
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,
Plus,
Minus,
LogicalNot,
BitwiseNot,
PreIncrement,
PostIncrement,
PreDecrement,
PostDecrement,
AddressOf,
Dereference,
}
#[derive(Debug, Clone)]
pub enum AssignmentOperator {
Assign, PlusAssign, MinusAssign, MultiplyAssign, DivideAssign,
#[allow(dead_code)] ModuloAssign,
#[allow(dead_code)] BitwiseAndAssign,
#[allow(dead_code)] BitwiseOrAssign,
#[allow(dead_code)] BitwiseXorAssign,
#[allow(dead_code)] LeftShiftAssign,
#[allow(dead_code)] RightShiftAssign,
Assign,
PlusAssign,
MinusAssign,
MultiplyAssign,
DivideAssign,
#[allow(dead_code)]
ModuloAssign,
#[allow(dead_code)]
BitwiseAndAssign,
#[allow(dead_code)]
BitwiseOrAssign,
#[allow(dead_code)]
BitwiseXorAssign,
#[allow(dead_code)]
LeftShiftAssign,
#[allow(dead_code)]
RightShiftAssign,
}
#[derive(Debug, Clone)]
@@ -236,8 +265,10 @@ impl Parser {
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) {
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)
@@ -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));
}
@@ -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));
}
@@ -377,7 +414,8 @@ impl Parser {
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 {
let variant_name = if let TokenType::Identifier(name) = &self.advance()?.token_type
{
name.clone()
} else {
return Err(AleccError::ParseError {
@@ -415,7 +453,9 @@ impl Parser {
// Helper methods
fn current_token(&self) -> Result<&Token> {
self.tokens.get(self.current).ok_or_else(|| AleccError::ParseError {
self.tokens
.get(self.current)
.ok_or_else(|| AleccError::ParseError {
line: 0,
column: 0,
message: "Unexpected end of input".to_string(),
@@ -445,7 +485,9 @@ impl Parser {
}
fn previous(&self) -> Result<&Token> {
self.tokens.get(self.current - 1).ok_or_else(|| AleccError::ParseError {
self.tokens
.get(self.current - 1)
.ok_or_else(|| AleccError::ParseError {
line: 0,
column: 0,
message: "No previous token".to_string(),
@@ -453,7 +495,9 @@ impl Parser {
}
fn peek_ahead(&self, offset: usize) -> Result<&Token> {
self.tokens.get(self.current + offset).ok_or_else(|| AleccError::ParseError {
self.tokens
.get(self.current + offset)
.ok_or_else(|| AleccError::ParseError {
line: 0,
column: 0,
message: "Unexpected end of input".to_string(),
@@ -461,16 +505,19 @@ impl Parser {
}
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))
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)
std::mem::discriminant(&self.current_token().unwrap().token_type)
== std::mem::discriminant(token_type)
}
}
@@ -526,7 +573,11 @@ impl Parser {
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 {
name.clone()
} else {
@@ -572,7 +623,10 @@ impl Parser {
self.advance()?; // Consume the LeftBrace
self.parse_block_statement()?
} else {
self.consume(&TokenType::Semicolon, "Expected ';' after function declaration")?;
self.consume(
&TokenType::Semicolon,
"Expected ';' after function 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 {
name.clone()
} else {
@@ -605,7 +663,10 @@ impl Parser {
None
};
self.consume(&TokenType::Semicolon, "Expected ';' after variable declaration")?;
self.consume(
&TokenType::Semicolon,
"Expected ';' after variable declaration",
)?;
Ok(Declaration::Variable(name, var_type, initializer))
}
@@ -676,7 +737,10 @@ impl Parser {
None
};
self.consume(&TokenType::Semicolon, "Expected ';' after variable declaration")?;
self.consume(
&TokenType::Semicolon,
"Expected ';' after variable declaration",
)?;
Ok(Statement::Declaration {
name,
@@ -757,10 +821,18 @@ impl Parser {
}
fn is_type(&self, token_type: &TokenType) -> bool {
matches!(token_type,
TokenType::Int | TokenType::Float | TokenType::Double |
TokenType::Char | TokenType::Void | TokenType::Short |
TokenType::Long | TokenType::Signed | TokenType::Unsigned)
matches!(
token_type,
TokenType::Int
| TokenType::Float
| TokenType::Double
| TokenType::Char
| TokenType::Void
| TokenType::Short
| TokenType::Long
| TokenType::Signed
| TokenType::Unsigned
)
}
fn parse_expression(&mut self) -> Result<Expression> {
@@ -913,8 +985,12 @@ impl Parser {
fn parse_comparison(&mut self) -> Result<Expression> {
let mut expr = self.parse_shift()?;
while self.match_tokens(&[TokenType::Greater, TokenType::GreaterEqual,
TokenType::Less, TokenType::LessEqual]) {
while self.match_tokens(&[
TokenType::Greater,
TokenType::GreaterEqual,
TokenType::Less,
TokenType::LessEqual,
]) {
let operator = match self.previous()?.token_type {
TokenType::Greater => BinaryOperator::Greater,
TokenType::GreaterEqual => BinaryOperator::GreaterEqual,
@@ -995,7 +1071,16 @@ impl Parser {
}
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 {
TokenType::LogicalNot => UnaryOperator::LogicalNot,
TokenType::Minus => UnaryOperator::Minus,

Ver fichero

@@ -131,8 +131,15 @@ 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"],
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",
],
}
}

Ver fichero

@@ -1,11 +1,11 @@
#[cfg(test)]
mod tests {
use alecc::cli::Args;
use alecc::codegen::CodeGenerator;
use alecc::compiler::Compiler;
use alecc::lexer::{Lexer, TokenType};
use alecc::parser::Parser;
use alecc::codegen::CodeGenerator;
use alecc::targets::Target;
use alecc::compiler::Compiler;
use alecc::cli::Args;
use std::path::PathBuf;
#[test]
@@ -24,7 +24,10 @@ mod tests {
let mut lexer = Lexer::new(input);
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[2].token_type, TokenType::CharLiteral('a')));
assert!(matches!(tokens[3].token_type, TokenType::StringLiteral(_)));
@@ -51,7 +54,8 @@ mod tests {
let tokens = lexer.tokenize().unwrap();
// Comments should be filtered out
let identifier_count = tokens.iter()
let identifier_count = tokens
.iter()
.filter(|t| matches!(t.token_type, TokenType::Identifier(_)))
.count();
assert_eq!(identifier_count, 2); // x and y