diff --git a/src/assembler/mod.rs b/src/assembler/mod.rs index 860bc79..ac53e37 100644 --- a/src/assembler/mod.rs +++ b/src/assembler/mod.rs @@ -38,10 +38,10 @@ impl Section { } } - /// Converts a section to binary. Needs symbol table to + /// Converts this section to binary. Needs symbol table to /// resolve labels, and to quickly get the address of /// this own section. - fn to_binary(&self, sy: &SymbolTable) -> Option> { + fn to_binary(&self, sy: &SymbolTable) -> Option { let own_address = sy.lookup(&self.name)?; match &self.content { SectionContent::Code(c) => { @@ -52,14 +52,16 @@ impl Section { let mut pc = own_address; for op in c.iter() { trace!("converting {:?}", op); + res.push(CodeFormat::encode_op(op, sy, pc)?); // pc simply increases by one after each operation. pc += 1; } - return Some(res); + + return Some(crate::loader::Section::new(self.name.clone(), &res)); } SectionContent::CString(s) => { - return Some(make_string(s)); + return Some(crate::loader::Section::new(self.name.clone(), &make_string(s))); } SectionContent::CVec() => todo!(), } @@ -118,16 +120,16 @@ fn make_symbol_table<'a>(sections: &'a Vec
) -> Option { } /// Converts a vector of sections into binary. -pub fn to_binary(sections: Vec
) -> Option> { +pub fn to_binary(sections: Vec
) -> Option> { let sorted = sort_sections(sections)?; trace!("sorted sections: {:?}", sorted); let sy = make_symbol_table(&sorted)?; debug!("symbol table: {:?}", sy); - let k: Vec> = sorted + let k = sorted .iter() .map(|x| x.to_binary(&sy)) - .collect::>>>()?; + .collect::>>()?; trace!("binary sections: {:?}", k); - return Some(k.into_iter().flatten().collect()); + return Some(k); } diff --git a/src/assembler/parser.rs b/src/assembler/parser.rs index 0327e31..c2a0edb 100644 --- a/src/assembler/parser.rs +++ b/src/assembler/parser.rs @@ -123,7 +123,7 @@ pub struct Section { impl Parser { - pub fn parse_sections(&mut self) -> Result, ParseError> { + pub fn parse_sections(&self) -> Result, ParseError> { let mut res = vec![]; let mut lines = self.input.iter().map(|x| x.as_str()).into_iter(); diff --git a/src/assembler/tests.rs b/src/assembler/tests.rs index 907f0ee..5fa7853 100644 --- a/src/assembler/tests.rs +++ b/src/assembler/tests.rs @@ -9,7 +9,7 @@ mod tests { println!("Parser test begins"); let code = std::fs::read_to_string("./tests/assembly/hello_world.grasm").unwrap(); - let mut parser = parser::Parser::new(code); + let parser = parser::Parser::new(code); let r = parser.parse_sections().unwrap(); diff --git a/src/cli/mod.rs b/src/cli/mod.rs new file mode 100644 index 0000000..4d39bfa --- /dev/null +++ b/src/cli/mod.rs @@ -0,0 +1,26 @@ + + + +use clap::{Parser, Subcommand}; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +pub struct Cli { + + + #[command(subcommand)] + pub comm: Option, + + /// Debug level + #[arg(short, long, default_value_t = 1)] + pub debug: u8, +} + +#[derive(Subcommand, Debug)] +pub enum Subc { + + Run {filename: String}, + Build {filename: String, output: String}, + View {filename: String}, + +} diff --git a/src/lib.rs b/src/lib.rs index 2d22733..f4921bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,3 +20,50 @@ pub fn interpret_as_unsigned(x: i16) -> u16 { return transmute::(x); } } + +pub fn transmute_to_vecu16_as_is(x: Vec) -> Vec { + + let mut rb = x.iter(); + // raw_bytes must be converted to u16. + // + let bytes: Vec = { + let mut res = vec![]; + // highly cursed: depends on the order in which the arguments of a tuple are + // evaluated. Does its job! + while let (Some(word0), Some(word1)) = (rb.next(), rb.next()) { + // println!("Pair: {}, {}, word: {:?}", word0, word1, raw_bytes); + res.push(((*word0 as u16) << 8) + (*word1 as u16)); + } + // if we branch into this else, either there's a single word left or zero. + // since, in case a single word was left, the first rb.next() call in the line + // above would've consumed it, we have to gather that last element again + match x.len() { + 0 => res, + n => { + if n % 2 != 0 { + // if there's an uneven number of chunks of 8 bits, + // we introduce padding! + // println!("Adding last one too"); + res.push((*x.last().unwrap() as u16) << 8); + } + res + } + } + }; + + return bytes; +} + +pub fn transmute_to_vecu8_as_is(x: Vec) -> Vec { + + let mut bytes = vec![]; + + for b in x.iter() { + let x0 = (*b & 0xFF00) >> 8; + let x1 = *b & 0x00FF; + bytes.push(x0 as u8); + bytes.push(x1 as u8); + } + + return bytes; +} diff --git a/src/loader/loader.rs b/src/loader/loader.rs index 1b301cf..4d394d7 100644 --- a/src/loader/loader.rs +++ b/src/loader/loader.rs @@ -1,5 +1,7 @@ use crate::cpu::Word; +use log::trace; + use super::Section; #[derive(Debug)] @@ -22,11 +24,11 @@ pub fn find_and_read_string(s: &[u16]) -> Result<(String, usize), ParseError> { let mut index: usize = 0; for b in s.iter() { + index += 1; let x0 = (*b & 0xFF00) >> 8; let x1 = *b & 0x00FF; // exit when the first 0 bit is found. if x0 == 0 { - index += 1; break; }; bytes.push(x0 as u8); @@ -35,7 +37,6 @@ pub fn find_and_read_string(s: &[u16]) -> Result<(String, usize), ParseError> { break; }; bytes.push(x1 as u8); - index += 1; } let s = String::from_utf8(bytes).map_err(|_| ParseError::Utf8ConvError)?; @@ -43,31 +44,6 @@ pub fn find_and_read_string(s: &[u16]) -> Result<(String, usize), ParseError> { return Ok((s, index)); } -/// Takes a binary file and returns a list of sections -pub fn read_binary(b: &[u16]) -> Result, ParseError> { - let mut res = vec![]; - - let headers = parse_header(b)?; - let hlen = headers.len() * 2 + 2; // two 16bits words for every entry, - // and 2 etxra 16 bits number at the start - - for (offset, length) in headers { - // section start. The name begins here - let start = hlen + offset as usize; - let str_buffer = b.get(start..).ok_or(ParseError::UnexpectedHeaderEnd)?; - let (name, i) = find_and_read_string(str_buffer)?; - - let c_start = start + i; - let c_end = start + (length as usize) + i; - - println!("{:?}, start: {}, end: {}", b, c_start, c_end); - let Some(content) = b.get((c_start)..(c_end)) else {return Err(ParseError::UnexpectedFileEnd)}; - - res.push(Section::new(name, content)) - } - - Ok(res) -} /// Parses binary headers fn parse_header(b: &[Word]) -> Result, ParseError> { @@ -98,3 +74,49 @@ fn parse_header(b: &[Word]) -> Result, ParseError> { Ok(res) } + +/// Takes a binary file and returns a list of sections +pub fn read_binary(b: &[u16]) -> Result, ParseError> { + let mut res = vec![]; + + let headers = parse_header(b)?; + let hlen = headers.len() * 2 + 2; // two 16bits words for every entry, + // and 2 etxra 16 bits number at the start + trace!("hlen: {:?}, headers: {:?}", hlen, headers); + + for (offset, length) in headers { + // section start. The name begins here + let start = hlen + offset as usize; + let str_buffer = b.get(start..).ok_or(ParseError::UnexpectedHeaderEnd)?; + let (name, i) = find_and_read_string(str_buffer)?; + + let c_start = start + i; + let c_end = start + (length as usize) + i; + + trace!("{:?}, name: {:?}, start: {}, end: {}, i: {}", b, name, c_start, c_end, i); + let Some(content) = b.get((c_start)..(c_end)) else {return Err(ParseError::UnexpectedFileEnd)}; + + res.push(Section::new(name, content)) + } + + Ok(res) +} + + +/// Takes a list of sections and joins them, preparing for execution. +/// +/// Simply joins togheter the section contents. +/// Assumes the binary is well-defined (main in front, according +/// to spec.) It will not attempt to find sections or re-order them. +pub fn prepare_memory(sections: Vec
) -> Vec { + + let mut res = vec![]; + + for s in sections.into_iter() { + res.append(&mut s.content.to_owned()); + } + + return res; + +} + diff --git a/src/loader/mod.rs b/src/loader/mod.rs index 8eea153..5f29dda 100644 --- a/src/loader/mod.rs +++ b/src/loader/mod.rs @@ -9,15 +9,15 @@ mod tests; /// Represents a section, or symbol, that must end up in the /// binary file. #[derive(Debug)] -pub struct Section<'a> { +pub struct Section { /// Name of the symbol/section name: String, /// Content in bytes - content: &'a [u16], + content: Vec, } -impl Section<'_> { - pub fn new<'a>(name: String, content: &'a [u16]) -> Section<'a> { - Section { name, content } +impl Section { + pub fn new(name: String, content: &[u16]) -> Section { + Section { name, content: content.to_owned() } } } diff --git a/src/loader/unloader.rs b/src/loader/unloader.rs index 27ced25..57f5541 100644 --- a/src/loader/unloader.rs +++ b/src/loader/unloader.rs @@ -2,7 +2,7 @@ use super::constants::MAGIC; use super::Section; -impl Section<'_> { +impl Section { /// Converts the entry's name to utf8 packed in bits of length 16. fn serialize_name(&self) -> Vec { return make_string(&self.name); @@ -30,33 +30,7 @@ struct STEntry { pub fn make_string(s: &str) -> Vec { let raw_bytes: &[u8] = s.as_bytes(); - let mut rb = raw_bytes.iter(); - // raw_bytes must be converted to u16. - // - let mut bytes: Vec = { - let mut res = vec![]; - // highly cursed: depends on the order in which the arguments of a tuple are - // evaluated. Does its job! - while let (Some(word0), Some(word1)) = (rb.next(), rb.next()) { - // println!("Pair: {}, {}, word: {:?}", word0, word1, raw_bytes); - res.push(((*word0 as u16) << 8) + (*word1 as u16)); - } - // if we branch into this else, either there's a single word left or zero. - // since, in case a single word was left, the first rb.next() call in the line - // above would've consumed it, we have to gather that last element again - match raw_bytes.len() { - 0 => res, - n => { - if n % 2 != 0 { - // if there's an uneven number of chunks of 8 bits, - // we introduce padding! - // println!("Adding last one too"); - res.push((*raw_bytes.last().unwrap() as u16) << 8); - } - res - } - } - }; + let mut bytes = crate::transmute_to_vecu16_as_is(raw_bytes.to_vec()); // adding null termination byte bytes.push(0); diff --git a/src/main.rs b/src/main.rs index 5d9c53b..41d3dfd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,40 +1,143 @@ -use std::env::args; -use dekejit::assembler::parser; -use dekejit::assembler::to_binary; +use dekejit::cli::{Cli, Subc::*}; use dekejit::cpu::IOBuffer; use dekejit::cpu::CPU; -// use simple_logger::SimpleLogger; +use clap::Parser; +use dekejit::loader::loader::prepare_memory; +use dekejit::loader::loader::read_binary; +use dekejit::transmute_to_vecu8_as_is; +use log::{info, debug}; fn main() { + let cli: Cli = Cli::parse(); - simple_logger::init_with_level(log::Level::Warn).unwrap(); - - - let args: Vec = args().collect(); - - if args.len() < 2 { - println!("Scialla"); - return; - } - - // let code = std::fs::read_to_string("./tests/assembly/hello_world.grasm").unwrap(); - let code = match std::fs::read_to_string(&args[1]) { - Ok(p) => p, - Err(_) => { - println!("Could not open file '{}'", &args[1]); - return; - } + let loglevel = match cli.debug { + 0 => log::Level::Error, + 1 => log::Level::Warn, + 2 => log::Level::Info, + 3 => log::Level::Debug, + _ => log::Level::Trace, + // anything higher than 4 or equal is trace. }; - let mut parser = parser::Parser::new(code); + simple_logger::init_with_level(loglevel).unwrap(); - let r = parser.parse_sections().unwrap(); + match cli.comm { + Some(Run { filename }) => { - // println!("Parsed sections: {:?}", r); + info!("Trying to read {}", filename); - let code = to_binary(r).unwrap(); + let Ok(content) = std::fs::read(&filename) else { + println!("File {} does not exist or cannot be read.", &filename); + return; + }; + + + let bytes = dekejit::transmute_to_vecu16_as_is(content.to_vec()); + + info!("Begin parsing file {}", &filename); + let sections = match read_binary(&bytes) { + Ok(k) => k, + Err(p) => { + println!("Parsing error: {:?}", p); + return; + } + }; + + let bin = prepare_memory(sections); + + info!("{:?}", bin); + + let mut env = IOBuffer::default(); + // + let mut cpu = CPU::new(&mut env); + + match cpu.run_code_raw(&bin) { + Ok(_) => { + println!("Result: {}", env.output) + } + Err(e) => println!("Err: {:?}", e), + }; + } + Some(Build { filename, output }) => { + + let Ok(inp_content) = std::fs::read_to_string(filename.clone()) else { + println!("Could not read file {}", &filename); + return; + }; + + let prs = dekejit::assembler::parser::Parser::new(inp_content); + + let sections = match prs.parse_sections() { + Ok(s) => s, + Err(p_err) => { + println!("Parser error: {:?}", p_err); + return; + }, + }; + + + let Some(bin) = dekejit::assembler::to_binary(sections) else { + println!("Unspecified error while converting file to binary. Must fix."); + return; + }; + + info!("{:?}", bin); + + let out_bin = dekejit::loader::unloader::make_binary(&bin); + + info!("{:?}", out_bin); + + let out_bin = transmute_to_vecu8_as_is(out_bin); + + + info!("{:?}", out_bin); + + match std::fs::write(output.clone(), out_bin) { + Ok(_) => {}, + Err(_) => { + println!("could not write file {}", output);}, + }; + + } + Some(View {filename}) => { + + info!("Trying to read {}", filename); + + let Ok(content) = std::fs::read(&filename) else { + println!("File {} does not exist or cannot be read.", &filename); + return; + }; + + + let bytes = dekejit::transmute_to_vecu16_as_is(content.to_vec()); + + info!("{:?}", bytes); + + info!("Begin parsing file {}", &filename); + let sections = match read_binary(&bytes) { + Ok(k) => k, + Err(p) => { + println!("Parsing error: {:?}", p); + return; + } + }; + + println!("{:?}", sections); + } + None => {} + } + + + + // let parser = parser::Parser::new(code); + // + // let r = parser.parse_sections().unwrap(); + // + // // println!("Parsed sections: {:?}", r); + // + // let code = to_binary(r).unwrap(); // let mut k = make_string("Hello world!"); // @@ -46,18 +149,18 @@ fn main() { // // code.append(&mut k); // - let mut env = IOBuffer::default(); - // - let mut cpu = CPU::new(&mut env); - // - // for c in &code[..] { - // // println!("{:#018b}", c); - // } - // - match cpu.run_code_raw(&code) { - Ok(_) => { - println!("Result: {}", env.output) - } - Err(e) => println!("Err: {:?}", e), - }; + // let mut env = IOBuffer::default(); + // // + // let mut cpu = CPU::new(&mut env); + // // + // // for c in &code[..] { + // // // println!("{:#018b}", c); + // // } + // // + // match cpu.run_code_raw(&code) { + // Ok(_) => { + // println!("Result: {}", env.output) + // } + // Err(e) => println!("Err: {:?}", e), + // }; }