use crate::objdump::DumpEntry;
use crate::semantic::SemanticInterpreter;
use std::path::PathBuf;
use std::fs;
use std::io::Write;
pub struct TableGenerator {
c_code_width: usize,
}
impl TableGenerator {
pub fn new() -> Self {
Self {
c_code_width: 80, }
}
pub fn generate_table(&self, entries: &[DumpEntry]) -> String {
let mut output = String::new();
output.push_str("| C代码 | 汇编指令 | 语义解释 |\n");
output.push_str("|-------|----------|----------|\n");
let mut current_c_code = String::new();
for entry in entries {
if entry.asm_instruction.is_empty() {
output.push_str(&format!(
"| {} | | |\n",
&entry.c_code ));
continue;
}
let c_code = if entry.c_code.is_empty() || entry.c_code == current_c_code {
String::from("") } else {
current_c_code = entry.c_code.clone();
self.format_c_code(&entry.c_code)
};
let asm_inst = &entry.asm_instruction;
let semantic = if let Some(ref parsed) = entry.parsed_instruction {
SemanticInterpreter::interpret(parsed)
} else {
Self::basic_interpret(asm_inst)
};
output.push_str(&format!(
"| {} | {} | {} |\n",
c_code, asm_inst, semantic
));
}
output
}
fn basic_interpret(asm_inst: &str) -> String {
let inst_lower = asm_inst.to_lowercase();
if inst_lower.starts_with("ldp") {
Self::interpret_ldp_basic(asm_inst)
} else if inst_lower.starts_with("stp") {
Self::interpret_stp_basic(asm_inst)
} else if inst_lower.starts_with("ldr") {
Self::interpret_ldr_basic(asm_inst)
} else if inst_lower.starts_with("str") {
Self::interpret_str_basic(asm_inst)
} else if inst_lower.starts_with("bl ") {
String::from("调用函数")
} else if inst_lower.starts_with("b.") {
String::from("条件跳转")
} else if inst_lower.starts_with("b ") {
String::from("无条件跳转")
} else if inst_lower.starts_with("ccmp") {
String::from("条件比较")
} else if inst_lower.starts_with("mov") {
Self::interpret_mov_basic(asm_inst)
} else if inst_lower.starts_with("add") {
String::from("加法运算")
} else if inst_lower.starts_with("sub") {
String::from("减法运算")
} else if inst_lower.starts_with("cmp") {
String::from("比较运算")
} else if inst_lower.starts_with("ret") {
String::from("函数返回")
} else if inst_lower.starts_with("nop") {
String::from("空操作")
} else {
String::from("指令")
}
}
fn interpret_ldr_basic(asm: &str) -> String {
if let Some(parts) = asm.split_whitespace().nth(1) {
if let Some(reg) = parts.split(',').next() {
return format!("从内存加载到 {}", reg.trim());
}
}
String::from("从内存加载")
}
fn interpret_str_basic(asm: &str) -> String {
if let Some(parts) = asm.split_whitespace().nth(1) {
if let Some(reg) = parts.split(',').next() {
return format!("将 {} 存储到内存", reg.trim());
}
}
String::from("存储到内存")
}
fn interpret_ldp_basic(asm: &str) -> String {
if let Some(operands) = asm.split_whitespace().nth(1) {
let regs: Vec<&str> = operands.split(',').take(2).collect();
if regs.len() == 2 {
return format!("从内存加载 {} 和 {}", regs[0].trim(), regs[1].trim());
}
}
String::from("从内存加载一对寄存器")
}
fn interpret_stp_basic(asm: &str) -> String {
if let Some(operands) = asm.split_whitespace().nth(1) {
let regs: Vec<&str> = operands.split(',').take(2).collect();
if regs.len() == 2 {
return format!("将 {} 和 {} 存储到内存", regs[0].trim(), regs[1].trim());
}
}
String::from("存储一对寄存器到内存")
}
fn interpret_mov_basic(asm: &str) -> String {
if let Some(operands) = asm.split_whitespace().nth(1) {
let parts: Vec<&str> = operands.split(',').take(2).collect();
if parts.len() == 2 {
return format!("{} = {}", parts[0].trim(), parts[1].trim());
}
}
String::from("数据移动")
}
pub fn generate_comparison_table(
&self,
o0_entries: &[DumpEntry],
o1_entries: &[DumpEntry],
o2_entries: &[DumpEntry],
) -> String {
let mut output = String::new();
output.push_str("## 优化级别对比\n\n");
output.push_str("### O0 (无优化)\n\n");
output.push_str(&self.generate_table(o0_entries));
output.push_str("\n");
output.push_str("### O1 (基础优化)\n\n");
output.push_str(&self.generate_table(o1_entries));
output.push_str("\n");
output.push_str("### O2 (高级优化)\n\n");
output.push_str(&self.generate_table(o2_entries));
output.push_str("\n");
output.push_str("### 统计信息\n\n");
output.push_str(&format!("- O0: {} 条指令\n", o0_entries.len()));
output.push_str(&format!("- O1: {} 条指令\n", o1_entries.len()));
output.push_str(&format!("- O2: {} 条指令\n", o2_entries.len()));
output.push_str("\n");
output
}
fn format_c_code(&self, code: &str) -> String {
if code.is_empty() {
return String::from("");
}
let code = code.replace("<br>", " ");
let code = code.split_whitespace().collect::<Vec<_>>().join(" ");
if code.len() > self.c_code_width {
if let Some(pos) = code[..self.c_code_width].rfind(|c: char| c == ',' || c == ';' || c == ')' || c == ' ') {
format!("{}...", &code[..pos + 1].trim())
} else {
format!("{}...", &code[..self.c_code_width - 3])
}
} else {
code
}
}
pub fn save_to_file(&self, content: &str, path: &PathBuf) -> std::io::Result<()> {
let mut file = fs::File::create(path)?;
file.write_all(content.as_bytes())?;
Ok(())
}
pub fn generate_from_dumps(
&self,
function_name: &str,
dump_prefix: &str,
output_dir: Option<&PathBuf>,
) -> anyhow::Result<()> {
use crate::objdump::ObjdumpParser;
let clean_prefix = dump_prefix
.strip_suffix(".dump").unwrap_or(dump_prefix)
.trim_end_matches("_O0")
.trim_end_matches("_O1")
.trim_end_matches("_O2");
let o0_path = format!("{}_O0.dump", clean_prefix);
let o1_path = format!("{}_O1.dump", clean_prefix);
let o2_path = format!("{}_O2.dump", clean_prefix);
println!("读取 {} ...", o0_path);
let o0_parser = ObjdumpParser::from_file(&o0_path)?;
let o0_entries = o0_parser.extract_function_data(function_name)?;
println!("读取 {} ...", o1_path);
let o1_parser = ObjdumpParser::from_file(&o1_path)?;
let o1_entries = o1_parser.extract_function_data(function_name)?;
println!("读取 {} ...", o2_path);
let o2_parser = ObjdumpParser::from_file(&o2_path)?;
let o2_entries = o2_parser.extract_function_data(function_name)?;
println!("生成对比表格...");
let table = self.generate_comparison_table(&o0_entries, &o1_entries, &o2_entries);
let output_path = if let Some(dir) = output_dir {
dir.join(format!("{}_comparison.md", function_name))
} else {
PathBuf::from(format!("{}_comparison.md", function_name))
};
println!("保存到 {} ...", output_path.display());
self.save_to_file(&table, &output_path)?;
println!("完成!");
Ok(())
}
pub fn generate_from_single_dump(
&self,
function_name: &str,
dump_path: &str,
output_dir: Option<&PathBuf>,
) -> anyhow::Result<()> {
use crate::objdump::ObjdumpParser;
println!("读取 {} ...", dump_path);
let parser = ObjdumpParser::from_file(dump_path)?;
let entries = parser.extract_function_data(function_name)?;
println!("生成分析表格...");
let table = self.generate_table(&entries);
let output_path = if let Some(dir) = output_dir {
dir.join(format!("{}_analysis.md", function_name))
} else {
PathBuf::from(format!("{}_analysis.md", function_name))
};
println!("保存到 {} ...", output_path.display());
self.save_to_file(&table, &output_path)?;
println!("完成!");
Ok(())
}
}
impl Default for TableGenerator {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::instruction::{Instruction, InstructionType, Operand};
use crate::register::Register;
#[test]
fn test_generate_table() {
let generator = TableGenerator::new();
let entries = vec![
DumpEntry {
c_line: Some(1),
c_code: String::from("int a = 0;"),
address: String::from("0x1000"),
machine_code: String::from("d2800000"),
asm_instruction: String::from("mov x0, #0"),
parsed_instruction: Some(Instruction::new(
InstructionType::MOV,
vec![
Operand::Register(Register::X0),
Operand::Immediate(0),
],
0x1000,
)),
},
];
let table = generator.generate_table(&entries);
assert!(table.contains("C代码"));
assert!(table.contains("语义解释"));
assert!(table.contains("mov x0, #0"));
}
}