From 2d5e94608ce1719782e83de7df0bad562495986c Mon Sep 17 00:00:00 2001 From: MCorange Date: Mon, 20 Mar 2023 14:36:38 +0200 Subject: [PATCH] added including of files --- src/compile/linux_x86_64.rs | 32 +++++++++--------- src/constants.rs | 7 +++- src/interpret/linux_x86_64/mod.rs | 8 ++--- src/lexer.rs | 23 +++---------- src/main.rs | 53 +++++++++++++++++++++++++---- src/parser.rs | 1 + src/preprocessor.rs | 56 +++++++++++++++++++++++++++---- test.mcl | 4 +-- 8 files changed, 127 insertions(+), 57 deletions(-) diff --git a/src/compile/linux_x86_64.rs b/src/compile/linux_x86_64.rs index 16f9ec0..592c77c 100644 --- a/src/compile/linux_x86_64.rs +++ b/src/compile/linux_x86_64.rs @@ -17,7 +17,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ let of_a = PathBuf::from(&args.out_file); (of_o, of_a) }; - + of_c.set_extension(""); of_o.set_extension("o"); of_a.set_extension("nasm"); @@ -30,7 +30,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ writeln!(writer, "BITS 64")?; writeln!(writer, "segment .text")?; - + writeln!(writer, "print:")?; writeln!(writer, " mov r9, -3689348814741910323")?; writeln!(writer, " sub rsp, 40")?; @@ -64,14 +64,14 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ writeln!(writer, " syscall")?; writeln!(writer, " add rsp, 40")?; writeln!(writer, " ret")?; - + writeln!(writer, "global _start")?; writeln!(writer, "_start:")?; - + let mut ti = 0; while ti < tokens.len() { let token = &tokens[ti]; - + writeln!(writer, "addr_{}:", ti)?; match token.typ { // stack @@ -106,7 +106,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ writeln!(writer, " pop rax")?; writeln!(writer, " push rax")?; writeln!(writer, " push rax")?; - + ti += 1; }, OpType::Dup2 => { @@ -117,7 +117,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ writeln!(writer, " push rbx")?; writeln!(writer, " push rax")?; writeln!(writer, " push rbx")?; - + ti += 1; }, @@ -129,7 +129,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ writeln!(writer, " push rbx")?; writeln!(writer, " push rax")?; writeln!(writer, " push rcx")?; - + ti += 1; }, OpType::Swap => { @@ -138,7 +138,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ writeln!(writer, " pop rbx")?; writeln!(writer, " push rax")?; writeln!(writer, " push rbx")?; - + ti += 1; }, OpType::Over => { @@ -148,7 +148,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ writeln!(writer, " push rbx")?; writeln!(writer, " push rax")?; writeln!(writer, " push rbx")?; - + ti += 1; }, @@ -279,7 +279,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ //writeln!(writer, " push rdx")?; ti += 1; }, - + // block OpType::If => { @@ -312,10 +312,6 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ } ti += 1; }, - - OpType::Macro => { - panic!(); - } OpType::Syscall0 => { writeln!(writer, " ;; -- syscall0")?; writeln!(writer, " pop rax")?; @@ -348,7 +344,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ writeln!(writer, " pop rdx")?; writeln!(writer, " syscall")?; writeln!(writer, " push rax")?; - + ti += 1; }, OpType::Syscall4 => { @@ -387,7 +383,9 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ writeln!(writer, " push rax")?; ti += 1; }, - OpType::None => unreachable!() + OpType::None => unreachable!(), + OpType::Macro => unreachable!(), + OpType::Include => unreachable!() } } writeln!(writer, "addr_{}:", ti)?; diff --git a/src/constants.rs b/src/constants.rs index 25c1d01..4e79b4c 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,4 +1,7 @@ +pub const ALLOW_MACRO_REDEFINITION: bool = true; + + #[derive(Debug, Clone, PartialEq)] pub enum OpType { @@ -39,6 +42,7 @@ pub enum OpType { While, Do, Macro, + Include, // syscalls Syscall0, @@ -49,7 +53,7 @@ pub enum OpType { Syscall5, Syscall6, - None + None // Used for macros and any other non built in word definitions } @@ -106,6 +110,7 @@ impl OpType { &OpType::While => "while", &OpType::Do => "do", &OpType::Macro => "macro", + &OpType::Include => "include", &OpType::Mem => "mem", &OpType::Load8 => "!8", &OpType::Store8 => "@8", diff --git a/src/interpret/linux_x86_64/mod.rs b/src/interpret/linux_x86_64/mod.rs index 58a17b5..a502152 100644 --- a/src/interpret/linux_x86_64/mod.rs +++ b/src/interpret/linux_x86_64/mod.rs @@ -223,11 +223,7 @@ pub fn run(tokens: Vec) -> Result<()>{ } else { ti += 1; } - } - OpType::Macro => { - panic!(); } - OpType::Syscall0 => { todo!(); // ti += 1; @@ -269,7 +265,9 @@ pub fn run(tokens: Vec) -> Result<()>{ todo!(); // ti += 1; }, - OpType::None => unreachable!() + OpType::None => unreachable!(), + OpType::Macro => unreachable!(), + OpType::Include => unreachable!() } } diff --git a/src/lexer.rs b/src/lexer.rs index 33a6cd6..4112c14 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -1,5 +1,5 @@ -use crate::{constants::{Token, TokenType}, preprocessor::preprocess}; +use crate::{constants::{Token, TokenType}, preprocessor::preprocess, Args}; use color_eyre::Result; fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) { @@ -68,22 +68,7 @@ fn lex_line(text: String) -> Result> { Ok(tokens) } - -// fn lex_text(text: String) -> Result>{ -// let tokens: Vec = Vec::new(); - -// let mut row = 0; -// let mut col = 0; -// let mut index = find_col(text.clone(), 0, |x| x.is_whitespace())?; - -// while index < text.len() as u32 { - -// } - -// Ok(tokens) -// } - -pub fn lex(code: String, file: &String) -> Result> { +pub fn lex(code: String, file: &String, args: Args, preprocessing: bool) -> Result> { let lines: Vec<(usize, &str)> = code .split(['\n', '\r']) .enumerate() @@ -112,6 +97,8 @@ pub fn lex(code: String, file: &String) -> Result> { // for token in tokens.clone() { // println!("tok: {:?}", token.text); // } - tokens = preprocess(tokens)?; + if preprocessing { + tokens = preprocess(tokens, args)?; + } Ok(tokens) } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 1be3af6..83f2922 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,10 @@ use color_eyre::Result; use clap::Parser; pub const DEFAULT_OUT_FILE: &str = "a.out"; +pub const DEFAULT_INCLUDES: [&str;2] = [ + "./include", + "~/.mclang/include", +]; #[derive(Parser, Debug, Clone)] #[command(author, version, about, long_about = None)] @@ -39,28 +43,65 @@ pub struct Args { /// Dont print any output exept the actual running codes output #[arg(long, short)] quiet: bool, + + /// Add an include directory [default: ["./include", "~/.mclang/include"]] + #[arg(long, short='I')] + include: Vec, + + + //#[arg(long, short='F')] + //features: Vec, } fn main() -> Result<()> { let args = Args::parse(); - - let code = fs::read_to_string(&args.in_file)?; - let tokens = lexer::lex(code, &args.in_file)?; + let code = match fs::read_to_string(&args.in_file) { + Ok(t) => t, + Err(_) => { + error!("Failed to read file {}, exiting!", &args.in_file); + return Ok(()); + } + }; + let tokens = match lexer::lex(code, &args.in_file, args.clone(), true) { + Ok(t) => t, + Err(_) => { + error!("Lexing failed, exiting!"); + return Ok(()); + } + }; // for token in &tokens { // println!("(f: {}, l: {}, c: {}, t: {})", token.file, token.line, token.col, token.text); // } let mut parser = parser::Parser::new(tokens); - let tokens = parser.parse()?; + let tokens = match parser.parse() { + Ok(t) => t, + Err(_) => { + error!("Parsing failed, exiting!"); + return Ok(()); + } + }; if args.compile && args.interpret { error!("Cannot compile and interpret at the same time"); } else if args.interpret { - interpret::linux_x86_64::run(tokens)?; + match interpret::linux_x86_64::run(tokens) { + Ok(_) => (), + Err(_) => { + error!("Interpretation failed, exiting!"); + return Ok(()); + } + }; } else if args.compile { - compile::linux_x86_64::compile(tokens, args)?; + match compile::linux_x86_64::compile(tokens, args) { + Ok(_) => (), + Err(_) => { + error!("Compilation failed, exiting!"); + return Ok(()); + } + }; } else { error!("Did not choose to compile or to interpret, exiting"); } diff --git a/src/parser.rs b/src/parser.rs index 11cb48d..09e9cbf 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -134,6 +134,7 @@ pub fn lookup_word>(s: String, _pos: P) -> ("while", OpType::While), ("do", OpType::Do), ("macro", OpType::Macro), + ("include", OpType::Include), // technically not but it fits next to macros // mem ("mem", OpType::Mem), diff --git a/src/preprocessor.rs b/src/preprocessor.rs index 79bbe98..7a8fe81 100644 --- a/src/preprocessor.rs +++ b/src/preprocessor.rs @@ -1,10 +1,12 @@ use std::collections::HashMap; +use std::path::PathBuf; use color_eyre::Result; use eyre::eyre; use crate::constants::{Token, Loc, OpType, TokenType}; -use crate::{lerror, lnote}; +use crate::lexer::lex; +use crate::{lerror, lnote, Args}; use crate::parser::lookup_word; #[derive(Debug)] @@ -13,7 +15,7 @@ pub struct Macro { pub tokens: Vec } -pub fn preprocess(tokens: Vec) -> Result>{ +pub fn preprocess(tokens: Vec, args: Args) -> Result>{ let mut program: Vec = Vec::new(); let mut macros: HashMap = HashMap::new(); @@ -41,11 +43,12 @@ pub fn preprocess(tokens: Vec) -> Result>{ return Err(eyre!("")); } - - if macros.get(¯o_name.text.clone()).is_some() { //? Maybe allow? - lerror!(¯o_name.loc(), "Macro redefinition is not allowed"); - lnote!(¯os.get(¯o_name.text.clone()).unwrap().loc, "First definition here"); - return Err(eyre!("")); + if crate::constants::ALLOW_MACRO_REDEFINITION { + if macros.get(¯o_name.text.clone()).is_some() { + lerror!(¯o_name.loc(), "Macro redefinition is not allowed"); + lnote!(¯os.get(¯o_name.text.clone()).unwrap().loc, "First definition here"); + return Err(eyre!("")); + } } let mut macr = Macro{ loc: macro_name.loc(), tokens: Vec::new() }; @@ -75,6 +78,45 @@ pub fn preprocess(tokens: Vec) -> Result>{ } + _ if op_type == OpType::Include => { + if rtokens.len() == 0 { + lerror!(&token.loc(), "Include path not found, expected {} but found nothing", TokenType::String.human()); + return Err(eyre!("")); + } + + let include_path = rtokens.pop().unwrap(); + + if include_path.typ != TokenType::String { + lerror!(&include_path.loc(), "Bad include path, expected {} but found {}", TokenType::String.human(), include_path.typ.human()); + return Err(eyre!("")); + } + + let mut in_paths = args.include.clone(); + in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| f.to_string()).collect::>()); + + let mut include_code = String::new(); + + for path in in_paths { + let p = PathBuf::from(path); + let p = p.join(include_path.text.clone()); + + if p.exists() { + include_code = std::fs::read_to_string(p)?; + } + + } + + if include_code.is_empty() { + lerror!(&include_path.loc(), "Include file in path '{}' was not found", include_path.text); + return Err(eyre!("")); + } + + let mut code = lex(include_code, &include_path.text, args.clone(), false)?; + code.reverse(); + rtokens.append(&mut code); + + + } _ => { program.push(token); } diff --git a/test.mcl b/test.mcl index facf167..a4bde0d 100644 --- a/test.mcl +++ b/test.mcl @@ -1,5 +1,3 @@ -macro write - 1 1 syscall3 drop -end +include "io.mcl" "HEnlo world!\n" write \ No newline at end of file