worked on CLI, fixed find_and_read_string bug
This commit is contained in:
parent
82f7e19690
commit
03668a71e8
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
26
src/cli/mod.rs
Normal 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},
|
||||
|
||||
}
|
47
src/lib.rs
47
src/lib.rs
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
@ -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() }
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
181
src/main.rs
181
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<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),
|
||||
// };
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user