1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
use crate::*;
use std::collections::HashMap;
/// Doesn't truncate trailing null bytes.
pub fn generate_bytecode(semantic: &Program) -> Result<AssembledProgram, Vec<Tracked<BytecodeError>>> {
let mut generator = BytecodeGenerator::new(&semantic.definitions);
generator.parse(&semantic.tokens, false);
generator.fill_slots();
let mut symbols = Vec::new();
for (name, information) in generator.labels {
let source = semantic.definitions.get(&name).unwrap().source.clone();
let address = information.address;
symbols.push(AssembledSymbol { name, address, source });
}
match generator.errors.is_empty() {
true => Ok(
AssembledProgram {
bytecode: generator.bytecode,
symbols,
}
),
false => Err(generator.errors),
}
}
pub struct BytecodeGenerator<'a> {
definitions: &'a HashMap<String, Tracked<Definition>>,
labels: HashMap<String, LabelInformation>,
stack: Vec<usize>,
bytecode: Vec<u8>,
errors: Vec<Tracked<BytecodeError>>,
}
struct LabelInformation {
address: usize,
slots: Vec<usize>,
}
impl<'a> BytecodeGenerator<'a> {
pub fn new(definitions: &'a HashMap<String, Tracked<Definition>>) -> Self {
let mut labels = HashMap::new();
for (name, definition) in definitions {
if let DefinitionVariant::LabelDefinition = definition.variant {
// Use fake address for now.
let information = LabelInformation { address: 0, slots: Vec::new() };
labels.insert(name.to_string(), information);
}
}
Self {
definitions,
labels,
stack: Vec::new(),
bytecode: Vec::new(),
errors: Vec::new(),
}
}
pub fn parse(&mut self, tokens: &[Tracked<SemanticToken>], in_macro: bool) {
macro_rules! byte {
($byte:expr) => {
self.bytecode.push($byte)
};
}
macro_rules! double {
($double:expr) => {{
let [high, low] = u16::to_be_bytes($double);
self.bytecode.push(high); self.bytecode.push(low);
}};
}
for token in tokens {
let i = self.bytecode.len();
match &token.value {
SemanticToken::Literal(value) => match value {
Value::Byte(byte) => byte!(*byte),
Value::Double(double) => double!(*double),
}
SemanticToken::Pad(value) => {
self.bytecode.resize(i + usize::from(value), 0);
},
SemanticToken::String(bytes) => {
self.bytecode.extend_from_slice(bytes)
},
SemanticToken::Comment(_) => (),
SemanticToken::BlockOpen(_) => {
self.stack.push(i);
// Use a fake index for now.
double!(0);
}
SemanticToken::BlockClose(_) => {
if i > 0xFFFF {
let error = BytecodeError::InvalidBlockAddress(i);
self.errors.push(Tracked::from(error, token.source.clone()));
}
let Some(addr) = self.stack.pop() else {
unreachable!("Uncaught unmatched block terminator");
};
let [high, low] = (i as u16).to_be_bytes();
self.bytecode[addr] = high;
self.bytecode[addr+1] = low;
}
SemanticToken::Symbol(name) => {
if let Some(definition) = self.definitions.get(name) {
match &definition.variant {
DefinitionVariant::MacroDefinition(body) => {
self.parse(body, true);
}
DefinitionVariant::LabelDefinition => {
let information = self.labels.get_mut(name).unwrap();
information.slots.push(i);
// Use a fake index for now.
double!(0);
}
}
} else {
unreachable!("Uncaught undefined symbol '{name}'");
}
}
SemanticToken::Instruction(instruction) => {
byte!(instruction.value)
}
SemanticToken::LabelDefinition(name) => if in_macro {
unreachable!("Uncaught label definition in macro");
} else {
if i > 0xFFFF {
let error = BytecodeError::InvalidLabelAddress(i);
self.errors.push(Tracked::from(error, token.source.clone()));
}
let information = self.labels.get_mut(name).unwrap();
// Replace fake index with real index.
information.address = i;
}
SemanticToken::MacroDefinition{ .. } => if in_macro {
unreachable!("Uncaught macro definition in macro");
}
}
}
if !self.stack.is_empty() {
unreachable!("Uncaught unterminated block");
}
}
/// Fill each label slot with a real label address.
pub fn fill_slots(&mut self) {
for information in self.labels.values() {
let [high, low] = (information.address as u16).to_be_bytes();
for addr in &information.slots {
self.bytecode[*addr] = high;
self.bytecode[*addr + 1] = low;
}
}
}
}
|