1use std::collections::BTreeMap;
2use std::collections::HashMap;
3use std::error::Error;
4use std::fs::File;
5use std::io;
6use std::io::prelude::*;
7use std::io::BufRead;
8use std::u64;
9mod number_parser;
10mod parser;
11use parser::ICode;
12
13pub struct Y86Assembler {
14 bytes: Vec<u8>,
15}
16
17impl Y86Assembler {
18 pub fn from_file(file_name: String) -> Result<Self, Box<dyn Error>> {
19 let lines_iter = read_lines(file_name)?;
20 let lines: Vec<String> = lines_iter.map(|val| val.unwrap()).collect();
21 let mut positions: BTreeMap<u64, Vec<u8>> = BTreeMap::new();
22 get_positions(&mut positions, &lines)?;
23 Ok(Y86Assembler {
24 bytes: merge_position(&positions),
25 })
26 }
27
28 pub fn save_file(&mut self, file_name: String) -> Result<(), Box<dyn Error>> {
29 let mut file = File::create(file_name)?;
30 file.write_all(&self.bytes)?;
31 Ok(())
32 }
33
34 pub fn print(&self) {
35 self.bytes.iter().for_each(|b| print!("{:02x}", b));
36 println!();
37 }
38}
39
40fn merge_position(positions: &BTreeMap<u64, Vec<u8>>) -> Vec<u8> {
41 let iter = positions.iter();
42 let mut res = vec![];
43 for (key, val) in iter {
44 while res.len() < *key as usize {
45 res.push(0);
46 }
47 val.iter().for_each(|&b| res.push(b));
48 }
49 res
50}
51
52fn get_positions(
53 positions: &mut BTreeMap<u64, Vec<u8>>,
54 lines: &[String],
55) -> Result<(), Box<dyn Error>> {
56 let mut curr_position = 0;
57 let trimmed: Vec<String> = lines.iter().map(|line| trim_line(&line)).collect();
58 let mapping: HashMap<&str, u64> = map_labels(&trimmed)?;
59 let val: Result<(), Box<dyn Error>> = trimmed
60 .iter()
61 .map(|line| apply_mapping(&mapping, &line))
62 .try_for_each(|line| {
63 if line.starts_with(".pos") {
64 let position: u64 = number_parser::parse_num(&line[5..])?;
65 positions.insert(position, vec![]);
66 curr_position = position;
67 } else {
68 let curr_vec = positions.entry(curr_position).or_insert_with(|| vec![]);
69 curr_vec.append(&mut convert_line(&line)?);
70 }
71 Ok(())
72 });
73 val
74}
75
76fn trim_line(line: &str) -> String {
77 let mut res = line.trim().to_string();
78 if res.contains('#') {
79 res = res[..res.find('#').unwrap()].to_string();
80 }
81 res.replace("$", "")
82}
83
84fn apply_mapping(mapping: &HashMap<&str, u64>, line: &str) -> String {
85 let mut res = String::new();
86 if line.contains(':') {
87 res.push_str(line[line.find(':').unwrap() + 1..].trim());
88 } else {
89 res = line.to_string();
90 }
91 let mut v: Vec<(&str, u64)> = Vec::new();
92 mapping.iter().for_each(|(key, &val)| v.push((key, val)));
93 v.sort_by(|a, b| {
94 let (key, _val) = a;
95 let (key_2, _val_2) = b;
96 key_2.len().partial_cmp(&key.len()).unwrap()
97 });
98 v.iter().for_each(|(key, val)| {
99 let mut expected = " ".to_string();
100 expected.push_str(key);
101 if res.contains(&expected) {
102 res = res.replace(key, &format!("0x{:x}", val));
103 }
104 });
105 res
106}
107
108fn instr_size(line: &str) -> Result<u64, Box<dyn Error>> {
109 let mut split = line.split(' ');
110 let instr = split.next().unwrap();
111 let val = match parser::get_icode_from_string(instr)? {
112 ICode::IIRMOVQ | ICode::IRMMOVQ | ICode::IMRMOVQ => 10,
113 ICode::IRRMVXX | ICode::IOPQ | ICode::IPOPQ | ICode::IPUSHQ => 2,
114 ICode::IJXX | ICode::ICALL => 9,
115 ICode::IHALT | ICode::INOP | ICode::IRET => 1,
116 _ => 0,
117 };
118 Ok(val)
119}
120
121fn map_labels(lines: &[String]) -> Result<HashMap<&str, u64>, Box<dyn Error>> {
122 let mut res: HashMap<&str, u64> = HashMap::new();
123 let mut curr_addr = 0;
124 let val: Result<(), Box<dyn Error>> = lines.iter().try_for_each(|line| {
125 if line.starts_with(".pos") {
126 let position: u64 = number_parser::parse_num(&line[5..])?;
127 curr_addr = position;
128 } else {
129 if line.contains(':') {
130 let mut split = line.split(':');
131 res.insert(split.next().unwrap().trim(), curr_addr);
132 }
133 if line.contains(".quad") {
134 curr_addr += 8;
135 } else if !line.is_empty() {
136 let mut line = line.clone();
137 if line.contains(':') {
138 line = line[line.find(':').unwrap() + 1..].trim().to_string();
139 }
140 curr_addr += instr_size(&line)?;
141 }
142 }
143 Ok(())
144 });
145 val?;
146 Ok(res)
147}
148
149fn convert_line(line: &str) -> Result<Vec<u8>, Box<dyn Error>> {
150 if line.trim().is_empty() {
151 return Ok(vec![]);
152 }
153 parser::parse(line)
154}
155
156fn read_lines(file_name: String) -> io::Result<io::Lines<io::BufReader<File>>> {
157 let file = File::open(file_name)?;
158 Ok(io::BufReader::new(file).lines())
159}
160
161