This repository has been archived on 2025-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
corten/src/assembler/instruction_parser.rs
Anthony Foxclaw 13069b7ebd Fixed a few old bugs
- Fixed a where the VM excuted one loop regardless of instructions.
- Use the full 32 bits if an instruction is less.
2020-02-09 18:43:23 -05:00

147 lines
No EOL
3.6 KiB
Rust

use crate::assembler::opcode_parser::opcode;
use crate::assembler::operand_parser::integer_operand;
use crate::assembler::register_parser::register;
use crate::assembler::Token;
use nom::*;
use nom::types::CompleteStr;
#[derive(Debug, PartialEq)]
pub struct AssemblerInstruction {
opcode: Token,
operand1: Option<Token>,
operand2: Option<Token>,
operand3: Option<Token>,
}
impl AssemblerInstruction {
pub fn to_bytes(&self) -> Vec<u8> {
let mut results = vec![];
match self.opcode.to_owned() {
Token::Opcode { code } => match code {
_ => {
results.push(code.into());
}
},
_ => {
println!("Incorrect opcode!");
std::process::exit(1);
}
};
for operand in &[&self.operand1, &self.operand2, &self.operand3] {
if let Some(token) = operand {
AssemblerInstruction::extract_operand(token, &mut results)
}
}
while results.len() < 4 {
results.push(0);
}
results
}
fn extract_operand(t: &Token, results: &mut Vec<u8>) {
match t {
Token::Register { reg_num } => {
results.push(*reg_num);
}
Token::Number { value } => {
let conv = *value as u16;
let byte1 = conv;
let byte2 = conv >> 8;
results.push(byte2 as u8);
results.push(byte1 as u8);
}
_ => {
println!("Opcode found in operand field");
std::process::exit(1);
}
};
}
}
named!(instruction_two<CompleteStr, AssemblerInstruction>,
do_parse!(
o: opcode >>
opt!(multispace) >>
(
AssemblerInstruction{
opcode: o,
operand1: None,
operand2: None,
operand3: None
}
)
)
);
named!(pub instruction<CompleteStr, AssemblerInstruction>,
do_parse!(
ins: alt!(
instruction_one |
instruction_two
) >>
(
ins
)
)
);
named!(instruction_one<CompleteStr, AssemblerInstruction>,
do_parse!(
o: opcode >>
r: register >>
i: integer_operand >>
(
AssemblerInstruction{
opcode: o,
operand1: Some(r),
operand2: Some(i),
operand3: None
}
)
)
);
#[cfg(test)]
mod instruction_parser_test {
use super::*;
use crate::assembler::Opcode;
#[test]
fn test_parse_instruction_form_one() {
let result = instruction_one(CompleteStr("load $0 #100\n"));
assert_eq!(
result,
Ok((
CompleteStr(""),
AssemblerInstruction {
opcode: Token::Opcode { code: Opcode::LOAD },
operand1: Some(Token::Register { reg_num: 0 }),
operand2: Some(Token::Number { value: 100 }),
operand3: None
}
))
);
}
#[test]
fn test_parse_instruction_form_two() {
let result = instruction_two(CompleteStr("hlt\n"));
assert_eq!(
result,
Ok((
CompleteStr(""),
AssemblerInstruction {
opcode: Token::Opcode { code: Opcode::HLT },
operand1: None,
operand2: None,
operand3: None
}
))
);
}
}