diff --git a/src/bin/ponderosa-asm.rs b/src/bin/ponderosa-asm.rs index b1da48d..a334f43 100644 --- a/src/bin/ponderosa-asm.rs +++ b/src/bin/ponderosa-asm.rs @@ -6,11 +6,24 @@ use std::collections::{HashMap, BTreeMap, VecDeque}; use ponderosa::state::{Land, Rule}; +macro_rules! assert_argument_count { + ($tokens:expr, $count:expr) => { + if $tokens.len() < $count { + return Err("Too few arguments".to_owned()); + } + + if $tokens.len() > $count { + return Err("Too many arguments".to_owned()); + } + }; +} + fn parse_number(string: &str) -> u16 { string.parse::().unwrap() } -fn stack_bit(c: char) -> Result { +fn stack_bit(token: &String) -> Result { + let c = token.as_bytes()[0] as char; match c { 'r' => Ok(0), 't' => Ok(1), @@ -18,27 +31,42 @@ fn stack_bit(c: char) -> Result { } } -fn parse_binary_math_format<'a>(tokens: &Vec, opcode: u16, signed: bool) -> Result { - if tokens.len() < 4 { Err("Too few arguments".to_owned()) } - else if tokens.len() > 4 { Err("Too many arguments".to_owned()) } - else { - let left_parse = stack_bit(tokens[1].as_bytes()[0] as char); - let right_parse = stack_bit(tokens[2].as_bytes()[0] as char); - let dest_parse = stack_bit(tokens[3].as_bytes()[0] as char); +fn parse_unary_math_format<'a>(tokens: &Vec, opcode: u16, signed: bool) -> Result { + assert_argument_count!(tokens, 4); - match (left_parse, right_parse, dest_parse) { - (Ok(left), Ok(right), Ok(dest)) => Ok( - opcode << 11 & - left << 10 & - right << 9 & - dest << 8 & - (signed as u16) << 7 - ), - (Err(e), _, _) => Err(e), - (_, Err(e), _) => Err(e), - (_, _, Err(e)) => Err(e), - } + let src = stack_bit(&tokens[1])?; + let dest = stack_bit(&tokens[2])?; + + Ok(opcode<<11 & src<<9 & dest<<8 & (signed as u16)<<7) +} + +fn parse_binary_math_format<'a>(tokens: &Vec, opcode: u16, signed: bool) -> Result { + assert_argument_count!(tokens, 4); + + let left = stack_bit(&tokens[1])?; + let right = stack_bit(&tokens[2])?; + let dest = stack_bit(&tokens[3])?; + + Ok(opcode<<11 & left<<10 & right<<9 & dest<<8 & (signed as u16)<<7) +} + +fn parse_push(tokens: &Vec, opcode: u16, signed: bool) -> Result { + assert_argument_count!(tokens, 3); + + let dest = stack_bit(&tokens[1])?; + let signed_immediate = tokens[2].parse::() + .map_err(|_| format!("Cannot parse number: {t}", t=tokens[2]))?; + + let unsigned_immediate = tokens[2].parse::() + .map_err(|_| format!("Cannot parse number: {t}", t=tokens[2]))?; + + let immediate = if signed { signed_immediate as u16 } else { unsigned_immediate }; + + if immediate > 511 { + return Err("Cannot push number larger than 511 due to bit width limitations".to_owned()); } + + Ok(opcode<<11 & dest<<10 & (signed as u16) << 9 & immediate) } fn main() -> io::Result<()> {