New parser #2
|
@ -18,7 +18,10 @@ fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
|
|
||||||
let file = File::open(&args.path)?;
|
let file = File::open(&args.path)?;
|
||||||
parse_vcd(file).unwrap();
|
let vcd = parse_vcd(file).unwrap();
|
||||||
|
|
||||||
|
println!("printing signal tree");
|
||||||
|
vcd.print_scopes();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
129
src/vcd/parse.rs
129
src/vcd/parse.rs
|
@ -35,6 +35,8 @@ fn parse_var<'a>(
|
||||||
"reg" => {Ok(Sig_Type::Reg)}
|
"reg" => {Ok(Sig_Type::Reg)}
|
||||||
"string" => {Ok(Sig_Type::Str)}
|
"string" => {Ok(Sig_Type::Str)}
|
||||||
"wire" => {Ok(Sig_Type::Wire)}
|
"wire" => {Ok(Sig_Type::Wire)}
|
||||||
|
"tri1" => {Ok(Sig_Type::Tri1)}
|
||||||
|
"time" => {Ok(Sig_Type::Time)}
|
||||||
_ => {
|
_ => {
|
||||||
let err = format!("found keyword `{word}` but expected one of {expected_types} on {cursor:?}");
|
let err = format!("found keyword `{word}` but expected one of {expected_types} on {cursor:?}");
|
||||||
Err(err)
|
Err(err)
|
||||||
|
@ -118,22 +120,38 @@ fn parse_signal_tree<'a>(
|
||||||
// $scope module reg_mag_i $end
|
// $scope module reg_mag_i $end
|
||||||
// ^^^^^^ - module keyword
|
// ^^^^^^ - module keyword
|
||||||
let err = format!("reached end of file without parser leaving {}", function_name!());
|
let err = format!("reached end of file without parser leaving {}", function_name!());
|
||||||
ident(word_reader, "module")?;
|
let (keyword, cursor) = word_reader.next_word().ok_or(&err)?;
|
||||||
|
|
||||||
|
// TODO : just check if keyword is in expected
|
||||||
|
let expected = ["module", "begin", "task", "function"];
|
||||||
|
match keyword {
|
||||||
|
"module" => {Ok(())}
|
||||||
|
"begin" => {Ok(())}
|
||||||
|
"task" => {Ok(())}
|
||||||
|
"function" => {Ok(())}
|
||||||
|
_ => {
|
||||||
|
let err = format!("found keyword `{keyword}` but expected one of `{expected:?}` on {cursor:?}");
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}.unwrap();
|
||||||
|
|
||||||
// $scope module reg_mag_i $end
|
// $scope module reg_mag_i $end
|
||||||
// ^^^^^^^^^ - scope name
|
// ^^^^^^^^^ - scope name
|
||||||
let (scope_name, _) = word_reader.next_word().ok_or(err)?;
|
let (scope_name, _) = word_reader.next_word().ok_or(&err)?;
|
||||||
|
|
||||||
let curr_scope_idx = Scope_Idx(vcd.all_scopes.len());
|
let curr_scope_idx = Scope_Idx(vcd.all_scopes.len());
|
||||||
|
|
||||||
// register this scope as a child of the current parent scope
|
// register this scope as a child of the current parent scope
|
||||||
// if there is a parent scope
|
// if there is a parent scope, or else we register this scope as
|
||||||
|
// root scope
|
||||||
match parent_scope_idx {
|
match parent_scope_idx {
|
||||||
Some(Scope_Idx(parent_scope_idx)) => {
|
Some(Scope_Idx(parent_scope_idx)) => {
|
||||||
let parent_scope = vcd.all_scopes.get_mut(parent_scope_idx).unwrap();
|
let parent_scope = vcd.all_scopes.get_mut(parent_scope_idx).unwrap();
|
||||||
parent_scope.child_scopes.push(curr_scope_idx);
|
parent_scope.child_scopes.push(curr_scope_idx);
|
||||||
}
|
}
|
||||||
None => {}
|
None => {
|
||||||
|
vcd.scope_roots.push(curr_scope_idx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add this scope to list of existing scopes
|
// add this scope to list of existing scopes
|
||||||
|
@ -161,7 +179,7 @@ fn parse_signal_tree<'a>(
|
||||||
match residual {
|
match residual {
|
||||||
"scope" => {
|
"scope" => {
|
||||||
// recursive - parse inside of current scope tree
|
// recursive - parse inside of current scope tree
|
||||||
parse_signal_tree(word_reader, Some(curr_scope_idx), vcd, signal_map);
|
parse_signal_tree(word_reader, Some(curr_scope_idx), vcd, signal_map)?;
|
||||||
}
|
}
|
||||||
"var" => {
|
"var" => {
|
||||||
parse_var(word_reader, curr_scope_idx, vcd, signal_map)?;
|
parse_var(word_reader, curr_scope_idx, vcd, signal_map)?;
|
||||||
|
@ -170,8 +188,14 @@ fn parse_signal_tree<'a>(
|
||||||
ident(word_reader, "$end")?;
|
ident(word_reader, "$end")?;
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
// we ignore comments
|
||||||
|
"comment" => {
|
||||||
|
loop {
|
||||||
|
if ident(word_reader, "$end").is_ok() {break}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let err = format!("found keyword `{residual}` but expected `$scope`, `$var`, or `$upscope` on {cursor:?}");
|
let err = format!("found keyword `{residual}` but expected `$scope`, `$var`, `$comment`, or `$upscope` on {cursor:?}");
|
||||||
return Err(err)
|
return Err(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,47 +211,52 @@ fn parse_signal_tree<'a>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : make this a generic traversal function that applies specified
|
#[named]
|
||||||
// functions upon encountering scopes and signals
|
fn parse_scopes<'a>(
|
||||||
fn print_signal_tree(
|
word_reader : &mut WordReader,
|
||||||
root_scope_idx : Scope_Idx,
|
parent_scope_idx : Option<Scope_Idx>,
|
||||||
all_scopes : &Vec<Scope>,
|
vcd : &'a mut VCD,
|
||||||
all_signals : &Vec<Signal>,
|
signal_map : &mut HashMap<String, Signal_Idx>
|
||||||
depth : usize)
|
) -> Result<(), String> {
|
||||||
{
|
// we've already seen `$scope`, so here we just jump right in
|
||||||
let indent = " ".repeat(depth * 4);
|
parse_signal_tree(word_reader, None, vcd, signal_map)?;
|
||||||
let Scope_Idx(root_scope_idx) = root_scope_idx;
|
|
||||||
let root_scope = &all_scopes[root_scope_idx];
|
|
||||||
let root_scope_name = &root_scope.name;
|
|
||||||
|
|
||||||
println!("{indent}scope: {root_scope_name}");
|
let err = format!("reached end of file without parser leaving {}", function_name!());
|
||||||
|
let expected_keywords = ["$scope", "$enddefinitions"];
|
||||||
|
|
||||||
for Signal_Idx(ref signal_idx) in &root_scope.child_signals {
|
loop {
|
||||||
let child_signal = &all_signals[*signal_idx];
|
let (word, cursor) = word_reader.next_word().ok_or(&err)?;
|
||||||
let name = match child_signal {
|
match word {
|
||||||
Signal::Data{name, ..} => {name}
|
"$scope" => {
|
||||||
Signal::Alias{name, ..} => {name}
|
parse_signal_tree(word_reader, None, vcd, signal_map)?;
|
||||||
};
|
|
||||||
println!("{indent} - sig: {name}")
|
|
||||||
}
|
}
|
||||||
println!();
|
"$enddefinitions" => {
|
||||||
|
ident(word_reader, "$end")?;
|
||||||
for scope_idx in &root_scope.child_scopes {
|
break
|
||||||
// let Scope_Idx(ref scope_idx_usize) = scope_idx;
|
|
||||||
// let child_scope = &all_scopes[*scope_idx_usize];
|
|
||||||
print_signal_tree(*scope_idx, all_scopes, all_signals, depth+1);
|
|
||||||
}
|
}
|
||||||
// let root = vcd.all_scopes;
|
// we ignore comments
|
||||||
|
"comment" => {
|
||||||
|
loop {
|
||||||
|
if ident(word_reader, "$end").is_ok() {break}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let err = format!("found keyword `{word}` but expected oneof `{expected_keywords:?}` on {cursor:?}");
|
||||||
|
return Err(err)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_vcd(file : File) -> Result<(), String> {
|
|
||||||
|
pub fn parse_vcd(file : File) -> Result<VCD, String> {
|
||||||
let mut word_gen = WordReader::new(file);
|
let mut word_gen = WordReader::new(file);
|
||||||
|
|
||||||
let header = parse_metadata(&mut word_gen)?;
|
let header = parse_metadata(&mut word_gen)?;
|
||||||
dbg!(&header);
|
|
||||||
|
|
||||||
// let (word, cursor) = word_gen.next_word().unwrap();
|
|
||||||
// cursor.error(word).unwrap();
|
|
||||||
let mut signal_map = std::collections::HashMap::new();
|
let mut signal_map = std::collections::HashMap::new();
|
||||||
|
|
||||||
let mut vcd = VCD{
|
let mut vcd = VCD{
|
||||||
|
@ -237,10 +266,9 @@ pub fn parse_vcd(file : File) -> Result<(), String> {
|
||||||
scope_roots: vec![],
|
scope_roots: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
parse_signal_tree(&mut word_gen, None, &mut vcd, &mut signal_map)?;
|
parse_scopes(&mut word_gen, None, &mut vcd, &mut signal_map)?;
|
||||||
println!("printing signal tree");
|
|
||||||
print_signal_tree(Scope_Idx(0), &vcd.all_scopes, &vcd.all_signals, 0);
|
Ok(vcd)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -278,4 +306,23 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn scopes() {
|
||||||
|
// TODO: eventually, once all dates pass, merge the following
|
||||||
|
// two loops
|
||||||
|
// testing dates
|
||||||
|
for file_name in test::files {
|
||||||
|
let file = File::open(file_name).unwrap();
|
||||||
|
let vcd = parse_vcd(file);
|
||||||
|
|
||||||
|
if !vcd.is_ok() {
|
||||||
|
dbg!(file_name);
|
||||||
|
vcd.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert!(vcd.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -21,7 +21,7 @@ pub(super) struct Scope_Idx(pub(super) usize);
|
||||||
pub(super) struct Signal_Idx(pub(super) usize);
|
pub(super) struct Signal_Idx(pub(super) usize);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum Sig_Type {Integer, Parameter, Real, Reg, Str, Wire,}
|
pub(super) enum Sig_Type {Integer, Parameter, Real, Reg, Str, Wire, Tri1, Time}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum Sig_Value {
|
pub(super) enum Sig_Value {
|
||||||
|
@ -61,3 +61,46 @@ pub struct VCD {
|
||||||
pub(super) all_signals : Vec<Signal>,
|
pub(super) all_signals : Vec<Signal>,
|
||||||
pub(super) all_scopes : Vec<Scope>,
|
pub(super) all_scopes : Vec<Scope>,
|
||||||
pub(super) scope_roots : Vec<Scope_Idx>}
|
pub(super) scope_roots : Vec<Scope_Idx>}
|
||||||
|
|
||||||
|
impl VCD {
|
||||||
|
// TODO : make this a generic traversal function that applies specified
|
||||||
|
// functions upon encountering scopes and signals
|
||||||
|
fn print_scope_tree(
|
||||||
|
&self,
|
||||||
|
root_scope_idx : Scope_Idx,
|
||||||
|
depth : usize)
|
||||||
|
{
|
||||||
|
let all_scopes = &self.all_scopes;
|
||||||
|
let all_signals = &self.all_signals;
|
||||||
|
|
||||||
|
let indent = " ".repeat(depth * 4);
|
||||||
|
let Scope_Idx(root_scope_idx) = root_scope_idx;
|
||||||
|
let root_scope = &all_scopes[root_scope_idx];
|
||||||
|
let root_scope_name = &root_scope.name;
|
||||||
|
|
||||||
|
println!("{indent}scope: {root_scope_name}");
|
||||||
|
|
||||||
|
for Signal_Idx(ref signal_idx) in &root_scope.child_signals {
|
||||||
|
let child_signal = &all_signals[*signal_idx];
|
||||||
|
let name = match child_signal {
|
||||||
|
Signal::Data{name, ..} => {name}
|
||||||
|
Signal::Alias{name, ..} => {name}
|
||||||
|
};
|
||||||
|
println!("{indent} - sig: {name}")
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
|
||||||
|
for scope_idx in &root_scope.child_scopes {
|
||||||
|
// let Scope_Idx(ref scope_idx_usize) = scope_idx;
|
||||||
|
// let child_scope = &all_scopes[*scope_idx_usize];
|
||||||
|
self.print_scope_tree(*scope_idx, depth+1);
|
||||||
|
}
|
||||||
|
// let root = vcd.all_scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_scopes(&self) {
|
||||||
|
for scope_root in &self.scope_roots {
|
||||||
|
self.print_scope_tree(*scope_root, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue