diff --git a/src/fox32.pest b/src/fox32.pest index e7fee2d..fa85d6d 100644 --- a/src/fox32.pest +++ b/src/fox32.pest @@ -65,6 +65,13 @@ size = @{ ".32" } +incdec_amount = @{ + "1" | + "2" | + "4" | + "8" +} + condition = @{ "ifz" | "ifnz" | @@ -83,6 +90,7 @@ instruction = { instruction_conditional = { instruction_zero ~ size? | instruction_one ~ size? ~ operand | + instruction_incdec ~ size? ~ operand ~ ("," ~ incdec_amount)? | instruction_two ~ size? ~ operand ~ "," ~ operand } @@ -99,8 +107,6 @@ instruction_zero = @{ } instruction_one = @{ - "inc" | - "dec" | "not" | "jmp" | "call" | @@ -115,6 +121,11 @@ instruction_one = @{ "flp" } +instruction_incdec = @{ + "inc" | + "dec" +} + instruction_two = @{ "add" | "sub" | diff --git a/src/main.rs b/src/main.rs index 690c47d..561ebe2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -168,8 +168,6 @@ enum InstructionZero { #[derive(PartialEq, Debug, Clone, Copy)] enum InstructionOne { // one operand - Inc, - Dec, Not, Jmp, Call, @@ -184,6 +182,13 @@ enum InstructionOne { Flp, } +#[derive(PartialEq, Debug, Clone, Copy)] +enum InstructionIncDec { + // one or two operands + Inc, + Dec, +} + #[derive(PartialEq, Debug, Clone, Copy)] enum InstructionTwo { // two operands @@ -254,6 +259,13 @@ enum AstNode { instruction: InstructionOne, operand: Box, }, + OperationIncDec { + size: Size, + condition: Condition, + instruction: InstructionIncDec, + lhs: Box, + rhs: Box, + }, OperationTwo { size: Size, condition: Condition, @@ -713,6 +725,16 @@ fn parse_size(pair: &pest::iterators::Pair) -> Size { } } +fn parse_incdec_amount(pair: pest::iterators::Pair) -> AstNode { + match pair.as_str() { + "1" => AstNode::Immediate8(0), + "2" => AstNode::Immediate8(1), + "4" => AstNode::Immediate8(2), + "8" => AstNode::Immediate8(3), + _ => panic!("Unsupported increment/decrement: {}", pair.as_str()), + } +} + fn parse_condition(pair: &pest::iterators::Pair) -> Condition { match pair.as_str() { "ifz" => Condition::Zero, @@ -754,6 +776,21 @@ fn parse_instruction(pair: pest::iterators::Pair) -> AstNode { let operand_ast = build_ast_from_expression(operand); parse_instruction_one(instruction_conditional_pair, operand_ast, size, condition) } + Rule::instruction_incdec => { + if inner_pair.peek().unwrap().as_rule() == Rule::size { + size = parse_size(&inner_pair.next().unwrap()); + } + *CURRENT_SIZE.lock().unwrap() = size; + let lhs = inner_pair.next().unwrap(); + let lhs_ast = build_ast_from_expression(lhs); + let rhs_ast = if inner_pair.peek().is_some() { + let rhs = inner_pair.next().unwrap(); + parse_incdec_amount(rhs) + } else { + AstNode::Immediate8(0) + }; + parse_instruction_incdec(instruction_conditional_pair, lhs_ast, rhs_ast, size, condition) + } Rule::instruction_two => { if inner_pair.peek().unwrap().as_rule() == Rule::size { size = parse_size(&inner_pair.next().unwrap()); @@ -878,8 +915,6 @@ fn parse_instruction_one(pair: pest::iterators::Pair, mut operand: AstNode size: size, condition: condition, instruction: match pair.as_str() { - "inc" => InstructionOne::Inc, - "dec" => InstructionOne::Dec, "not" => InstructionOne::Not, "jmp" => InstructionOne::Jmp, "call" => InstructionOne::Call, @@ -925,6 +960,21 @@ fn parse_instruction_one(pair: pest::iterators::Pair, mut operand: AstNode } } +fn parse_instruction_incdec(pair: pest::iterators::Pair, lhs: AstNode, rhs: AstNode, size: Size, condition: Condition) -> AstNode { + AstNode::OperationIncDec { + size: size, + condition: condition, + instruction: match pair.as_str() { + "inc" => InstructionIncDec::Inc, + "dec" => InstructionIncDec::Dec, + _ => panic!("Unsupported conditional instruction (two): {}", pair.as_str()), + }, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + } +} + + fn parse_instruction_two(pair: pest::iterators::Pair, mut lhs: AstNode, mut rhs: AstNode, size: Size, condition: Condition) -> AstNode { AstNode::OperationTwo { size: size, @@ -1055,8 +1105,6 @@ fn instruction_to_byte(node: &AstNode) -> u8 { } AstNode::OperationOne {size, instruction, ..} => { match instruction { - InstructionOne::Inc => 0x11 | size_to_byte(size), - InstructionOne::Dec => 0x31 | size_to_byte(size), InstructionOne::Not => 0x33 | size_to_byte(size), InstructionOne::Jmp => 0x08 | size_to_byte(size), InstructionOne::Call => 0x18 | size_to_byte(size), @@ -1071,6 +1119,12 @@ fn instruction_to_byte(node: &AstNode) -> u8 { InstructionOne::Flp => 0x3D | size_to_byte(size), } } + AstNode::OperationIncDec {size, instruction, ..} => { + match instruction { + InstructionIncDec::Inc => 0x11 | size_to_byte(size), + InstructionIncDec::Dec => 0x31 | size_to_byte(size), + } + } AstNode::OperationTwo {size, instruction, ..} => { match instruction { InstructionTwo::Add => 0x01 | size_to_byte(size), @@ -1128,6 +1182,15 @@ fn condition_source_destination_to_byte(node: &AstNode) -> u8 { _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node), } } + AstNode::OperationIncDec {lhs, ..} => { + match lhs.as_ref() { + AstNode::Register(_) => 0x00, + AstNode::RegisterPointer(_) => 0x01, + AstNode::Immediate8(_) | AstNode::Immediate16(_) | AstNode::Immediate32(_) | AstNode::LabelOperand {..} => 0x02, + AstNode::ImmediatePointer(_) | AstNode::LabelOperandPointer {..} => 0x03, + _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node), + } + } AstNode::OperationTwo {rhs, ..} => { match rhs.as_ref() { AstNode::Register(_) => 0x00, @@ -1142,6 +1205,12 @@ fn condition_source_destination_to_byte(node: &AstNode) -> u8 { let destination: u8 = match node { AstNode::OperationZero {..} => 0x00, AstNode::OperationOne {..} => 0x00, + AstNode::OperationIncDec { rhs, ..} => { + match rhs.as_ref() { + AstNode::Immediate8(n) => *n << 2, + _ => panic!(""), + } + } AstNode::OperationTwo {lhs, ..} => { match lhs.as_ref() { AstNode::Register(_) => 0x00, @@ -1156,6 +1225,7 @@ fn condition_source_destination_to_byte(node: &AstNode) -> u8 { let condition: u8 = match node { AstNode::OperationZero {condition, ..} => condition_to_bits(condition), AstNode::OperationOne {condition, ..} => condition_to_bits(condition), + AstNode::OperationIncDec {condition, ..} => condition_to_bits(condition), AstNode::OperationTwo {condition, ..} => condition_to_bits(condition), _ => panic!("Attempting to parse a non-instruction AST node as an instruction: {:#?}", node), }; @@ -1219,6 +1289,9 @@ fn node_to_immediate_values(node: &AstNode, instruction: &AssembledInstruction) AstNode::OperationOne {operand, ..} => operand_to_immediate_value(instruction, operand.as_ref()), + AstNode::OperationIncDec {lhs, ..} => + operand_to_immediate_value(instruction, lhs.as_ref()), + AstNode::OperationTwo {rhs, ..} => operand_to_immediate_value(instruction, rhs.as_ref()), @@ -1229,6 +1302,7 @@ fn node_to_immediate_values(node: &AstNode, instruction: &AssembledInstruction) match node { AstNode::OperationZero {..} => {} AstNode::OperationOne {..} => {} + AstNode::OperationIncDec {..} => {} AstNode::OperationTwo {lhs, ..} => operand_to_immediate_value(instruction, lhs.as_ref()),