Added a fmt file and formatted the whole project
parent
659f9fbe65
commit
f39dde9c64
|
@ -0,0 +1,8 @@
|
||||||
|
unstable_features = true
|
||||||
|
reorder_imports = true
|
||||||
|
hard_tabs = true
|
||||||
|
control_brace_style = "ClosingNextLine"
|
||||||
|
imports_granularity = "Crate"
|
||||||
|
group_imports = "StdExternalCrate"
|
||||||
|
edition = "2021"
|
||||||
|
newline_style = "Unix"
|
114
src/asm_gen.rs
114
src/asm_gen.rs
|
@ -3,88 +3,88 @@ use std::collections::VecDeque;
|
||||||
use crate::tokenizer::{Token, TokenType};
|
use crate::tokenizer::{Token, TokenType};
|
||||||
|
|
||||||
pub fn generate(tokens: Vec<Token>) -> String {
|
pub fn generate(tokens: Vec<Token>) -> String {
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
|
|
||||||
// reserving mem
|
// reserving mem
|
||||||
output.push_str(
|
output.push_str(
|
||||||
"section .bss\n\
|
"section .bss\n\
|
||||||
data: resb 65536\n",
|
data: resb 65536\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
// global start label
|
// global start label
|
||||||
output.push_str(
|
output.push_str(
|
||||||
"global _start\n\
|
"global _start\n\
|
||||||
section .text\n\
|
section .text\n\
|
||||||
_start:\n",
|
_start:\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
// create the pointer for our data
|
// create the pointer for our data
|
||||||
output.push_str("mov rdx, data\n");
|
output.push_str("mov rdx, data\n");
|
||||||
|
|
||||||
let mut loops = 0;
|
let mut loops = 0;
|
||||||
let mut stack: VecDeque<usize> = VecDeque::new();
|
let mut stack: VecDeque<usize> = VecDeque::new();
|
||||||
for token in tokens {
|
for token in tokens {
|
||||||
match token.r#type {
|
match token.r#type {
|
||||||
TokenType::Plus(x) => {
|
TokenType::Plus(x) => {
|
||||||
output.push_str(&format!("add byte[rdx], {x}\n"));
|
output.push_str(&format!("add byte[rdx], {x}\n"));
|
||||||
}
|
}
|
||||||
TokenType::Minus(x) => {
|
TokenType::Minus(x) => {
|
||||||
output.push_str(&format!("sub byte[rdx], {x}\n"));
|
output.push_str(&format!("sub byte[rdx], {x}\n"));
|
||||||
}
|
}
|
||||||
TokenType::MoveRight(x) => {
|
TokenType::MoveRight(x) => {
|
||||||
output.push_str(&format!("add rdx, {x}\n"));
|
output.push_str(&format!("add rdx, {x}\n"));
|
||||||
}
|
}
|
||||||
TokenType::MoveLeft(x) => {
|
TokenType::MoveLeft(x) => {
|
||||||
output.push_str(&format!("sub rdx, {x}\n"));
|
output.push_str(&format!("sub rdx, {x}\n"));
|
||||||
}
|
}
|
||||||
TokenType::Output => {
|
TokenType::Output => {
|
||||||
output.push_str(
|
output.push_str(
|
||||||
"push rdx\n\
|
"push rdx\n\
|
||||||
mov rax, 1\n\
|
mov rax, 1\n\
|
||||||
mov rdi, 1\n\
|
mov rdi, 1\n\
|
||||||
mov rsi, rdx\n\
|
mov rsi, rdx\n\
|
||||||
mov rdx, 1\n\
|
mov rdx, 1\n\
|
||||||
syscall\n\
|
syscall\n\
|
||||||
pop rdx\n",
|
pop rdx\n",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
TokenType::Input => {
|
TokenType::Input => {
|
||||||
output.push_str(
|
output.push_str(
|
||||||
"push rdx\n\
|
"push rdx\n\
|
||||||
mov rax, 0\n\
|
mov rax, 0\n\
|
||||||
mov rdi, 0\n\
|
mov rdi, 0\n\
|
||||||
mov rsi, rdx\n\
|
mov rsi, rdx\n\
|
||||||
mov rdx, 1\n\
|
mov rdx, 1\n\
|
||||||
syscall\n\
|
syscall\n\
|
||||||
pop rdx\n",
|
pop rdx\n",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
TokenType::BracketOpen => {
|
TokenType::BracketOpen => {
|
||||||
output.push_str(&format!(
|
output.push_str(&format!(
|
||||||
".loop_{loops}_start:\n\
|
".loop_{loops}_start:\n\
|
||||||
cmp byte[rdx], 0\n\
|
cmp byte[rdx], 0\n\
|
||||||
je .loop_{loops}_end\n"
|
je .loop_{loops}_end\n"
|
||||||
));
|
));
|
||||||
stack.push_back(loops);
|
stack.push_back(loops);
|
||||||
loops += 1;
|
loops += 1;
|
||||||
}
|
}
|
||||||
TokenType::BracketClose => {
|
TokenType::BracketClose => {
|
||||||
let current_loop = stack.pop_back().unwrap();
|
let current_loop = stack.pop_back().unwrap();
|
||||||
output.push_str(&format!(
|
output.push_str(&format!(
|
||||||
"cmp byte[rdx], 0\n\
|
"cmp byte[rdx], 0\n\
|
||||||
jne .loop_{current_loop}_start\n\
|
jne .loop_{current_loop}_start\n\
|
||||||
.loop_{current_loop}_end:\n",
|
.loop_{current_loop}_end:\n",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// exit syscall
|
// exit syscall
|
||||||
output.push_str(
|
output.push_str(
|
||||||
"mov rax, 60\n\
|
"mov rax, 60\n\
|
||||||
mov rdi, 0\n\
|
mov rdi, 0\n\
|
||||||
syscall\n",
|
syscall\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@ use std::{fs, io::Write, path::PathBuf};
|
||||||
use crate::{asm_gen, tokenizer};
|
use crate::{asm_gen, tokenizer};
|
||||||
|
|
||||||
pub fn compile(program: Vec<u8>, name: String) {
|
pub fn compile(program: Vec<u8>, name: String) {
|
||||||
let tokens = tokenizer::tokenize(program);
|
let tokens = tokenizer::tokenize(program);
|
||||||
let asm = asm_gen::generate(tokens);
|
let asm = asm_gen::generate(tokens);
|
||||||
|
|
||||||
let path: PathBuf = [".", &format!("./{name}.asm")].iter().collect();
|
let path: PathBuf = [".", &format!("./{name}.asm")].iter().collect();
|
||||||
let mut file = fs::File::create(path).unwrap();
|
let mut file = fs::File::create(path).unwrap();
|
||||||
file.write_all(asm.as_bytes()).unwrap();
|
file.write_all(asm.as_bytes()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,93 +1,95 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn run(program: Vec<u8>) {
|
pub fn run(program: Vec<u8>) {
|
||||||
let mut tape: Vec<u8> = vec![0];
|
let mut tape: Vec<u8> = vec![0];
|
||||||
let mut cell_index: usize = 0;
|
let mut cell_index: usize = 0;
|
||||||
|
|
||||||
let mut ip: usize = 0;
|
let mut ip: usize = 0;
|
||||||
let mut icount: usize = 0;
|
let mut icount: usize = 0;
|
||||||
let mut user_input: Vec<u8> = vec![];
|
let mut user_input: Vec<u8> = vec![];
|
||||||
|
|
||||||
let mut table: HashMap<usize, usize> = HashMap::new();
|
let mut table: HashMap<usize, usize> = HashMap::new();
|
||||||
let mut stack: VecDeque<usize> = VecDeque::new();
|
let mut stack: VecDeque<usize> = VecDeque::new();
|
||||||
for (ip, instruction) in program.iter().enumerate() {
|
for (ip, instruction) in program.iter().enumerate() {
|
||||||
if *instruction == b'[' {
|
if *instruction == b'[' {
|
||||||
stack.push_back(ip);
|
stack.push_back(ip);
|
||||||
} else if *instruction == b']' {
|
}
|
||||||
let begin_index = stack.pop_back().unwrap();
|
else if *instruction == b']' {
|
||||||
table.insert(begin_index, ip);
|
let begin_index = stack.pop_back().unwrap();
|
||||||
table.insert(ip, begin_index);
|
table.insert(begin_index, ip);
|
||||||
}
|
table.insert(ip, begin_index);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while ip < program.len() {
|
while ip < program.len() {
|
||||||
let Some(instruction) = program.get(ip) else {
|
let Some(instruction) = program.get(ip)
|
||||||
break;
|
else {
|
||||||
};
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
match instruction {
|
match instruction {
|
||||||
b'+' => {
|
b'+' => {
|
||||||
tape[cell_index] = tape[cell_index].wrapping_add(1);
|
tape[cell_index] = tape[cell_index].wrapping_add(1);
|
||||||
icount += 1;
|
icount += 1;
|
||||||
}
|
}
|
||||||
b'-' => {
|
b'-' => {
|
||||||
tape[cell_index] = tape[cell_index].wrapping_sub(1);
|
tape[cell_index] = tape[cell_index].wrapping_sub(1);
|
||||||
icount += 1;
|
icount += 1;
|
||||||
}
|
}
|
||||||
b'>' => {
|
b'>' => {
|
||||||
cell_index = cell_index.wrapping_add(1);
|
cell_index = cell_index.wrapping_add(1);
|
||||||
if tape.len() <= cell_index {
|
if tape.len() <= cell_index {
|
||||||
tape.push(0);
|
tape.push(0);
|
||||||
}
|
}
|
||||||
icount += 1;
|
icount += 1;
|
||||||
}
|
}
|
||||||
b'<' => {
|
b'<' => {
|
||||||
cell_index = cell_index.wrapping_sub(1);
|
cell_index = cell_index.wrapping_sub(1);
|
||||||
icount += 1;
|
icount += 1;
|
||||||
}
|
}
|
||||||
b'.' => {
|
b'.' => {
|
||||||
print!("{}", tape[cell_index] as char);
|
print!("{}", tape[cell_index] as char);
|
||||||
icount += 1;
|
icount += 1;
|
||||||
}
|
}
|
||||||
b',' => {
|
b',' => {
|
||||||
if user_input.is_empty() {
|
if user_input.is_empty() {
|
||||||
user_input = input();
|
user_input = input();
|
||||||
}
|
}
|
||||||
tape[cell_index] = user_input.remove(0);
|
tape[cell_index] = user_input.remove(0);
|
||||||
icount += 1;
|
icount += 1;
|
||||||
}
|
}
|
||||||
b'[' => {
|
b'[' => {
|
||||||
if tape[cell_index] == 0 {
|
if tape[cell_index] == 0 {
|
||||||
ip = *table.get(&ip).unwrap();
|
ip = *table.get(&ip).unwrap();
|
||||||
}
|
}
|
||||||
icount += 1;
|
icount += 1;
|
||||||
}
|
}
|
||||||
b']' => {
|
b']' => {
|
||||||
if tape[cell_index] != 0 {
|
if tape[cell_index] != 0 {
|
||||||
ip = *table.get(&ip).unwrap();
|
ip = *table.get(&ip).unwrap();
|
||||||
}
|
}
|
||||||
icount += 1;
|
icount += 1;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
ip += 1;
|
ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
println!("Instructions ran: {icount}");
|
println!("Instructions ran: {icount}");
|
||||||
// println!("{tape:?}");
|
// println!("{tape:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input() -> Vec<u8> {
|
fn input() -> Vec<u8> {
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
|
|
||||||
print!("Input: ");
|
print!("Input: ");
|
||||||
let _ = io::stdout().flush();
|
let _ = io::stdout().flush();
|
||||||
let _ = io::stdin().read_line(&mut input);
|
let _ = io::stdin().read_line(&mut input);
|
||||||
|
|
||||||
input.as_bytes().to_vec()
|
input.as_bytes().to_vec()
|
||||||
}
|
}
|
||||||
|
|
40
src/main.rs
40
src/main.rs
|
@ -8,28 +8,28 @@ mod interpreter;
|
||||||
mod tokenizer;
|
mod tokenizer;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
let mode = args.get(1).expect("mode expected");
|
let mode = args.get(1).expect("mode expected");
|
||||||
let input = args.get(2).expect("malformed arguments");
|
let input = args.get(2).expect("malformed arguments");
|
||||||
let program: Vec<u8> = load_program(input);
|
let program: Vec<u8> = load_program(input);
|
||||||
let name = args
|
let name = args
|
||||||
.get(3)
|
.get(3)
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
.unwrap_or_else(|| "program".to_string());
|
.unwrap_or_else(|| "program".to_string());
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
x if x == "c" => {
|
x if x == "c" => {
|
||||||
compiler::compile(program, name);
|
compiler::compile(program, name);
|
||||||
}
|
}
|
||||||
x if x == "i" => {
|
x if x == "i" => {
|
||||||
interpreter::run(program);
|
interpreter::run(program);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_program(input: &str) -> Vec<u8> {
|
fn load_program(input: &str) -> Vec<u8> {
|
||||||
let path: PathBuf = input.into();
|
let path: PathBuf = input.into();
|
||||||
let input = fs::read_to_string(path).expect("failed to read the program file");
|
let input = fs::read_to_string(path).expect("failed to read the program file");
|
||||||
input.as_bytes().to_vec()
|
input.as_bytes().to_vec()
|
||||||
}
|
}
|
||||||
|
|
127
src/tokenizer.rs
127
src/tokenizer.rs
|
@ -1,85 +1,86 @@
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TokenType {
|
pub enum TokenType {
|
||||||
Plus(u32),
|
Plus(u32),
|
||||||
Minus(u32),
|
Minus(u32),
|
||||||
MoveRight(u32),
|
MoveRight(u32),
|
||||||
MoveLeft(u32),
|
MoveLeft(u32),
|
||||||
Output,
|
Output,
|
||||||
Input,
|
Input,
|
||||||
BracketOpen,
|
BracketOpen,
|
||||||
BracketClose,
|
BracketClose,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
pub r#type: TokenType,
|
pub r#type: TokenType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Token {
|
impl Token {
|
||||||
fn new(r#type: TokenType) -> Self {
|
fn new(r#type: TokenType) -> Self {
|
||||||
Self { r#type }
|
Self { r#type }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tokenize(program: Vec<u8>) -> Vec<Token> {
|
pub fn tokenize(program: Vec<u8>) -> Vec<Token> {
|
||||||
let mut tokens = vec![];
|
let mut tokens = vec![];
|
||||||
|
|
||||||
let mut ip = 0;
|
let mut ip = 0;
|
||||||
while ip < program.len() {
|
while ip < program.len() {
|
||||||
let Some(instruction) = program.get(ip) else {
|
let Some(instruction) = program.get(ip)
|
||||||
break;
|
else {
|
||||||
};
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
ip += 1;
|
ip += 1;
|
||||||
|
|
||||||
match instruction {
|
match instruction {
|
||||||
b'+' => {
|
b'+' => {
|
||||||
let count = check_next(&program, &mut ip, instruction);
|
let count = check_next(&program, &mut ip, instruction);
|
||||||
tokens.push(Token::new(TokenType::Plus(count)));
|
tokens.push(Token::new(TokenType::Plus(count)));
|
||||||
}
|
}
|
||||||
b'-' => {
|
b'-' => {
|
||||||
let count = check_next(&program, &mut ip, instruction);
|
let count = check_next(&program, &mut ip, instruction);
|
||||||
tokens.push(Token::new(TokenType::Minus(count)));
|
tokens.push(Token::new(TokenType::Minus(count)));
|
||||||
}
|
}
|
||||||
b'>' => {
|
b'>' => {
|
||||||
let count = check_next(&program, &mut ip, instruction);
|
let count = check_next(&program, &mut ip, instruction);
|
||||||
tokens.push(Token::new(TokenType::MoveRight(count)));
|
tokens.push(Token::new(TokenType::MoveRight(count)));
|
||||||
}
|
}
|
||||||
b'<' => {
|
b'<' => {
|
||||||
let count = check_next(&program, &mut ip, instruction);
|
let count = check_next(&program, &mut ip, instruction);
|
||||||
tokens.push(Token::new(TokenType::MoveLeft(count)));
|
tokens.push(Token::new(TokenType::MoveLeft(count)));
|
||||||
}
|
}
|
||||||
b'.' => {
|
b'.' => {
|
||||||
tokens.push(Token::new(TokenType::Output));
|
tokens.push(Token::new(TokenType::Output));
|
||||||
}
|
}
|
||||||
b',' => {
|
b',' => {
|
||||||
tokens.push(Token::new(TokenType::Input));
|
tokens.push(Token::new(TokenType::Input));
|
||||||
}
|
}
|
||||||
b'[' => {
|
b'[' => {
|
||||||
tokens.push(Token::new(TokenType::BracketOpen));
|
tokens.push(Token::new(TokenType::BracketOpen));
|
||||||
}
|
}
|
||||||
b']' => {
|
b']' => {
|
||||||
tokens.push(Token::new(TokenType::BracketClose));
|
tokens.push(Token::new(TokenType::BracketClose));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// dbg!(&tokens);
|
// dbg!(&tokens);
|
||||||
|
|
||||||
tokens
|
tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_next(program: &[u8], ip: &mut usize, instruction: &u8) -> u32 {
|
fn check_next(program: &[u8], ip: &mut usize, instruction: &u8) -> u32 {
|
||||||
let mut icount = 1;
|
let mut icount = 1;
|
||||||
let mut next_instruction = program.get(*ip);
|
let mut next_instruction = program.get(*ip);
|
||||||
while let Some(next) = next_instruction
|
while let Some(next) = next_instruction
|
||||||
&& *next == *instruction
|
&& *next == *instruction
|
||||||
{
|
{
|
||||||
icount += 1;
|
icount += 1;
|
||||||
*ip += 1;
|
*ip += 1;
|
||||||
next_instruction = program.get(*ip);
|
next_instruction = program.get(*ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
icount
|
icount
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue