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
/// 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)?;
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<Section>) -> Option<SymbolTable> {
}
/// 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)?;
trace!("sorted sections: {:?}", sorted);
let sy = make_symbol_table(&sorted)?;
debug!("symbol table: {:?}", sy);
let k: Vec<Vec<u16>> = sorted
let k = sorted
.iter()
.map(|x| x.to_binary(&sy))
.collect::<Option<Vec<Vec<u16>>>>()?;
.collect::<Option<Vec<crate::loader::Section>>>()?;
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 {
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 lines = self.input.iter().map(|x| x.as_str()).into_iter();

View File

@ -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();

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);
}
}
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 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<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
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)
}
/// 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
/// 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<u16>,
}
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() }
}
}

View File

@ -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<u16> {
return make_string(&self.name);
@ -30,33 +30,7 @@ struct STEntry {
pub fn make_string(s: &str) -> Vec<u16> {
let raw_bytes: &[u8] = s.as_bytes();
let mut rb = raw_bytes.iter();
// 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
}
}
};
let mut bytes = crate::transmute_to_vecu16_as_is(raw_bytes.to_vec());
// adding null termination byte
bytes.push(0);

View File

@ -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<String> = 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),
// };
}