From 7fb49e0ee04bc3f76a90e7d1dc4f8017dc47bb61 Mon Sep 17 00:00:00 2001 From: Robert-M-Lucas Date: Tue, 18 Jun 2024 14:27:36 +0100 Subject: [PATCH] If and boolean --- .idea/workspace.xml | 60 ++++++++++--- build.rs | 8 ++ build/out.asm | 98 ++++++++++----------- build/out.o | Bin 1088 -> 1248 bytes build/out.out | Bin 16744 -> 16880 bytes main.why | 23 ++--- src/root/assembler/assembly_builder.rs | 29 ++++++ src/root/assembler/mod.rs | 1 + src/root/builtin/mod.rs | 2 + src/root/builtin/types/bool/mod.rs | 59 +++++++++++++ src/root/builtin/types/bool/printb.rs | 63 +++++++++++++ src/root/builtin/types/int/mod.rs | 6 +- src/root/builtin/types/int/printi.rs | 7 +- src/root/builtin/types/mod.rs | 1 + src/root/compiler/assembly/utils.rs | 23 +++-- src/root/compiler/compile.rs | 2 +- src/root/compiler/compile_evaluable.rs | 15 +--- src/root/compiler/compile_function.rs | 62 +++++++------ src/root/compiler/compile_function_call.rs | 36 +++----- src/root/compiler/global_tracker.rs | 9 +- src/root/parser/parse_function/parse_if.rs | 4 +- test/test.asm | 60 +++++++++++++ types.toml | 20 ----- 23 files changed, 409 insertions(+), 179 deletions(-) create mode 100644 build.rs create mode 100644 src/root/assembler/assembly_builder.rs create mode 100644 src/root/builtin/types/bool/mod.rs create mode 100644 src/root/builtin/types/bool/printb.rs create mode 100644 test/test.asm delete mode 100644 types.toml diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 3433c62..021cb71 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -7,19 +7,23 @@ - - + + + + + - - + + - - + + + + @@ -133,6 +139,26 @@ @@ -441,7 +478,8 @@ - diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..613fb5c --- /dev/null +++ b/build.rs @@ -0,0 +1,8 @@ +use std::fs; +use std::path::PathBuf; + +fn main() { + if PathBuf::from("types.toml").is_file() { + fs::remove_file(PathBuf::from("types.toml")).unwrap(); + } +} \ No newline at end of file diff --git a/build/out.asm b/build/out.asm index 2740025..06f1ecf 100644 --- a/build/out.asm +++ b/build/out.asm @@ -5,62 +5,54 @@ section .text main: push rbp mov rbp, rsp - - mov qword [rbp-8], 0 - mov qword [rbp-16], 1 - mov rax, qword [rbp-16] - mov qword [rbp-40], rax + mov qword [rbp-8], 3 + mov qword [rbp-16], 4 + mov byte [rbp-17], 1 + mov al, byte [rbp-17] + mov byte [rbp-18], al + mov rdi, __6_fstr + mov rsi, 0 + mov sil, [rbp-18] + mov al, 0 + sub rsp, 18 + extern printf + call printf + add rsp, 18 + mov al, byte [rbp-17] + mov byte [rbp-19], al + cmp byte [rbp-19], 0 + jz main_0 mov rax, qword [rbp-8] - mov qword [rbp-48], rax - sub rsp, 48 - call _1 - add rsp, 48 - mov qword [rbp-40], 255 - mov rax, qword [rbp-40] - leave - ret - -_1: - push rbp - mov rbp, rsp - - mov rax, qword [rbp+16] - mov qword [rbp-8], rax - - mov rdi, __10_fstr - mov rsi, [rbp-8] + mov qword [rbp-27], rax + mov rdi, __4_fstr + mov rsi, [rbp-27] mov al, 0 - sub rsp, 8 + sub rsp, 27 extern printf call printf - add rsp, 8 - - mov rax, qword [rbp+16] - mov qword [rbp-24], rax - mov rax, qword [rbp+24] - mov qword [rbp-32], rax - mov rax, qword [rbp-24] - add rax, qword [rbp-32] - mov qword [rbp-16], rax - mov rax, qword [rbp+24] - mov qword [rbp-40], rax - mov qword [rbp-48], 12 - mov rax, 60 - mov rdi, [rbp-48] - syscall - mov rax, qword [rbp-40] - mov qword [rbp-56], rax + add rsp, 27 + mov qword [rbp-35], 13 + mov rax, qword [rbp-35] + leave + ret + jmp main_1 + main_0: mov rax, qword [rbp-16] - mov qword [rbp-64], rax - mov rax, qword [rbp-64] - mov qword [rbp-88], rax - mov rax, qword [rbp-56] - mov qword [rbp-96], rax - sub rsp, 96 - call _1 - add rsp, 96 - leave - ret + mov qword [rbp-27], rax + mov rdi, __4_fstr + mov rsi, [rbp-27] + mov al, 0 + sub rsp, 27 + extern printf + call printf + add rsp, 27 + mov qword [rbp-35], 12 + mov rax, qword [rbp-35] + leave + ret + main_1: + -section .data - __10_fstr db `Integer: %d\n`,0 \ No newline at end of file +section .data_readonly + __6_fstr db `Boolean: %d\n`,0 + __4_fstr db `Integer: %d\n`,0 \ No newline at end of file diff --git a/build/out.o b/build/out.o index 120e41fe7ec4523a96d096b23ab1526fb687b1ee..a350db6809d058f172ca54653b71ab0bd0c005cb 100644 GIT binary patch literal 1248 zcmbVKJxc>Y5S>fnCyF76h-rc#XcOZnq98#yIl;n4+v6ms29k?hHlT&5q%o%P7x)`2 ztW{7He}rHY5HuP)3qf~w=aO)_5OH94=DmGyXLs2{b#>XNDBy$wi%>%j3lOiBRL7wM z{B`XAO6-NB-EH?t;?l(jUATi|^pm{0dPBrem63(}ZUdb5y2Ug37h3oueBIp}EfLzZ zf`CUGADuK158}jQln<}|!GKtXR{djKMp9{@d5y?3!U*y1cm@oo|GHKvX%Ffbo`L5I z>h9GK3%wxJ@^>MjD<2({fz4<|^-C+LrJ74C=1Rg4 zb_`+O7+vzf8UtNpahgl#irNRQLPGviwZ;Pc08(Jx-QamDZPQ^G=~z_Cj{ zOuYO5j|sl<$4wHCPg@^-90Wbi(=YgXCDog`WGXS9$+4)BO+(s9TCi&;Ew&|UJtorx w==!X_#UGIu)3Oj7L}(j)pZb42M?9Xqi;wRg85_hqdguJfCi-F%{dp7pFNY|W!~g&Q literal 1088 zcmbVLF-t;G6h5Y=M4?2GQ@KPw=z{ON=R4nb&b`-rAC%MM1)q<`!$*fSiN-8ZdNLLBG=<1N z#r|)~z4*5%+ZR0IL*k=S974=~c_n?}Uy<|yDdxQFWywJJ_awc1HtWa>=`Uqm6m1JO z2;@D6MH~~j37p$skUK&*2D$$>67rr{8x>?y7&&CG-2Yr{eX8$@%`)JKHL9VE)Rtlb zZD3z*4wKd@Cz@|bh)l;5nZ1r{HEp^9$D+gaUAr>_Buo-RlRUgsO`tM z@=M&C5_;iQr$k=UHA>Vk>v~Psa+uv!JQQ)QP}V%D>-zJ<=M4Yx$DQ7Y$muNrznt5>L^m8z6U(RHm<)r*wLq>`B; a&cv1S=S<9af7ACeD|lWJzqxOmIgcL;n2ApS diff --git a/build/out.out b/build/out.out index 2bcb0cfe1bbfa7cf6f02968ddf7fe32df0978f80..a78d355719990dd579722a409aa1ca63650f0790 100755 GIT binary patch delta 1478 zcmZ`&Z)jUp6u4Ko82@^+NAB$*(A54VXwlVg8QI|S)}b&sO_w& zFj2HtWnKNy^?-g7MEo#O*hc)&F<7gc8{0%hDu}aGrG?tLMzqlIQMc)lZgO_ZA9omX*5`Dr3Y*@-gof zb&dDu^Nu+Vn12jRUm6&QR5!jSN>w*9a#7@uuc>fe4N(T!YOrrp8tTAy@>95X4Cq-F&jC%;L36x8kTbjLAL!!+PmH zmaD}2%u_W}zHLTVllw+zL(Gi)ci*7Jgw*Ii}mK$j{*D+UtBd MVR_F`xZd&je~FDYs{jB1 delta 1305 zcmZWoOKcle6uobpG-EeTX2v$Q3B)fVty`h`8&bz@JQKiTyyzlQy8~iG8?r$3qeO_G zs*qC2WRv8skb+3WrVEOidO^Esj9f@8SOj%r!Jv3a%O^9zpR7f@jd?~?0V!V*h*`&{u5PP0d{ z#2r!Mn!S*)BHRtWad2ySc=0nld%5z<|F6gESHG)lRX_K%`*U2=Kp(c|$-oV(LjS5Z z>0Px5^WOMeeSAF89lK;lb;mTgW&5WeaJ(t?F^+#pJ;B~2$y0$-dgWi^Q`0nmZSPE? zPflF4^M`-9C!V2}8EtV{@N!c5nRDa{R9rDFScROiKlGX{W zGt~%dgjWdH374oz+4z{=gqoBab%5{xk-HYSbb$4Ej`dTFhaPFuG$#mCgc@O)@FXGN z3H}N*@H`KM+K6knI2xRuH|bfbe#6K7SQ8?+eIzGi?~d$HJ2;Z**}cQ{O#gn-E%7TFt_Uw9&$r=A z*#%D&qPUU`u^_HxlPrLbvgyNT-7LEYO+VR-2(&(Xi~kv?2f~;t?DHtFh|2?UJXhEk z2!UA8S{57s#?gUrbc@yu!eFSoRUgW)g-a#65F8>Px<73zAWpnQd~^?=AYKu=Y1*AO zV5LRha;x^Hoy28Q-zQZTBoO)T+H?2^sTb|qC|I}p*>MTkVEDZgR$u4>O>)$Ou4U1! z+I!9`Hs1xQJ>T>y@v;zkuFFmQWbn6+u{4a0rBl^+kJcC-8LC$w4E-puFn)Wy%5LH4 zaPsLD00qAuzKnBu-q)a`P$~%Sk?4PHuX5ZWCU7(#V|Q?+pt8I8kmmm|t*XKn;03iH zJO;e37MOq!)fkg;J|F87DNdwf>uy`4^>Wdav+qEe68(5y3$rLzv^aYKS7<$j4K0q> yw6;)(W3*>p)@;0u-VrqQhWFAoi0_QN>YW&LlvSJ`IqHq)oZT_n#hw6WWFut& diff --git a/main.why b/main.why index 770974e..a88ebe4 100644 --- a/main.why +++ b/main.why @@ -1,12 +1,15 @@ -fn fib(a: int, b: int) { - printi(a); - let d: int = a + b; - let c: int = b; - exit(12); - fib(c, d); -} - fn main() -> int { - fib(0, 1); - return 255; + let i: int = 3; + let j: int = 4; + let x: bool = true; + printb(x); + + if (x) { + printi(i); + return 13; + } + else { + printi(j); + return 12; + } } diff --git a/src/root/assembler/assembly_builder.rs b/src/root/assembler/assembly_builder.rs new file mode 100644 index 0000000..8e3b1b2 --- /dev/null +++ b/src/root/assembler/assembly_builder.rs @@ -0,0 +1,29 @@ + +pub struct AssemblyBuilder { + inner: String +} + +impl AssemblyBuilder { + pub fn new() -> AssemblyBuilder { + AssemblyBuilder { inner: String::new() } + } + + pub fn line(&mut self, line: &str) { + self.inner += " "; + self.inner += line; + self.inner.push('\n'); + } + + pub fn toplevel(&mut self, line: &str) { + self.inner += line; + self.inner.push('\n'); + } + + pub fn other(&mut self, other: &str) { + self.inner += other; + } + + pub fn finish(self) -> String { + self.inner + } +} \ No newline at end of file diff --git a/src/root/assembler/mod.rs b/src/root/assembler/mod.rs index e69de29..4bf604d 100644 --- a/src/root/assembler/mod.rs +++ b/src/root/assembler/mod.rs @@ -0,0 +1 @@ +pub mod assembly_builder; \ No newline at end of file diff --git a/src/root/builtin/mod.rs b/src/root/builtin/mod.rs index d278c39..5ada487 100644 --- a/src/root/builtin/mod.rs +++ b/src/root/builtin/mod.rs @@ -2,6 +2,7 @@ pub mod types; pub mod functions; use crate::root::builtin::functions::register_functions; +use crate::root::builtin::types::bool::register_bool; use crate::root::builtin::types::int::register_int; use crate::root::compiler::global_tracker::GlobalTracker; use crate::root::errors::WErr; @@ -13,6 +14,7 @@ use crate::root::shared::types::Type; pub fn register_builtin(global_table: &mut GlobalDefinitionTable) { register_functions(global_table); register_int(global_table); + register_bool(global_table); } pub type InlineFunctionGenerator = fn(&[LocalAddress], Option, &mut GlobalTracker, ByteSize) -> String; diff --git a/src/root/builtin/types/bool/mod.rs b/src/root/builtin/types/bool/mod.rs new file mode 100644 index 0000000..86ec615 --- /dev/null +++ b/src/root/builtin/types/bool/mod.rs @@ -0,0 +1,59 @@ +mod printb; + +use b_box::b; +use unique_type_id::UniqueTypeId; +use crate::root::builtin::t_id; +use crate::root::builtin::types::bool::printb::PrintB; +use crate::root::errors::WErr; +use crate::root::name_resolver::name_resolvers::GlobalDefinitionTable; +use crate::root::parser::parse_function::parse_literal::{LiteralToken, LiteralTokens}; +use crate::root::shared::common::{ByteSize, LocalAddress, TypeID}; +use crate::root::shared::types::Type; + +pub fn register_bool(global_table: &mut GlobalDefinitionTable) { + global_table.register_builtin_type(b!(BoolType)); + global_table.register_inline_function(&PrintB); +} + +#[derive(UniqueTypeId)] +#[UniqueTypeIdType = "u16"] +pub struct BoolType; + +impl BoolType { + pub const fn id() -> TypeID { + t_id(BoolType::unique_type_id().0) + } +} + +impl Type for BoolType { + fn id(&self) -> TypeID { Self::id() } + + fn size(&self) -> ByteSize { + ByteSize(1) + } + + fn name(&self) -> &str { + "bool" + } + + fn instantiate_from_literal(&self, location: &LocalAddress, literal: &LiteralToken) -> Result { + Ok(match literal.literal() { + LiteralTokens::Bool(value) => { + if *value { + format!(" mov byte {location}, 1\n") + } + else { + format!(" mov byte {location}, 0\n") + } + } + LiteralTokens::Int(value) => { + if *value == 0 { + format!(" mov byte {location}, 0\n") + } + else { + format!(" mov byte {location}, 1\n") + } + } + }) + } +} diff --git a/src/root/builtin/types/bool/printb.rs b/src/root/builtin/types/bool/printb.rs new file mode 100644 index 0000000..c195478 --- /dev/null +++ b/src/root/builtin/types/bool/printb.rs @@ -0,0 +1,63 @@ +use unique_type_id::UniqueTypeId; +use crate::root::builtin::{BuiltinInlineFunction, f_id, InlineFunctionGenerator}; +use crate::root::builtin::types::bool::BoolType; +use crate::root::builtin::types::int::IntType; +use crate::root::errors::WErr; +use crate::root::name_resolver::name_resolvers::NameResult::Function; +use crate::root::name_resolver::resolve_function_signatures::FunctionSignature; + +use crate::root::shared::common::{FunctionID, Indirection, LocalAddress, TypeID, TypeRef}; + +#[derive(UniqueTypeId)] +#[UniqueTypeIdType = "u16"] +pub struct PrintB; + +impl PrintB { + pub const fn id() -> FunctionID { + f_id(PrintB::unique_type_id().0) + } +} + +impl BuiltinInlineFunction for PrintB { + fn id(&self) -> FunctionID { + Self::id() + } + + fn name(&self) -> &'static str { + "printb" + } + + fn signature(&self) -> FunctionSignature { + FunctionSignature::new_inline_builtin( + false, + &[("lhs", BoolType::id().immediate())], + None + ) + } + + fn inline(&self) -> InlineFunctionGenerator { + |args: &[LocalAddress], _, gt, sz| -> String { + let id = format!("{}_fstr", Self::id().string_id()); + + let data = format!("{id} db `Boolean: %d\\n`,0"); + + gt.add_readonly_data(&id, &data); + + let lhs = args[0]; + format!( +" mov rdi, {id} + mov rsi, 0 + mov sil, {lhs} + mov al, 0 + sub rsp, {sz} + extern printf + call printf + add rsp, {sz} +") + } + } + + fn parent_type(&self) -> Option { + None + } +} diff --git a/src/root/builtin/types/int/mod.rs b/src/root/builtin/types/int/mod.rs index 55a2925..078ddf8 100644 --- a/src/root/builtin/types/int/mod.rs +++ b/src/root/builtin/types/int/mod.rs @@ -49,14 +49,14 @@ impl Type for IntType { Ok(match literal.literal() { LiteralTokens::Bool(value) => { if *value { - format!(" mov qword {location}, 0") + format!(" mov qword {location}, 0\n") } else { - format!(" mov qword {location}, 1") + format!(" mov qword {location}, 1\n") } } LiteralTokens::Int(value) => { - format!(" mov qword {location}, {value}") + format!(" mov qword {location}, {value}\n") } }) } diff --git a/src/root/builtin/types/int/printi.rs b/src/root/builtin/types/int/printi.rs index 3b6b02d..45cb4fc 100644 --- a/src/root/builtin/types/int/printi.rs +++ b/src/root/builtin/types/int/printi.rs @@ -36,8 +36,6 @@ impl BuiltinInlineFunction for PrintI { fn inline(&self) -> InlineFunctionGenerator { |args: &[LocalAddress], _, gt, sz| -> String { - let lhs = &args[0]; - let id = format!("{}_fstr", Self::id().string_id()); let data = format!("{id} db `Integer: %d\\n`,0"); @@ -46,15 +44,14 @@ impl BuiltinInlineFunction for PrintI { let lhs = args[0]; format!( - " - mov rdi, {id} +" mov rdi, {id} mov rsi, {lhs} mov al, 0 sub rsp, {sz} extern printf call printf add rsp, {sz} - ") +") } } diff --git a/src/root/builtin/types/mod.rs b/src/root/builtin/types/mod.rs index 8aa5d8f..f2fe61d 100644 --- a/src/root/builtin/types/mod.rs +++ b/src/root/builtin/types/mod.rs @@ -1 +1,2 @@ pub mod int; +pub mod bool; \ No newline at end of file diff --git a/src/root/compiler/assembly/utils.rs b/src/root/compiler/assembly/utils.rs index 47bb6bc..f75a17f 100644 --- a/src/root/compiler/assembly/utils.rs +++ b/src/root/compiler/assembly/utils.rs @@ -1,4 +1,5 @@ use std::fmt::format; +use crate::root::assembler::assembly_builder::AssemblyBuilder; use crate::root::shared::common::{ByteSize, FunctionID, LocalAddress}; @@ -82,36 +83,34 @@ pub fn copy(from: LocalAddress, to: LocalAddress, amount: ByteSize) -> String { let to = to.0; let mut written = 0; - let mut output = String::new(); + let mut output = AssemblyBuilder::new(); loop { let to_write = amount.0 - written; if to_write >= 8 { - output += &format!(" mov rax, qword {}\n", LocalAddress(from + written as isize)); - output += &format!(" mov qword {}, rax", &LocalAddress(to + written as isize)); + output.line(&format!("mov rax, qword {}", LocalAddress(from + written as isize))); + output.line(&format!("mov qword {}, rax", &LocalAddress(to + written as isize))); written += 8; } else if to_write >= 4 { - output += &format!(" mov rax, dword {}\n", LocalAddress(from + written as isize)); - output += &format!(" mov dword {}, rax", &LocalAddress(to + written as isize)); + output.line(&format!("mov eax, dword {}", LocalAddress(from + written as isize))); + output.line(&format!("mov dword {}, eax", &LocalAddress(to + written as isize))); written += 4; } else if to_write >= 2 { - output += &format!(" mov rax, word {}\n", LocalAddress(from + written as isize)); - output += &format!(" mov word {}, rax", &LocalAddress(to + written as isize)); + output.line(&format!("mov ax, word {}", LocalAddress(from + written as isize))); + output.line(&format!("mov word {}, ax", &LocalAddress(to + written as isize))); written += 2; } else if to_write >= 1 { - output += &format!(" mov rax, byte {}\n", LocalAddress(from + written as isize)); - output += &format!(" mov byte {}, rax", &LocalAddress(to + written as isize)); + output.line(&format!("mov al, byte {}", LocalAddress(from + written as isize))); + output.line(&format!("mov byte {}, al", &LocalAddress(to + written as isize))); written += 1; } else { break; } if written == amount.0 { break; } - output += "\n"; } - - output + output.finish() } \ No newline at end of file diff --git a/src/root/compiler/compile.rs b/src/root/compiler/compile.rs index 42a077e..da01c20 100644 --- a/src/root/compiler/compile.rs +++ b/src/root/compiler/compile.rs @@ -53,7 +53,7 @@ section .text } if !global_tracker.readonly_data_section().is_empty() { - s += "section .data"; + s += "section .data_readonly"; s += global_tracker.readonly_data_section(); } diff --git a/src/root/compiler/compile_evaluable.rs b/src/root/compiler/compile_evaluable.rs index d19542e..3099733 100644 --- a/src/root/compiler/compile_evaluable.rs +++ b/src/root/compiler/compile_evaluable.rs @@ -111,8 +111,6 @@ pub fn compile_evaluable_into( t.instantiate_from_literal(target.local_address(), literal)? } EvaluableTokens::InfixOperator(lhs, op, rhs) => { - let mut code = String::new(); - let lhs_type = compile_evaluable_type_only(fid, lhs, local_variables, global_table, global_tracker)?; let op_fn = global_table.get_operator_function(*lhs_type.type_id(), op, PrefixOrInfixEx::Infix)?; let signature = global_table.get_function_signature(op_fn); @@ -144,13 +142,9 @@ pub fn compile_evaluable_into( let (c, _) = call_function(fid, op_fn, &[Left(lhs), Left(rhs)], Some(target), global_table, local_variables, global_tracker)?; - code += &c; - - code + c }, EvaluableTokens::PrefixOperator(op, lhs) => { - let mut code = String::new(); - let lhs_type = compile_evaluable_type_only(fid, lhs, local_variables, global_table, global_tracker)?; let op_fn = global_table.get_operator_function(*lhs_type.type_id(), op, PrefixOrInfixEx::Prefix)?; let signature = global_table.get_function_signature(op_fn); @@ -181,10 +175,7 @@ pub fn compile_evaluable_into( } let (c, _) = call_function(fid, op_fn, &[Left(lhs)], Some(target), global_table, local_variables, global_tracker)?; - - code += &c; - - code + c }, EvaluableTokens::DynamicAccess(_, _) => todo!(), // Accessed methods must be called EvaluableTokens::StaticAccess(_, n) => return Err(WErr::n(NRErrors::CannotFindConstantAttribute(n.name().clone()), n.location().clone())), // Accessed methods must be called @@ -225,7 +216,7 @@ pub fn compile_evaluable_reference( NameResult::Function(_) => return Err(WErr::n(EvalErrs::FunctionMustBeCalled(name.name().clone()), name.location().clone())), NameResult::Type(_) => return Err(WErr::n(EvalErrs::CannotEvalStandaloneType(name.name().clone()), name.location().clone())), NameResult::Variable(address) => { - ("".to_string(), Some(address)) + (String::new(), Some(address)) } } }, diff --git a/src/root/compiler/compile_function.rs b/src/root/compiler/compile_function.rs index 79e3ad3..bf50186 100644 --- a/src/root/compiler/compile_function.rs +++ b/src/root/compiler/compile_function.rs @@ -1,4 +1,7 @@ use std::collections::HashSet; +use std::fmt::format; +use crate::root::assembler::assembly_builder::AssemblyBuilder; +use crate::root::builtin::types::bool::BoolType; use crate::root::builtin::types::int::IntType; use crate::root::compiler::assembly::utils::{align_16_bytes, align_16_bytes_plus_8}; use crate::root::compiler::compile_evaluable::{compile_evaluable, compile_evaluable_into, compile_evaluable_reference}; @@ -51,24 +54,21 @@ pub fn compile_function(fid: FunctionID, function: FunctionToken, global_table: "{}: push rbp mov rbp, rsp - {}", +{}", fid.string_id(), full_contents ); // if fid.is_main() { - final_contents += "\n\tleave\n\tret"; + // final_contents += "\n\tleave\n\tret"; // } Ok(final_contents) } fn recursively_compile_lines(fid: FunctionID, lines: &[LineTokens], return_variable: &Option, local_variables: &mut LocalVariableTable, global_table: &mut GlobalDefinitionTable, global_tracker: &mut GlobalTracker) -> Result { - for i in lines { - println!("{:#?}", i); - } local_variables.enter_block(); - let mut contents = String::new(); + let mut contents = AssemblyBuilder::new(); let mut last_is_return = false; @@ -78,11 +78,30 @@ fn recursively_compile_lines(fid: FunctionID, lines: &[LineTokens], return_varia LineTokens::Initialisation(it) => { let (name, type_name, value) = (it.name(), it.type_name(), it.value()); let address = global_table.add_local_variable_named(name.name().clone(), type_name, local_variables)?; - contents += "\n"; - contents += &compile_evaluable_into(fid, value, address, local_variables, global_table, global_tracker)?; + contents.other(&compile_evaluable_into(fid, value, address, local_variables, global_table, global_tracker)?); }, LineTokens::Assignment(_) => todo!(), - LineTokens::If(_) => todo!(), + LineTokens::If(if_token) => { + let condition_addr = global_table.add_local_variable_unnamed_base(BoolType::id().immediate(), local_variables); + contents.other(&compile_evaluable_into(fid, if_token.if_condition(), condition_addr.clone(), local_variables, global_table, global_tracker)?); + contents.line(&format!("cmp byte {}, 0", condition_addr.local_address())); + + let end_if_tag = global_tracker.get_unique_tag(fid); + contents.line(&format!("jz {end_if_tag}")); + contents.other(&recursively_compile_lines(fid, if_token.if_contents(), &None, local_variables, global_table, global_tracker)?); + + if let Some(else_contents) = if_token.else_contents() { + let end_else_tag = global_tracker.get_unique_tag(fid); + contents.line(&format!("jmp {end_else_tag}")); + contents.line(&format!("{end_if_tag}:")); + contents.other(&recursively_compile_lines(fid, else_contents, &None, local_variables, global_table, global_tracker)?); + contents.line(&format!("{end_else_tag}:")); + } + else { + contents.line(&format!("{end_if_tag}:")); + } + + }, LineTokens::While(_) => todo!(), LineTokens::Return(rt) => { last_is_return = true; @@ -92,10 +111,8 @@ fn recursively_compile_lines(fid: FunctionID, lines: &[LineTokens], return_varia } let address = global_table.add_local_variable_unnamed_base(TypeRef::new(IntType::id(), Indirection(0)), local_variables); - let code = compile_evaluable_into(fid, rt.return_value().as_ref().unwrap(), address.clone(), local_variables, global_table, global_tracker)?; - contents += "\n"; - contents += &code; - contents += &format!("\n\tmov rax, qword {}", address.local_address()); + contents.other(&compile_evaluable_into(fid, rt.return_value().as_ref().unwrap(), address.clone(), local_variables, global_table, global_tracker)?); + contents.line(&format!("mov rax, qword {}", address.local_address())); } else { if let Some(return_value) = rt.return_value() { @@ -103,33 +120,26 @@ fn recursively_compile_lines(fid: FunctionID, lines: &[LineTokens], return_varia todo!() } - let code = compile_evaluable_into(fid, return_value, return_variable.clone().unwrap(), local_variables, global_table, global_tracker)?; - contents += "\n"; - contents += &code; + contents.other(&compile_evaluable_into(fid, return_value, return_variable.clone().unwrap(), local_variables, global_table, global_tracker)?); } else { if return_variable.is_some() { todo!() } } - - contents += "\n leave"; - contents += "\n ret"; } + + contents.line("leave"); + contents.line("ret"); } LineTokens::Break(_) => todo!(), LineTokens::NoOp(et) => { - contents += "\n"; - contents += &compile_evaluable_reference(fid, et, local_variables, global_table, global_tracker)?.0; + contents.other(&compile_evaluable_reference(fid, et, local_variables, global_table, global_tracker)?.0); } } } - if (return_variable.is_some() || fid.is_main()) && !last_is_return { - todo!() - } - local_variables.leave_block(); - Ok(contents) + Ok(contents.finish()) } \ No newline at end of file diff --git a/src/root/compiler/compile_function_call.rs b/src/root/compiler/compile_function_call.rs index 682b5b7..aed95d0 100644 --- a/src/root/compiler/compile_function_call.rs +++ b/src/root/compiler/compile_function_call.rs @@ -1,6 +1,7 @@ use std::collections::HashSet; use either::Either; use itertools::Itertools; +use crate::root::assembler::assembly_builder::AssemblyBuilder; use crate::root::compiler::assembly::utils::{align_16_bytes, align_16_bytes_plus_8, copy}; use crate::root::compiler::compile_evaluable::{compile_evaluable, compile_evaluable_into}; use crate::root::compiler::global_tracker::GlobalTracker; @@ -29,7 +30,7 @@ pub fn call_function( let inline_o = inline.clone(); - let mut code = String::new(); + let mut code = AssemblyBuilder::new(); let return_into = if let Some(expected_return) = global_table.get_function(fid).0.return_type().clone() { if let Some(return_address) = return_address { @@ -59,12 +60,7 @@ pub fn call_function( Either::Left(eval) => { let into = global_table.add_local_variable_unnamed_base(signature_args[i].clone(), local_variables); let c = compile_evaluable_into(parent_fid, eval, into.clone(), local_variables, global_table, global_tracker)?; - - if i != 0 { - code += "\n"; - } - - code += &c; + code.other(&c); args.push(*into.local_address()); } Either::Right(addr) => { @@ -74,12 +70,11 @@ pub fn call_function( } } - code += "\n"; - code += &inline_o(&args, return_into.as_ref().map(|x| *x.local_address()), global_tracker, local_variables.stack_size()); - Ok((code, return_into)) + code.other(&inline_o(&args, return_into.as_ref().map(|x| *x.local_address()), global_tracker, local_variables.stack_size())); + Ok((code.finish(), return_into)) } else { - let mut code = String::new(); + let mut code = AssemblyBuilder::new(); // TODO: Check args length let mut args = Vec::new(); @@ -92,10 +87,7 @@ pub fn call_function( let into = global_table.add_local_variable_unnamed_base(signature_args[i].clone(), local_variables); size += global_table.get_size(into.type_ref()); let c = compile_evaluable_into(parent_fid, eval, into.clone(), local_variables, global_table, global_tracker)?; - if i != 0 { - code += "\n"; - } - code += &c; + code.other(&c); args.push(into); } Either::Right(addr) => { @@ -131,13 +123,12 @@ pub fn call_function( // ? Arguments for arg in args.iter().rev() { let into = global_table.add_local_variable_unnamed_base(arg.type_ref().clone(), local_variables); - code += "\n"; - code += ©(*arg.local_address(), *into.local_address(), global_table.get_size(into.type_ref())); + code.other(©(*arg.local_address(), *into.local_address(), global_table.get_size(into.type_ref()))); } - code += &format!("\n sub rsp, {}", local_variables.stack_size().0); - code += &format!("\n call {}", fid.string_id()); - code += &format!("\n add rsp, {}", local_variables.stack_size().0); + code.line(&format!("sub rsp, {}", local_variables.stack_size().0)); + code.line(&format!("call {}", fid.string_id())); + code.line(&format!("add rsp, {}", local_variables.stack_size().0)); // ? Leave block (invalidate parameters) local_variables.leave_block(); @@ -147,14 +138,13 @@ pub fn call_function( todo!() } - code += "\n"; - code += ©(*return_addr.as_ref().unwrap().local_address(), *return_address.local_address(), global_table.get_size(return_addr.as_ref().unwrap().type_ref())); + code.other(©(*return_addr.as_ref().unwrap().local_address(), *return_address.local_address(), global_table.get_size(return_addr.as_ref().unwrap().type_ref()))); Some(return_address) } else { return_addr }; - Ok((code, return_addr)) + Ok((code.finish(), return_addr)) } } \ No newline at end of file diff --git a/src/root/compiler/global_tracker.rs b/src/root/compiler/global_tracker.rs index 898c076..4749d7b 100644 --- a/src/root/compiler/global_tracker.rs +++ b/src/root/compiler/global_tracker.rs @@ -6,7 +6,8 @@ use crate::root::shared::common::FunctionID; pub struct GlobalTracker { function_calls: HashSet, readonly_contents: HashSet, - readonly_data_section: String + readonly_data_section: String, + unique_tag_counter: usize } impl GlobalTracker { @@ -29,4 +30,10 @@ impl GlobalTracker { self.readonly_data_section += data; } } + + pub fn get_unique_tag(&mut self, function: FunctionID) -> String { + let r = format!("{}_{}", function.string_id(), self.unique_tag_counter); + self.unique_tag_counter += 1; + r + } } \ No newline at end of file diff --git a/src/root/parser/parse_function/parse_if.rs b/src/root/parser/parse_function/parse_if.rs index 14c919b..6ef0755 100644 --- a/src/root/parser/parse_function/parse_if.rs +++ b/src/root/parser/parse_function/parse_if.rs @@ -1,4 +1,4 @@ - +use derive_getters::Getters; use nom::sequence::Tuple; use nom_supreme::tag::complete::tag; @@ -9,7 +9,7 @@ use crate::root::parser::parse_function::parse_line::{parse_lines, LineTestFn, L use crate::root::parser::parse_name::SimpleNameToken; use crate::root::parser::parse_util::{discard_ignored, require_ignored}; -#[derive(Debug)] +#[derive(Debug, Getters)] pub struct IfToken { location: Location, if_condition: EvaluableToken, diff --git a/test/test.asm b/test/test.asm new file mode 100644 index 0000000..e668ed3 --- /dev/null +++ b/test/test.asm @@ -0,0 +1,60 @@ + global main + +section .text + +main: + push rbp + mov rbp, rsp + + mov qword [rbp-8], 3 + mov qword [rbp-16], 4 + + mov rax, qword [rbp-16] + leave + ret + + mov qword [rbp-17], 0 + mov al, byte [rbp-17] + mov byte [rbp-18], al + cmp byte [rbp-18], 0 + + + + jz main_0 + + mov rax, qword [rbp-8] + mov qword [rbp-26], rax + + mov rdi, __4_fstr + mov rsi, [rbp-26] + mov al, 0 + sub rsp, 26 + extern printf + call printf + add rsp, 26 + + mov qword [rbp-34], 13 + mov rax, qword [rbp-34] + leave + ret + jmp main_1 + main_0: + mov rax, qword [rbp-16] + mov qword [rbp-26], rax + + mov rdi, __4_fstr + mov rsi, [rbp-26] + mov al, 0 + sub rsp, 26 + extern printf + call printf + add rsp, 26 + + mov qword [rbp-34], 12 + mov rax, qword [rbp-34] + leave + ret + main_1: + +section .data + __4_fstr db `Integer: %d\n`,0 \ No newline at end of file diff --git a/types.toml b/types.toml deleted file mode 100644 index 684024f..0000000 --- a/types.toml +++ /dev/null @@ -1,20 +0,0 @@ -IntType=0 -IntAdd=1 -IntSub=2 -IntPSub=3 -P=4 -Pr=5 -Pri=6 -Prin=7 -Print=8 -PrintI=9 -E=10 -Ex=11 -Exi=12 -Exit=13 -ExitF=14 -ExitFu=15 -ExitFun=16 -ExitFunctio=17 -ExitFunction=18 -ExitFunctions=19