diff --git a/Cargo.toml b/Cargo.toml index 494728b..ee63622 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,6 @@ edition = "2021" [dependencies] num = "0.4" clap = { version = "3.1.8", features = ["derive"] } +chrono = "0.4" +nom = "7.1.1" +nom-bufreader = "0.2.0" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 5423c94..f6d5982 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,27 @@ use std::fs::File; use num::*; use clap::Parser; +use chrono::prelude::*; +use std::collections::BTreeMap; + +use nom_bufreader::bufreader::BufReader; +use nom_bufreader::{Error, Parse}; +use nom::{ + branch::alt, + bytes::streaming::{tag, take_until, take_while1}, + character::is_alphanumeric, + character::complete::none_of, + character::streaming::{ + space0, alpha1, multispace0, + multispace1, digit1, line_ending, + alphanumeric1}, + combinator::map_res, + IResult, + sequence::{tuple, delimited, terminated, preceded} +}; + +// TODO : Remove +use std::str::from_utf8; #[derive(Parser)] struct Cli { @@ -12,49 +33,192 @@ struct Cli { path: std::path::PathBuf, } -struct Timestamp{ - file_offset: u64, - timestamp: BigInt +// TODO: implement any timescales greater than a second +#[derive(Debug)] +enum Timescale {ps, ns, us, ms, s, unit} + +#[derive(Debug)] +struct Scope_Idx(usize); + +#[derive(Debug)] +struct Signal_Idx(usize); + +#[derive(Debug)] +struct Version(String); + +#[derive(Debug)] +struct Metadata { + date : Option>, + version : Option, + timescale : (Option, Timescale)} + +#[derive(Debug)] +enum SignalGeneric{ + Signal{ + name : String, + timeline : BTreeMap, + scope_parent : Scope_Idx}, + SignalAlias{ + name : String, + signal_alias : Signal_Idx} } -fn main() -> std::io::Result<()> { +#[derive(Debug)] +struct Scope { + name : String, + child_signals : Vec, + child_scopes : Vec} + + +#[derive(Debug)] +struct VCD { + metadata : Metadata, + all_signals : Vec, + // the root scope should always be placed at index 0 + all_scopes : Vec} + +fn date(i: &[u8]) -> IResult<&[u8], DateTime, ()> { + let (i, _) = tag("$date")(i)?; + + let (i, _) = multispace1(i)?; + let (i, weekday) = alt(( + tag("Mon"), tag("Tue"), tag("Wed"), tag("Thu"), + tag("Fri"), tag("Sat"), tag("Sun")))(i)?; + + let (i, _) = multispace1(i)?; + let (i, month) = alt(( + tag("Jan"), tag("Feb"), tag("Mar"), tag("Apr"), + tag("May"), tag("Jun"), tag("July"), tag("Sept"), + tag("Oct"), tag("Nov"), tag("Dec")))(i)?; + + let (i, _) = multispace1(i)?; + let (i, day) = digit1(i)?; + + let (i, _) = multispace1(i)?; + let (i, hour) = digit1(i)?; + + let (i, _) = tag(":")(i)?; + let (i, minute) = digit1(i)?; + + let (i, _) = tag(":")(i)?; + let (i, second) = digit1(i)?; + + let (i, _) = multispace1(i)?; + let (i, year) = digit1(i)?; + + let (i, _) = multispace1(i)?; + let (i, _) = tag("$end")(i)?; + + let (weekday, month, day, hour, minute, second, year) = ( + from_utf8(weekday).unwrap(), + from_utf8(month).unwrap(), + from_utf8(day).unwrap(), + from_utf8(hour).unwrap(), + from_utf8(minute).unwrap(), + from_utf8(second).unwrap(), + from_utf8(year).unwrap(), + ); + + let dt = Utc.datetime_from_str( + format!("{weekday} {month} {day} {hour}:{minute}:{second} {year}") + .as_str(), "%a %b %e %T %Y") + .unwrap(); + + Ok((i, dt)) + +} + +fn version(i: &[u8]) -> IResult<&[u8], String, ()> { + let (i, _) = tag("$version")(i)?; + let (mut i, _) = multispace1(i)?; + + let mut version = "".to_string(); + let mut reached_end = false; + + while (reached_end == false) { + let (_i, next_word) = take_while1( + |c| + c != 36 && // not $ + c >= 33 && // between ! and ~ + c <= 126 + )(i)?; + i = _i; + let next_word = from_utf8(next_word).unwrap(); + + version = format!("{version} {next_word}"); + let (_i, _) = multispace1(i)?; + i = _i; + + match tag::<&str, &[u8], ()>("$end")(i) { + Ok((_i, _)) => { + i = _i; + reached_end = true; + } + Err(_) => {} + }; + + } + + // strip the initial space + version = version[1..].to_string(); + + Ok((i, version)) + +} + +fn timescale(i: &[u8]) -> IResult<&[u8], (Option, Timescale), ()> { + let (i, _) = tag("$timescale")(i)?; + dbg!("here"); + let (i, _) = multispace1(i)?; + + let (i, scale) = digit1(i)?; + let (i, _) = multispace1(i)?; + + let (i, unit) = alpha1(i)?; + let (i, _) = multispace1(i)?; + + let (i, _) = tag("$end")(i)?; + + let scale = from_utf8(scale).unwrap().to_string(); + let scale = scale.parse::().unwrap(); + + let unit = match from_utf8(unit).unwrap() { + "ps" => Ok(Timescale::ps), + "ns" => Ok(Timescale::ns), + "us" => Ok(Timescale::us), + "ms" => Ok(Timescale::ms), + "s" => Ok(Timescale::s), + _ => Err(()) + }.unwrap(); + + + Ok((i, (Some(scale), unit))) + +} + +fn f_multispace0(i: &[u8]) -> IResult<&[u8], (), ()> { + let (i, _) = multispace0(i)?; + Ok((i, ())) +} + +fn main() -> Result<(), Error<()>> { let args = Cli::parse(); let file = File::open(&args.path)?; - let mut reader = io::BufReader::new(file); + let mut reader = BufReader::new(file); - let mut buffer = String::new(); - let mut timestamp_offsets = Vec::new(); - let mut timestamps = Vec::new(); + reader.parse(f_multispace0).unwrap(); + let date = reader.parse(date).expect("failed to parse date"); - while { - let bytes_read = reader.read_line(&mut buffer).unwrap(); - bytes_read > 0 - } { - if &buffer[0..1] == "#" { - let pos = reader.stream_position().unwrap(); - timestamp_offsets.push(pos); + reader.parse(f_multispace0).unwrap(); + let version = reader.parse(version).expect("failed to parse version"); - let timestamp = { - let len = buffer.len(); - let str_val = &buffer[1..(len - 1)].as_bytes(); - BigInt::parse_bytes(str_val, 10).unwrap() - }; - timestamps.push(timestamp); - } - buffer.clear() - } + reader.parse(f_multispace0).unwrap(); + let timescale = reader.parse(timescale).expect("failed to parse timescale"); - let index = 4; - let timestamp_offset = timestamp_offsets.get(index).unwrap(); - let timestamp = timestamps.get(index).unwrap(); - dbg!((timestamp_offset, timestamp)); - - // seek to where we found the first timestamp and read - // out the next line - reader.seek(io::SeekFrom::Start(*timestamp_offset)); - reader.read_line(&mut buffer); - dbg!(buffer); + dbg!(date.to_rfc2822()); + dbg!(version); + dbg!(timescale); Ok(()) -} +} \ No newline at end of file