WIP assembly gen

This commit is contained in:
0x4261756D 2022-12-23 14:49:09 +01:00
parent 97bd50fa55
commit e3a1223ac9
1 changed files with 139 additions and 0 deletions

View File

@ -1,6 +1,7 @@
use core::panic;
use std::collections::HashMap;
use std::env;
use std::fmt::format;
use std::fs;
use std::iter::Peekable;
use std::process::exit;
@ -218,9 +219,147 @@ fn compile(file_content: &String, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec
{
None
};
if !interpret
{
match generate_assembly_linux_x64(&operations, &functions, &intrinsics, &arrays, debug)
{
Ok(()) => return Ok(None),
Err(error) => return Err(error.to_string()),
}
}
return Ok(output);
}
struct AssemblyData
{
strings: String,
code: String,
arrays: String,
}
fn merge_assemblies(data: &mut AssemblyData, data2: AssemblyData)
{
data.arrays += data2.arrays.as_str();
data.code += data2.code.as_str();
data.strings += data2.strings.as_str();
}
const ASSEMBLY_LINUX_X64_QUEUE_LENGTH: u32 = 1024;
const ASSEMBLY_LINUX_X64_HEADER: &str = "format ELF64 executable 3\n";
const ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE: &str = "\tcmp r8, r9\n\tcmove r8, r10\n\tcmove r9, r10\n";
const ASSEMBLY_LINUX_X64_EXIT: &str = "\tmov rax, 60\n\tmov rdi, 0\n\tsyscall\n";
fn generate_assembly_linux_x64(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> Result<(), std::io::Error>
{
let mut data = AssemblyData
{
arrays: format!("segment readable writeable\n\tqueue: rq {}\n", ASSEMBLY_LINUX_X64_QUEUE_LENGTH),
strings: String::from("segment readable\n"),
code: String::from("segment executable\n"),
};
for array in arrays
{
data.arrays += format!("\tarr_{}: rq {}\n", array.name, array.length).as_str();
}
for function in functions
{
merge_assemblies(&mut data, generate_assembly_linux_x64_function(function.name.as_str(), &function.content, functions, intrinsics, arrays, debug));
}
merge_assemblies(&mut data, generate_assembly_linux_x64_function("_start", operations, functions, intrinsics, arrays, debug));
data.code += ASSEMBLY_LINUX_X64_EXIT;
return fs::write("out.asm", format!("{}{}{}{}", ASSEMBLY_LINUX_X64_HEADER, data.code, data.arrays, data.strings));
}
// r8: head
// r9: tail
// r10: base
fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> AssemblyData
{
let mut data = AssemblyData
{
arrays: String::new(),
code: String::new(),
strings: String::new(),
};
for operation in operations
{
match operation
{
Operation::Dequeue(line, col) =>
{
data.code += format!("\t;;deq {}:{}\n", line, col).as_str();
data.code += "\tinc r8\n";
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
}
Operation::Enqueue(datatype, value, line, col) =>
{
data.code += format!("\t;;enq {:?} {} {}:{}\n", datatype, value, line, col).as_str();
match datatype
{
Datatype::Int | Datatype::Bool =>
{
data.code += format!("\tmov qword [queue+r9], {}\n", value).as_str();
}
_ => todo!("enq {:?}", datatype)
}
data.code += "\tinc r9\n";
}
Operation::While(while_operations, line, col) =>
{
data.code += format!("\t;;while {}:{}\n", line, col).as_str();
data.code += format!("while_{}_{}:\n", line, col).as_str();
data.code += "\tcmp qword [queue+r8], 0\n";
data.code += format!("\tje while_{}_{}_end\n", line, col).as_str();
data.code += "\tinc r8\n";
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
merge_assemblies(&mut data, generate_assembly_linux_x64_block(while_operations, functions, intrinsics, arrays, debug));
data.code += format!("\tjmp while_{}_{}\n", line, col).as_str();
data.code += format!("while_{}_{}_end:\n", line, col).as_str();
data.code += "\tinc r8\n";
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
}
Operation::Dup(line, col) =>
{
data.code += format!("\t;;dup {}:{}\n", line, col).as_str();
data.code += "\tmov qword [queue+r9], [queue+r8]\n";
data.code += "\tinc r9\n";
}
Operation::Intrinsic(name, line, col) =>
{
data.code += format!("\t;;intrinsic {} {}:{}", name, line, col).as_str();
match name.as_str()
{
"print" =>
{
// For now printing numbers directly is unsupported
data.code += "\trax, 1\n";
data.code += "\trdi, 1\n";
data.code += "\tmov rsi, [queue+r8]\n";
data.code += "\tmov "
}
_ => todo!("intrinsic {} {}:{}", name, line, col)
}
}
_ => todo!("{:?}", operation)
}
}
return data;
}
fn generate_assembly_linux_x64_function(name: &str, operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> AssemblyData
{
let mut data = AssemblyData
{
arrays: String::new(),
code: format!("{}:\n", name),
strings: String::new(),
};
merge_assemblies(&mut data, generate_assembly_linux_x64_block(operations, functions, intrinsics, arrays, debug));
return data;
}
fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, functions: &Vec<Function>, arrays: &mut Vec<Arr>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<String,String>
{
let mut output = String::new();