From 42139862026cfbecf8ad833ba4fdd3081d0e7532 Mon Sep 17 00:00:00 2001 From: MCorange <gvidasjuknevicius2@gmail.com> Date: Tue, 28 Mar 2023 02:09:41 +0300 Subject: [PATCH] Added simple C preprocessor style macros to enable support for multiple system types --- src/compile/linux_x86_64/mod.rs | 5 +- src/compile/win32_x86_64/commands.rs | 8 +- src/compile/win32_x86_64/mod.rs | 6 +- src/constants.rs | 19 +++- src/interpret/linux_x86_64/mod.rs | 5 +- src/main.rs | 5 +- src/parser.rs | 8 +- src/preprocessor.rs | 156 ++++++++++++++++++++++++++- test | Bin 3533 -> 0 bytes test.exe | Bin 3533 -> 0 bytes test.mcl | 4 +- test.nasm | 8 +- test.o | Bin 588 -> 0 bytes tests/fail_unknown_word.mcl | 1 - tests/math.mcl | 7 -- 15 files changed, 203 insertions(+), 29 deletions(-) delete mode 100644 test delete mode 100644 test.exe delete mode 100644 test.o delete mode 100644 tests/fail_unknown_word.mcl delete mode 100644 tests/math.mcl diff --git a/src/compile/linux_x86_64/mod.rs b/src/compile/linux_x86_64/mod.rs index f7e3bc2..d861492 100644 --- a/src/compile/linux_x86_64/mod.rs +++ b/src/compile/linux_x86_64/mod.rs @@ -391,7 +391,10 @@ pub fn compile(tokens: &[Operator], args: &Args, folders: &Folders) -> Result<i3 writeln!(writer, " push rax")?; ti += 1; }, - OpType::Instruction(InstructionType::None) | OpType::Keyword(KeywordType::Macro) | OpType::Keyword(KeywordType::Include) => unreachable!() + OpType::Instruction(InstructionType::None) | + OpType::Keyword(KeywordType::Macro) | + OpType::Keyword(KeywordType::Include) | + OpType::Preprocessor(_) => unreachable!() } } writeln!(writer, "addr_{ti}:")?; diff --git a/src/compile/win32_x86_64/commands.rs b/src/compile/win32_x86_64/commands.rs index 3dddff7..2b20a41 100644 --- a/src/compile/win32_x86_64/commands.rs +++ b/src/compile/win32_x86_64/commands.rs @@ -7,7 +7,7 @@ use crate::info; pub fn linux_x86_64_compile_and_link(folders: &Folders, quiet: bool) -> Result<()> { let nasm_args = [ - "-felf64", + "-fwin32", folders.of_a.to_str().unwrap(), "-o", folders.of_o.to_str().unwrap() @@ -16,7 +16,11 @@ pub fn linux_x86_64_compile_and_link(folders: &Folders, quiet: bool) -> Result<( let ld_args = [ folders.of_o.to_str().unwrap(), "-o", - folders.of_c.to_str().unwrap() + folders.of_c.to_str().unwrap(), + "-L", + "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Lib", + "-l", + "kernel32" ]; diff --git a/src/compile/win32_x86_64/mod.rs b/src/compile/win32_x86_64/mod.rs index b72541a..3e1526a 100644 --- a/src/compile/win32_x86_64/mod.rs +++ b/src/compile/win32_x86_64/mod.rs @@ -9,7 +9,6 @@ use crate::constants::InstructionType; use super::Folders; pub fn compile(tokens: &[Operator], args: &Args, folders: &Folders) -> Result<i32>{ - let file = fs::File::create(&folders.of_a)?; let mut writer = BufWriter::new(&file); @@ -389,7 +388,10 @@ pub fn compile(tokens: &[Operator], args: &Args, folders: &Folders) -> Result<i3 writeln!(writer, " push rax")?; ti += 1; }, - OpType::Instruction(InstructionType::None) | OpType::Keyword(KeywordType::Macro) | OpType::Keyword(KeywordType::Include) => unreachable!() + OpType::Instruction(InstructionType::None) | + OpType::Keyword(KeywordType::Macro) | + OpType::Keyword(KeywordType::Include) | + OpType::Preprocessor(_) => unreachable!() } } writeln!(writer, "addr_{ti}:")?; diff --git a/src/constants.rs b/src/constants.rs index d9b13ff..6d57931 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -60,10 +60,20 @@ pub enum KeywordType { Include, } +#[derive(Debug, Clone, PartialEq)] +pub enum PreprocessorType { + IfDefined, + IfNotDefined, + Else, + EndIf, + Define +} + #[derive(Debug, Clone, PartialEq)] pub enum OpType { Keyword(KeywordType), - Instruction(InstructionType) + Instruction(InstructionType), + Preprocessor(PreprocessorType) } #[derive(Debug, Clone)] @@ -132,7 +142,12 @@ impl OpType { OpType::Instruction(InstructionType::Syscall4) => "syscall4", OpType::Instruction(InstructionType::Syscall5) => "syscall5", OpType::Instruction(InstructionType::Syscall6) => "syscall6", - OpType::Instruction(InstructionType::None) => "None" + OpType::Instruction(InstructionType::None) => "None", + OpType::Preprocessor(PreprocessorType::IfDefined) => "#ifdef", + OpType::Preprocessor(PreprocessorType::IfNotDefined) => "#ifndef", + OpType::Preprocessor(PreprocessorType::Else) => "#else", + OpType::Preprocessor(PreprocessorType::EndIf) => "#endif", + OpType::Preprocessor(PreprocessorType::Define) => "#define", }.to_string() } } diff --git a/src/interpret/linux_x86_64/mod.rs b/src/interpret/linux_x86_64/mod.rs index a53f34d..89be2c3 100644 --- a/src/interpret/linux_x86_64/mod.rs +++ b/src/interpret/linux_x86_64/mod.rs @@ -272,7 +272,10 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{ todo!(); // ti += 1; }, - OpType::Instruction(InstructionType::None) | OpType::Keyword(KeywordType::Macro) | OpType::Keyword(KeywordType::Include) => unreachable!() + OpType::Instruction(InstructionType::None) | + OpType::Keyword(KeywordType::Macro) | + OpType::Keyword(KeywordType::Include) | + OpType::Preprocessor(_) => unreachable!() } } diff --git a/src/main.rs b/src/main.rs index 8c9493b..15d5b80 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,10 +7,13 @@ mod lexer; mod preprocessor; use std::fs; - use clap::Parser; use constants::targets; +/* + TODO: add simple macro support on vscode syntax highlighting + */ + pub const DEFAULT_OUT_FILE: &str = "a.out"; pub const DEFAULT_INCLUDES: [&str;2] = [ "./include", diff --git a/src/parser.rs b/src/parser.rs index 9c8f444..c0ca927 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,6 +1,6 @@ use std::ops::Deref; -use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType}, lerror}; +use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType, PreprocessorType}, lerror}; use color_eyre::Result; use eyre::eyre; @@ -156,6 +156,12 @@ pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType { "syscall4" => OpType::Instruction(InstructionType::Syscall4), "syscall5" => OpType::Instruction(InstructionType::Syscall5), "syscall6" => OpType::Instruction(InstructionType::Syscall6), + + "#ifdef" => OpType::Preprocessor(PreprocessorType::IfDefined), + "#ifndef" => OpType::Preprocessor(PreprocessorType::IfNotDefined), + "#else" => OpType::Preprocessor(PreprocessorType::Else), + "#endif" => OpType::Preprocessor(PreprocessorType::EndIf), + "#define" => OpType::Preprocessor(PreprocessorType::Define), _ => OpType::Instruction(InstructionType::None) } diff --git a/src/preprocessor.rs b/src/preprocessor.rs index d539ee0..da2a110 100644 --- a/src/preprocessor.rs +++ b/src/preprocessor.rs @@ -4,11 +4,22 @@ use std::path::PathBuf; use color_eyre::Result; use eyre::eyre; -use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType}; +use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType, PreprocessorType}; use crate::lexer::lex; use crate::{lerror, lnote, Args, warn}; use crate::parser::lookup_word; +fn get_predefined_basic_macros(args: &Args) -> Vec<String> { + let mut a: Vec<String> = Vec::new(); + if args.target.as_str() == crate::constants::targets::WIN32_X86_64 { + a.push("__win32__".to_string()); + } else + if args.target.as_str() == crate::constants::targets::LINUX_X86_64 { + a.push("__linux__".to_string()); + } + a +} + #[derive(Debug)] pub struct Macro { pub loc: Loc, @@ -18,7 +29,11 @@ pub struct Macro { pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{ let mut program: Vec<Token> = Vec::new(); let mut macros: HashMap<String, Macro> = HashMap::new(); - + let mut basic_macros: Vec<String> = get_predefined_basic_macros(args); + + //* predefined basic macros + + let mut rtokens = tokens; rtokens.reverse(); while !rtokens.is_empty() { @@ -71,8 +86,6 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{ macros.insert(macro_name.text, macr); - - } _ if op_type == OpType::Keyword(KeywordType::Include) => { @@ -114,6 +127,141 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{ } + + _ if op_type == OpType::Preprocessor(PreprocessorType::Define) => { + if rtokens.is_empty(){ + lerror!(&token.loc(), "Basic macro contents not found, expected {} but found nothing", TokenType::Word.human()); + return Err(eyre!("")); + } + + let basic_macro_name = rtokens.pop().unwrap(); + + if basic_macro_name.typ != TokenType::Word { + lerror!(&basic_macro_name.loc(), "Bad basic macro contents, expected {} but found {}", TokenType::Word.human(), basic_macro_name.typ.human()); + return Err(eyre!("")); + } + + let word = lookup_word(&basic_macro_name.text, &basic_macro_name.loc()); + if word != OpType::Instruction(InstructionType::None) { + lerror!(&basic_macro_name.loc(), "Basic macro contents cannot be a built in word, got '{}'", word.human()); + return Err(eyre!("")); + } + + basic_macros.push(basic_macro_name.text); + } + _ if op_type == OpType::Preprocessor(PreprocessorType::IfDefined) => { + if rtokens.is_empty(){ + lerror!(&token.loc(), "Basic macro contents not found, expected {} but found nothing", TokenType::Word.human()); + return Err(eyre!("")); + } + + let basic_macro_name = rtokens.pop().unwrap(); + + let exists = basic_macros.contains(&basic_macro_name.text); + + #[allow(unused_assignments)] + let mut skip = false; + let mut skip_this = false; + let mut els = false; + skip = if !exists { true } else { false }; + while !rtokens.is_empty() { + let token = rtokens.pop().unwrap(); + let op_typ = lookup_word(&token.text, &token.loc()); + if exists { + if op_typ == OpType::Preprocessor(PreprocessorType::Else) { + if els { + todo!(); + } + els = true; + skip = true; + } + } else { + if op_typ == OpType::Preprocessor(PreprocessorType::Else) { + if els { + todo!(); + } + els = true; + skip = false; + skip_this = true; + } + } + + if op_typ == OpType::Preprocessor(PreprocessorType::EndIf) { + break; + } + + if !skip { + #[allow(unused_assignments)] + if skip_this { + skip_this = false; + } else { + program.push(token); + } + } + + } + + }, + + _ if op_type == OpType::Preprocessor(PreprocessorType::IfNotDefined) => { + if rtokens.is_empty(){ + lerror!(&token.loc(), "Basic macro contents not found, expected {} but found nothing", TokenType::Word.human()); + return Err(eyre!("")); + } + + let basic_macro_name = rtokens.pop().unwrap(); + + let exists = basic_macros.contains(&basic_macro_name.text); + + #[allow(unused_assignments)] + let mut skip = false; + let mut skip_this = false; + let mut els = false; + skip = if exists { true } else { false }; + while !rtokens.is_empty() { + let token = rtokens.pop().unwrap(); + let op_typ = lookup_word(&token.text, &token.loc()); + if !exists { + if op_typ == OpType::Preprocessor(PreprocessorType::Else) { + if els { + todo!(); + } + els = true; + skip = true; + } + } else { + if op_typ == OpType::Preprocessor(PreprocessorType::Else) { + if els { + todo!(); + } + els = true; + skip = false; + skip_this = true; + } + } + + if op_typ == OpType::Preprocessor(PreprocessorType::EndIf) { + break; + } + + if !skip { + #[allow(unused_assignments)] + if skip_this { + skip_this = false; + } else { + program.push(token); + } + } + + } + + + }, + _ if op_type == OpType::Preprocessor(PreprocessorType::Else) || + op_type == OpType::Preprocessor(PreprocessorType::EndIf) => { + + unreachable!() + }, _ => { program.push(token); } diff --git a/test b/test deleted file mode 100644 index 06a65882ee5f80256931a519747245dc68677b27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3533 zcmeHJOKclO82&e=prlIRPzer*ZbbymW#v{}Dk17pTUtwQV<qmTLK?>Q#M!bBv%4vw z;!)uXK?*{Z;J~>DZg2p}aA{~O#4Cs!2ZRK-7LeLYX?wx^|IDsur*62xDI?9!%=f<^ zp7Dv(??DLw9>6&o0Ss}aQIX$&|C~qi-2N}-;M3{t14FB^eW11KC3ZiKdNB{|4iCd9 zwcEmu*FxJ1?dsyP9YkH>%+AitXR4bufQD6qKhD`*co5(@#D9f{N_(xT$6*Q&G_Otr zJc27tIVx(8H1gZRNvj$&Qs!b0WLyAtCWpeA{8$YM+?<AeO7MUEI;mJs(c*_>l^n`r zrE@lHXujyQlSCdV2X;;|*Yi-`a=b22IjC4LCaF&+MG91q&y)nHf4=>_8t&lFgI`tW z_s_VSjrk|sjXRCa>bzaQ{TpuU3tzim{$6r7pSj>#f4K`c2V3R0EhM-bKe-#<x`XSM zJGe9b$~P{_T%v-w3zrXVxtr-eyRmV3NXWx`+`-j@SB5t3o9x<KqtR&iEbcGiL?Rxs z|ELSqO8echn}OX7{FfPURy<#zfjOLi<L|F$IWMFlNu7`<L1s9=tLR8S<dXGHM$yao zo<fMOvXUilZOwo?hqsf+U!!YJzBMK2$6hFph)B%}aT<po8za2ijaeBWHjzUB>n3s- z;Egd7h}`?kAE>Mdo;u|+*`XVTUcKzy!26d_@*Chu`WOf*h6^|~&#{b$bSSB2hG?EH zAvnmE;(3jZs97WL69RSt`54c1ZEK$Ihy|sztzRaP8xx4UN)aW?%K9w1X2c~^Vff=_ zJlfW217WP|`;3vbf`?~_$3WhcNTtB@Zl*`abrBJId9|%iG9Fr#&p%8cKO;ijr+Kc^ z7GFml>8(skX=X{vV{Ed#f0X7uv=~`^6cJPNQ;M|^#Subq>L?m`GV8?=(Qz>*!Y*aZ zuoWSX*-@_}LQGoo2ZR_>A4#5KRzE|8qSR7XCZv8ugc728u1P&b<ZdRVv$~hm8d6VB zAVᵽA}5L%|-Wn36zOQ%k@>L+Tfxm-I{U1UqO#^Q0-s4urLE!a@_w?&mm9$B@u zxTL8p^^*cMPFX*Rg&%b?loVh`c2;@JJE@4hB=wL+iWBdgV9^RmcV1$hC<wgtK7?2# zB0ei5CE#bGm?dlN<kch<0Xr+=#EU}ZSO<--`vqs1M7;YTs^pB}f43ra=S0*_Rt?uy z1@9MKR;KzzWzu**>n_FuFGSa)#PHb*cu%l4PgHn`=%f@5_q|>ih)|`Yeylatva^Td zQsuE7H|j)@<`m^@XW}e>hbot*uu)a48WxXUrF;BT#knU!a$f5-dna!InapCDm4j(P zkku(u&tsyfamMwhpk)W<p(!6!T8qu$N4zUyw&L@iYQADfD2#ekfwb<TxS~y}-MJij K!{nhT2mb-HT^>9D diff --git a/test.exe b/test.exe deleted file mode 100644 index 50b8025533acbab8472e23d398f6c77e1cfd70a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3533 zcmeHJOKclO82&e=prlIRPzer*ZbSslW#v{}kgDQRTUtwQV<qmTLK?>Q#M!bBv%4wb zUEvEs3PP3Oz?lO#IDllhG_)1s6~wI)2nlX2LZTO-T<ZS+%&uprZn(iIBhAjt_rD*W z@yRpqKnVcu!8sZM3~{AVk>7v+oJaE9!O!R5lj)uLq1D)#Z>@QW-H)SQ%mcf_!!Szi zwy@*%(Dp*Ry0l^kQCB##voi~s>Shg~VU=M1WxEUa0vtp97r3vq-<o<Drtm=X$~3?O zxYCrPqV`B5zb%}!sxc#Fe(Zsa3&76gP&ktxt093K({Mlu{;yvr6&op9e4nh6LwT%p z&V~)mXPtJE$Rp*z&MD@49?IK}*X1b(6${2B_35NYfeP}Ok^uG3cD_@?9sGXi%j&|x z8F#C(@QAy4v$0iOu<L*Sirf0)SMC?TmE5f-F1XfT?&6KXcKJ;U3GU`qck>%}aNTkT zH>Y3t+9jEbR1kOZ(&24)D?MO0HZKhcxqqKKxN_+7(8hg}U3+6R8V!%){vu8!;t~6g zx=^jO-y3@w*vr6wnE_|j^9351!+8sTe?7~2CKXBQgggl{!}(oBNBSX`thX|XUdHzn zLUfgtEO~2d2HZKkokadRU3>DaDM3H>LU}|)YF3ETIP%aK;oWY`$^fy690u4hks|=F zjgdg)-e>+mWmWLhDVNC(-7xg(W$y;wzl4(C0FTngKu|GUz^QqTXFQ}sNi{P>^K=Qp zLADgnD|AH78hMuxunWjXc&2Mx^L$GzD5Y)vJc0Z%fyk>AQL?P8&ys6KTrw4gKW@gO zZJjX?#=5@G7+EWLc$Rn!<aLQu3OsLTdURYLAVM#%w)JtwLyPkH`w8SHM5y~T&vn}3 z>!>6BGm}!9S(5S?n=J1irFkDMMphq0#MJzlVl71RBq2C;6b(F?_2P)=xEK>*mojG9 zijc?bs8<moCaw8BLJX-7B~LM{pCUq0YN^W;Qa>O<3DG>)q@E)3PbQ_ax}Ve<Qjbp{ zPZ5G1YAK!}v`oSCxG=_+PoHYlPu5s-rFOcy#FlG~r4y`CUuj`lu%Ym8iz<;kvTAE- zSyNf+Ck1MpvVIZ^Kk8&CDZq~Gtnrw4QW1Me>LHC3C*DhfMXMy;d5(3WAn?+=5Mq&t z_?(cGfS-+GmaMmv7n4*3?3{=bFA9}o9W=h-7o1@d@$Q1Ck~4<?-HO!R6Hz-=HC$U0 zykB%#nd%pnN#p&jyBG_+5M7TF!)GtxJ;B;MQQ;+`lTtX`_j+L<LY0pC@zz+&?jDXy zmB)6%s1rq+Q<SrviL?A2s$81FMpdzDSUh@_?(kC;=Z*-;d9By%oxA~LGK*za4yFY` zR;NrojftYh8P}hJmK~UfrhHIoEjEWA@vey3s?U3>`HCT-FzQhS(z=V{iZ-cs_j2S7 JlZT=lybS|%9jO2S diff --git a/test.mcl b/test.mcl index 1613b36..c23c68e 100644 --- a/test.mcl +++ b/test.mcl @@ -1 +1,3 @@ -' ' print \ No newline at end of file +#ifdef __win32__ + 69 +#endif \ No newline at end of file diff --git a/test.nasm b/test.nasm index 73029a5..f222410 100644 --- a/test.nasm +++ b/test.nasm @@ -36,14 +36,10 @@ print: global _start _start: addr_0: - ;; -- push int 32 - mov rax, 32 + ;; -- push int 69 + mov rax, 69 push rax addr_1: - ;; -- print - pop rdi - call print -addr_2: mov rax, 60 mov rdi, 0 syscall diff --git a/test.o b/test.o deleted file mode 100644 index a62d83f48b8d8099df6f8fc5f8de1c21bdd2a8e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 588 zcmeZaWM=5AQb-YFWMB|vfB?Oc)QS=)8$@*haSsrK)WCoOLqLLFN@7VOOaMxQ)F7*K zU@$nKmsDJgqU;DK3Kzs_0IKucdG-thcr?G!IOd`v&*jnUqax?g`NOBzMMc5$`$Hhp zQ}cw!!B@;4y(W`97{7UFerP^m(7_0l@aVkm(Rs?F`6Z)A^AFDQlO7;F`$2B@&^%;# zz@xWBM8T)?&<>CYKdVRc5skw;6oBl2_!mw8|Nq}%17z<9VxXj6T4qivhzSJ${xdM7 zGwQ{Zq!yRx<s}y9LWCKRLkVOgGb1RRPyuoXF#)BRK?>0Ta_BGv<$!81!bdMLsW?BU z6dWo4f$m{uC@9LzgT)cpc8G|ckC6n>42Vd4aY<qkP*D+7goz<BC8a3d03pH*5iw+7 nsDSGNt1)6=sDq2-ro#LTvKfRO(oz#k^b8C@_CVaj0%QRIQ`c`+ diff --git a/tests/fail_unknown_word.mcl b/tests/fail_unknown_word.mcl deleted file mode 100644 index 13724a0..0000000 --- a/tests/fail_unknown_word.mcl +++ /dev/null @@ -1 +0,0 @@ -gftdesd5ryutfgyhibugtf6r4 \ No newline at end of file diff --git a/tests/math.mcl b/tests/math.mcl deleted file mode 100644 index 89d4cd5..0000000 --- a/tests/math.mcl +++ /dev/null @@ -1,7 +0,0 @@ -34 35 + print - -800 380 - print - -10 5 * print - -40 5 / print \ No newline at end of file