Skip to main content

b2c2_stat/
lib.rs

1// b2c2-stat crate
2// author: Leonardone @ NEETSDKASU
3
4use b2c2_casl2::*;
5use std::collections::{BTreeMap, HashMap};
6
7pub fn analyze(statements: &[Statement]) -> String {
8    let mut comment_lines: usize = 0;
9    let mut with_comment_lines: usize = 0;
10    let mut labels = HashMap::<String, usize>::new();
11    let mut commands = HashMap::<String, usize>::new();
12    let mut total_ds_size: usize = 0;
13    let mut total_dc_size: usize = 0;
14    let mut total_dc_item_count: usize = 0;
15    let mut registers = vec![0_usize; 8];
16    let mut index_registers = vec![0_usize; 8];
17    let mut literals = HashMap::<String, usize>::new();
18    let mut r_codes = HashMap::<String, usize>::new();
19    let mut a_codes = HashMap::<String, usize>::new();
20    let mut p_codes = HashMap::<String, usize>::new();
21    let mut name: String = String::new();
22
23    for stmt in statements.iter() {
24        match stmt {
25            Statement::Comment { .. } => {
26                comment_lines += 1;
27            }
28            Statement::Code {
29                label,
30                command,
31                comment,
32            } => {
33                if comment.is_some() {
34                    with_comment_lines += 1;
35                }
36                if let Some(label) = label {
37                    let key = label.as_str().to_string();
38                    labels.entry(key).or_insert(0);
39                }
40                match command {
41                    Command::Start { entry_point } => {
42                        if let Some(label) = label {
43                            name.push_str(label.as_str());
44                        }
45                        if let Some(label) = entry_point {
46                            let key = label.as_str().to_string();
47                            *labels.entry(key).or_insert(0) += 1;
48                        }
49                        *commands.entry("START".to_string()).or_insert(0) += 1;
50                    }
51                    Command::End => *commands.entry("END".to_string()).or_insert(0) += 1,
52                    Command::Ds { size } => {
53                        total_ds_size += *size as usize;
54                        *commands.entry("DS".to_string()).or_insert(0) += 1;
55                    }
56                    Command::Dc { constants } => {
57                        total_dc_item_count += constants.len();
58                        total_dc_size += constants.len();
59                        for cnst in constants.iter() {
60                            match cnst {
61                                Constant::Label(label) => {
62                                    let key = label.as_str().to_string();
63                                    *labels.entry(key).or_insert(0) += 1;
64                                }
65                                Constant::Str(s) => {
66                                    total_dc_size += s.chars().count();
67                                    total_dc_size -= 1;
68                                }
69                                _ => {}
70                            }
71                        }
72                        *commands.entry("DC".to_string()).or_insert(0) += 1;
73                    }
74                    Command::In { pos, len } => {
75                        *labels.entry(pos.as_str().to_string()).or_insert(0) += 1;
76                        *labels.entry(len.as_str().to_string()).or_insert(0) += 1;
77                        *commands.entry("IN".to_string()).or_insert(0) += 1;
78                    }
79                    Command::Out { pos, len } => {
80                        *labels.entry(pos.as_str().to_string()).or_insert(0) += 1;
81                        *labels.entry(len.as_str().to_string()).or_insert(0) += 1;
82                        *commands.entry("OUT".to_string()).or_insert(0) += 1;
83                    }
84                    Command::Rpush => *commands.entry("RPUSH".to_string()).or_insert(0) += 1,
85                    Command::Rpop => *commands.entry("RPOP".to_string()).or_insert(0) += 1,
86                    Command::R { code, r1, r2 } => {
87                        registers[*r1 as usize] += 1;
88                        registers[*r2 as usize] += 1;
89                        use R::*;
90                        let s = match code {
91                            Ld => "LD",
92                            Adda => "ADDA",
93                            Addl => "ADDL",
94                            Suba => "SUBA",
95                            Subl => "SUBL",
96                            And => "AND",
97                            Or => "OR",
98                            Xor => "XOR",
99                            Cpa => "CPA",
100                            Cpl => "CPL",
101                        };
102                        *r_codes.entry(s.to_string()).or_insert(0) += 1;
103                    }
104                    Command::A { code, r, adr, x } => {
105                        registers[*r as usize] += 1;
106                        if let Some(reg) = x {
107                            index_registers[*reg as usize] += 1;
108                        }
109                        if let Adr::Label(label) = adr {
110                            let key = label.as_str().to_string();
111                            *labels.entry(key).or_insert(0) += 1;
112                        } else if matches!(
113                            adr,
114                            Adr::LiteralDec(_) | Adr::LiteralHex(_) | Adr::LiteralStr(_)
115                        ) {
116                            *literals.entry(adr.to_string()).or_insert(0) += 1;
117                        }
118                        use A::*;
119                        let s = match code {
120                            Ld => "LD",
121                            St => "ST",
122                            Lad => "LAD",
123                            Adda => "ADDA",
124                            Addl => "ADDL",
125                            Suba => "SUBA",
126                            Subl => "SUBL",
127                            And => "AND",
128                            Or => "OR",
129                            Xor => "XOR",
130                            Cpa => "CPA",
131                            Cpl => "CPL",
132                            Sla => "SLA",
133                            Sra => "SRA",
134                            Sll => "SLL",
135                            Srl => "SRL",
136                        };
137                        *a_codes.entry(s.to_string()).or_insert(0) += 1;
138                    }
139                    Command::P { code, adr, x } => {
140                        if let Some(reg) = x {
141                            index_registers[*reg as usize] += 1;
142                        }
143                        if let Adr::Label(label) = adr {
144                            let key = label.as_str().to_string();
145                            *labels.entry(key).or_insert(0) += 1;
146                        } else if matches!(
147                            adr,
148                            Adr::LiteralDec(_) | Adr::LiteralHex(_) | Adr::LiteralStr(_)
149                        ) {
150                            *literals.entry(adr.to_string()).or_insert(0) += 1;
151                        }
152                        use P::*;
153                        let s = match code {
154                            Jpl => "JPL",
155                            Jmi => "JMI",
156                            Jnz => "JNZ",
157                            Jze => "JZE",
158                            Jov => "JOV",
159                            Jump => "JUMP",
160                            Push => "PUSH",
161                            Call => "CALL",
162                            Svc => "SVC",
163                        };
164                        *p_codes.entry(s.to_string()).or_insert(0) += 1;
165                    }
166                    Command::Pop { r } => {
167                        registers[*r as usize] += 1;
168                        *commands.entry("POP".to_string()).or_insert(0) += 1;
169                    }
170                    Command::Ret => *commands.entry("RET".to_string()).or_insert(0) += 1,
171                    Command::Nop => *commands.entry("NOP".to_string()).or_insert(0) += 1,
172                    Command::DebugBasicStep { .. } => {}
173                }
174            }
175        }
176    }
177    format!(
178        r#"
179STATISTICS
180
181name: {name}
182
183lines: {lines}
184    comment: {comments}
185    code: {codes}
186        with_comment: {with_comment}
187
188total_ds_size: {total_ds_size}
189
190total_dc_item_count: {total_dc_item_count}
191total_dc_size: {total_dc_size}
192
193labels:
194    total: {total_label}
195    unused: {unused_label}
196    {labels}
197
198registers:
199    [GR0,GR1,GR2,GR3,GR4,GR5,GR6,GR7]
200    {registers}
201
202index registers:
203    [---,GR1,GR2,GR3,GR4,GR5,GR6,GR7]
204    {index_registers}
205
206literals:
207    {literals}
208
209commands:
210    {commands}
211    {p_codes}
212
213commands(r1,r2):
214    {r_codes}
215
216commands(r,adr,x):
217    {a_codes}
218
219"#,
220        name = name,
221        lines = statements.len(),
222        comments = comment_lines,
223        codes = statements.len() - comment_lines,
224        with_comment = with_comment_lines,
225        labels = format_args!("{:?}", labels.iter().collect::<BTreeMap<_, _>>()),
226        total_label = labels.len(),
227        unused_label = labels.iter().filter(|(_, c)| **c == 0).count(),
228        commands = format_args!("{:?}", commands.iter().collect::<BTreeMap<_, _>>()),
229        p_codes = format_args!("{:?}", p_codes.iter().collect::<BTreeMap<_, _>>()),
230        total_ds_size = total_ds_size,
231        total_dc_item_count = total_dc_item_count,
232        total_dc_size = total_dc_size,
233        registers = format_args!("{:?}", registers),
234        index_registers = format_args!("{:?}", index_registers),
235        literals = format_args!("{:?}", literals.iter().collect::<BTreeMap<_, _>>()),
236        r_codes = format_args!("{:?}", r_codes.iter().collect::<BTreeMap<_, _>>()),
237        a_codes = format_args!("{:?}", a_codes.iter().collect::<BTreeMap<_, _>>())
238    )
239}