aboutsummaryrefslogtreecommitdiff
path: root/src/assembler.rs
diff options
context:
space:
mode:
authorkrolxon <krolyxon@tutanota.com>2026-01-04 23:49:04 +0530
committerkrolxon <krolyxon@tutanota.com>2026-01-04 23:49:04 +0530
commitdebe2ecbc4f819dfec7f5ca7c1f0e2fd6bc37708 (patch)
tree714a4f6164e646e17ce1c40babb731365c795444 /src/assembler.rs
parenta566c1737bc8cfa0c65ccd684af534c7430c35f6 (diff)
add simple assembler
Diffstat (limited to 'src/assembler.rs')
-rw-r--r--src/assembler.rs73
1 files changed, 73 insertions, 0 deletions
diff --git a/src/assembler.rs b/src/assembler.rs
new file mode 100644
index 0000000..3cd2bf8
--- /dev/null
+++ b/src/assembler.rs
@@ -0,0 +1,73 @@
+use crate::instructions::Instruction;
+
+fn tokenize(line: &str) -> Vec<String> {
+ line.split(|c| c == ' ' || c == ',' || c == '\t')
+ .filter(|s| !s.is_empty())
+ .map(|s| s.to_lowercase())
+ .collect()
+}
+
+fn parse_reg(s: &str) -> u8 {
+ match s {
+ "a" => 0,
+ "b" => 1,
+ "c" => 2,
+ "d" => 3,
+ _ => panic!("Unknown register {}", s),
+ }
+}
+
+pub fn assembler(source: &str) -> Vec<u8> {
+ let mut bytes = Vec::new();
+
+ for (line_no, line) in source.lines().enumerate() {
+ let line = line.trim();
+
+ // Comments in assembly start with ";"
+ if line.is_empty() || line.starts_with(';') {
+ continue;
+ }
+
+ let tokens = tokenize(line);
+
+ match tokens[0].as_str() {
+ "mov" => {
+ // mov reg, imm
+ let reg = parse_reg(&tokens[1]);
+ let imm: u8 = tokens[2].parse().unwrap();
+
+ bytes.push(Instruction::MOV as u8);
+ bytes.push(reg);
+ bytes.push(imm);
+ }
+
+ "add" => {
+ // add a, b
+ let r1 = parse_reg(&tokens[1]);
+ let r2 = parse_reg(&tokens[2]);
+
+ bytes.push(Instruction::ADD as u8);
+ bytes.push(r1);
+ bytes.push(r2);
+ }
+
+ "sub" => {
+ // sub a, b
+ let r1 = parse_reg(&tokens[1]);
+ let r2 = parse_reg(&tokens[2]);
+
+ bytes.push(Instruction::SUB as u8);
+ bytes.push(r1);
+ bytes.push(r2);
+ }
+
+ "hlt" => {
+ bytes.push(Instruction::HLT as u8);
+ }
+
+ _ => panic!("Line {}: unknown instruction", line_no + 1),
+ }
+ }
+
+ bytes
+}