From 59221648ca1e4108f78d7eed9927fe5ad2bdcb0c Mon Sep 17 00:00:00 2001 From: Chris Mounce Date: Sat, 9 Mar 2024 01:39:34 -0800 Subject: [PATCH] Expand Stat parsing to cover all fields Also in this commit: taking nom for a spin. --- Cargo.lock | 23 +++++++++++++++++ Cargo.toml | 1 + src/main.rs | 73 +++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 84 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e6b41aa..e3f45e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,6 +7,7 @@ name = "assembler" version = "0.1.0" dependencies = [ "byteorder", + "nom", ] [[package]] @@ -14,3 +15,25 @@ name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] diff --git a/Cargo.toml b/Cargo.toml index 0d5df31..f0f0393 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ edition = "2021" [dependencies] byteorder = "1.5.0" +nom = "7.1.3" diff --git a/src/main.rs b/src/main.rs index 64cc94a..640ab14 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,10 @@ use byteorder::{ByteOrder, LittleEndian}; +use nom::{ + bytes::complete::take, + number::complete::{le_i16, le_u8}, + sequence::tuple, + IResult, +}; use std::{env, error::Error, fs, process::exit}; struct World { @@ -14,7 +20,20 @@ struct Board { } struct Stat { - info: Vec, + x: u8, + y: u8, + x_step: i16, + y_step: i16, + cycle: i16, + p1: u8, + p2: u8, + p3: u8, + follower: i16, + leader: i16, + under_element: u8, + under_color: u8, + instruction_pointer: i16, + bind_index: i16, code: Vec, } @@ -74,18 +93,10 @@ impl Board { u16::from_le_bytes((&bytes[offset..offset + 2]).try_into().unwrap()) as usize + 1; offset += 2; let mut stats = Vec::with_capacity(num_stats); + let mut input = &bytes[offset..]; for _ in 0..num_stats { - let mut stat = Stat { - info: Vec::from(&bytes[offset..offset + 25]), - code: vec![], - }; - offset += 25 + 8; - let code_len = i16::from_le_bytes((&stat.info[23..25]).try_into().unwrap()); - if code_len > 0 { - let code_len = code_len as usize; - stat.code = Vec::from(&bytes[offset..offset + code_len]); - offset += code_len; - } + let (next_input, stat) = Stat::parse(input).map_err(|e| e.to_owned())?; + input = next_input; stats.push(stat); } Ok(Board { @@ -97,6 +108,39 @@ impl Board { } } +impl Stat { + fn parse(input: &[u8]) -> IResult<&[u8], Self> { + let (input, (x, y, x_step, y_step)) = tuple((le_u8, le_u8, le_i16, le_i16))(input)?; + let (input, (cycle, p1, p2, p3)) = tuple((le_i16, le_u8, le_u8, le_u8))(input)?; + let (input, (follower, leader)) = tuple((le_i16, le_i16))(input)?; + let (input, (under_element, under_color)) = tuple((le_u8, le_u8))(input)?; + let (input, _) = take(4usize)(input)?; + let (input, (instruction_pointer, length)) = tuple((le_i16, le_i16))(input)?; + let (input, _) = take(8usize)(input)?; + let (input, code) = take(0.max(length) as usize)(input)?; + Ok(( + input, + Stat { + x, + y, + x_step, + y_step, + follower, + leader, + cycle, + p1, + p2, + p3, + under_element, + under_color, + instruction_pointer, + bind_index: 0.min(length), + code: Vec::from(code), + }, + )) + } +} + fn to_latin1(bytes: &[u8]) -> String { bytes.iter().map(|&x| x as char).collect() } @@ -111,11 +155,14 @@ fn main() -> Result<(), Box> { let bytes = fs::read(&args[1])?; let world = World::from(&bytes)?; + // Print some of the data parsed. + // TODO: Implement some macros, or other code modification + // Then, we can try writing a copy to disk. println!("num boards: {}", &world.boards.len()); for board in &world.boards { println!("board: {}", to_latin1(&board.name)); for stat in &board.stats { - let (x, y) = (stat.info[0] as usize, stat.info[1] as usize); + let (x, y) = (stat.x as usize, stat.y as usize); println!( " stat at ({}, {}): {:?}, {:?}", x,