解析器算法
概述
RustSim的解析器模块负责将SPICE网表文件转换为内部数据结构。该模块采用了混合解析策略,结合正则表达式和nom组合器库,实现了对复杂SPICE语法的健壮解析。
SPICE语法解析原理
SPICE网表格式
SPICE网表文件包含以下主要元素:
- 标题行:电路描述
- 元件定义:电阻、电容、电感、电压源、电流源等
- 分析指令:.op、.tran、.dc等
- 参数定义:.param等
- 结束标记:.end
解析策略
RustSim采用分层解析策略:
- 预处理层:清理注释、空行,标准化格式
- 分类层:识别行类型(元件、指令、参数等)
- 解析层:根据类型进行具体解析
- 验证层:检查解析结果的正确性
混合解析器实现
正则表达式解析器
对于元件行,RustSim使用正则表达式进行快速解析:
lazy_static! {
static ref COMPONENT_REGEX: Regex = Regex::new(
r"^([VRCLID][A-Za-z0-9]*)\s+([A-Za-z0-9]+)\s+([A-Za-z0-9]+)\s+(.+)$"
).unwrap();
}
优势:
- 解析速度快
- 错误处理简单
- 支持复杂模式匹配
实现细节:
fn parse_component_regex(line: &str) -> Result<Component, String> {
if let Some(captures) = COMPONENT_REGEX.captures(line) {
let name = captures[1].to_string();
let node1 = captures[2].to_string();
let node2 = captures[3].to_string();
let params = captures[4].trim();
// 解析元件类型和参数
let component_type = match name.chars().next().unwrap().to_ascii_uppercase() {
'R' => ComponentType::Resistor,
'C' => ComponentType::Capacitor,
'L' => ComponentType::Inductor,
'V' => ComponentType::VoltageSource,
'I' => ComponentType::CurrentSource,
'D' => ComponentType::Diode,
_ => return Err(format!("Unknown component type: {}", name)),
};
// 解析数值参数
let value = parse_value_with_unit(params)?;
Ok(Component {
name,
component_type,
nodes: vec![node1, node2],
value,
model: None,
})
} else {
Err(format!("Failed to parse component line: {}", line))
}
}
Nom组合器解析器
对于复杂的语法结构,使用nom组合器库:
fn parse_netlist_line(input: &str) -> IResult<&str, NetlistLine> {
let (input, _) = multispace0(input)?;
let (input, result) = terminated(
alt((
map(parse_component, NetlistLine::Component),
map(parse_analysis, NetlistLine::Analysis),
map(parse_parameter, |(name, value)| NetlistLine::Parameter(name, value)),
map(tag_no_case(".end"), |_| NetlistLine::End),
)),
multispace0,
)(input)?;
Ok((input, result))
}
单位转换算法
支持的单位
RustSim支持多种工程单位:
- 电阻:Ω, k (kΩ), meg (MΩ), m (mΩ), u (μΩ)
- 电容:F, m (mF), u (μF), n (nF), p (pF)
- 电感:H, m (mH), u (μH), n (nH)
- 时间:s, ms, us, ns, ps, fs
- 电压/电流:V, mV, uV / A, mA, uA, nA
转换算法实现
fn parse_value_with_unit(value_str: &str) -> Result<f64> {
let value_str = value_str.trim().to_lowercase();
if let Some(num_str) = value_str.strip_suffix("meg") {
Ok(num_str.parse::<f64>()? * 1e6)
} else if let Some(num_str) = value_str.strip_suffix("k") {
Ok(num_str.parse::<f64>()? * 1e3)
} else if let Some(num_str) = value_str.strip_suffix("m") {
Ok(num_str.parse::<f64>()? * 1e-3)
} else if let Some(num_str) = value_str.strip_suffix("u") {
Ok(num_str.parse::<f64>()? * 1e-6)
} else if let Some(num_str) = value_str.strip_suffix("n") {
Ok(num_str.parse::<f64>()? * 1e-9)
} else if let Some(num_str) = value_str.strip_suffix("p") {
Ok(num_str.parse::<f64>()? * 1e-12)
} else if let Some(num_str) = value_str.strip_suffix("f") {
Ok(num_str.parse::<f64>()? * 1e-15)
} else if let Some(num_str) = value_str.strip_suffix("v") {
Ok(num_str.parse::<f64>()?)
} else {
Ok(value_str.parse::<f64>()?)
}
}
错误处理和恢复机制
错误类型分类
- 语法错误:格式不正确、缺少参数
- 语义错误:参数值超出范围、元件类型不匹配
- 文件错误:文件不存在、权限问题
- 系统错误:内存不足、解析器内部错误
错误恢复策略
pub fn parse_netlist(&self, content: &str) -> Result<SpiceNetlist> {
let lines = self.preprocess_lines(content);
let mut components = Vec::new();
let mut analyses = Vec::new();
let mut parameters = HashMap::new();
for (line_num, line) in lines.iter().enumerate() {
if line.trim().is_empty() || line.trim().starts_with('*') {
continue; // 跳过空行和注释
}
// 首先尝试正则表达式解析
if let Ok(component) = parse_component_regex(line) {
components.push(component);
continue;
}
// 正则解析失败,尝试nom解析
match parse_netlist_line(line) {
Ok((_, NetlistLine::Component(component))) => {
components.push(component);
}
Ok((_, NetlistLine::Analysis(analysis))) => {
analyses.push(analysis);
}
Ok((_, NetlistLine::Parameter(name, value))) => {
parameters.insert(name, value);
}
Ok((_, NetlistLine::End)) => {
break; // 停止解析
}
Err(e) => {
// 记录错误但继续解析
println!("DEBUG: Failed to parse line {}: '{}', error: {:?}",
line_num + 1, line, e);
}
}
}
// 构建结果
let mut node_names = std::collections::HashSet::new();
for comp in &components {
for node in &comp.nodes {
node_names.insert(node.clone());
}
}
let nodes: Vec<Node> = node_names.into_iter()
.map(|name| Node::new(name))
.collect();
Ok(SpiceNetlist {
title: "".to_string(),
components,
nodes,
subcircuits: Vec::new(),
parameters,
analyses,
})
}
性能优化
1. 缓存机制
- 编译时正则表达式
- 解析结果缓存
- 单位转换表缓存
2. 并行处理
- 多行并行解析(未来扩展)
- 异步文件读取
3. 内存优化
- 字符串复用
- 零拷贝解析
- 智能内存分配
扩展性设计
1. 新元件类型支持
通过扩展正则表达式模式和解析函数,可以轻松添加新的元件类型。
2. 新分析类型支持
通过扩展nom组合器,可以支持新的分析指令。
3. 新单位支持
通过扩展单位转换表,可以支持新的工程单位。
测试和验证
1. 单元测试
每个解析函数都有对应的单元测试,确保正确性。
2. 集成测试
完整的网表文件解析测试,验证端到端功能。
3. 性能测试
解析速度和内存使用测试,确保性能要求。
总结
RustSim的解析器模块通过混合解析策略,实现了对SPICE语法的健壮解析。正则表达式提供了快速的元件解析,而nom组合器处理复杂的语法结构。完善的错误处理和恢复机制确保了系统的稳定性,而性能优化和扩展性设计为未来的功能扩展提供了基础。