preparing to refactor
renamed AST to ast, following rust naming convention, removed some useless test files and moved the tests to the appropriate files.
This commit is contained in:
parent
9358bfa77f
commit
8f894174d9
@ -1,9 +1,8 @@
|
|||||||
use super::AST::*;
|
use super::ast::*;
|
||||||
use crate::cpu::get_num;
|
use crate::cpu::get_num;
|
||||||
|
|
||||||
use log::{trace, warn};
|
use log::{trace, warn};
|
||||||
|
|
||||||
|
|
||||||
/// Trait to represent a format we can translate our assembly to.
|
/// Trait to represent a format we can translate our assembly to.
|
||||||
pub trait CodeFormat {
|
pub trait CodeFormat {
|
||||||
fn encode_op(op: &Operation, sy: &SymbolTable, current_pc: u16) -> Option<Self>
|
fn encode_op(op: &Operation, sy: &SymbolTable, current_pc: u16) -> Option<Self>
|
||||||
@ -36,7 +35,7 @@ impl SymbolTable {
|
|||||||
// query, sy
|
// query, sy
|
||||||
// );
|
// );
|
||||||
warn!("Symbol {} not found in symbol table.", query);
|
warn!("Symbol {} not found in symbol table.", query);
|
||||||
return None
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
mod AST;
|
mod ast;
|
||||||
pub mod encoder;
|
pub mod encoder;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
mod tests;
|
|
||||||
|
|
||||||
use encoder::CodeFormat;
|
use encoder::CodeFormat;
|
||||||
use encoder::SymbolTable;
|
use encoder::SymbolTable;
|
||||||
|
|
||||||
pub use AST::print_op;
|
pub use ast::print_op;
|
||||||
|
|
||||||
use log::{trace, debug};
|
use log::{debug, trace};
|
||||||
|
|
||||||
use parser::Section;
|
use parser::Section;
|
||||||
|
|
||||||
@ -26,7 +25,7 @@ impl Section {
|
|||||||
// UTF-8 strings are collections of 8-bit chunks, but they're
|
// UTF-8 strings are collections of 8-bit chunks, but they're
|
||||||
// packed into words of 16 bits + 16 bit NULL.
|
// packed into words of 16 bits + 16 bit NULL.
|
||||||
//
|
//
|
||||||
// If there's an uneven number of bytes in a string,
|
// If there's an uneven number of bytes in a string,
|
||||||
// we add a 8 bit empty padding and then the NULL byte.
|
// we add a 8 bit empty padding and then the NULL byte.
|
||||||
SectionContent::CString(s) => {
|
SectionContent::CString(s) => {
|
||||||
let c = s.len();
|
let c = s.len();
|
||||||
@ -41,7 +40,7 @@ impl Section {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Converts this 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<crate::loader::Section> {
|
fn to_binary(&self, sy: &SymbolTable) -> Option<crate::loader::Section> {
|
||||||
let own_address = sy.lookup(&self.name)?;
|
let own_address = sy.lookup(&self.name)?;
|
||||||
@ -63,17 +62,19 @@ impl Section {
|
|||||||
return Some(crate::loader::Section::new(self.name.clone(), &res));
|
return Some(crate::loader::Section::new(self.name.clone(), &res));
|
||||||
}
|
}
|
||||||
SectionContent::CString(s) => {
|
SectionContent::CString(s) => {
|
||||||
return Some(crate::loader::Section::new(self.name.clone(), &make_string(s)));
|
return Some(crate::loader::Section::new(
|
||||||
|
self.name.clone(),
|
||||||
|
&make_string(s),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
SectionContent::CVec() => todo!(),
|
SectionContent::CVec() => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Sorts a list of sections.
|
/// Sorts a list of sections.
|
||||||
/// All .text sections containing code are
|
/// All .text sections containing code are
|
||||||
/// put at the beginning of the binary file, in the order they
|
/// put at the beginning of the binary file, in the order they
|
||||||
/// appear in the assembly file, except the "main" section,
|
/// appear in the assembly file, except the "main" section,
|
||||||
/// which is the entrypoint of our program and must be put
|
/// which is the entrypoint of our program and must be put
|
||||||
/// at the very beginning.
|
/// at the very beginning.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::AST::{Const, Operation};
|
use super::ast::{Const, Operation};
|
||||||
use Operation::*;
|
use Operation::*;
|
||||||
|
|
||||||
use log::*;
|
use log::*;
|
||||||
@ -16,14 +16,12 @@ pub enum ParseError {
|
|||||||
/// represents the state of our parser.
|
/// represents the state of our parser.
|
||||||
/// Sadly parsing is stateless,
|
/// Sadly parsing is stateless,
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
input: Vec<String>, // input file
|
input: Vec<String>, // input file
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
pub fn new(i: String) -> Self {
|
pub fn new(i: String) -> Self {
|
||||||
Parser {
|
Parser { input: sanitize(i) }
|
||||||
input: sanitize(i),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,19 +87,20 @@ fn take_between(i: &str, start: &str, stop: &str) -> Option<(String, String)> {
|
|||||||
return take_alpha_till(&s1, stop);
|
return take_alpha_till(&s1, stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// finds special escaped characters in a string
|
|
||||||
/// (such as \n) and replaces them with the actual special
|
|
||||||
/// character
|
|
||||||
fn escaped_codes() {}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn take_between_test() {
|
fn take_between_test1() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
take_between("\"wow\" etc", "\"", "\""),
|
take_between("\"wow\" etc", "\"", "\""),
|
||||||
Some(("wow".to_string(), " etc".to_string()))
|
Some(("wow".to_string(), " etc".to_string()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// finds special escaped characters in a string
|
||||||
|
/// (such as \n) and replaces them with the actual special
|
||||||
|
/// character
|
||||||
|
/// #TODO: do we need this? I forgot.
|
||||||
|
fn _escaped_codes() {}
|
||||||
|
|
||||||
//// SECTION PARSING
|
//// SECTION PARSING
|
||||||
|
|
||||||
/// Enum to represent possible section content.
|
/// Enum to represent possible section content.
|
||||||
@ -121,7 +120,6 @@ pub struct Section {
|
|||||||
pub content: SectionContent,
|
pub content: SectionContent,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
pub fn parse_sections(&self) -> Result<Vec<Section>, ParseError> {
|
pub fn parse_sections(&self) -> Result<Vec<Section>, ParseError> {
|
||||||
let mut res = vec![];
|
let mut res = vec![];
|
||||||
@ -151,8 +149,12 @@ impl Parser {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
"asciiz" => {
|
"asciiz" => {
|
||||||
let Some(s) = lines.next() else {return Err(ParseError::UnexpectedEOF)};
|
let Some(s) = lines.next() else {
|
||||||
let Some((s, _)) = take_between(s.trim(), "\"", "\"") else {return Err(ParseError::BadSectionContent)};
|
return Err(ParseError::UnexpectedEOF);
|
||||||
|
};
|
||||||
|
let Some((s, _)) = take_between(s.trim(), "\"", "\"") else {
|
||||||
|
return Err(ParseError::BadSectionContent);
|
||||||
|
};
|
||||||
res.push(Section {
|
res.push(Section {
|
||||||
name: name.trim().to_owned(),
|
name: name.trim().to_owned(),
|
||||||
content: CString(s),
|
content: CString(s),
|
||||||
@ -200,7 +202,9 @@ fn parse_code_line(i: &str) -> Result<Operation, ParseError> {
|
|||||||
// every operation has at most 3 arguments
|
// every operation has at most 3 arguments
|
||||||
let mut bits = i.split_whitespace();
|
let mut bits = i.split_whitespace();
|
||||||
trace!("current parse code line: {}", i);
|
trace!("current parse code line: {}", i);
|
||||||
let Some(op) = bits.next() else {return Err(ParseError::BadInstruction)};
|
let Some(op) = bits.next() else {
|
||||||
|
return Err(ParseError::BadInstruction);
|
||||||
|
};
|
||||||
|
|
||||||
// no type
|
// no type
|
||||||
match op {
|
match op {
|
||||||
@ -214,8 +218,12 @@ fn parse_code_line(i: &str) -> Result<Operation, ParseError> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// I-type
|
// I-type
|
||||||
let Some(r1) = bits.next() else {return Err(ParseError::BadInstruction)};
|
let Some(r1) = bits.next() else {
|
||||||
let Some(r2) = bits.next() else {return Err(ParseError::BadInstruction)};
|
return Err(ParseError::BadInstruction);
|
||||||
|
};
|
||||||
|
let Some(r2) = bits.next() else {
|
||||||
|
return Err(ParseError::BadInstruction);
|
||||||
|
};
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
"addi" => {
|
"addi" => {
|
||||||
@ -230,7 +238,9 @@ fn parse_code_line(i: &str) -> Result<Operation, ParseError> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(r3) = bits.next() else {return Err(ParseError::BadInstruction)};
|
let Some(r3) = bits.next() else {
|
||||||
|
return Err(ParseError::BadInstruction);
|
||||||
|
};
|
||||||
|
|
||||||
// R-type
|
// R-type
|
||||||
match op {
|
match op {
|
||||||
@ -277,3 +287,17 @@ fn parse_const(i: &str) -> Result<Const, ParseError> {
|
|||||||
};
|
};
|
||||||
return Ok(Const::C(num));
|
return Ok(Const::C(num));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TESTS
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parser_test() {
|
||||||
|
let code = std::fs::read_to_string("./tests/assembly/hello_world.grasm").unwrap();
|
||||||
|
|
||||||
|
let parser = Parser::new(code);
|
||||||
|
|
||||||
|
let _r = parser.parse_sections();
|
||||||
|
|
||||||
|
// #TODO: WRITE PARSER TEST SUITE!
|
||||||
|
//assert_eq!(r, Ok(vec![]));
|
||||||
|
}
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
// use super::*;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::assembler::parser;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parser_test() {
|
|
||||||
println!("Parser test begins");
|
|
||||||
let code = std::fs::read_to_string("./tests/assembly/hello_world.grasm").unwrap();
|
|
||||||
|
|
||||||
let parser = parser::Parser::new(code);
|
|
||||||
|
|
||||||
let r = parser.parse_sections().unwrap();
|
|
||||||
|
|
||||||
println!("Parsed sections: {:?}", r);
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ pub mod cpu;
|
|||||||
pub mod jit;
|
pub mod jit;
|
||||||
pub mod loader;
|
pub mod loader;
|
||||||
pub mod pretty_printers;
|
pub mod pretty_printers;
|
||||||
//
|
|
||||||
|
|
||||||
pub fn interpret_as_signed(x: u16) -> i16 {
|
pub fn interpret_as_signed(x: u16) -> i16 {
|
||||||
// the two types have the same size.
|
// the two types have the same size.
|
||||||
@ -28,8 +27,8 @@ pub fn transmute_to_vecu16_as_is(x: Vec<u8>) -> Vec<u16> {
|
|||||||
//
|
//
|
||||||
let bytes: Vec<u16> = {
|
let bytes: Vec<u16> = {
|
||||||
let mut res = vec![];
|
let mut res = vec![];
|
||||||
// highly cursed: depends on the order in which the arguments of a tuple are
|
// Depends on the order in which the arguments of a tuple are
|
||||||
// evaluated. Does its job!
|
// evaluated. Rust guarantees to be left-to-right.
|
||||||
while let (Some(word0), Some(word1)) = (rb.next(), rb.next()) {
|
while let (Some(word0), Some(word1)) = (rb.next(), rb.next()) {
|
||||||
// println!("Pair: {}, {}, word: {:?}", word0, word1, raw_bytes);
|
// println!("Pair: {}, {}, word: {:?}", word0, word1, raw_bytes);
|
||||||
res.push(((*word0 as u16) << 8) + (*word1 as u16));
|
res.push(((*word0 as u16) << 8) + (*word1 as u16));
|
||||||
|
35
src/main.rs
35
src/main.rs
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
use dekejit::assembler::parser;
|
use dekejit::assembler::parser;
|
||||||
use dekejit::cli::{Cli, Subc::*};
|
use dekejit::cli::{Cli, Subc::*};
|
||||||
use dekejit::cpu::IOBuffer;
|
use dekejit::cpu::IOBuffer;
|
||||||
@ -6,10 +5,10 @@ use dekejit::cpu::CPU;
|
|||||||
use dekejit::pretty_printers::*;
|
use dekejit::pretty_printers::*;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use dekejit::loader::loader::{prepare_memory, self};
|
|
||||||
use dekejit::loader::loader::read_binary;
|
use dekejit::loader::loader::read_binary;
|
||||||
|
use dekejit::loader::loader::{self, prepare_memory};
|
||||||
use dekejit::transmute_to_vecu8_as_is;
|
use dekejit::transmute_to_vecu8_as_is;
|
||||||
use log::{info, debug};
|
use log::{debug, info};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let cli: Cli = Cli::parse();
|
let cli: Cli = Cli::parse();
|
||||||
@ -27,7 +26,6 @@ fn main() {
|
|||||||
|
|
||||||
match cli.comm {
|
match cli.comm {
|
||||||
Some(Run { filename }) => {
|
Some(Run { filename }) => {
|
||||||
|
|
||||||
info!("Trying to read {}", filename);
|
info!("Trying to read {}", filename);
|
||||||
|
|
||||||
let Ok(content) = std::fs::read(&filename) else {
|
let Ok(content) = std::fs::read(&filename) else {
|
||||||
@ -35,7 +33,6 @@ fn main() {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let bytes = dekejit::transmute_to_vecu16_as_is(content.to_vec());
|
let bytes = dekejit::transmute_to_vecu16_as_is(content.to_vec());
|
||||||
|
|
||||||
info!("Begin parsing file {}", &filename);
|
info!("Begin parsing file {}", &filename);
|
||||||
@ -63,23 +60,21 @@ fn main() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
Some(Build { filename, output }) => {
|
Some(Build { filename, output }) => {
|
||||||
|
|
||||||
let Ok(inp_content) = std::fs::read_to_string(filename.clone()) else {
|
let Ok(inp_content) = std::fs::read_to_string(filename.clone()) else {
|
||||||
println!("Could not read file {}", &filename);
|
println!("Could not read file {}", &filename);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let prs = dekejit::assembler::parser::Parser::new(inp_content);
|
let prs = dekejit::assembler::parser::Parser::new(inp_content);
|
||||||
|
|
||||||
let sections = match prs.parse_sections() {
|
let sections = match prs.parse_sections() {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(p_err) => {
|
Err(p_err) => {
|
||||||
println!("Parser error: {:?}", p_err);
|
println!("Parser error: {:?}", p_err);
|
||||||
return;
|
return;
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let Some(bin) = dekejit::assembler::to_binary(sections) else {
|
let Some(bin) = dekejit::assembler::to_binary(sections) else {
|
||||||
println!("Unspecified error while converting file to binary. Must fix.");
|
println!("Unspecified error while converting file to binary. Must fix.");
|
||||||
return;
|
return;
|
||||||
@ -93,18 +88,16 @@ fn main() {
|
|||||||
|
|
||||||
let out_bin = transmute_to_vecu8_as_is(out_bin);
|
let out_bin = transmute_to_vecu8_as_is(out_bin);
|
||||||
|
|
||||||
|
|
||||||
info!("{:?}", out_bin);
|
info!("{:?}", out_bin);
|
||||||
|
|
||||||
match std::fs::write(output.clone(), out_bin) {
|
match std::fs::write(output.clone(), out_bin) {
|
||||||
Ok(_) => {},
|
Ok(_) => {}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("could not write file {}", output);},
|
println!("could not write file {}", output);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
Some(View {filename, format}) => {
|
Some(View { filename, format }) => {
|
||||||
|
|
||||||
info!("Trying to read {}", filename);
|
info!("Trying to read {}", filename);
|
||||||
|
|
||||||
let Ok(content) = std::fs::read_to_string(&filename) else {
|
let Ok(content) = std::fs::read_to_string(&filename) else {
|
||||||
@ -114,10 +107,12 @@ fn main() {
|
|||||||
|
|
||||||
let p = parser::Parser::new(content);
|
let p = parser::Parser::new(content);
|
||||||
|
|
||||||
|
|
||||||
let s = p.parse_sections().unwrap();
|
let s = p.parse_sections().unwrap();
|
||||||
|
|
||||||
println!("{}", format_code(dekejit::pretty_printers::CodeWrapper::Asm(s), format).unwrap());
|
println!(
|
||||||
|
"{}",
|
||||||
|
format_code(dekejit::pretty_printers::CodeWrapper::Asm(s), format).unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
// let Ok(content) = std::fs::read(&filename) else {
|
// let Ok(content) = std::fs::read(&filename) else {
|
||||||
// println!("File {} does not exist or cannot be read.", &filename);
|
// println!("File {} does not exist or cannot be read.", &filename);
|
||||||
@ -139,15 +134,11 @@ fn main() {
|
|||||||
// };
|
// };
|
||||||
//
|
//
|
||||||
// println!("{:?}", sections);
|
// println!("{:?}", sections);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Some(Debug) => {},
|
Some(Debug) => {}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// let parser = parser::Parser::new(code);
|
// let parser = parser::Parser::new(code);
|
||||||
//
|
//
|
||||||
// let r = parser.parse_sections().unwrap();
|
// let r = parser.parse_sections().unwrap();
|
||||||
|
Loading…
Reference in New Issue
Block a user