From 2c932cef4b0a59ce1e19f43f1184c62fcff09c43 Mon Sep 17 00:00:00 2001 From: jn Date: Wed, 1 Feb 2023 23:23:03 +0100 Subject: [PATCH 1/2] Print parse errors in a somewhat nicer way MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before: fox32asm 0.3.0 (94dd0fe) Generating raw binary Parsing includes... Parsing file... thread 'main' panicked at 'parse was unsuccessful: Error { variant: ParsingError { positives: [EOI, origin, include_bin, data, constant, label_kind, size, instruction], negatives: [] }, location: Pos(4), line_col: Pos((1, 5)), path: None, line: "nop 42␊", continued_line: None }', src/main.rs:529:60 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace After: fox32asm 0.3.0 (2abba95) Generating raw binary Parsing includes... Parsing file... Error { variant: ParsingError { positives: [ EOI, origin, include_bin, data, constant, label_kind, size, instruction, ], negatives: [], }, location: Pos( 4, ), line_col: Pos( ( 1, 5, ), ), path: None, line: "nop 42␊", continued_line: None, } --- src/main.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index ee37e74..de293dc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -351,13 +351,19 @@ fn main() { } println!("Parsing file..."); - let ast = parse(&input_file); + let ast = match parse(&input_file) { + Ok(x) => x, + Err(x) => { + print!("{:#?}\n", x); + std::process::exit(1); + }, + }; let mut instructions: Vec = Vec::new(); let mut current_address: u32 = 0; println!("Assembling..."); - for node in ast.unwrap() { + for node in ast { if let AstNode::LabelDefine {name, ..} = node { let mut address_table = LABEL_ADDRESSES.lock().unwrap(); if let Some(_) = address_table.get(&name) { @@ -525,7 +531,7 @@ fn include_binary_file(pair: pest::iterators::Pair) -> AstNode { fn parse(source: &str) -> Result, Error> { let mut ast = vec![]; - let pairs = Fox32Parser::parse(Rule::assembly, source).expect("parse was unsuccessful"); + let pairs = Fox32Parser::parse(Rule::assembly, source)?; for pair in pairs.peek().unwrap().into_inner() { match pair.as_rule() { From 0c47ce79af5b7e6b78050152eb6a633d2992e145 Mon Sep 17 00:00:00 2001 From: jn Date: Wed, 1 Feb 2023 21:37:03 +0100 Subject: [PATCH 2/2] Allow specifying width on zero-operand instructions nop.8 exists and is valid, so fox32asm should assemble it. It might be a good idea to reject some invalid instructions, though, such as out.8. --- src/fox32.pest | 2 +- src/main.rs | 34 ++++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/fox32.pest b/src/fox32.pest index 1d30191..47022cc 100644 --- a/src/fox32.pest +++ b/src/fox32.pest @@ -80,7 +80,7 @@ instruction = { } instruction_conditional = { - instruction_zero | + instruction_zero ~ size? | instruction_one ~ size? ~ operand | instruction_two ~ size? ~ operand ~ "," ~ operand } diff --git a/src/main.rs b/src/main.rs index de293dc..ecbcce4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -244,6 +244,7 @@ enum LabelKind { #[derive(PartialEq, Debug, Clone)] enum AstNode { OperationZero { + size: Size, condition: Condition, instruction: InstructionZero, }, @@ -729,7 +730,15 @@ fn parse_instruction(pair: pest::iterators::Pair) -> AstNode { let mut inner_pair = pair.into_inner(); let instruction_conditional_pair = inner_pair.next().unwrap(); match instruction_conditional_pair.as_rule() { - Rule::instruction_zero => parse_instruction_zero(instruction_conditional_pair, condition), + Rule::instruction_zero => { + if let Some(inner) = inner_pair.peek() { + if inner.as_rule() == Rule::size { + size = parse_size(&inner_pair.next().unwrap()); + } + } + *CURRENT_SIZE.lock().unwrap() = size; + parse_instruction_zero(instruction_conditional_pair, size, condition) + } Rule::instruction_one => { if inner_pair.peek().unwrap().as_rule() == Rule::size { size = parse_size(&inner_pair.next().unwrap()); @@ -859,8 +868,9 @@ fn parse_operand(mut pair: pest::iterators::Pair, is_pointer: bool) -> Ast } } -fn parse_instruction_zero(pair: pest::iterators::Pair, condition: Condition) -> AstNode { +fn parse_instruction_zero(pair: pest::iterators::Pair, size: Size, condition: Condition) -> AstNode { AstNode::OperationZero { + size: size, condition: condition, instruction: match pair.as_str() { "nop" => InstructionZero::Nop, @@ -1044,17 +1054,17 @@ fn size_to_byte(size: &Size) -> u8 { fn instruction_to_byte(node: &AstNode) -> u8 { match node { - AstNode::OperationZero {instruction, ..} => { + AstNode::OperationZero {size, instruction, ..} => { match instruction { - InstructionZero::Nop => 0x00 | size_to_byte(&Size::Word), - InstructionZero::Halt => 0x10 | size_to_byte(&Size::Word), - InstructionZero::Brk => 0x20 | size_to_byte(&Size::Word), - InstructionZero::Ret => 0x2A | size_to_byte(&Size::Word), - InstructionZero::Reti => 0x3A | size_to_byte(&Size::Word), - InstructionZero::Ise => 0x0C | size_to_byte(&Size::Word), - InstructionZero::Icl => 0x1C | size_to_byte(&Size::Word), - InstructionZero::Mse => 0x0D | size_to_byte(&Size::Word), - InstructionZero::Mcl => 0x1D | size_to_byte(&Size::Word), + InstructionZero::Nop => 0x00 | size_to_byte(size), + InstructionZero::Halt => 0x10 | size_to_byte(size), + InstructionZero::Brk => 0x20 | size_to_byte(size), + InstructionZero::Ret => 0x2A | size_to_byte(size), + InstructionZero::Reti => 0x3A | size_to_byte(size), + InstructionZero::Ise => 0x0C | size_to_byte(size), + InstructionZero::Icl => 0x1C | size_to_byte(size), + InstructionZero::Mse => 0x0D | size_to_byte(size), + InstructionZero::Mcl => 0x1D | size_to_byte(size), } } AstNode::OperationOne {size, instruction, ..} => {