Find labels before assembly

This commit is contained in:
wborgeaud 2022-07-05 16:11:55 +02:00
parent f6d48f1328
commit 8873eaba11

View File

@ -1,5 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use itertools::izip;
use super::ast::PushTarget; use super::ast::PushTarget;
use crate::cpu::kernel::{ use crate::cpu::kernel::{
ast::{File, Item}, ast::{File, Item},
@ -19,12 +21,24 @@ pub struct Kernel {
pub(crate) fn assemble(files: Vec<File>) -> Kernel { pub(crate) fn assemble(files: Vec<File>) -> Kernel {
let macros = find_macros(&files); let macros = find_macros(&files);
let mut code = vec![];
let mut global_labels = HashMap::new(); let mut global_labels = HashMap::new();
let mut offset = 0;
let mut expanded_files = Vec::with_capacity(files.len());
let mut local_labels = Vec::with_capacity(files.len());
for file in files { for file in files {
let expanded_file = expand_macros(file.body, &macros); let expanded_file = expand_macros(file.body, &macros);
assemble_file(expanded_file, &mut code, &mut global_labels); local_labels.push(find_labels(&expanded_file, &mut offset, &mut global_labels));
expanded_files.push(expanded_file);
} }
let mut code = vec![];
for (file, locals) in izip!(expanded_files, local_labels) {
assemble_file(file, &mut code, locals, &global_labels);
}
assert_eq!(
code.len(),
offset,
"Code length {} doesn't match offset {}."
);
Kernel { Kernel {
code, code,
global_labels, global_labels,
@ -67,30 +81,41 @@ fn expand_macros(body: Vec<Item>, macros: &HashMap<String, Vec<Item>>) -> Vec<It
expanded expanded
} }
fn assemble_file(body: Vec<Item>, code: &mut Vec<u8>, global_labels: &mut HashMap<String, usize>) { fn find_labels(
// First discover the offset of each label in this file. body: &[Item],
offset: &mut usize,
global_labels: &mut HashMap<String, usize>,
) -> HashMap<String, usize> {
// Discover the offset of each label in this file.
let mut local_labels = HashMap::<String, usize>::new(); let mut local_labels = HashMap::<String, usize>::new();
let mut offset = code.len(); for item in body {
for item in &body {
match item { match item {
Item::MacroDef(_, _) | Item::MacroCall(_) => { Item::MacroDef(_, _) | Item::MacroCall(_) => {
panic!("Macros should have been expanded already") panic!("Macros should have been expanded already")
} }
Item::GlobalLabelDeclaration(label) => { Item::GlobalLabelDeclaration(label) => {
let old = global_labels.insert(label.clone(), offset); let old = global_labels.insert(label.clone(), *offset);
assert!(old.is_none(), "Duplicate global label: {}", label); assert!(old.is_none(), "Duplicate global label: {}", label);
} }
Item::LocalLabelDeclaration(label) => { Item::LocalLabelDeclaration(label) => {
let old = local_labels.insert(label.clone(), offset); let old = local_labels.insert(label.clone(), *offset);
assert!(old.is_none(), "Duplicate local label: {}", label); assert!(old.is_none(), "Duplicate local label: {}", label);
} }
Item::Push(target) => offset += 1 + push_target_size(target) as usize, Item::Push(target) => *offset += 1 + push_target_size(target) as usize,
Item::StandardOp(_) => offset += 1, Item::StandardOp(_) => *offset += 1,
Item::Bytes(bytes) => offset += bytes.len(), Item::Bytes(bytes) => *offset += bytes.len(),
} }
} }
local_labels
}
// Now that we have label offsets, we can assemble the file. fn assemble_file(
body: Vec<Item>,
code: &mut Vec<u8>,
local_labels: HashMap<String, usize>,
global_labels: &HashMap<String, usize>,
) {
// Assemble the file.
for item in body { for item in body {
match item { match item {
Item::MacroDef(_, _) | Item::MacroCall(_) => { Item::MacroDef(_, _) | Item::MacroCall(_) => {
@ -124,12 +149,6 @@ fn assemble_file(body: Vec<Item>, code: &mut Vec<u8>, global_labels: &mut HashMa
Item::Bytes(bytes) => code.extend(bytes.iter().map(|b| b.to_u8())), Item::Bytes(bytes) => code.extend(bytes.iter().map(|b| b.to_u8())),
} }
} }
assert_eq!(
code.len(),
offset,
"The two phases gave different code lengths"
);
} }
/// The size of a `PushTarget`, in bytes. /// The size of a `PushTarget`, in bytes.