worked on CLI, fixed find_and_read_string bug

This commit is contained in:
raphy 2023-05-05 21:04:13 +02:00
parent 82f7e19690
commit 03668a71e8
9 changed files with 283 additions and 109 deletions

View File

@ -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 /// resolve labels, and to quickly get the address of
/// this own section. /// this own section.
fn to_binary(&self, sy: &SymbolTable) -> Option<Vec<u16>> { fn to_binary(&self, sy: &SymbolTable) -> Option<crate::loader::Section> {
let own_address = sy.lookup(&self.name)?; let own_address = sy.lookup(&self.name)?;
match &self.content { match &self.content {
SectionContent::Code(c) => { SectionContent::Code(c) => {
@ -52,14 +52,16 @@ impl Section {
let mut pc = own_address; let mut pc = own_address;
for op in c.iter() { for op in c.iter() {
trace!("converting {:?}", op); trace!("converting {:?}", op);
res.push(CodeFormat::encode_op(op, sy, pc)?); res.push(CodeFormat::encode_op(op, sy, pc)?);
// pc simply increases by one after each operation. // pc simply increases by one after each operation.
pc += 1; pc += 1;
} }
return Some(res);
return Some(crate::loader::Section::new(self.name.clone(), &res));
} }
SectionContent::CString(s) => { SectionContent::CString(s) => {
return Some(make_string(s)); return Some(crate::loader::Section::new(self.name.clone(), &make_string(s)));
} }
SectionContent::CVec() => todo!(), SectionContent::CVec() => todo!(),
} }
@ -118,16 +120,16 @@ fn make_symbol_table<'a>(sections: &'a Vec<Section>) -> Option<SymbolTable> {
} }
/// Converts a vector of sections into binary. /// Converts a vector of sections into binary.
pub fn to_binary(sections: Vec<Section>) -> Option<Vec<u16>> { pub fn to_binary(sections: Vec<Section>) -> Option<Vec<crate::loader::Section>> {
let sorted = sort_sections(sections)?; let sorted = sort_sections(sections)?;
trace!("sorted sections: {:?}", sorted); trace!("sorted sections: {:?}", sorted);
let sy = make_symbol_table(&sorted)?; let sy = make_symbol_table(&sorted)?;
debug!("symbol table: {:?}", sy); debug!("symbol table: {:?}", sy);
let k: Vec<Vec<u16>> = sorted let k = sorted
.iter() .iter()
.map(|x| x.to_binary(&sy)) .map(|x| x.to_binary(&sy))
.collect::<Option<Vec<Vec<u16>>>>()?; .collect::<Option<Vec<crate::loader::Section>>>()?;
trace!("binary sections: {:?}", k); trace!("binary sections: {:?}", k);
return Some(k.into_iter().flatten().collect()); return Some(k);
} }

View File

@ -123,7 +123,7 @@ pub struct Section {
impl Parser { impl Parser {
pub fn parse_sections(&mut self) -> Result<Vec<Section>, ParseError> { pub fn parse_sections(&self) -> Result<Vec<Section>, ParseError> {
let mut res = vec![]; let mut res = vec![];
let mut lines = self.input.iter().map(|x| x.as_str()).into_iter(); let mut lines = self.input.iter().map(|x| x.as_str()).into_iter();

View File

@ -9,7 +9,7 @@ mod tests {
println!("Parser test begins"); println!("Parser test begins");
let code = std::fs::read_to_string("./tests/assembly/hello_world.grasm").unwrap(); 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(); let r = parser.parse_sections().unwrap();

26
src/cli/mod.rs Normal file
View File

@ -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<Subc>,
/// 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},
}

View File

@ -20,3 +20,50 @@ pub fn interpret_as_unsigned(x: i16) -> u16 {
return transmute::<i16, u16>(x); return transmute::<i16, u16>(x);
} }
} }
pub fn transmute_to_vecu16_as_is(x: Vec<u8>) -> Vec<u16> {
let mut rb = x.iter();
// raw_bytes must be converted to u16.
//
let bytes: Vec<u16> = {
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<u16>) -> Vec<u8> {
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;
}

View File

@ -1,5 +1,7 @@
use crate::cpu::Word; use crate::cpu::Word;
use log::trace;
use super::Section; use super::Section;
#[derive(Debug)] #[derive(Debug)]
@ -22,11 +24,11 @@ pub fn find_and_read_string(s: &[u16]) -> Result<(String, usize), ParseError> {
let mut index: usize = 0; let mut index: usize = 0;
for b in s.iter() { for b in s.iter() {
index += 1;
let x0 = (*b & 0xFF00) >> 8; let x0 = (*b & 0xFF00) >> 8;
let x1 = *b & 0x00FF; let x1 = *b & 0x00FF;
// exit when the first 0 bit is found. // exit when the first 0 bit is found.
if x0 == 0 { if x0 == 0 {
index += 1;
break; break;
}; };
bytes.push(x0 as u8); bytes.push(x0 as u8);
@ -35,7 +37,6 @@ pub fn find_and_read_string(s: &[u16]) -> Result<(String, usize), ParseError> {
break; break;
}; };
bytes.push(x1 as u8); bytes.push(x1 as u8);
index += 1;
} }
let s = String::from_utf8(bytes).map_err(|_| ParseError::Utf8ConvError)?; 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)); return Ok((s, index));
} }
/// Takes a binary file and returns a list of sections
pub fn read_binary(b: &[u16]) -> Result<Vec<Section>, 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 /// Parses binary headers
fn parse_header(b: &[Word]) -> Result<Vec<(u16, u16)>, ParseError> { fn parse_header(b: &[Word]) -> Result<Vec<(u16, u16)>, ParseError> {
@ -98,3 +74,49 @@ fn parse_header(b: &[Word]) -> Result<Vec<(u16, u16)>, ParseError> {
Ok(res) Ok(res)
} }
/// Takes a binary file and returns a list of sections
pub fn read_binary(b: &[u16]) -> Result<Vec<Section>, 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<Section>) -> Vec<u16> {
let mut res = vec![];
for s in sections.into_iter() {
res.append(&mut s.content.to_owned());
}
return res;
}

View File

@ -9,15 +9,15 @@ mod tests;
/// Represents a section, or symbol, that must end up in the /// Represents a section, or symbol, that must end up in the
/// binary file. /// binary file.
#[derive(Debug)] #[derive(Debug)]
pub struct Section<'a> { pub struct Section {
/// Name of the symbol/section /// Name of the symbol/section
name: String, name: String,
/// Content in bytes /// Content in bytes
content: &'a [u16], content: Vec<u16>,
} }
impl Section<'_> { impl Section {
pub fn new<'a>(name: String, content: &'a [u16]) -> Section<'a> { pub fn new(name: String, content: &[u16]) -> Section {
Section { name, content } Section { name, content: content.to_owned() }
} }
} }

View File

@ -2,7 +2,7 @@ use super::constants::MAGIC;
use super::Section; use super::Section;
impl Section<'_> { impl Section {
/// Converts the entry's name to utf8 packed in bits of length 16. /// Converts the entry's name to utf8 packed in bits of length 16.
fn serialize_name(&self) -> Vec<u16> { fn serialize_name(&self) -> Vec<u16> {
return make_string(&self.name); return make_string(&self.name);
@ -30,33 +30,7 @@ struct STEntry {
pub fn make_string(s: &str) -> Vec<u16> { pub fn make_string(s: &str) -> Vec<u16> {
let raw_bytes: &[u8] = s.as_bytes(); let raw_bytes: &[u8] = s.as_bytes();
let mut rb = raw_bytes.iter(); let mut bytes = crate::transmute_to_vecu16_as_is(raw_bytes.to_vec());
// raw_bytes must be converted to u16.
//
let mut bytes: Vec<u16> = {
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
}
}
};
// adding null termination byte // adding null termination byte
bytes.push(0); bytes.push(0);

View File

@ -1,40 +1,143 @@
use std::env::args;
use dekejit::assembler::parser; use dekejit::cli::{Cli, Subc::*};
use dekejit::assembler::to_binary;
use dekejit::cpu::IOBuffer; use dekejit::cpu::IOBuffer;
use dekejit::cpu::CPU; 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() { fn main() {
let cli: Cli = Cli::parse();
simple_logger::init_with_level(log::Level::Warn).unwrap(); 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.
};
simple_logger::init_with_level(loglevel).unwrap();
let args: Vec<String> = args().collect(); match cli.comm {
Some(Run { filename }) => {
if args.len() < 2 { info!("Trying to read {}", filename);
println!("Scialla");
let Ok(content) = std::fs::read(&filename) else {
println!("File {} does not exist or cannot be read.", &filename);
return; return;
} };
// let code = std::fs::read_to_string("./tests/assembly/hello_world.grasm").unwrap();
let code = match std::fs::read_to_string(&args[1]) { let bytes = dekejit::transmute_to_vecu16_as_is(content.to_vec());
Ok(p) => p,
Err(_) => { info!("Begin parsing file {}", &filename);
println!("Could not open file '{}'", &args[1]); let sections = match read_binary(&bytes) {
Ok(k) => k,
Err(p) => {
println!("Parsing error: {:?}", p);
return; return;
} }
}; };
let mut parser = parser::Parser::new(code); let bin = prepare_memory(sections);
let r = parser.parse_sections().unwrap(); info!("{:?}", bin);
// println!("Parsed sections: {:?}", r); let mut env = IOBuffer::default();
//
let mut cpu = CPU::new(&mut env);
let code = to_binary(r).unwrap(); 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!"); // let mut k = make_string("Hello world!");
// //
@ -46,18 +149,18 @@ fn main() {
// //
// code.append(&mut k); // code.append(&mut k);
// //
let mut env = IOBuffer::default(); // let mut env = IOBuffer::default();
// // //
let mut cpu = CPU::new(&mut env); // let mut cpu = CPU::new(&mut env);
// // //
// for c in &code[..] { // // for c in &code[..] {
// // println!("{:#018b}", c); // // // println!("{:#018b}", c);
// // }
// //
// match cpu.run_code_raw(&code) {
// Ok(_) => {
// println!("Result: {}", env.output)
// } // }
// // Err(e) => println!("Err: {:?}", e),
match cpu.run_code_raw(&code) { // };
Ok(_) => {
println!("Result: {}", env.output)
}
Err(e) => println!("Err: {:?}", e),
};
} }