298
src/codegen.rs
298
src/codegen.rs
@@ -1,4 +1,4 @@
|
|||||||
use crate::parser::{Program, Function, Expression, Statement, Type};
|
use crate::parser::{Program, Function, Expression, Statement, Type, BinaryOperator};
|
||||||
use crate::targets::Target;
|
use crate::targets::Target;
|
||||||
use crate::error::{AleccError, Result};
|
use crate::error::{AleccError, Result};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -8,6 +8,7 @@ pub struct CodeGenerator {
|
|||||||
output: String,
|
output: String,
|
||||||
label_counter: usize,
|
label_counter: usize,
|
||||||
string_literals: HashMap<String, String>,
|
string_literals: HashMap<String, String>,
|
||||||
|
current_function_params: Vec<(String, i32)>, // (name, stack_offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CodeGenerator {
|
impl CodeGenerator {
|
||||||
@@ -17,6 +18,7 @@ impl CodeGenerator {
|
|||||||
output: String::new(),
|
output: String::new(),
|
||||||
label_counter: 0,
|
label_counter: 0,
|
||||||
string_literals: HashMap::new(),
|
string_literals: HashMap::new(),
|
||||||
|
current_function_params: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,9 +51,35 @@ impl CodeGenerator {
|
|||||||
self.generate_function(function)?;
|
self.generate_function(function)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate _start entry point
|
||||||
|
self.generate_start_function()?;
|
||||||
|
|
||||||
Ok(self.output.clone())
|
Ok(self.output.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_start_function(&mut self) -> Result<()> {
|
||||||
|
self.emit_line("");
|
||||||
|
self.emit_line(".globl _start");
|
||||||
|
self.emit_line("_start:");
|
||||||
|
|
||||||
|
// Set up stack and call main
|
||||||
|
self.emit_line(" push rbp");
|
||||||
|
self.emit_line(" mov rbp, rsp");
|
||||||
|
|
||||||
|
// Reserve space for temporary operations (prevents stack corruption)
|
||||||
|
self.emit_line(" sub rsp, 128");
|
||||||
|
|
||||||
|
// Call main function
|
||||||
|
self.emit_line(" call main");
|
||||||
|
|
||||||
|
// Exit syscall with main's return value
|
||||||
|
self.emit_line(" mov rdi, rax"); // exit status = main's return value
|
||||||
|
self.emit_line(" mov rax, 60"); // sys_exit syscall number
|
||||||
|
self.emit_line(" syscall"); // invoke syscall
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn emit_header(&mut self) {
|
fn emit_header(&mut self) {
|
||||||
match self.target {
|
match self.target {
|
||||||
Target::I386 => {
|
Target::I386 => {
|
||||||
@@ -59,7 +87,6 @@ impl CodeGenerator {
|
|||||||
self.emit_line(".intel_syntax noprefix");
|
self.emit_line(".intel_syntax noprefix");
|
||||||
}
|
}
|
||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
self.emit_line(".arch x86_64");
|
|
||||||
self.emit_line(".intel_syntax noprefix");
|
self.emit_line(".intel_syntax noprefix");
|
||||||
}
|
}
|
||||||
Target::Arm64 => {
|
Target::Arm64 => {
|
||||||
@@ -73,6 +100,9 @@ impl CodeGenerator {
|
|||||||
self.emit_line(&format!(".globl {}", function.name));
|
self.emit_line(&format!(".globl {}", function.name));
|
||||||
self.emit_line(&format!("{}:", function.name));
|
self.emit_line(&format!("{}:", function.name));
|
||||||
|
|
||||||
|
// Set up parameter tracking
|
||||||
|
self.current_function_params.clear();
|
||||||
|
|
||||||
// Function prologue
|
// Function prologue
|
||||||
self.emit_function_prologue(&function.parameters)?;
|
self.emit_function_prologue(&function.parameters)?;
|
||||||
|
|
||||||
@@ -92,28 +122,63 @@ impl CodeGenerator {
|
|||||||
self.emit_line(" push ebp");
|
self.emit_line(" push ebp");
|
||||||
self.emit_line(" mov ebp, esp");
|
self.emit_line(" mov ebp, esp");
|
||||||
|
|
||||||
// Reserve space for local variables (simplified)
|
// Reserve space for parameters + 128 bytes for temporaries
|
||||||
let stack_space = parameters.len() * 4; // Simplified calculation
|
let stack_space = parameters.len() * 4 + 128;
|
||||||
if stack_space > 0 {
|
self.emit_line(&format!(" sub esp, {}", stack_space));
|
||||||
self.emit_line(&format!(" sub esp, {}", stack_space));
|
|
||||||
|
// Store parameters from stack (i386 calling convention)
|
||||||
|
for (i, (name, _)) in parameters.iter().enumerate() {
|
||||||
|
let param_offset = -(i as i32 + 1) * 4;
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Target::Amd64 => {
|
Target::Amd64 => {
|
||||||
self.emit_line(" push rbp");
|
self.emit_line(" push rbp");
|
||||||
self.emit_line(" mov rbp, rsp");
|
self.emit_line(" mov rbp, rsp");
|
||||||
|
|
||||||
let stack_space = parameters.len() * 8;
|
// Reserve space for parameters + 128 bytes for temporaries
|
||||||
if stack_space > 0 {
|
let stack_space = parameters.len() * 8 + 128;
|
||||||
self.emit_line(&format!(" sub rsp, {}", stack_space));
|
self.emit_line(&format!(" sub rsp, {}", stack_space));
|
||||||
|
|
||||||
|
// Store parameters from registers (x86_64 calling convention)
|
||||||
|
let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||||
|
for (i, (name, _)) in parameters.iter().enumerate() {
|
||||||
|
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]));
|
||||||
|
} 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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Target::Arm64 => {
|
Target::Arm64 => {
|
||||||
self.emit_line(" stp x29, x30, [sp, #-16]!");
|
self.emit_line(" stp x29, x30, [sp, #-16]!");
|
||||||
self.emit_line(" mov x29, sp");
|
self.emit_line(" mov x29, sp");
|
||||||
|
|
||||||
let stack_space = (parameters.len() * 8 + 15) & !15; // 16-byte aligned
|
let stack_space = (parameters.len() * 8 + 128 + 15) & !15; // 16-byte aligned
|
||||||
if stack_space > 0 {
|
self.emit_line(&format!(" sub sp, sp, #{}", stack_space));
|
||||||
self.emit_line(&format!(" sub sp, sp, #{}", stack_space));
|
|
||||||
|
// Store parameters from registers (ARM64 calling convention)
|
||||||
|
for (i, (name, _)) in parameters.iter().enumerate() {
|
||||||
|
let param_offset = -(i as i32 + 1) * 8;
|
||||||
|
if i < 8 {
|
||||||
|
// Parameter passed in register x0-x7
|
||||||
|
self.emit_line(&format!(" str x{}, [x29, #{}]", i, param_offset));
|
||||||
|
} else {
|
||||||
|
// Parameter passed on stack
|
||||||
|
let stack_offset = 16 + (i - 8) as i32 * 8;
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,26 +305,77 @@ impl CodeGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Identifier(name) => {
|
Expression::Identifier(name) => {
|
||||||
// Load variable (simplified - assumes it's a parameter or global)
|
// Check if it's a function parameter first
|
||||||
match self.target {
|
if let Some((_, offset)) = self.current_function_params.iter().find(|(param_name, _)| param_name == name) {
|
||||||
Target::I386 => {
|
// Load parameter from stack
|
||||||
self.emit_line(&format!(" mov eax, DWORD PTR [{}]", name));
|
match self.target {
|
||||||
|
Target::I386 => {
|
||||||
|
self.emit_line(&format!(" mov eax, DWORD PTR [ebp + {}]", offset));
|
||||||
|
}
|
||||||
|
Target::Amd64 => {
|
||||||
|
self.emit_line(&format!(" mov rax, QWORD PTR [rbp + {}]", offset));
|
||||||
|
}
|
||||||
|
Target::Arm64 => {
|
||||||
|
self.emit_line(&format!(" ldr x0, [x29, #{}]", offset));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Target::Amd64 => {
|
} else {
|
||||||
self.emit_line(&format!(" mov rax, QWORD PTR [{}]", name));
|
// Load global variable
|
||||||
}
|
match self.target {
|
||||||
Target::Arm64 => {
|
Target::I386 => {
|
||||||
self.emit_line(&format!(" adrp x1, {}", name));
|
self.emit_line(&format!(" mov eax, DWORD PTR [{}]", name));
|
||||||
self.emit_line(&format!(" add x1, x1, :lo12:{}", name));
|
}
|
||||||
self.emit_line(" ldr x0, [x1]");
|
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 } => {
|
Expression::Call { function, arguments } => {
|
||||||
// Generate arguments in reverse order
|
// Generate arguments and place in calling convention registers/stack
|
||||||
for (i, arg) in arguments.iter().enumerate().rev() {
|
match self.target {
|
||||||
self.generate_expression(arg)?;
|
Target::I386 => {
|
||||||
self.push_argument(i)?;
|
// i386: push arguments in reverse order
|
||||||
|
for arg in arguments.iter().rev() {
|
||||||
|
self.generate_expression(arg)?;
|
||||||
|
self.emit_line(" push eax");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Target::Amd64 => {
|
||||||
|
// x86_64: first 6 args in registers, rest on stack
|
||||||
|
let param_registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||||
|
|
||||||
|
// Generate arguments and store in registers/stack
|
||||||
|
for (i, arg) in arguments.iter().enumerate() {
|
||||||
|
self.generate_expression(arg)?;
|
||||||
|
if i < param_registers.len() {
|
||||||
|
// Move to parameter register
|
||||||
|
self.emit_line(&format!(" mov {}, rax", param_registers[i]));
|
||||||
|
} else {
|
||||||
|
// Push to stack (reverse order for stack args)
|
||||||
|
self.emit_line(" push rax");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Target::Arm64 => {
|
||||||
|
// ARM64: first 8 args in x0-x7, rest on stack
|
||||||
|
for (i, arg) in arguments.iter().enumerate() {
|
||||||
|
self.generate_expression(arg)?;
|
||||||
|
if i < 8 {
|
||||||
|
if i > 0 {
|
||||||
|
self.emit_line(&format!(" mov x{}, x0", i));
|
||||||
|
}
|
||||||
|
// x0 already has the result for first argument
|
||||||
|
} else {
|
||||||
|
self.emit_line(" str x0, [sp, #-16]!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Expression::Identifier(func_name) = function.as_ref() {
|
if let Expression::Identifier(func_name) = function.as_ref() {
|
||||||
@@ -270,18 +386,128 @@ impl CodeGenerator {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up stack
|
// Clean up stack for arguments that were pushed
|
||||||
let stack_cleanup = arguments.len() * self.target.pointer_size();
|
match self.target {
|
||||||
if stack_cleanup > 0 {
|
Target::I386 => {
|
||||||
match self.target {
|
let stack_cleanup = arguments.len() * 4;
|
||||||
Target::I386 => {
|
if stack_cleanup > 0 {
|
||||||
self.emit_line(&format!(" add esp, {}", stack_cleanup));
|
self.emit_line(&format!(" add esp, {}", stack_cleanup));
|
||||||
}
|
}
|
||||||
Target::Amd64 => {
|
}
|
||||||
// Arguments passed in registers, no cleanup needed
|
Target::Amd64 => {
|
||||||
|
// Clean up stack arguments (if any)
|
||||||
|
let stack_args = if arguments.len() > 6 { arguments.len() - 6 } else { 0 };
|
||||||
|
if stack_args > 0 {
|
||||||
|
self.emit_line(&format!(" add rsp, {}", stack_args * 8));
|
||||||
}
|
}
|
||||||
Target::Arm64 => {
|
}
|
||||||
// Arguments passed in registers, no cleanup needed
|
Target::Arm64 => {
|
||||||
|
// Clean up stack arguments (if any)
|
||||||
|
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 } => {
|
||||||
|
// Generate binary operations
|
||||||
|
// First generate right operand and save it
|
||||||
|
self.generate_expression(right)?;
|
||||||
|
match self.target {
|
||||||
|
Target::I386 => {
|
||||||
|
self.emit_line(" push eax"); // Save right operand
|
||||||
|
}
|
||||||
|
Target::Amd64 => {
|
||||||
|
self.emit_line(" push rax"); // Save right operand
|
||||||
|
}
|
||||||
|
Target::Arm64 => {
|
||||||
|
self.emit_line(" str x0, [sp, #-16]!"); // Save right operand
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate left operand
|
||||||
|
self.generate_expression(left)?;
|
||||||
|
|
||||||
|
// Pop right operand and perform operation
|
||||||
|
match self.target {
|
||||||
|
Target::I386 => {
|
||||||
|
self.emit_line(" pop ebx"); // Right operand in ebx
|
||||||
|
match operator {
|
||||||
|
BinaryOperator::Add => self.emit_line(" add eax, ebx"),
|
||||||
|
BinaryOperator::Subtract => self.emit_line(" sub eax, ebx"),
|
||||||
|
BinaryOperator::Multiply => self.emit_line(" imul eax, ebx"),
|
||||||
|
BinaryOperator::Divide => {
|
||||||
|
self.emit_line(" cdq"); // Sign extend eax to edx:eax
|
||||||
|
self.emit_line(" idiv ebx");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(AleccError::CodegenError {
|
||||||
|
message: format!("Binary operator {:?} not implemented for i386", operator),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Target::Amd64 => {
|
||||||
|
self.emit_line(" pop rbx"); // Right operand in rbx
|
||||||
|
match operator {
|
||||||
|
BinaryOperator::Add => self.emit_line(" add rax, rbx"),
|
||||||
|
BinaryOperator::Subtract => self.emit_line(" sub rax, rbx"),
|
||||||
|
BinaryOperator::Multiply => self.emit_line(" imul rax, rbx"),
|
||||||
|
BinaryOperator::Divide => {
|
||||||
|
self.emit_line(" cqo"); // Sign extend rax to rdx:rax
|
||||||
|
self.emit_line(" idiv rbx");
|
||||||
|
}
|
||||||
|
// Comparison operators
|
||||||
|
BinaryOperator::Equal => {
|
||||||
|
self.emit_line(" cmp rax, rbx");
|
||||||
|
self.emit_line(" sete al");
|
||||||
|
self.emit_line(" movzx rax, al");
|
||||||
|
}
|
||||||
|
BinaryOperator::NotEqual => {
|
||||||
|
self.emit_line(" cmp rax, rbx");
|
||||||
|
self.emit_line(" setne al");
|
||||||
|
self.emit_line(" movzx rax, al");
|
||||||
|
}
|
||||||
|
BinaryOperator::Less => {
|
||||||
|
self.emit_line(" cmp rax, rbx");
|
||||||
|
self.emit_line(" setl al");
|
||||||
|
self.emit_line(" movzx rax, al");
|
||||||
|
}
|
||||||
|
BinaryOperator::Greater => {
|
||||||
|
self.emit_line(" cmp rax, rbx");
|
||||||
|
self.emit_line(" setg al");
|
||||||
|
self.emit_line(" movzx rax, al");
|
||||||
|
}
|
||||||
|
BinaryOperator::LessEqual => {
|
||||||
|
self.emit_line(" cmp rax, rbx");
|
||||||
|
self.emit_line(" setle al");
|
||||||
|
self.emit_line(" movzx rax, al");
|
||||||
|
}
|
||||||
|
BinaryOperator::GreaterEqual => {
|
||||||
|
self.emit_line(" cmp rax, rbx");
|
||||||
|
self.emit_line(" setge al");
|
||||||
|
self.emit_line(" movzx rax, al");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(AleccError::CodegenError {
|
||||||
|
message: format!("Binary operator {:?} not implemented for amd64", operator),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Target::Arm64 => {
|
||||||
|
self.emit_line(" ldr x1, [sp], #16"); // Right operand in x1
|
||||||
|
match operator {
|
||||||
|
BinaryOperator::Add => self.emit_line(" add x0, x0, x1"),
|
||||||
|
BinaryOperator::Subtract => self.emit_line(" sub x0, x0, x1"),
|
||||||
|
BinaryOperator::Multiply => self.emit_line(" mul x0, x0, x1"),
|
||||||
|
BinaryOperator::Divide => self.emit_line(" sdiv x0, x0, x1"),
|
||||||
|
_ => {
|
||||||
|
return Err(AleccError::CodegenError {
|
||||||
|
message: format!("Binary operator {:?} not implemented for arm64", operator),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,40 +210,20 @@ impl Linker {
|
|||||||
command.push(lib.clone());
|
command.push(lib.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standard libraries
|
// Standard libraries - skip for now to avoid conflicts
|
||||||
|
// Our programs use custom runtime with syscalls
|
||||||
|
/*
|
||||||
if !self.static_link {
|
if !self.static_link {
|
||||||
command.push("-lc".to_string());
|
command.push("-lc".to_string());
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
Ok(command)
|
Ok(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_standard_startup_files(&self, command: &mut Vec<String>) -> Result<()> {
|
fn add_standard_startup_files(&self, command: &mut Vec<String>) -> Result<()> {
|
||||||
let lib_path = match self.target {
|
// Skip startup files when we have our own _start
|
||||||
Target::I386 => "/usr/lib/i386-linux-gnu",
|
// This prevents conflicts with our custom _start implementation
|
||||||
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
326
src/parser.rs
326
src/parser.rs
@@ -169,7 +169,9 @@ pub struct Parser {
|
|||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
pub fn new(tokens: Vec<Token>) -> Self {
|
pub fn new(tokens: Vec<Token>) -> Self {
|
||||||
Self { tokens, current: 0 }
|
let mut parser = Self { tokens, current: 0 };
|
||||||
|
parser.skip_newlines(); // Skip initial newlines
|
||||||
|
parser
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(&mut self) -> Result<Program> {
|
pub fn parse(&mut self) -> Result<Program> {
|
||||||
@@ -384,9 +386,24 @@ impl Parser {
|
|||||||
if !self.is_at_end() {
|
if !self.is_at_end() {
|
||||||
self.current += 1;
|
self.current += 1;
|
||||||
}
|
}
|
||||||
|
self.skip_newlines();
|
||||||
self.previous()
|
self.previous()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn skip_newlines(&mut self) {
|
||||||
|
while !self.is_at_end() {
|
||||||
|
if let Ok(token) = self.current_token() {
|
||||||
|
if token.token_type == TokenType::Newline {
|
||||||
|
self.current += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn previous(&self) -> Result<&Token> {
|
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,
|
line: 0,
|
||||||
@@ -426,6 +443,16 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn match_tokens(&mut self, token_types: &[TokenType]) -> bool {
|
||||||
|
for token_type in token_types {
|
||||||
|
if self.check(token_type) {
|
||||||
|
self.advance().unwrap();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn consume(&mut self, token_type: &TokenType, message: &str) -> Result<&Token> {
|
fn consume(&mut self, token_type: &TokenType, message: &str) -> Result<&Token> {
|
||||||
if self.check(token_type) {
|
if self.check(token_type) {
|
||||||
self.advance()
|
self.advance()
|
||||||
@@ -495,6 +522,7 @@ impl Parser {
|
|||||||
self.consume(&TokenType::RightParen, "Expected ')' after parameters")?;
|
self.consume(&TokenType::RightParen, "Expected ')' after parameters")?;
|
||||||
|
|
||||||
let body = if self.check(&TokenType::LeftBrace) {
|
let body = if self.check(&TokenType::LeftBrace) {
|
||||||
|
self.advance()?; // Consume the LeftBrace
|
||||||
self.parse_block_statement()?
|
self.parse_block_statement()?
|
||||||
} else {
|
} else {
|
||||||
self.consume(&TokenType::Semicolon, "Expected ';' after function declaration")?;
|
self.consume(&TokenType::Semicolon, "Expected ';' after function declaration")?;
|
||||||
@@ -535,8 +563,7 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block_statement(&mut self) -> Result<Statement> {
|
fn parse_block_statement(&mut self) -> Result<Statement> {
|
||||||
self.consume(&TokenType::LeftBrace, "Expected '{'")?;
|
// Note: LeftBrace was already consumed by match_token in parse_statement
|
||||||
|
|
||||||
let mut statements = Vec::new();
|
let mut statements = Vec::new();
|
||||||
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
|
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
|
||||||
statements.push(self.parse_statement()?);
|
statements.push(self.parse_statement()?);
|
||||||
@@ -547,7 +574,7 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_statement(&mut self) -> Result<Statement> {
|
fn parse_statement(&mut self) -> Result<Statement> {
|
||||||
// Simplified statement parsing
|
// Try to parse different types of statements
|
||||||
if self.match_token(&TokenType::Return) {
|
if self.match_token(&TokenType::Return) {
|
||||||
let expr = if !self.check(&TokenType::Semicolon) {
|
let expr = if !self.check(&TokenType::Semicolon) {
|
||||||
Some(self.parse_expression()?)
|
Some(self.parse_expression()?)
|
||||||
@@ -556,25 +583,306 @@ impl Parser {
|
|||||||
};
|
};
|
||||||
self.consume(&TokenType::Semicolon, "Expected ';' after return")?;
|
self.consume(&TokenType::Semicolon, "Expected ';' after return")?;
|
||||||
Ok(Statement::Return(expr))
|
Ok(Statement::Return(expr))
|
||||||
|
} else if self.match_token(&TokenType::If) {
|
||||||
|
self.parse_if_statement()
|
||||||
|
} else if self.match_token(&TokenType::While) {
|
||||||
|
self.parse_while_statement()
|
||||||
|
} else if self.match_token(&TokenType::For) {
|
||||||
|
self.parse_for_statement()
|
||||||
|
} else if self.match_token(&TokenType::LeftBrace) {
|
||||||
|
self.parse_block_statement()
|
||||||
|
} else if self.is_type(&self.current_token()?.token_type) {
|
||||||
|
// Variable declaration - convert to Statement format
|
||||||
|
let var_type = self.parse_type()?;
|
||||||
|
let 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(Statement::Declaration {
|
||||||
|
name,
|
||||||
|
var_type,
|
||||||
|
initializer,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
|
// Expression statement
|
||||||
let expr = self.parse_expression()?;
|
let expr = self.parse_expression()?;
|
||||||
self.consume(&TokenType::Semicolon, "Expected ';' after expression")?;
|
self.consume(&TokenType::Semicolon, "Expected ';' after expression")?;
|
||||||
Ok(Statement::Expression(expr))
|
Ok(Statement::Expression(expr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_if_statement(&mut self) -> Result<Statement> {
|
||||||
|
self.consume(&TokenType::LeftParen, "Expected '(' after 'if'")?;
|
||||||
|
let condition = self.parse_expression()?;
|
||||||
|
self.consume(&TokenType::RightParen, "Expected ')' after if condition")?;
|
||||||
|
|
||||||
|
let then_stmt = Box::new(self.parse_statement()?);
|
||||||
|
let else_stmt = if self.match_token(&TokenType::Else) {
|
||||||
|
Some(Box::new(self.parse_statement()?))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Statement::If {
|
||||||
|
condition,
|
||||||
|
then_stmt,
|
||||||
|
else_stmt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_while_statement(&mut self) -> Result<Statement> {
|
||||||
|
self.consume(&TokenType::LeftParen, "Expected '(' after 'while'")?;
|
||||||
|
let condition = self.parse_expression()?;
|
||||||
|
self.consume(&TokenType::RightParen, "Expected ')' after while condition")?;
|
||||||
|
let body = Box::new(self.parse_statement()?);
|
||||||
|
|
||||||
|
Ok(Statement::While { condition, body })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_for_statement(&mut self) -> Result<Statement> {
|
||||||
|
self.consume(&TokenType::LeftParen, "Expected '(' after 'for'")?;
|
||||||
|
|
||||||
|
let init = if self.check(&TokenType::Semicolon) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Box::new(self.parse_statement()?))
|
||||||
|
};
|
||||||
|
|
||||||
|
if init.is_none() {
|
||||||
|
self.advance()?; // consume semicolon
|
||||||
|
}
|
||||||
|
|
||||||
|
let condition = if self.check(&TokenType::Semicolon) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.parse_expression()?)
|
||||||
|
};
|
||||||
|
self.consume(&TokenType::Semicolon, "Expected ';' after for condition")?;
|
||||||
|
|
||||||
|
let increment = if self.check(&TokenType::RightParen) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.parse_expression()?)
|
||||||
|
};
|
||||||
|
self.consume(&TokenType::RightParen, "Expected ')' after for clauses")?;
|
||||||
|
|
||||||
|
let body = Box::new(self.parse_statement()?);
|
||||||
|
|
||||||
|
Ok(Statement::For {
|
||||||
|
init,
|
||||||
|
condition,
|
||||||
|
increment,
|
||||||
|
body,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_expression(&mut self) -> Result<Expression> {
|
fn parse_expression(&mut self) -> Result<Expression> {
|
||||||
// Simplified expression parsing - just literals and identifiers for now
|
self.parse_logical_or()
|
||||||
match &self.advance()?.token_type {
|
}
|
||||||
|
|
||||||
|
fn parse_logical_or(&mut self) -> Result<Expression> {
|
||||||
|
let mut expr = self.parse_logical_and()?;
|
||||||
|
|
||||||
|
while self.match_token(&TokenType::LogicalOr) {
|
||||||
|
let operator = BinaryOperator::LogicalOr;
|
||||||
|
let right = self.parse_logical_and()?;
|
||||||
|
expr = Expression::Binary {
|
||||||
|
left: Box::new(expr),
|
||||||
|
operator,
|
||||||
|
right: Box::new(right),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_logical_and(&mut self) -> Result<Expression> {
|
||||||
|
let mut expr = self.parse_equality()?;
|
||||||
|
|
||||||
|
while self.match_token(&TokenType::LogicalAnd) {
|
||||||
|
let operator = BinaryOperator::LogicalAnd;
|
||||||
|
let right = self.parse_equality()?;
|
||||||
|
expr = Expression::Binary {
|
||||||
|
left: Box::new(expr),
|
||||||
|
operator,
|
||||||
|
right: Box::new(right),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_equality(&mut self) -> Result<Expression> {
|
||||||
|
let mut expr = self.parse_comparison()?;
|
||||||
|
|
||||||
|
while self.match_tokens(&[TokenType::Equal, TokenType::NotEqual]) {
|
||||||
|
let operator = match self.previous()?.token_type {
|
||||||
|
TokenType::Equal => BinaryOperator::Equal,
|
||||||
|
TokenType::NotEqual => BinaryOperator::NotEqual,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let right = self.parse_comparison()?;
|
||||||
|
expr = Expression::Binary {
|
||||||
|
left: Box::new(expr),
|
||||||
|
operator,
|
||||||
|
right: Box::new(right),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_comparison(&mut self) -> Result<Expression> {
|
||||||
|
let mut expr = self.parse_term()?;
|
||||||
|
|
||||||
|
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,
|
||||||
|
TokenType::Less => BinaryOperator::Less,
|
||||||
|
TokenType::LessEqual => BinaryOperator::LessEqual,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let right = self.parse_term()?;
|
||||||
|
expr = Expression::Binary {
|
||||||
|
left: Box::new(expr),
|
||||||
|
operator,
|
||||||
|
right: Box::new(right),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_term(&mut self) -> Result<Expression> {
|
||||||
|
let mut expr = self.parse_factor()?;
|
||||||
|
|
||||||
|
while self.match_tokens(&[TokenType::Minus, TokenType::Plus]) {
|
||||||
|
let operator = match self.previous()?.token_type {
|
||||||
|
TokenType::Minus => BinaryOperator::Subtract,
|
||||||
|
TokenType::Plus => BinaryOperator::Add,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let right = self.parse_factor()?;
|
||||||
|
expr = Expression::Binary {
|
||||||
|
left: Box::new(expr),
|
||||||
|
operator,
|
||||||
|
right: Box::new(right),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_factor(&mut self) -> Result<Expression> {
|
||||||
|
let mut expr = self.parse_unary()?;
|
||||||
|
|
||||||
|
while self.match_tokens(&[TokenType::Divide, TokenType::Multiply, TokenType::Modulo]) {
|
||||||
|
let operator = match self.previous()?.token_type {
|
||||||
|
TokenType::Divide => BinaryOperator::Divide,
|
||||||
|
TokenType::Multiply => BinaryOperator::Multiply,
|
||||||
|
TokenType::Modulo => BinaryOperator::Modulo,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let right = self.parse_unary()?;
|
||||||
|
expr = Expression::Binary {
|
||||||
|
left: Box::new(expr),
|
||||||
|
operator,
|
||||||
|
right: Box::new(right),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_unary(&mut self) -> Result<Expression> {
|
||||||
|
if self.match_tokens(&[TokenType::LogicalNot, TokenType::Minus, TokenType::Plus]) {
|
||||||
|
let operator = match self.previous()?.token_type {
|
||||||
|
TokenType::LogicalNot => UnaryOperator::LogicalNot,
|
||||||
|
TokenType::Minus => UnaryOperator::Minus,
|
||||||
|
TokenType::Plus => UnaryOperator::Plus,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let right = self.parse_unary()?;
|
||||||
|
return Ok(Expression::Unary {
|
||||||
|
operator,
|
||||||
|
operand: Box::new(right),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.parse_call()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_call(&mut self) -> Result<Expression> {
|
||||||
|
let mut expr = self.parse_primary()?;
|
||||||
|
|
||||||
|
while self.match_token(&TokenType::LeftParen) {
|
||||||
|
expr = self.finish_call(expr)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_call(&mut self, callee: Expression) -> Result<Expression> {
|
||||||
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
|
if !self.check(&TokenType::RightParen) {
|
||||||
|
loop {
|
||||||
|
arguments.push(self.parse_expression()?);
|
||||||
|
if !self.match_token(&TokenType::Comma) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.consume(&TokenType::RightParen, "Expected ')' after arguments")?;
|
||||||
|
|
||||||
|
Ok(Expression::Call {
|
||||||
|
function: Box::new(callee),
|
||||||
|
arguments,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_primary(&mut self) -> Result<Expression> {
|
||||||
|
if self.match_token(&TokenType::LeftParen) {
|
||||||
|
let expr = self.parse_expression()?;
|
||||||
|
self.consume(&TokenType::RightParen, "Expected ')' after expression")?;
|
||||||
|
return Ok(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
let token = self.advance()?;
|
||||||
|
match &token.token_type {
|
||||||
TokenType::IntegerLiteral(value) => Ok(Expression::IntegerLiteral(*value)),
|
TokenType::IntegerLiteral(value) => Ok(Expression::IntegerLiteral(*value)),
|
||||||
TokenType::FloatLiteral(value) => Ok(Expression::FloatLiteral(*value)),
|
TokenType::FloatLiteral(value) => Ok(Expression::FloatLiteral(*value)),
|
||||||
TokenType::StringLiteral(value) => Ok(Expression::StringLiteral(value.clone())),
|
TokenType::StringLiteral(value) => Ok(Expression::StringLiteral(value.clone())),
|
||||||
TokenType::CharLiteral(value) => Ok(Expression::CharLiteral(*value)),
|
TokenType::CharLiteral(value) => Ok(Expression::CharLiteral(*value)),
|
||||||
TokenType::Identifier(name) => Ok(Expression::Identifier(name.clone())),
|
TokenType::Identifier(name) => Ok(Expression::Identifier(name.clone())),
|
||||||
_ => Err(AleccError::ParseError {
|
_ => Err(AleccError::ParseError {
|
||||||
line: self.current_token()?.line,
|
line: token.line,
|
||||||
column: self.current_token()?.column,
|
column: token.column,
|
||||||
message: "Expected expression".to_string(),
|
message: format!("Expected expression, found {:?}", token.token_type),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user