Cleaned up the code
This commit is contained in:
parent
5aa2393c8f
commit
0d66ab1009
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::{PathBuf, Path};
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
use std::{process, fs};
|
use std::{process, fs};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
@ -47,10 +47,10 @@ fn run_test<P: Into<PathBuf> + std::convert::AsRef<std::ffi::OsStr>>(f_in: PathB
|
||||||
let mut command = process::Command::new(compiler);
|
let mut command = process::Command::new(compiler);
|
||||||
command.stdout(Stdio::piped());
|
command.stdout(Stdio::piped());
|
||||||
command.stderr(Stdio::piped());
|
command.stderr(Stdio::piped());
|
||||||
if !compile_mode {
|
if compile_mode {
|
||||||
command.arg("-sq");
|
|
||||||
} else {
|
|
||||||
command.arg("-cqr");
|
command.arg("-cqr");
|
||||||
|
} else {
|
||||||
|
command.arg("-sq");
|
||||||
}
|
}
|
||||||
|
|
||||||
command.arg("-i");
|
command.arg("-i");
|
||||||
|
@ -63,18 +63,18 @@ fn run_test<P: Into<PathBuf> + std::convert::AsRef<std::ffi::OsStr>>(f_in: PathB
|
||||||
let out = child.wait_with_output()?;
|
let out = child.wait_with_output()?;
|
||||||
|
|
||||||
let stdout = out.stdout.iter().map(|c| {
|
let stdout = out.stdout.iter().map(|c| {
|
||||||
char::from_u32((*c) as u32).expect("Failed to parse stdout char").to_string()
|
char::from_u32(u32::from(*c)).expect("Failed to parse stdout char").to_string()
|
||||||
}).collect::<String>();
|
}).collect::<String>();
|
||||||
|
|
||||||
let stderr = out.stderr.iter().map(|c| {
|
let stderr = out.stderr.iter().map(|c| {
|
||||||
char::from_u32((*c) as u32).expect("Failed to parse stderr char").to_string()
|
char::from_u32(u32::from(*c)).expect("Failed to parse stderr char").to_string()
|
||||||
}).collect::<String>();
|
}).collect::<String>();
|
||||||
|
|
||||||
|
|
||||||
Ok(TestOutput {
|
Ok(TestOutput {
|
||||||
stdout: stdout,
|
stdout,
|
||||||
stderr: stderr,
|
stderr,
|
||||||
stdin: stdin,
|
stdin,
|
||||||
status: out.status.code().unwrap()
|
status: out.status.code().unwrap()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -91,14 +91,14 @@ fn run_tests(args: Args) -> Result<()>{
|
||||||
|
|
||||||
let intp = run_test(file.path(), &f_out, &args.compiler_path, false, String::new())?;
|
let intp = run_test(file.path(), &f_out, &args.compiler_path, false, String::new())?;
|
||||||
let comp = run_test(file.path(), &f_out, &args.compiler_path, true, String::new())?;
|
let comp = run_test(file.path(), &f_out, &args.compiler_path, true, String::new())?;
|
||||||
compare_results(intp, comp, file.path())?;
|
compare_results(&intp, &comp, &file.path())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn compare_results(intp: TestOutput, comp: TestOutput, f_in: PathBuf) -> Result<()> {
|
fn compare_results(intp: &TestOutput, comp: &TestOutput, f_in: &Path) -> Result<()> {
|
||||||
|
|
||||||
if intp.stdout != comp.stdout {
|
if intp.stdout != comp.stdout {
|
||||||
println!("{b}[ {r}ERR{rs}{b} ]{rs} {f} compiled and interpreted stdout versions differ", r=color::FG_RED, rs=color::RESET, b=color::BRIGHT, f=f_in.display());
|
println!("{b}[ {r}ERR{rs}{b} ]{rs} {f} compiled and interpreted stdout versions differ", r=color::FG_RED, rs=color::RESET, b=color::BRIGHT, f=f_in.display());
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use std::path::PathBuf;
|
use std::path::{PathBuf, Path};
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use crate::info;
|
use crate::info;
|
||||||
|
|
||||||
pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &PathBuf, quiet: bool) -> Result<()> {
|
pub fn linux_x86_64_compile_and_link(of_a: &Path, of_o: &Path, of_c: &Path, quiet: bool) -> Result<()> {
|
||||||
|
|
||||||
let nasm_args = [
|
let nasm_args = [
|
||||||
"-felf64",
|
"-felf64",
|
||||||
|
@ -23,7 +23,7 @@ pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &Path
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
Command::new("nasm")
|
Command::new("nasm")
|
||||||
.args(&nasm_args)
|
.args(nasm_args)
|
||||||
.stdout(Stdio::inherit())
|
.stdout(Stdio::inherit())
|
||||||
.stderr(Stdio::inherit())
|
.stderr(Stdio::inherit())
|
||||||
.spawn()?
|
.spawn()?
|
||||||
|
@ -42,7 +42,7 @@ pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &Path
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
Command::new("ld")
|
Command::new("ld")
|
||||||
.args(&ld_args)
|
.args(ld_args)
|
||||||
.stdout(Stdio::inherit())
|
.stdout(Stdio::inherit())
|
||||||
.stderr(Stdio::inherit())
|
.stderr(Stdio::inherit())
|
||||||
.spawn()?
|
.spawn()?
|
||||||
|
@ -60,28 +60,28 @@ pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &Path
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn linux_x86_64_run(_bin: &PathBuf, args: Vec<String>, quiet: bool) -> Result<i32> {
|
pub fn linux_x86_64_run(bin: &Path, args: &[String], quiet: bool) -> Result<i32> {
|
||||||
|
|
||||||
let bin = PathBuf::from(
|
let bin = PathBuf::from(
|
||||||
format!("./{}", _bin.to_string_lossy())
|
format!("./{}", bin.to_string_lossy())
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut proc = if cfg!(target_os = "windows") {
|
let mut proc = if cfg!(target_os = "windows") {
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
} else {
|
} else {
|
||||||
Command::new(bin)
|
Command::new(bin.clone())
|
||||||
.args(&args)
|
.args(args)
|
||||||
.stdout(Stdio::inherit())
|
.stdout(Stdio::inherit())
|
||||||
.stderr(Stdio::inherit())
|
.stderr(Stdio::inherit())
|
||||||
.spawn()?
|
.spawn()?
|
||||||
};
|
};
|
||||||
// println!("{}", quiet);
|
// println!("{}", quiet);
|
||||||
if !quiet {
|
if !quiet {
|
||||||
info!("running {} {}", _bin.to_string_lossy(), args.join(" "));
|
info!("running {} {}", bin.to_string_lossy(), args.join(" "));
|
||||||
}
|
}
|
||||||
let exit = proc.wait()?;
|
let exit = proc.wait()?;
|
||||||
if !quiet {
|
if !quiet {
|
||||||
info!("{} process exited with code {}", _bin.to_string_lossy(), exit);
|
info!("{} process exited with code {}", bin.to_string_lossy(), exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(exit.code().unwrap_or(0))
|
Ok(exit.code().unwrap_or(0))
|
||||||
|
|
|
@ -6,9 +6,9 @@ use crate::compile::commands::linux_x86_64_compile_and_link;
|
||||||
use super::commands::linux_x86_64_run;
|
use super::commands::linux_x86_64_run;
|
||||||
|
|
||||||
|
|
||||||
pub fn compile(tokens: Vec<Operator>, args: Args) -> Result<i32>{
|
pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
||||||
let mut of_c = PathBuf::from(&args.out_file);
|
let mut of_c = PathBuf::from(&args.out_file);
|
||||||
let (mut of_o, mut of_a) = if &args.out_file == &crate::DEFAULT_OUT_FILE.to_string() {
|
let (mut of_o, mut of_a) = if args.out_file == *crate::DEFAULT_OUT_FILE {
|
||||||
let of_o = PathBuf::from("/tmp/mclang_comp.o");
|
let of_o = PathBuf::from("/tmp/mclang_comp.o");
|
||||||
let of_a = PathBuf::from("/tmp/mclang_comp.nasm");
|
let of_a = PathBuf::from("/tmp/mclang_comp.nasm");
|
||||||
(of_o, of_a)
|
(of_o, of_a)
|
||||||
|
@ -22,6 +22,8 @@ pub fn compile(tokens: Vec<Operator>, args: Args) -> Result<i32>{
|
||||||
of_o.set_extension("o");
|
of_o.set_extension("o");
|
||||||
of_a.set_extension("nasm");
|
of_a.set_extension("nasm");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let file = fs::File::create(&of_a)?;
|
let file = fs::File::create(&of_a)?;
|
||||||
let mut writer = BufWriter::new(&file);
|
let mut writer = BufWriter::new(&file);
|
||||||
|
|
||||||
|
@ -72,7 +74,7 @@ pub fn compile(tokens: Vec<Operator>, args: Args) -> Result<i32>{
|
||||||
while ti < tokens.len() {
|
while ti < tokens.len() {
|
||||||
let token = &tokens[ti];
|
let token = &tokens[ti];
|
||||||
|
|
||||||
writeln!(writer, "addr_{}:", ti)?;
|
writeln!(writer, "addr_{ti}:")?;
|
||||||
match token.typ {
|
match token.typ {
|
||||||
// stack
|
// stack
|
||||||
OpType::PushInt => {
|
OpType::PushInt => {
|
||||||
|
@ -336,7 +338,7 @@ pub fn compile(tokens: Vec<Operator>, args: Args) -> Result<i32>{
|
||||||
}
|
}
|
||||||
OpType::End => {
|
OpType::End => {
|
||||||
writeln!(writer, " ;; -- end")?;
|
writeln!(writer, " ;; -- end")?;
|
||||||
if ti + 1 != token.jmp as usize {
|
if ti + 1 != token.jmp {
|
||||||
writeln!(writer, " jmp addr_{}", token.jmp)?;
|
writeln!(writer, " jmp addr_{}", token.jmp)?;
|
||||||
}
|
}
|
||||||
ti += 1;
|
ti += 1;
|
||||||
|
@ -412,20 +414,18 @@ pub fn compile(tokens: Vec<Operator>, args: Args) -> Result<i32>{
|
||||||
writeln!(writer, " push rax")?;
|
writeln!(writer, " push rax")?;
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
OpType::None => unreachable!(),
|
OpType::None | OpType::Macro | OpType::Include => unreachable!()
|
||||||
OpType::Macro => unreachable!(),
|
|
||||||
OpType::Include => unreachable!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeln!(writer, "addr_{}:", ti)?;
|
writeln!(writer, "addr_{ti}:")?;
|
||||||
writeln!(writer, " mov rax, 60")?;
|
writeln!(writer, " mov rax, 60")?;
|
||||||
writeln!(writer, " mov rdi, 0")?;
|
writeln!(writer, " mov rdi, 0")?;
|
||||||
writeln!(writer, " syscall")?;
|
writeln!(writer, " syscall")?;
|
||||||
writeln!(writer, "segment .data")?;
|
writeln!(writer, "segment .data")?;
|
||||||
for s in 0..strings.len() {
|
for (_, s) in strings.iter().enumerate() {
|
||||||
let s_chars = strings[s].chars().map(|c| (c as u32).to_string()).collect::<Vec<String>>();
|
let s_chars = s.chars().map(|c| (c as u32).to_string()).collect::<Vec<String>>();
|
||||||
let s_list = s_chars.join(",");
|
let s_list = s_chars.join(",");
|
||||||
writeln!(writer, " str_{}: db {} ; {}", s, s_list, strings[s].escape_default())?;
|
writeln!(writer, " str_{}: db {} ; {}", s, s_list, s.escape_default())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(writer, "segment .bss")?;
|
writeln!(writer, "segment .bss")?;
|
||||||
|
@ -434,7 +434,7 @@ pub fn compile(tokens: Vec<Operator>, args: Args) -> Result<i32>{
|
||||||
writer.flush()?;
|
writer.flush()?;
|
||||||
linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet)?;
|
linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet)?;
|
||||||
if args.run {
|
if args.run {
|
||||||
let c = linux_x86_64_run(&of_c, vec![], args.quiet)?;
|
let c = linux_x86_64_run(&of_c, &[], args.quiet)?;
|
||||||
return Ok(c);
|
return Ok(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pub mod linux_x86_64;
|
pub mod linux_x86_64;
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
|
|
||||||
pub const MEM_SZ: u32 = 640 * 1000; // 4kb
|
pub const MEM_SZ: usize = 640 * 1000; // 4kb
|
||||||
pub const STRING_SZ: u32 = 640 * 1000; // 4kb
|
pub const STRING_SZ: usize = 640 * 1000; // 4kb
|
||||||
|
|
106
src/constants.rs
106
src/constants.rs
|
@ -63,20 +63,20 @@ pub enum OpType {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Operator {
|
pub struct Operator {
|
||||||
pub typ: OpType,
|
pub typ: OpType,
|
||||||
pub value: i64,
|
pub value: usize,
|
||||||
pub text: String, //? only used for OpType::PushStr
|
pub text: String, //? only used for OpType::PushStr
|
||||||
pub addr: i64, //? only used for OpType::PushStr
|
pub addr: Option<usize>, //? only used for OpType::PushStr
|
||||||
pub jmp: i32,
|
pub jmp: usize,
|
||||||
pub loc: (String, u32, u32)
|
pub loc: (String, usize, usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operator {
|
impl Operator {
|
||||||
pub fn new(typ: OpType, value: i64, text: String, file: String, row: u32, col: u32) -> Self {
|
pub fn new(typ: OpType, value: usize, text: String, file: String, row: usize, col: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
typ,
|
typ,
|
||||||
value,
|
value,
|
||||||
jmp: 0,
|
jmp: 0,
|
||||||
addr: -1,
|
addr: None,
|
||||||
text,
|
text,
|
||||||
loc: (file, row, col)
|
loc: (file, row, col)
|
||||||
}
|
}
|
||||||
|
@ -86,48 +86,48 @@ impl Operator {
|
||||||
|
|
||||||
impl OpType {
|
impl OpType {
|
||||||
pub fn human(&self) -> String {
|
pub fn human(&self) -> String {
|
||||||
match self {
|
match *self {
|
||||||
&OpType::PushInt => "Number",
|
OpType::PushInt => "Number",
|
||||||
&OpType::PushStr => "String",
|
OpType::PushStr => "String",
|
||||||
&OpType::Print => "print",
|
OpType::Print => "print",
|
||||||
&OpType::Dup => "dup",
|
OpType::Dup => "dup",
|
||||||
&OpType::Drop => "drop",
|
OpType::Drop => "drop",
|
||||||
&OpType::Dup2 => "2dup",
|
OpType::Dup2 => "2dup",
|
||||||
&OpType::Rot => "rot",
|
OpType::Rot => "rot",
|
||||||
&OpType::Over => "over",
|
OpType::Over => "over",
|
||||||
&OpType::Swap => "swap",
|
OpType::Swap => "swap",
|
||||||
&OpType::Plus => "+",
|
OpType::Plus => "+",
|
||||||
&OpType::Minus => "-",
|
OpType::Minus => "-",
|
||||||
&OpType::Equals => "=",
|
OpType::Equals => "=",
|
||||||
&OpType::Gt => ">",
|
OpType::Gt => ">",
|
||||||
&OpType::Lt => "<",
|
OpType::Lt => "<",
|
||||||
&OpType::NotEquals => "!=",
|
OpType::NotEquals => "!=",
|
||||||
&OpType::Le => "<=",
|
OpType::Le => "<=",
|
||||||
&OpType::Ge => ">=",
|
OpType::Ge => ">=",
|
||||||
&OpType::Band => "band",
|
OpType::Band => "band",
|
||||||
&OpType::Bor => "bor",
|
OpType::Bor => "bor",
|
||||||
&OpType::Shr => "shr",
|
OpType::Shr => "shr",
|
||||||
&OpType::Shl => "shl",
|
OpType::Shl => "shl",
|
||||||
&OpType::DivMod => "divmod",
|
OpType::DivMod => "divmod",
|
||||||
&OpType::Mul => "*",
|
OpType::Mul => "*",
|
||||||
&OpType::If => "if",
|
OpType::If => "if",
|
||||||
&OpType::Else => "else",
|
OpType::Else => "else",
|
||||||
&OpType::End => "end",
|
OpType::End => "end",
|
||||||
&OpType::While => "while",
|
OpType::While => "while",
|
||||||
&OpType::Do => "do",
|
OpType::Do => "do",
|
||||||
&OpType::Macro => "macro",
|
OpType::Macro => "macro",
|
||||||
&OpType::Include => "include",
|
OpType::Include => "include",
|
||||||
&OpType::Mem => "mem",
|
OpType::Mem => "mem",
|
||||||
&OpType::Load8 => "!8",
|
OpType::Load8 => "!8",
|
||||||
&OpType::Store8 => "@8",
|
OpType::Store8 => "@8",
|
||||||
&OpType::Syscall0 => "syscall0",
|
OpType::Syscall0 => "syscall0",
|
||||||
&OpType::Syscall1 => "syscall1",
|
OpType::Syscall1 => "syscall1",
|
||||||
&OpType::Syscall2 => "syscall2",
|
OpType::Syscall2 => "syscall2",
|
||||||
&OpType::Syscall3 => "syscall3",
|
OpType::Syscall3 => "syscall3",
|
||||||
&OpType::Syscall4 => "syscall4",
|
OpType::Syscall4 => "syscall4",
|
||||||
&OpType::Syscall5 => "syscall5",
|
OpType::Syscall5 => "syscall5",
|
||||||
&OpType::Syscall6 => "syscall6",
|
OpType::Syscall6 => "syscall6",
|
||||||
&OpType::None => "None"
|
OpType::None => "None"
|
||||||
}.to_string()
|
}.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,13 +135,13 @@ impl OpType {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
pub file: String,
|
pub file: String,
|
||||||
pub line: u32,
|
pub line: usize,
|
||||||
pub col: u32,
|
pub col: usize,
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub typ: TokenType
|
pub typ: TokenType
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||||
pub enum TokenType {
|
pub enum TokenType {
|
||||||
Word,
|
Word,
|
||||||
Int,
|
Int,
|
||||||
|
@ -160,7 +160,7 @@ impl Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokenType {
|
impl TokenType {
|
||||||
pub fn human(&self) -> String {
|
pub fn human(self) -> String {
|
||||||
match self {
|
match self {
|
||||||
TokenType::Word => "Word",
|
TokenType::Word => "Word",
|
||||||
TokenType::Int => "Int",
|
TokenType::Int => "Int",
|
||||||
|
@ -170,4 +170,4 @@ impl TokenType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Loc = (String, u32, u32);
|
pub type Loc = (String, usize, usize);
|
|
@ -1,23 +1,20 @@
|
||||||
use crate::{constants::OpType, lerror, error};
|
use crate::{constants::{OpType, Loc}, lerror, error};
|
||||||
// use crate::util::logger;
|
// use crate::util::logger;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use eyre::eyre;
|
use eyre::eyre;
|
||||||
mod syscalls;
|
mod syscalls;
|
||||||
|
|
||||||
fn stack_pop(stack: &mut Vec<u64>, pos: &(String, u32, u32)) -> Result<u64> {
|
fn stack_pop(stack: &mut Vec<usize>, pos: &Loc) -> Result<usize> {
|
||||||
match stack.pop() {
|
if let Some(i) = stack.pop() { Ok(i) } else {
|
||||||
Some(i) => Ok(i),
|
lerror!(&pos.clone(), "Stack underflow");
|
||||||
None => {
|
Err(eyre!("Stack underflow"))
|
||||||
lerror!(&pos.clone(), "Stack underflow");
|
|
||||||
Err(eyre!("Stack underflow"))
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<i32>{
|
pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
|
||||||
let mut stack: Vec<u64> = Vec::new();
|
let mut stack: Vec<usize> = Vec::new();
|
||||||
let mut ti = 0;
|
let mut ti = 0;
|
||||||
let mut mem: Vec<u8> = vec![0; crate::compile::MEM_SZ as usize + crate::compile::STRING_SZ as usize];
|
let mut mem: Vec<u8> = vec![0; crate::compile::MEM_SZ + crate::compile::STRING_SZ];
|
||||||
let mut string_idx = 0;
|
let mut string_idx = 0;
|
||||||
// for token in &tokens {
|
// for token in &tokens {
|
||||||
// println!("{{typ: \"{:?}\", val: {}, jmp: {}}}", token.typ, token.value, token.jmp);
|
// println!("{{typ: \"{:?}\", val: {}, jmp: {}}}", token.typ, token.value, token.jmp);
|
||||||
|
@ -31,21 +28,23 @@ pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<i32>{
|
||||||
|
|
||||||
// stack
|
// stack
|
||||||
OpType::PushInt => {
|
OpType::PushInt => {
|
||||||
stack.push(token.value as u64);
|
stack.push(token.value);
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
OpType::PushStr => {
|
OpType::PushStr => {
|
||||||
if token.addr < 0 {
|
if token.addr.is_none() {
|
||||||
stack.push(token.text.len() as u64); // string len
|
stack.push(token.text.len()); // string len
|
||||||
stack.push(string_idx + crate::compile::MEM_SZ as u64);
|
stack.push(string_idx + crate::compile::MEM_SZ);
|
||||||
|
|
||||||
for c in token.text.bytes() {
|
for c in token.text.bytes() {
|
||||||
mem[crate::compile::MEM_SZ as usize + string_idx as usize] = c;
|
mem[crate::compile::MEM_SZ + string_idx] = c;
|
||||||
string_idx += 1;
|
string_idx += 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
stack.push(token.text.len() as u64);
|
stack.push(token.text.len());
|
||||||
stack.push(token.addr as u64);
|
if let Some(addr) = token.addr {
|
||||||
|
stack.push(addr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,15 +108,16 @@ pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<i32>{
|
||||||
}
|
}
|
||||||
OpType::Load8 => {
|
OpType::Load8 => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let byte = mem[a as usize];
|
let byte = mem[a];
|
||||||
stack.push(byte as u64);
|
stack.push(byte as usize);
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
OpType::Store8 => {
|
OpType::Store8 => {
|
||||||
let val = stack_pop(&mut stack, &pos)?;
|
let val = stack_pop(&mut stack, &pos)?;
|
||||||
let addr = stack_pop(&mut stack, &pos)?;
|
let addr = stack_pop(&mut stack, &pos)?;
|
||||||
|
|
||||||
mem[addr as usize] = (val & 0xFF) as u8;
|
mem[addr] = (val & 0xFF) as u8;
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,79 +137,79 @@ pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<i32>{
|
||||||
OpType::Equals => {
|
OpType::Equals => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
let b = stack_pop(&mut stack, &pos)?;
|
||||||
stack.push((b == a) as u64);
|
stack.push(usize::from(b == a));
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
OpType::Gt => {
|
OpType::Gt => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
let b = stack_pop(&mut stack, &pos)?;
|
||||||
stack.push((b > a) as u64);
|
stack.push(usize::from(b > a));
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
OpType::Lt => {
|
OpType::Lt => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
let b = stack_pop(&mut stack, &pos)?;
|
||||||
stack.push((b < a) as u64);
|
stack.push(usize::from(b < a));
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
OpType::NotEquals => {
|
OpType::NotEquals => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
let b = stack_pop(&mut stack, &pos)?;
|
||||||
stack.push((b != a) as u64);
|
stack.push(usize::from(b != a));
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
OpType::Ge => {
|
OpType::Ge => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
let b = stack_pop(&mut stack, &pos)?;
|
||||||
stack.push((b >= a) as u64);
|
stack.push(usize::from(b >= a));
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
OpType::Le => {
|
OpType::Le => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
let b = stack_pop(&mut stack, &pos)?;
|
||||||
stack.push((b <= a) as u64);
|
stack.push(usize::from(b <= a));
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
OpType::Band => {
|
OpType::Band => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
let b = stack_pop(&mut stack, &pos)?;
|
||||||
stack.push((a & b) as u64);
|
stack.push(a & b);
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpType::Bor => {
|
OpType::Bor => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
let b = stack_pop(&mut stack, &pos)?;
|
||||||
stack.push((a | b) as u64);
|
stack.push(a | b);
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpType::Shr => {
|
OpType::Shr => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
let b = stack_pop(&mut stack, &pos)?;
|
||||||
stack.push((b >> a) as u64);
|
stack.push(b >> a);
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpType::Shl => {
|
OpType::Shl => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
let b = stack_pop(&mut stack, &pos)?;
|
||||||
stack.push((b << a) as u64);
|
stack.push(b << a);
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpType::DivMod => {
|
OpType::DivMod => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
let b = stack_pop(&mut stack, &pos)?;
|
||||||
stack.push((b / a) as u64);
|
stack.push(b / a);
|
||||||
stack.push((b % a) as u64);
|
stack.push(b % a);
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
OpType::Mul => {
|
OpType::Mul => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
let b = stack_pop(&mut stack, &pos)?;
|
||||||
stack.push((b * a) as u64);
|
stack.push(b * a);
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,18 +219,13 @@ pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<i32>{
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
if a == 0 {
|
if a == 0 {
|
||||||
// println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp);
|
// println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp);
|
||||||
ti = (token.jmp) as usize;
|
ti = token.jmp;
|
||||||
} else {
|
} else {
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
OpType::Else => {
|
OpType::Else | OpType::End => {
|
||||||
// println!("Else({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp);
|
ti = token.jmp;
|
||||||
ti = (token.jmp) as usize;
|
|
||||||
},
|
|
||||||
OpType::End => {
|
|
||||||
// println!("End({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp);
|
|
||||||
ti = (token.jmp) as usize;
|
|
||||||
}
|
}
|
||||||
OpType::While => {
|
OpType::While => {
|
||||||
ti += 1;
|
ti += 1;
|
||||||
|
@ -238,7 +233,7 @@ pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<i32>{
|
||||||
OpType::Do => {
|
OpType::Do => {
|
||||||
let a = stack.pop().unwrap();
|
let a = stack.pop().unwrap();
|
||||||
if a == 0 {
|
if a == 0 {
|
||||||
ti = (token.jmp) as usize;
|
ti = token.jmp;
|
||||||
} else {
|
} else {
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
|
@ -263,6 +258,7 @@ pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<i32>{
|
||||||
// println!("yes");
|
// println!("yes");
|
||||||
let ret = match rax {
|
let ret = match rax {
|
||||||
1 => syscalls::sys_write(rax, rdi, rsi, rdx, &mem),
|
1 => syscalls::sys_write(rax, rdi, rsi, rdx, &mem),
|
||||||
|
0 => 0, //? temp, so clippy doesnt complain
|
||||||
_ => {
|
_ => {
|
||||||
error!("Syscall(3) #{} is not implemented", rax);
|
error!("Syscall(3) #{} is not implemented", rax);
|
||||||
return Err(eyre!("Syscall not implemented"));
|
return Err(eyre!("Syscall not implemented"));
|
||||||
|
@ -284,9 +280,7 @@ pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<i32>{
|
||||||
todo!();
|
todo!();
|
||||||
// ti += 1;
|
// ti += 1;
|
||||||
},
|
},
|
||||||
OpType::None => unreachable!(),
|
OpType::None | OpType::Macro | OpType::Include => unreachable!()
|
||||||
OpType::Macro => unreachable!(),
|
|
||||||
OpType::Include => unreachable!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,20 @@
|
||||||
|
|
||||||
pub fn sys_write(sys_n: u64, fd: u64, buff: u64, count: u64, mem: &Vec<u8> ) -> u64 {
|
pub fn sys_write(sys_n: usize, fd: usize, buff: usize, count: usize, mem: &Vec<u8> ) -> usize {
|
||||||
let mem = (*mem).clone();
|
let mem = (*mem).clone();
|
||||||
let buff = buff as usize;
|
|
||||||
let count = count as usize;
|
|
||||||
// println!("{:?}", &mem[buff..(buff + count)]);
|
// println!("{:?}", &mem[buff..(buff + count)]);
|
||||||
// return 0 ;
|
// return 0 ;
|
||||||
let s = &mem[buff..(buff + count)].iter().map(|i| {
|
let s = &mem[buff..(buff + count)].iter().map(|i| {
|
||||||
char::from_u32((*i) as u32).unwrap_or('_').to_string()
|
char::from_u32(u32::from(*i)).unwrap_or('_').to_string()
|
||||||
}).collect::<Vec<String>>().join("");
|
}).collect::<String>();
|
||||||
|
|
||||||
match fd {
|
match fd {
|
||||||
1 => {
|
1 => {
|
||||||
print!("{}", s);
|
print!("{s}");
|
||||||
},
|
},
|
||||||
2 => {
|
2 => {
|
||||||
eprint!("{}", s);
|
eprint!("{s}");
|
||||||
},
|
},
|
||||||
_ => panic!("Unknown file {}", fd)
|
_ => panic!("Unknown file {fd}")
|
||||||
};
|
};
|
||||||
let _ = std::io::Write::flush(&mut std::io::stdout());
|
let _ = std::io::Write::flush(&mut std::io::stdout());
|
||||||
let _ = std::io::Write::flush(&mut std::io::stderr());
|
let _ = std::io::Write::flush(&mut std::io::stderr());
|
||||||
|
|
68
src/lexer.rs
68
src/lexer.rs
|
@ -5,45 +5,45 @@ use color_eyre::Result;
|
||||||
fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) {
|
fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) {
|
||||||
match s {
|
match s {
|
||||||
s if s.parse::<u64>().is_ok() && tok_type == TokenType::Word => { // negative numbers not yet implemented
|
s if s.parse::<u64>().is_ok() && tok_type == TokenType::Word => { // negative numbers not yet implemented
|
||||||
return (TokenType::Int, s);
|
(TokenType::Int, s)
|
||||||
},
|
},
|
||||||
s if tok_type == TokenType::Word => {
|
s if tok_type == TokenType::Word => {
|
||||||
return (TokenType::Word, s);
|
(TokenType::Word, s)
|
||||||
},
|
},
|
||||||
s if tok_type == TokenType::String => {
|
s if tok_type == TokenType::String => {
|
||||||
return (TokenType::String, s);
|
(TokenType::String, s)
|
||||||
}
|
}
|
||||||
s if tok_type == TokenType::Char=> {
|
s if tok_type == TokenType::Char => {
|
||||||
return (TokenType::Char, s);
|
(TokenType::Char, s)
|
||||||
}
|
}
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_col<F>(text: String, mut col: u32, predicate: F) -> Result<u32> where F: Fn(char, char) -> bool {
|
pub fn find_col<F>(text: &str, mut col: usize, predicate: F) -> usize where F: Fn(char, char) -> bool {
|
||||||
let mut last = '\0';
|
let mut last = '\0';
|
||||||
while (col as usize) < text.len() && !predicate(text.chars().nth(col as usize).unwrap(), last) {
|
while col < text.len() && !predicate(text.chars().nth(col).unwrap(), last) {
|
||||||
last = text.chars().nth(col as usize).unwrap();
|
last = text.chars().nth(col).unwrap();
|
||||||
col += 1;
|
col += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(col)
|
col
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: Implement multiline strings
|
// TODO: Implement multiline strings
|
||||||
fn lex_line(text: String) -> Result<Vec<(u32, String, TokenType)>> {
|
fn lex_line(text: &str) -> Vec<(usize, String, TokenType)> {
|
||||||
let mut tokens: Vec<(u32, String, TokenType)> = Vec::new();
|
let mut tokens: Vec<(usize, String, TokenType)> = Vec::new();
|
||||||
|
|
||||||
let mut col = find_col(text.clone(), 0, |x, _| !x.is_whitespace())?;
|
let mut col = find_col(text, 0, |x, _| !x.is_whitespace());
|
||||||
let mut col_end: u32 = 0;
|
let mut col_end: usize = 0;
|
||||||
while col_end < text.clone().len() as u32 {
|
while col_end < text.to_string().len() {
|
||||||
if (text.len() - col as usize) < 1 {
|
if (text.len() - col) < 1 {
|
||||||
return Ok(tokens);
|
return tokens;
|
||||||
}
|
}
|
||||||
if &text[(col as usize)..(col + 1) as usize] == "\"" {
|
if &text[col..=col] == "\"" {
|
||||||
col_end = find_col(text.clone(), col + 1, |x, x2| x == '"' && x2 != '\\')?;
|
col_end = find_col(text, col + 1, |x, x2| x == '"' && x2 != '\\');
|
||||||
let t = &text[((col + 1) as usize)..(col_end as usize)];
|
let t = &text[(col + 1)..col_end];
|
||||||
let t = t.replace("\\n", "\n")
|
let t = t.replace("\\n", "\n")
|
||||||
.replace("\\t", "\t")
|
.replace("\\t", "\t")
|
||||||
.replace("\\r", "\r")
|
.replace("\\r", "\r")
|
||||||
|
@ -53,11 +53,11 @@ fn lex_line(text: String) -> Result<Vec<(u32, String, TokenType)>> {
|
||||||
if !t.is_empty() {
|
if !t.is_empty() {
|
||||||
tokens.push((col, t.to_string(), TokenType::String));
|
tokens.push((col, t.to_string(), TokenType::String));
|
||||||
}
|
}
|
||||||
col = find_col(text.clone(), col_end + 1, |x, _| !x.is_whitespace())?;
|
col = find_col(text, col_end + 1, |x, _| !x.is_whitespace());
|
||||||
|
|
||||||
} else if &text[(col as usize)..(col + 1) as usize] == "'"{
|
} else if &text[col..=col] == "'"{
|
||||||
col_end = find_col(text.clone(), col + 1, |x, x2| x == '\'' && x2 != '\\')?;
|
col_end = find_col(text, col + 1, |x, x2| x == '\'' && x2 != '\\');
|
||||||
let t = &text[((col + 1) as usize)..(col_end as usize)];
|
let t = &text[(col + 1)..col_end];
|
||||||
let t = t.replace("\\n", "\n")
|
let t = t.replace("\\n", "\n")
|
||||||
.replace("\\t", "\t")
|
.replace("\\t", "\t")
|
||||||
.replace("\\r", "\r")
|
.replace("\\r", "\r")
|
||||||
|
@ -69,44 +69,44 @@ fn lex_line(text: String) -> Result<Vec<(u32, String, TokenType)>> {
|
||||||
if !t.is_empty() {
|
if !t.is_empty() {
|
||||||
tokens.push((col, t.to_string(), TokenType::Char));
|
tokens.push((col, t.to_string(), TokenType::Char));
|
||||||
}
|
}
|
||||||
col = find_col(text.clone(), col_end + 1, |x, _| !x.is_whitespace())?;
|
col = find_col(text, col_end + 1, |x, _| !x.is_whitespace());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
col_end = find_col(text.clone(), col, |x, _| x.is_whitespace())?;
|
col_end = find_col(text, col, |x, _| x.is_whitespace());
|
||||||
let t = &text[(col as usize)..((col_end as usize))];
|
let t = &text[col..col_end];
|
||||||
|
|
||||||
if t == "//" {
|
if t == "//" {
|
||||||
return Ok(tokens);
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !t.is_empty() {
|
if !t.is_empty() {
|
||||||
tokens.push((col, t.to_string(), TokenType::Word));
|
tokens.push((col, t.to_string(), TokenType::Word));
|
||||||
}
|
}
|
||||||
col = find_col(text.clone(), col_end, |x, _| !x.is_whitespace())?;
|
col = find_col(text, col_end, |x, _| !x.is_whitespace());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(tokens)
|
tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lex(code: String, file: &String, args: Args, preprocessing: bool) -> Result<Vec<Token>> {
|
pub fn lex<S: Into<String> + std::marker::Copy>(code: &str, file: S, args: &Args, preprocessing: bool) -> Result<Vec<Token>> {
|
||||||
let lines: Vec<(usize, &str)> = code
|
let lines: Vec<(usize, &str)> = code
|
||||||
.split(['\n', '\r'])
|
.split(['\n', '\r'])
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let lines: Vec<(u32, String)> = lines.iter().map(|i| (i.0 as u32, i.1.to_string())).collect();
|
let lines: Vec<(usize, String)> = lines.iter().map(|i| (i.0, i.1.to_string())).collect();
|
||||||
|
|
||||||
let mut tokens: Vec<Token> = Vec::new();
|
let mut tokens: Vec<Token> = Vec::new();
|
||||||
|
|
||||||
for (row, line) in lines {
|
for (row, line) in lines {
|
||||||
let lt = lex_line(line)?;
|
let lt = lex_line(&line);
|
||||||
for (col, tok, tok_type) in lt {
|
for (col, tok, tok_type) in lt {
|
||||||
let (tok_type, tok) = lex_word(tok, tok_type);
|
let (tok_type, tok) = lex_word(tok, tok_type);
|
||||||
let t = Token{
|
let t = Token{
|
||||||
file: file.clone(),
|
file: file.into(),
|
||||||
line: row + 1,
|
line: row + 1,
|
||||||
col: col,
|
col,
|
||||||
text: tok,
|
text: tok,
|
||||||
typ: tok_type
|
typ: tok_type
|
||||||
};
|
};
|
||||||
|
|
49
src/main.rs
49
src/main.rs
|
@ -8,7 +8,6 @@ mod preprocessor;
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
use color_eyre::Result;
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
pub const DEFAULT_OUT_FILE: &str = "a.out";
|
pub const DEFAULT_OUT_FILE: &str = "a.out";
|
||||||
|
@ -54,52 +53,38 @@ pub struct Args {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
let code = match fs::read_to_string(&args.in_file) {
|
let Ok(code) = fs::read_to_string(&args.in_file) else {
|
||||||
Ok(t) => t,
|
error!("Failed to read file {}, exiting!", &args.in_file);
|
||||||
Err(_) => {
|
return;
|
||||||
error!("Failed to read file {}, exiting!", &args.in_file);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let tokens = match lexer::lex(code, &args.in_file, args.clone(), true) {
|
let Ok(tokens) = lexer::lex(&code, &args.in_file, &args, true) else {
|
||||||
Ok(t) => t,
|
error!("Lexing failed, exiting!");
|
||||||
Err(_) => {
|
return;
|
||||||
error!("Lexing failed, exiting!");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let mut parser = parser::Parser::new(tokens);
|
let mut parser = parser::Parser::new(tokens);
|
||||||
let tokens = match parser.parse() {
|
let Ok(tokens) = parser.parse() else {
|
||||||
Ok(t) => t,
|
error!("Parsing failed, exiting!");
|
||||||
Err(_) => {
|
return;
|
||||||
error!("Parsing failed, exiting!");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let c = if args.compile && args.interpret {
|
let c = if args.compile && args.interpret {
|
||||||
error!("Cannot compile and interpret at the same time");
|
error!("Cannot compile and interpret at the same time");
|
||||||
0
|
0
|
||||||
} else if args.interpret {
|
} else if args.interpret {
|
||||||
match interpret::linux_x86_64::run(tokens) {
|
if let Ok(c) = interpret::linux_x86_64::run(&tokens) { c } else {
|
||||||
Ok(c) => c,
|
error!("Interpretation failed, exiting!");
|
||||||
Err(_) => {
|
1
|
||||||
error!("Interpretation failed, exiting!");
|
|
||||||
1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if args.compile {
|
} else if args.compile {
|
||||||
match compile::linux_x86_64::compile(tokens, args) {
|
if let Ok(c) = compile::linux_x86_64::compile(&tokens, &args) { c } else {
|
||||||
Ok(c) => c,
|
error!("Compilation failed, exiting!");
|
||||||
Err(_) => {
|
1
|
||||||
error!("Compilation failed, exiting!");
|
|
||||||
1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error!("Did not choose to compile or to interpret, exiting");
|
error!("Did not choose to compile or to interpret, exiting");
|
||||||
|
|
144
src/parser.rs
144
src/parser.rs
|
@ -1,61 +1,56 @@
|
||||||
use std::{collections::HashMap, ops::Deref};
|
use std::ops::Deref;
|
||||||
|
|
||||||
use crate::{constants::{Operator, OpType, Token, TokenType}, lerror};
|
use crate::{constants::{Operator, OpType, Token, TokenType, Loc}, lerror};
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use eyre::eyre;
|
use eyre::eyre;
|
||||||
|
|
||||||
pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
|
pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
|
||||||
let mut stack: Vec<u32> = Vec::new();
|
let mut stack: Vec<usize> = Vec::new();
|
||||||
for ip in 0..program.len() {
|
for ip in 0..program.len() {
|
||||||
let op = &program.clone()[ip];
|
let op = &program.clone()[ip];
|
||||||
match op.typ {
|
match op.typ {
|
||||||
OpType::If => {
|
OpType::If | OpType::While => {
|
||||||
stack.push(ip as u32)
|
stack.push(ip);
|
||||||
}
|
}
|
||||||
OpType::Else => {
|
OpType::Else => {
|
||||||
let if_ip = stack.pop().unwrap();
|
let if_ip = stack.pop().unwrap();
|
||||||
if program[if_ip as usize].typ != OpType::If {
|
if program[if_ip].typ != OpType::If {
|
||||||
lerror!(&op.clone().loc,"'end' can only close 'if' blocks");
|
lerror!(&op.clone().loc,"'end' can only close 'if' blocks");
|
||||||
return Err(eyre!("Bad block"));
|
return Err(eyre!("Bad block"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// let mut if_og = &mut tokens[if_ip as usize];
|
program[if_ip].jmp = ip + 1;
|
||||||
// (*if_og).jmp = (ip + 1) as i32;
|
stack.push(ip);
|
||||||
program[if_ip as usize].jmp = (ip + 1) as i32;
|
|
||||||
stack.push(ip as u32);
|
|
||||||
},
|
},
|
||||||
OpType::End => {
|
OpType::End => {
|
||||||
let block_ip = stack.pop().unwrap();
|
let block_ip = stack.pop().unwrap();
|
||||||
// let mut block_og = &mut tokens[block_ip as usize].clone();
|
|
||||||
if program[block_ip as usize].typ == OpType::If ||
|
|
||||||
program[block_ip as usize].typ == OpType::Else {
|
|
||||||
|
|
||||||
program[block_ip as usize].jmp = ip as i32;
|
|
||||||
program[ip as usize].jmp = (ip + 1)as i32;
|
|
||||||
|
|
||||||
} else if program[block_ip as usize].typ == OpType::Do {
|
if program[block_ip].typ == OpType::If ||
|
||||||
program[ip].jmp = program[block_ip as usize].jmp;
|
program[block_ip].typ == OpType::Else {
|
||||||
program[block_ip as usize].jmp = (ip + 1) as i32;
|
|
||||||
|
program[block_ip].jmp = ip;
|
||||||
|
program[ip].jmp = ip + 1;
|
||||||
|
|
||||||
|
} else if program[block_ip].typ == OpType::Do {
|
||||||
|
program[ip].jmp = program[block_ip].jmp;
|
||||||
|
program[block_ip].jmp = ip + 1;
|
||||||
} else {
|
} else {
|
||||||
lerror!(&op.clone().loc,"'end' can only close 'if' blocks");
|
lerror!(&op.clone().loc,"'end' can only close 'if' blocks");
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
OpType::While => {
|
|
||||||
stack.push(ip as u32);
|
|
||||||
}
|
|
||||||
OpType::Do => {
|
OpType::Do => {
|
||||||
let while_ip = stack.pop().unwrap();
|
let while_ip = stack.pop().unwrap();
|
||||||
program[ip as usize].jmp = while_ip as i32;
|
program[ip].jmp = while_ip;
|
||||||
stack.push(ip as u32);
|
stack.push(ip);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if stack.len() > 0 {
|
if !stack.is_empty() {
|
||||||
lerror!(&program[stack.pop().expect("Empy stack") as usize].clone().loc,"Unclosed block");
|
lerror!(&program[stack.pop().expect("Empy stack")].clone().loc,"Unclosed block");
|
||||||
return Err(eyre!("Unclosed block"));
|
return Err(eyre!("Unclosed block"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,11 +78,11 @@ impl Parser {
|
||||||
let pos = (token.file.clone(), token.line, token.col);
|
let pos = (token.file.clone(), token.line, token.col);
|
||||||
match token.typ {
|
match token.typ {
|
||||||
TokenType::Word => {
|
TokenType::Word => {
|
||||||
let word_type = lookup_word(token.text.clone(), &pos);
|
let word_type = lookup_word(&token.text, &pos);
|
||||||
tokens.push(Operator::new(word_type, 0, token.text.clone(), token.file.clone(), token.line, token.col));
|
tokens.push(Operator::new(word_type, 0, token.text.clone(), token.file.clone(), token.line, token.col));
|
||||||
},
|
},
|
||||||
TokenType::Int => {// negative numbers not yet implemented
|
TokenType::Int => {// negative numbers not yet implemented
|
||||||
tokens.push(Operator::new(OpType::PushInt, token.text.parse::<i64>()?, String::new(), token.file.clone(), token.line, token.col));
|
tokens.push(Operator::new(OpType::PushInt, token.text.parse::<usize>()?, String::new(), token.file.clone(), token.line, token.col));
|
||||||
},
|
},
|
||||||
TokenType::String => {
|
TokenType::String => {
|
||||||
tokens.push(Operator::new(OpType::PushStr, 0, token.text.clone(), token.file.clone(), token.line, token.col));
|
tokens.push(Operator::new(OpType::PushStr, 0, token.text.clone(), token.file.clone(), token.line, token.col));
|
||||||
|
@ -99,7 +94,7 @@ impl Parser {
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens.push(Operator::new(OpType::PushInt, token.text.chars().next().unwrap() as i64, String::new(), token.file.clone(), token.line, token.col));
|
tokens.push(Operator::new(OpType::PushInt, token.text.chars().next().unwrap() as usize, String::new(), token.file.clone(), token.line, token.col));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,66 +102,61 @@ impl Parser {
|
||||||
//"print" => tokens.push(Operator::new(OpType::Print, 0, token.file.clone(), token.line, token.col)),
|
//"print" => tokens.push(Operator::new(OpType::Print, 0, token.file.clone(), token.line, token.col)),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(cross_ref(tokens)?)
|
cross_ref(tokens)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn lookup_word<P: Deref<Target = (String, u32, u32)>>(s: String, _pos: P) -> OpType {
|
pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
|
||||||
let lookup_table: HashMap<&str, OpType> = HashMap::from([
|
match s {
|
||||||
//stack
|
//stack
|
||||||
("print", OpType::Print),
|
"print" => OpType::Print,
|
||||||
("dup", OpType::Dup),
|
"dup" => OpType::Dup,
|
||||||
("drop", OpType::Drop),
|
"drop" => OpType::Drop,
|
||||||
("2dup", OpType::Dup2),
|
"2dup" => OpType::Dup2,
|
||||||
("rot", OpType::Rot),
|
"rot" => OpType::Rot,
|
||||||
("over", OpType::Over),
|
"over" => OpType::Over,
|
||||||
("swap", OpType::Swap),
|
"swap" => OpType::Swap,
|
||||||
|
|
||||||
// comp and math
|
// comp and math
|
||||||
("+", OpType::Plus),
|
"+" => OpType::Plus,
|
||||||
("-", OpType::Minus),
|
"-" => OpType::Minus,
|
||||||
("=", OpType::Equals),
|
"=" => OpType::Equals,
|
||||||
("!=", OpType::NotEquals),
|
"!=" => OpType::NotEquals,
|
||||||
(">", OpType::Gt),
|
">" => OpType::Gt,
|
||||||
("<", OpType::Lt),
|
"<" => OpType::Lt,
|
||||||
(">=", OpType::Ge),
|
">=" => OpType::Ge,
|
||||||
("<=", OpType::Le),
|
"<=" => OpType::Le,
|
||||||
|
|
||||||
("band", OpType::Band),
|
"band" => OpType::Band,
|
||||||
("bor", OpType::Bor),
|
"bor" => OpType::Bor,
|
||||||
("shr", OpType::Shr),
|
"shr" => OpType::Shr,
|
||||||
("shl", OpType::Shl),
|
"shl" => OpType::Shl,
|
||||||
("divmod", OpType::DivMod),
|
"divmod" => OpType::DivMod,
|
||||||
("*", OpType::Mul),
|
"*" => OpType::Mul,
|
||||||
|
|
||||||
// block
|
// block
|
||||||
("if", OpType::If),
|
"if" => OpType::If,
|
||||||
("else", OpType::Else),
|
"else" => OpType::Else,
|
||||||
("end", OpType::End),
|
"end" => OpType::End,
|
||||||
("while", OpType::While),
|
"while" => OpType::While,
|
||||||
("do", OpType::Do),
|
"do" => OpType::Do,
|
||||||
("macro", OpType::Macro),
|
"macro" => OpType::Macro,
|
||||||
("include", OpType::Include), // technically not but it fits next to macros
|
"include" => OpType::Include,
|
||||||
|
|
||||||
// mem
|
// mem
|
||||||
("mem", OpType::Mem),
|
"mem" => OpType::Mem,
|
||||||
("!8", OpType::Load8),
|
"!8" => OpType::Load8,
|
||||||
("@8", OpType::Store8),
|
"@8" => OpType::Store8,
|
||||||
|
|
||||||
("syscall0", OpType::Syscall0),
|
"syscall0" => OpType::Syscall0,
|
||||||
("syscall1", OpType::Syscall1),
|
"syscall1" => OpType::Syscall1,
|
||||||
("syscall2", OpType::Syscall2),
|
"syscall2" => OpType::Syscall2,
|
||||||
("syscall3", OpType::Syscall3),
|
"syscall3" => OpType::Syscall3,
|
||||||
("syscall4", OpType::Syscall4),
|
"syscall4" => OpType::Syscall4,
|
||||||
("syscall5", OpType::Syscall5),
|
"syscall5" => OpType::Syscall5,
|
||||||
("syscall6", OpType::Syscall6),
|
"syscall6" => OpType::Syscall6,
|
||||||
]);
|
_ => OpType::None
|
||||||
|
|
||||||
match lookup_table.get(s.as_str()) {
|
|
||||||
Some(v) => v.clone(),
|
|
||||||
None => {
|
|
||||||
OpType::None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -15,19 +15,19 @@ pub struct Macro {
|
||||||
pub tokens: Vec<Token>
|
pub tokens: Vec<Token>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn preprocess(tokens: Vec<Token>, args: Args) -> Result<Vec<Token>>{
|
pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
|
||||||
let mut program: Vec<Token> = Vec::new();
|
let mut program: Vec<Token> = Vec::new();
|
||||||
let mut macros: HashMap<String, Macro> = HashMap::new();
|
let mut macros: HashMap<String, Macro> = HashMap::new();
|
||||||
|
|
||||||
let mut rtokens = tokens.clone();
|
let mut rtokens = tokens;
|
||||||
rtokens.reverse();
|
rtokens.reverse();
|
||||||
while rtokens.len() > 0 {
|
while !rtokens.is_empty() {
|
||||||
let token = rtokens.pop().unwrap();
|
let token = rtokens.pop().unwrap();
|
||||||
|
|
||||||
let op_type = lookup_word(token.text.clone(), &token.loc());
|
let op_type = lookup_word(&token.text, &token.loc());
|
||||||
match token.clone() {
|
match token.clone() {
|
||||||
_ if op_type == OpType::Macro => {
|
_ if op_type == OpType::Macro => {
|
||||||
if rtokens.len() == 0 {
|
if rtokens.is_empty(){
|
||||||
lerror!(&token.loc(), "Macro name not found, expected {} but found nothing", TokenType::Word.human());
|
lerror!(&token.loc(), "Macro name not found, expected {} but found nothing", TokenType::Word.human());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
@ -37,41 +37,36 @@ pub fn preprocess(tokens: Vec<Token>, args: Args) -> Result<Vec<Token>>{
|
||||||
lerror!(¯o_name.loc(), "Bad macro name, expected {} but found {}", TokenType::Word.human(), macro_name.typ.human());
|
lerror!(¯o_name.loc(), "Bad macro name, expected {} but found {}", TokenType::Word.human(), macro_name.typ.human());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
let word = lookup_word(macro_name.text.clone(), ¯o_name.loc());
|
let word = lookup_word(¯o_name.text, ¯o_name.loc());
|
||||||
if word != OpType::None {
|
if word != OpType::None {
|
||||||
lerror!(¯o_name.loc(), "Macro name cannot be a built in word, got '{}'", word.human());
|
lerror!(¯o_name.loc(), "Macro name cannot be a built in word, got '{}'", word.human());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
if macros.get(¯o_name.text.clone()).is_some() {
|
if macros.get(¯o_name.text.clone()).is_some() && crate::constants::ALLOW_MACRO_REDEFINITION {
|
||||||
if crate::constants::ALLOW_MACRO_REDEFINITION {
|
lerror!(¯o_name.loc(), "Macro redefinition is not allowed");
|
||||||
lerror!(¯o_name.loc(), "Macro redefinition is not allowed");
|
lnote!(¯os.get(¯o_name.text).unwrap().loc, "First definition here");
|
||||||
lnote!(¯os.get(¯o_name.text.clone()).unwrap().loc, "First definition here");
|
return Err(eyre!(""));
|
||||||
return Err(eyre!(""));
|
|
||||||
} else {
|
|
||||||
//TODO: somehow warn about redefinition of only built in macros
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut macr = Macro{ loc: macro_name.loc(), tokens: Vec::new() };
|
let mut macr = Macro{ loc: macro_name.loc(), tokens: Vec::new() };
|
||||||
|
|
||||||
let mut depth = 0;
|
let mut depth = 0;
|
||||||
while rtokens.len() > 0 {
|
while !rtokens.is_empty() {
|
||||||
let t = rtokens.pop().unwrap();
|
let t = rtokens.pop().unwrap();
|
||||||
let typ = lookup_word(t.text.clone(), &t.loc());
|
let typ = lookup_word(&t.text, &t.loc());
|
||||||
if typ == OpType::End && depth == 0 {
|
if typ == OpType::End && depth == 0 {
|
||||||
break;
|
break;
|
||||||
} else if typ == OpType::End && depth != 0 {
|
} else if typ == OpType::End && depth != 0 {
|
||||||
depth -= 1;
|
depth -= 1;
|
||||||
macr.tokens.push(t);
|
macr.tokens.push(t);
|
||||||
|
} else if typ == OpType::If || typ == OpType::Do {
|
||||||
|
macr.tokens.push(t);
|
||||||
|
depth += 1;
|
||||||
} else {
|
} else {
|
||||||
if typ == OpType::If || typ == OpType::Do {
|
macr.tokens.push(t);
|
||||||
macr.tokens.push(t);
|
|
||||||
depth += 1;
|
|
||||||
} else {
|
|
||||||
macr.tokens.push(t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +76,7 @@ pub fn preprocess(tokens: Vec<Token>, args: Args) -> Result<Vec<Token>>{
|
||||||
}
|
}
|
||||||
|
|
||||||
_ if op_type == OpType::Include => {
|
_ if op_type == OpType::Include => {
|
||||||
if rtokens.len() == 0 {
|
if rtokens.is_empty() {
|
||||||
lerror!(&token.loc(), "Include path not found, expected {} but found nothing", TokenType::String.human());
|
lerror!(&token.loc(), "Include path not found, expected {} but found nothing", TokenType::String.human());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
@ -94,7 +89,7 @@ pub fn preprocess(tokens: Vec<Token>, args: Args) -> Result<Vec<Token>>{
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut in_paths = args.include.clone();
|
let mut in_paths = args.include.clone();
|
||||||
in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| f.to_string()).collect::<Vec<String>>());
|
in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| (*f).to_string()).collect::<Vec<String>>());
|
||||||
|
|
||||||
let mut include_code = String::new();
|
let mut include_code = String::new();
|
||||||
|
|
||||||
|
@ -113,7 +108,7 @@ pub fn preprocess(tokens: Vec<Token>, args: Args) -> Result<Vec<Token>>{
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut code = lex(include_code, &include_path.text, args.clone(), false)?;
|
let mut code = lex(&include_code, &include_path.text, args, false)?;
|
||||||
code.reverse();
|
code.reverse();
|
||||||
rtokens.append(&mut code);
|
rtokens.append(&mut code);
|
||||||
|
|
||||||
|
@ -130,7 +125,7 @@ pub fn preprocess(tokens: Vec<Token>, args: Args) -> Result<Vec<Token>>{
|
||||||
let mut times = 0;
|
let mut times = 0;
|
||||||
while program.iter().map(|f| {
|
while program.iter().map(|f| {
|
||||||
if f.typ == TokenType::Word {
|
if f.typ == TokenType::Word {
|
||||||
lookup_word(f.text.clone(), &f.loc())
|
lookup_word(&f.text, &f.loc())
|
||||||
} else {
|
} else {
|
||||||
OpType::PushInt // i hate myself, this is a randomly picked optype so its happy and works
|
OpType::PushInt // i hate myself, this is a randomly picked optype so its happy and works
|
||||||
}
|
}
|
||||||
|
@ -152,18 +147,20 @@ pub fn preprocess(tokens: Vec<Token>, args: Args) -> Result<Vec<Token>>{
|
||||||
pub fn expand_macros(tokens: Vec<Token>, macros: &HashMap<String, Macro>) -> Result<Vec<Token>> {
|
pub fn expand_macros(tokens: Vec<Token>, macros: &HashMap<String, Macro>) -> Result<Vec<Token>> {
|
||||||
let mut program: Vec<Token> = Vec::new();
|
let mut program: Vec<Token> = Vec::new();
|
||||||
|
|
||||||
let mut rtokens = tokens.clone();
|
let mut rtokens = tokens;
|
||||||
rtokens.reverse();
|
rtokens.reverse();
|
||||||
|
|
||||||
while rtokens.len() > 0 {
|
while !rtokens.is_empty() {
|
||||||
let op = rtokens.pop().unwrap();
|
let op = rtokens.pop().unwrap();
|
||||||
let op_type = lookup_word(op.text.clone(), &op.loc());
|
let op_type = lookup_word(&op.text, &op.loc());
|
||||||
if op.typ == TokenType::Word {
|
if op.typ == TokenType::Word {
|
||||||
match op_type {
|
match op_type {
|
||||||
OpType::None => {
|
OpType::None => {
|
||||||
let m = macros.get(&op.text);
|
let m = macros.get(&op.text);
|
||||||
if m.is_some() {
|
if m.is_some() {
|
||||||
program.append(&mut m.unwrap().tokens.clone())
|
if let Some(m) = m {
|
||||||
|
program.append(&mut m.tokens.clone());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
lerror!(&op.loc(), "Unknown word '{}'", op.text.clone());
|
lerror!(&op.loc(), "Unknown word '{}'", op.text.clone());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
|
|
Loading…
Reference in New Issue
Block a user