1use 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}