diff --git a/.gitignore b/.gitignore index ea8c4bf..693d5d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +a \ No newline at end of file diff --git a/examples/rule110.mcl b/examples/rule110.mcl index ae869cb..ff3cfca 100755 --- a/examples/rule110.mcl +++ b/examples/rule110.mcl @@ -3,14 +3,14 @@ mem 98 + 1 @8 0 while dup 98 < do 0 while dup 100 < do dup mem + !8 if - dup mem + 100 + "*" @8 + dup mem + 100 + 42 @8 else - dup mem + 100 + " " @8 + dup mem + 100 + 32 @8 end 1 + end - mem + 100 + "\n" @8 + mem + 100 + 10 @8 101 mem 100 + 1 1 syscall3 drop diff --git a/src/compile/commands.rs b/src/compile/commands.rs index d2f2785..45f7db9 100644 --- a/src/compile/commands.rs +++ b/src/compile/commands.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use std::process::{Command, Stdio}; use color_eyre::Result; -use crate::util::logger; +use crate::info; pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &PathBuf, quiet: bool) -> Result<()> { @@ -29,12 +29,12 @@ pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &Path .spawn()? }; if !quiet { - logger::info(format!("running 'nasm {}'", nasm_args.join(" ")).as_str()); + info!("running 'nasm {}'", nasm_args.join(" ")); } let exit = proc.wait()?; if !quiet { - logger::info(format!("nasm process exited with code {}", exit).as_str()); + info!("nasm process exited with code {}", exit); } @@ -48,11 +48,11 @@ pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &Path .spawn()? }; if !quiet { - logger::info(format!("running 'ld {}'", ld_args.join(" ")).as_str()); + info!("running 'ld {}'", ld_args.join(" ")); } let exit2 = proc2.wait()?; if !quiet { - logger::info(format!("ld process exited with code {}", exit2).as_str()); + info!("ld process exited with code {}", exit2); } @@ -77,11 +77,11 @@ pub fn linux_x86_64_run(_bin: &PathBuf, args: Vec, quiet: bool) -> Resul }; // println!("{}", quiet); if !quiet { - logger::info(format!("running {} {}", _bin.to_string_lossy(), args.join(" ")).as_str()); + info!("running {} {}", _bin.to_string_lossy(), args.join(" ")); } let exit = proc.wait()?; if !quiet { - logger::info(format!("{} process exited with code {}", _bin.to_string_lossy(), exit).as_str()); + info!("{} process exited with code {}", _bin.to_string_lossy(), exit); } Ok(exit.code().unwrap_or(0)) diff --git a/src/compile/linux_x86_64.rs b/src/compile/linux_x86_64.rs index 00edbce..ee81201 100644 --- a/src/compile/linux_x86_64.rs +++ b/src/compile/linux_x86_64.rs @@ -8,8 +8,15 @@ use super::commands::linux_x86_64_run; pub fn compile(tokens: Vec, args: Args) -> Result<()>{ let mut of_c = PathBuf::from(&args.out_file); - let mut of_o = PathBuf::from(&args.out_file); - let mut of_a = PathBuf::from(&args.out_file); + let (mut of_o, mut of_a) = if &args.out_file == &crate::DEFAULT_OUT_FILE.to_string() { + let of_o = PathBuf::from("/tmp/mclang_comp.o"); + let of_a = PathBuf::from("/tmp/mclang_comp.nasm"); + (of_o, of_a) + } else { + let of_o = PathBuf::from(&args.out_file); + let of_a = PathBuf::from(&args.out_file); + (of_o, of_a) + }; of_c.set_extension(""); of_o.set_extension("o"); @@ -75,7 +82,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ ti += 1; }, OpType::PushStr => { - writeln!(writer, " ;; -- push str \"{}\"", token.text)?; + writeln!(writer, " ;; -- push str \"{}\"", token.text.escape_default())?; writeln!(writer, " mov rax, {}", token.text.len())?; writeln!(writer, " push rax")?; writeln!(writer, " push str_{}", strings.len())?; diff --git a/src/constants.rs b/src/constants.rs index 79c2c5b..815968a 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -90,4 +90,6 @@ pub enum TokenType { Int, String, //TODO: Add char -} \ No newline at end of file +} + +pub type Loc = (String, u32, u32); \ No newline at end of file diff --git a/src/interpret/linux_x86_64/mod.rs b/src/interpret/linux_x86_64/mod.rs index 6043077..b73912c 100644 --- a/src/interpret/linux_x86_64/mod.rs +++ b/src/interpret/linux_x86_64/mod.rs @@ -1,4 +1,4 @@ -use crate::{constants::OpType, util::{logger, self}}; +use crate::{constants::OpType, lerror, error}; // use crate::util::logger; use color_eyre::Result; use eyre::eyre; @@ -8,7 +8,7 @@ fn stack_pop(stack: &mut Vec, pos: &(String, u32, u32)) -> Result { match stack.pop() { Some(i) => Ok(i), None => { - util::logger::pos_error(&pos.clone(), "Stack underflow"); + lerror!(&pos.clone(), "Stack underflow"); Err(eyre!("Stack underflow")) }, } @@ -245,7 +245,7 @@ pub fn run(tokens: Vec) -> Result<()>{ let ret = match rax { 1 => syscalls::sys_write(rax, rdi, rsi, rdx, &mem), _ => { - logger::error(format!("Syscall(3) #{} is not implemented", rax).as_str()); + error!("Syscall(3) #{} is not implemented", rax); return Err(eyre!("Syscall not implemented")); } }; diff --git a/src/lexer.rs b/src/lexer.rs index 712ae64..bdd2f97 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -35,6 +35,9 @@ fn lex_line(text: String) -> Result> { let mut col = find_col(text.clone(), 0, |x, _| !x.is_whitespace())?; let mut col_end: u32 = 0; while col_end < text.clone().len() as u32 { + if (text.len() - col as usize) < 1 { + return Ok(tokens); + } if &text[(col as usize)..(col + 1) as usize] == "\"" { col_end = find_col(text.clone(), col + 1, |x, x2| x == '"' && x2 != '\\')?; let t = &text[((col + 1) as usize)..(col_end as usize)]; diff --git a/src/main.rs b/src/main.rs index 79aef36..d91ecd6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,8 @@ use std::fs; use color_eyre::Result; use clap::Parser; +pub const DEFAULT_OUT_FILE: &str = "a.out"; + #[derive(Parser, Debug, Clone)] #[command(author, version, about, long_about = None)] pub struct Args { @@ -18,7 +20,7 @@ pub struct Args { in_file: String, /// Output compiled file - #[arg(long, short, default_value_t=String::from("a.out"))] + #[arg(long, short, default_value_t=String::from(DEFAULT_OUT_FILE))] out_file: String, /// Compile @@ -53,13 +55,13 @@ fn main() -> Result<()> { let mut parser = parser::Parser::new(tokens); let tokens = parser.parse()?; if args.compile && args.interpret { - util::logger::error("Cannot compile and interpret at the same time"); + error!("Cannot compile and interpret at the same time"); } else if args.interpret { interpret::linux_x86_64::run(tokens)?; } else if args.compile { compile::linux_x86_64::compile(tokens, args)?; } else { - util::logger::error("Did not choose to compile or to interpret, exiting"); + error!("Did not choose to compile or to interpret, exiting"); } Ok(()) } diff --git a/src/parser.rs b/src/parser.rs index a8f2300..2b6f2ce 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, ops::Deref}; -use crate::{constants::{Operator, OpType, Token, TokenType}, util}; +use crate::{constants::{Operator, OpType, Token, TokenType}, lerror}; use color_eyre::Result; use eyre::eyre; @@ -15,7 +15,7 @@ pub fn cross_ref(mut program: Vec) -> Result> { OpType::Else => { let if_ip = stack.pop().unwrap(); if program[if_ip as usize].typ != OpType::If { - util::logger::pos_error(&op.clone().pos,"'end' can only close 'if' blocks"); + lerror!(&op.clone().pos,"'end' can only close 'if' blocks"); return Err(eyre!("Bad block")); } @@ -37,8 +37,8 @@ pub fn cross_ref(mut program: Vec) -> Result> { program[ip].jmp = program[block_ip as usize].jmp; program[block_ip as usize].jmp = (ip + 1) as i32; } else { - util::logger::pos_error(&op.clone().pos,"'end' can only close 'if' blocks"); - std::process::exit(1); // idc + lerror!(&op.clone().pos,"'end' can only close 'if' blocks"); + return Err(eyre!("")); } } @@ -55,7 +55,7 @@ pub fn cross_ref(mut program: Vec) -> Result> { } if stack.len() > 0 { - util::logger::pos_error(&program[stack.pop().expect("Empy stack") as usize].clone().pos,"Unclosed block"); + lerror!(&program[stack.pop().expect("Empy stack") as usize].clone().pos,"Unclosed block"); return Err(eyre!("Unclosed block")); } @@ -151,7 +151,7 @@ fn lookup_word>(s: String, pos: P) -> Resu match lookup_table.get(s.as_str()) { Some(v) => Ok(v.clone()), None => { - util::logger::pos_error(pos, format!("Unknown word '{}'", s).as_str()); + lerror!(pos, "Unknown word '{}'", s); return Err(eyre!("Unknown word")) } } diff --git a/src/util.rs b/src/util.rs index 9aa6d43..107d7a6 100644 --- a/src/util.rs +++ b/src/util.rs @@ -32,7 +32,7 @@ pub mod logger { #![allow(dead_code)] use std::ops::Deref; - use crate::util::color; + use crate::{util::color, constants::Loc}; pub fn error(msg: &str) { println!("{red}error{r}: {msg}", red=color::FG_RED, r=color::RESET); @@ -51,20 +51,31 @@ pub mod logger { } - pub fn pos_error>(pos: P, msg: &str) { - println!("{f}:{r}:{c} {red}error{rs}: {msg}", red=color::FG_RED, rs=color::RESET, f=pos.0, r=pos.1, c=pos.2); + pub fn lerror>(loc: P, msg: &str) { + println!("{f}:{r}:{c} {red}error{rs}: {msg}", red=color::FG_RED, rs=color::RESET, f=loc.0, r=loc.1, c=loc.2); } - pub fn pos_warn>(pos: P, msg: &str) { - println!("{f}:{r}:{c} {yellow}warn{rs}: {msg}", yellow=color::FG_YELLOW, rs=color::RESET, f=pos.0, r=pos.1, c=pos.2); + pub fn lwarn>(loc: P, msg: &str) { + println!("{f}:{r}:{c} {yellow}warn{rs}: {msg}", yellow=color::FG_YELLOW, rs=color::RESET, f=loc.0, r=loc.1, c=loc.2); } - pub fn pos_info>(pos: P, msg: &str) { - println!("{f}:{r}:{c} {green}info{rs}: {msg}", green=color::FG_GREEN, rs=color::RESET, f=pos.0, r=pos.1, c=pos.2); + pub fn linfo>(loc: P, msg: &str) { + println!("{f}:{r}:{c} {green}info{rs}: {msg}", green=color::FG_GREEN, rs=color::RESET, f=loc.0, r=loc.1, c=loc.2); } - pub fn pos_note>(pos: P, msg: &str) { - println!("{f}:{r}:{c} {blue}note{rs}: {msg}", blue=color::FG_BLUE, rs=color::RESET, f=pos.0, r=pos.1, c=pos.2); + pub fn lnote>(loc: P, msg: &str) { + println!("{f}:{r}:{c} {blue}note{rs}: {msg}", blue=color::FG_BLUE, rs=color::RESET, f=loc.0, r=loc.1, c=loc.2); + } + pub mod macros { + #[macro_export] macro_rules! error { ($($arg:tt)*) => { $crate::util::logger::error(std::format_args!($($arg)*).to_string().as_str()) }; } + #[macro_export] macro_rules! warn { ($($arg:tt)*) => { $crate::util::logger::warn( std::format_args!($($arg)*).to_string().as_str()) }; } + #[macro_export] macro_rules! info { ($($arg:tt)*) => { $crate::util::logger::info( std::format_args!($($arg)*).to_string().as_str()) }; } + #[macro_export] macro_rules! note { ($($arg:tt)*) => { $crate::util::logger::note( std::format_args!($($arg)*).to_string().as_str()) }; } + + #[macro_export] macro_rules! lerror { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::lerror($dst, std::format_args!($($arg)*).to_string().as_str()) }; } + #[macro_export] macro_rules! lwarn { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::lwarn($dst, std::format_args!($($arg)*).to_string().as_str()) }; } + #[macro_export] macro_rules! linfo { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::linfo($dst, std::format_args!($($arg)*).to_string().as_str()) }; } + #[macro_export] macro_rules! lnote { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::lnote($dst, std::format_args!($($arg)*).to_string().as_str()) }; } } } diff --git a/test.mcl b/test.mcl index 5022a1e..47f58d5 100644 --- a/test.mcl +++ b/test.mcl @@ -1 +1,6 @@ -"Hello world!\n\n\n\n\n\n" 1 1 syscall3 drop \ No newline at end of file +mem 0 @8 + +while mem !8 10 < do + "Hello world!\n" 1 1 syscall3 drop + mem !8 1 + mem swap @8 +end drop \ No newline at end of file