diff --git a/Cargo.lock b/Cargo.lock index 1cedf96b..51c8e9be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,6 +362,13 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "ycc" +version = "0.1.0" +dependencies = [ + "ygen", +] + [[package]] name = "ygen" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index dee4cb53..00cf60da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ members = [ "tools/simplelang", "tools/ytest", "tools/ylc", - "src/proc", + "src/proc", "tools/ycc", ] [workspace.dependencies] diff --git a/src/Target/mod.rs b/src/Target/mod.rs index 4422d9f7..447581ea 100644 --- a/src/Target/mod.rs +++ b/src/Target/mod.rs @@ -4,6 +4,7 @@ pub mod x64; pub mod wasm; mod registry; mod whitelist; + pub use x64::initializeX64Target; pub use wasm::initializeWasmTarget; pub use whitelist::*; @@ -318,4 +319,151 @@ pub enum ObjFormat { XCoff, /// Platforms default (e.g: Windows -> Coff) Default -} \ No newline at end of file +} + +impl std::fmt::Display for Arch { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + Arch::Unknown => "unknown", + Arch::Arm => "arm", + Arch::ArmEB => "armeb", + Arch::Aarch64 => "aarch64", + Arch::Aarch64BE => "aarch64_be", + Arch::Arc => "arc", + Arch::Avr => "avr", + Arch::Bpfel => "bpfel", + Arch::Bpfeb => "bpfeb", + Arch::Hexagon => "hexagon", + Arch::Mips => "mips", + Arch::Mipsel => "mipsel", + Arch::Mips64 => "mips64", + Arch::Mips64EL => "mips64el", + Arch::Msp420 => "msp430", + Arch::Ppc => "ppc", + Arch::Ppc64 => "ppc64", + Arch::Ppc64LE => "ppc64le", + Arch::R600 => "r600", + Arch::AmdGCN => "amdgcn", + Arch::Riscv32 => "riscv32", + Arch::Riscv64 => "riscv64", + Arch::Sparc => "sparc", + Arch::Sparcv9 => "sparcv9", + Arch::Sparcel => "sparcel", + Arch::SystemZ => "systemz", + Arch::Tce => "tce", + Arch::TceLe => "tcele", + Arch::Thumb => "thumb", + Arch::Thumbeb => "thumbeb", + Arch::X86 => "x86", + Arch::X86_64 => "x86_64", + Arch::Xcore => "xcore", + Arch::Nvptx => "nvptx", + Arch::Nvptx64 => "nvptx64", + Arch::Le32 => "le32", + Arch::Le64 => "le64", + Arch::AmdIL => "amdil", + Arch::AmdIL64 => "amdil64", + Arch::Hsail => "hsail", + Arch::Hsail64 => "hsail64", + Arch::Spir => "spir", + Arch::Spir64 => "spir64", + Arch::Kalimba => "kalimba", + Arch::Shave => "shave", + Arch::Lanai => "lanai", + Arch::Wasm32 => "wasm32", + Arch::Wasm64 => "wasm64", + Arch::Renderscript32 => "renderscript32", + Arch::Renderscript64 => "renderscript64", + }) + } +} + +impl std::fmt::Display for Vendor { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + Vendor::Unknown => "unknown", + Vendor::Apple => "apple", + Vendor::Pc => "pc", + Vendor::Scei => "scei", + Vendor::Bgp => "bgp", + Vendor::Freescale => "freescale", + Vendor::Ibm => "ibm", + Vendor::ImaginationTechnologies => "imagination", + Vendor::MipsTechnologies => "mips", + Vendor::Nvidia => "nvidia", + Vendor::Csr => "csr", + Vendor::Myriad => "myriad", + Vendor::Amd => "amd", + Vendor::Mesa => "mesa", + Vendor::Suse => "suse", + Vendor::OpenEmbedded => "oe", + }) + } +} +impl std::fmt::Display for OS { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + OS::Unknown => "unknown", + OS::Ananas => "ananas", + OS::CloudABI => "cloudabi", + OS::Darwin => "darwin", + OS::DragonFly => "dragonfly", + OS::FreeBSD => "freebsd", + OS::Fuchsia => "fuchsia", + OS::Ios => "ios", + OS::KFreeBSD => "kfreebsd", + OS::Linux => "linux", + OS::Lv2 => "lv2", + OS::MacOS => "macos", + OS::NetBSD => "netbsd", + OS::OpenBSD => "openbsd", + OS::Solaris => "solaris", + OS::Win32 => "windows", + OS::Haiku => "haiku", + OS::Minix => "minix", + OS::Rtems => "rtems", + OS::NaCl => "nacl", + OS::Cnk => "cnk", + OS::Aix => "aix", + OS::Cuda => "cuda", + OS::Nvcl => "nvcl", + OS::AmdHSA => "amdhsa", + OS::Ps4 => "ps4", + OS::ElfIAMCU => "elfiamcu", + OS::TvOS => "tvos", + OS::WatchOS => "watchos", + OS::Mesa3D => "mesa3d", + OS::Contiki => "contiki", + OS::AmdPAL => "amdpal", + OS::HermitCore => "hermitcore", + OS::Hurd => "hurd", + OS::Wasi => "wasi", + }) + } +} + +impl std::fmt::Display for Environment { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + Environment::Unknown => "unknown", + Environment::Gnu => "gnu", + Environment::GnuABIN32 => "gnun32", + Environment::GnuABI64 => "gnuabi64", + Environment::GnuEABI => "gnueabi", + Environment::GnuEABIHF => "gnueabihf", + Environment::GnuX32 => "gnux32", + Environment::Code16 => "code16", + Environment::Eabi => "eabi", + Environment::EabiHF => "eabihf", + Environment::Android => "android", + Environment::Musl => "musl", + Environment::MuslEABI => "musleabi", + Environment::MuslEABIHF => "musleabihf", + Environment::Msvc => "msvc", + Environment::Itanium => "itanium", + Environment::Cygnus => "cygnus", + Environment::CoreCLR => "coreclr", + Environment::Simulator => "simulator", + }) + } +} diff --git a/src/Target/triple.rs b/src/Target/triple.rs index d29a11c1..c72d10d0 100644 --- a/src/Target/triple.rs +++ b/src/Target/triple.rs @@ -49,6 +49,21 @@ impl Display for TripleError { impl Error for TripleError {} +impl Display for Triple { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut vendor = format!("-{}", self.vendor); + if self.vendor == Vendor::Unknown { vendor = String::new() }; + + let mut os = format!("-{}", self.os); + if self.os == OS::Unknown { os = String::new() }; + + let mut env = format!("-{}", self.env); + if self.env == Environment::Unknown { env = String::new() }; + + write!(f, "{}{}{}{}", self.arch, vendor, os, env) + } +} + impl Triple { /// Parses the target triple string. /// Returns the target triple or TripleError diff --git a/tools/ycc/Cargo.toml b/tools/ycc/Cargo.toml new file mode 100644 index 00000000..ee03cc1c --- /dev/null +++ b/tools/ycc/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "ycc" +version = "0.1.0" +edition = "2021" + +[dependencies] +ygen = { workspace = true } \ No newline at end of file diff --git a/tools/ycc/src/ast.rs b/tools/ycc/src/ast.rs new file mode 100644 index 00000000..e69de29b diff --git a/tools/ycc/src/codegen.rs b/tools/ycc/src/codegen.rs new file mode 100644 index 00000000..e69de29b diff --git a/tools/ycc/src/error.rs b/tools/ycc/src/error.rs new file mode 100644 index 00000000..7727bd64 --- /dev/null +++ b/tools/ycc/src/error.rs @@ -0,0 +1,32 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ErrorLoc { + pub line: u64, + pub col: u64, + pub length: u64, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct YccError { + loc: ErrorLoc, + + head: &'static str, + + where_string: String, +} + +impl YccError { + pub fn print(&self, code: &str, file_name: &str) { + let mut fab = ygen::Support::Error::new( + self.head, + file_name, + self.loc.line.to_string(), + self.loc.col.to_string() + ); + + fab.setCodeLine(code.to_string()); + + fab.addWhere(self.where_string.to_owned(), self.loc.col, self.loc.length); + + fab.print(); + } +} \ No newline at end of file diff --git a/tools/ycc/src/lexer.rs b/tools/ycc/src/lexer.rs new file mode 100644 index 00000000..a881b9a8 --- /dev/null +++ b/tools/ycc/src/lexer.rs @@ -0,0 +1,232 @@ +use crate::error::{ErrorLoc, YccError}; + +#[derive(Debug, Clone)] +pub enum TokenType { + /// ; + Semicolon, + /// = + Equal, + /// += + AddEqual, + /// -= + SubEqual, + /// *= + MulEqual, + /// /= + DivEqual, + /// %= + ModEqual, + /// ^= + XorEqual, + /// |= + OrEqual, + /// &= + AndEqual, + /// != + NotEqual, + /// == + EqualEqual, + /// + + Add, + /// - + Sub, + /// * + Mul, + /// / + Div, + /// % + Mod, + /// ^ + Xor, + /// | + Or, + /// & + And, + /// ! + Not, + /// unsigned + Unsigned, + /// signed + Signed, + /// char + Char, + /// bool + Bool, + /// short + Short, + /// int + Int, + /// Long + Long, + /// float + Float, + /// double + Double, + /// void + Void, + /// ( + LeftParan, + /// ) + RightParan, + /// , + Comma, + /// { + LeftBracket, + /// } + RightBracket, + /// if + If, + /// else + Else, + /// do + Do, + /// goto + Goto, + /// switch + Switch, + /// case + Case, + /// default + Default, + /// break + Break, + /// continue + Continue, + /// return + Return, + /// > + Bigger, + /// < + Smaller, + /// >= + BiggerOrEqual, + /// <= + SmallerOrEqual, + /// ++ + PlusPlus, + /// -- + SubSub, + /// << + ShiftLeft, + /// >> + ShiftRight, + /// <<= + ShiftLeftEqual, + /// >>= + ShiftRightEqual, + /// && + AndAnd, + /// || + OrOr, + /// ~ + BitwiseNot, + /// [ + LeftSquare, + /// ] + RightSquare, + /// const + Const, + /// enum + Enum, + /// struct + Struct, + /// union + Union, + /// typedef + Typedef, + /// sizeof + Sizeof, + /// extern + Extern, + /// static + Static, + /// Register + Register, + /// volatile + Volatile, + /// auto + Auto, + + /// Identifer + Ident(String), + /// Intenger literal + IntLiteral(i64), + /// Float literal + FloatLiteral(f64), + /// String literal + StringLiteral(String), + /// Char literal + CharLiteral(char), +} + +impl PartialEq for TokenType { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Ident(l0), Self::Ident(r0)) => l0 == r0, + (Self::IntLiteral(l0), Self::IntLiteral(r0)) => l0 == r0, + (Self::FloatLiteral(l0), Self::FloatLiteral(r0)) => l0 == r0, + (Self::StringLiteral(l0), Self::StringLiteral(r0)) => l0 == r0, + (Self::CharLiteral(l0), Self::CharLiteral(r0)) => l0 == r0, + _ => core::mem::discriminant(self) == core::mem::discriminant(other), + } + } +} + +impl Eq for TokenType {} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Token { + pub ty: TokenType, + pub pos: ErrorLoc, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Lexer<'a> { + tokens: Vec, + + line: u64, + col: u64, + + start: u64, + current: u64, + + code: &'a str, + + pub errors: Vec, + critical_error: bool, +} + +impl<'a> Lexer<'a> { + pub fn new(code: &'a str) -> Self { + Self { + tokens: Vec::new(), + line: 0, + col: 0, + start: 0, + current: 0, + code: code, + errors: Vec::new(), + critical_error: false, + } + } + + pub fn lex(&mut self) { + while !self.is_at_end() { + self.start = self.current; + + self.scan_token(); + + if self.critical_error { + break; + } + } + } + + fn scan_token(&mut self) { + todo!() + } + + fn is_at_end(&self) -> bool { + self.current == self.code.chars().count() as u64 + } +} \ No newline at end of file diff --git a/tools/ycc/src/main.rs b/tools/ycc/src/main.rs new file mode 100644 index 00000000..03d0b3f9 --- /dev/null +++ b/tools/ycc/src/main.rs @@ -0,0 +1,93 @@ +use ygen::{Support::Cli, Target::Triple}; + +mod ast; +mod codegen; +mod error; +mod lexer; +mod parser; +mod utils; + +fn main() { + let mut cli = Cli::new("ycc", "Ygens c compiler", "(latest)", "Cr0a3"); + + // Standart stuff + + cli.add_opt("h", "help", "Displays help"); + cli.add_opt("v", "version", "Displays the version"); + cli.add_opt("vv", "vversion", "Displays the version with more information"); + + // Files + + cli.add_arg("in", "input", "The input-file path", true); + + cli.add_arg("o", "out", "The output path", false); + + // Target + + cli.add_arg("triple", "triple", "The target triple (same as -target=...)", false); + cli.add_arg("target", "target", "The target triple (same as -triple=...)", false); + + // Output + + cli.add_opt("S", "asm", "Outputs assembly code"); + cli.add_opt("emit-ir", "emit-ir", "Outputs ygen ir"); + + // Optimization + + cli.add_opt("O0", "no-opt", "Disables all optimizations"); + cli.add_opt("O3", "max-opt", "Activates all optimizations"); + cli.add_arg("p", "passes", "The optimization passes to run", false); + + cli.scan(); + + if cli.opt("h") { + cli.help(); + } else if cli.opt("v") { + cli.version(); + } else if cli.opt("vv") { // verbose version information + println!("ycc v(latest) (c) Cr0a3"); + println!("Host-Target: {}", Triple::host()); + } + + let triple = { + if let Some(triple) = cli.arg_val("triple") { + match Triple::parse(&triple) { + Ok(triple) => triple, + Err(err) => { + println!("Error: {}", err); + std::process::exit(-1); + }, + } + } else { + Triple::host() + } + }; + + let infile = cli.arg_val("in").unwrap(); + + let code = utils::read_in_file(&infile); + let out = utils::out_file(&infile, cli.arg_val("out")); + + ///////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////// + // + // Lexing Phase + // + ///////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////// + + let mut lexer = lexer::Lexer::new(&code); + + lexer.lex(); + + let encountered_errors = lexer.errors.len() > 0; + + for error in lexer.errors { + error.print(&code, &infile); + } + + if encountered_errors { + std::process::exit(-1); + } + +} diff --git a/tools/ycc/src/parser.rs b/tools/ycc/src/parser.rs new file mode 100644 index 00000000..e69de29b diff --git a/tools/ycc/src/utils.rs b/tools/ycc/src/utils.rs new file mode 100644 index 00000000..4e2aa53c --- /dev/null +++ b/tools/ycc/src/utils.rs @@ -0,0 +1,53 @@ +use std::fs::File; +use std::io::Read; +use std::process::exit; + +pub fn read_in_file(path: &String) -> String { + let mut infile = match File::open(&path) { + Ok(file) => file, + Err(err) => { + println!("Error: {} {}", path, err); + exit(-1); + }, + }; + + let mut input = String::new(); + match infile.read_to_string(&mut input) { + Ok(_) => {}, + Err(err) => { + println!("Error: {} {}", path, err); + exit(-1); + } + }; + + input +} +pub fn out_file(in_path: &String, out_path: Option) -> File { + let path; + + if let Some(out_path) = out_path { path = out_path } + else { + let file = in_path.split("/").collect::>().last().unwrap_or(&&in_path.as_str()).to_string(); + let slices = file.split(".").collect::>(); + + let mut name = String::new(); + + for slice in &slices { + if slices.last() == Some(slice) { + break; + } + + name.push_str(slice); + } + + path = format!("{}.o", name); + } + + match File::options().create(true).write(true).truncate(true).open(&path) { + Ok(file) => file, + Err(err) => { + println!("Error: {} {}", path, err); + exit(-1); + }, + } +} \ No newline at end of file