summaryrefslogtreecommitdiff
path: root/src/parsers/bytecode.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parsers/bytecode.rs')
-rw-r--r--src/parsers/bytecode.rs78
1 files changed, 53 insertions, 25 deletions
diff --git a/src/parsers/bytecode.rs b/src/parsers/bytecode.rs
index ec19d9f..6cdfd3a 100644
--- a/src/parsers/bytecode.rs
+++ b/src/parsers/bytecode.rs
@@ -25,28 +25,7 @@ impl<'a> BytecodeGenerator<'a> {
for token in self.tokens {
match token {
AssembledToken::Word(assembled_word) => {
- let mut value = assembled_word.value;
- for field in &assembled_word.fields {
- let (field_value, source) = match &field.value {
- IntegerArgument::Expression(expr) =>
- (self.resolve_expression(expr), expr.source.clone()),
- IntegerArgument::LabelReference(name) =>
- (self.resolve_label_reference(name), name.source.clone()),
- IntegerArgument::Integer(integer) =>
- (integer.value, integer.source.clone()),
- };
- let bitcount = match field_value {
- 0 => 0,
- _ => (field_value.ilog2() + 1) as usize,
- };
- if field.bits < bitcount {
- let variant = BytecodeErrorVariant::ValueTooLarge(field.bits, bitcount);
- self.errors.push(BytecodeError { source, variant });
- } else {
- value |= (field_value << field.shift) as usize;
- }
- }
- self.words.push(Word { bits: assembled_word.bits, value });
+ self.assemble_word(assembled_word);
}
AssembledToken::PinnedAddress(pinned) => {
if self.words.len() > pinned.address {
@@ -74,7 +53,7 @@ impl<'a> BytecodeGenerator<'a> {
for token in self.tokens {
match token {
AssembledToken::LabelDefinition(definition) => {
- let address = Tracked::from(i, &definition.source);
+ let address = Tracked::from(i, definition.source.clone());
if let Some(_) = self.addresses.insert(definition.name.clone(), address) {
let name = definition.name.clone();
let variant = BytecodeErrorVariant::DuplicateLabelDefinition(name);
@@ -82,8 +61,8 @@ impl<'a> BytecodeGenerator<'a> {
self.errors.push(BytecodeError { source, variant });
}
}
- AssembledToken::Word(_) => {
- i += 1;
+ AssembledToken::Word(word) => {
+ i += word.count();
}
AssembledToken::PinnedAddress(pinned) => {
i = pinned.address;
@@ -158,4 +137,53 @@ impl<'a> BytecodeGenerator<'a> {
0
}
}
+
+ fn assemble_word(&mut self, assembled_word: &AssembledWord) {
+ let mut field_values = Vec::new();
+ for field in &assembled_word.fields {
+ match &field.value {
+ IntegerArgument::Expression(expr) => {
+ let source = expr.source.clone();
+ let value = self.resolve_expression(expr);
+ field_values.push(vec![Tracked::from(value, source)])
+ }
+ IntegerArgument::LabelReference(name) => {
+ let source = name.source.clone();
+ let value = self.resolve_label_reference(name);
+ field_values.push(vec![Tracked::from(value, source)])
+ }
+ IntegerArgument::Integer(integer) => {
+ let source = integer.source.clone();
+ let value = integer.value;
+ field_values.push(vec![Tracked::from(value, source)])
+ }
+ IntegerArgument::String(string) => {
+ let values = string.chars.iter()
+ .map(|c| Tracked::from(c.value as isize, c.source.clone()))
+ .collect();
+ field_values.push(values);
+ }
+ };
+ }
+ for i in 0..assembled_word.count() {
+ let mut value = assembled_word.value;
+ for (f, field) in assembled_word.fields.iter().enumerate() {
+ let (field_value, source) = match field_values[f].get(i) {
+ Some(tracked) => (tracked.value, Some(tracked.source.clone())),
+ None => (0, None),
+ };
+ let bitcount = match field_value {
+ 0 => 0,
+ _ => (field_value.ilog2() + 1) as usize,
+ };
+ if field.bits < bitcount {
+ let variant = BytecodeErrorVariant::ValueTooLarge(field.bits, bitcount);
+ self.errors.push(BytecodeError { source: source.unwrap(), variant });
+ } else {
+ value |= (field_value << field.shift) as usize;
+ }
+ }
+ self.words.push(Word { bits: assembled_word.bits, value });
+ }
+ }
}