From 39b79b8c611ee6ace7773232deff59b9175271d3 Mon Sep 17 00:00:00 2001 From: Natapat Samutpong Date: Thu, 24 Feb 2022 21:45:35 +0700 Subject: [PATCH] bool.h, running clang and clang-format on comp --- Makefile | 4 +++ README.md | 6 ++++- lib/bool.h | 3 +++ src/back/c.rs | 13 +++++++--- src/main.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++------ src/util.rs | 10 ++++++++ 6 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 Makefile create mode 100644 lib/bool.h create mode 100644 src/util.rs diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e96d554 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +# Build the libraries that are used by generated C code. +build_lib: + sudo mkdir -p /usr/include/hycron + sudo cp -r ./lib/* /usr/include/hycron \ No newline at end of file diff --git a/README.md b/README.md index d131744..04ac33e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,11 @@ # Hycron -Programming language +Programming language that compiles to C Note: The syntax can still be changed, if you have an idea, feel free to make an issues about it. +# Prerequistie +- `clang` and `clang-format` +- Rust (if you're going to build from source) + # TODO - Compliation - Optimization diff --git a/lib/bool.h b/lib/bool.h new file mode 100644 index 0000000..1b3abdb --- /dev/null +++ b/lib/bool.h @@ -0,0 +1,3 @@ +#define bool _Bool +#define true 1 +#define false 0 \ No newline at end of file diff --git a/src/back/c.rs b/src/back/c.rs index 2c115ad..8e008cc 100644 --- a/src/back/c.rs +++ b/src/back/c.rs @@ -15,12 +15,19 @@ impl Codegen { self.emitted.push_str(s.as_str()); } + fn emit_str(&mut self, s: &str) { + self.emitted.push_str(s); + } + pub fn gen(&mut self, exprs: &[Expr]) { - self.emit("#include \n#include \nint main() {\n".to_string()); + self.emit_str("#include \n"); + self.emit_str("#include \n"); + self.emit_str("int main() {\n"); for expr in exprs { self.gen_expr(expr); } - self.emit("return 0;\n}\n".to_string()); + self.emit_str("return 0;\n"); + self.emit_str("}\n"); } fn gen_expr(&mut self, expr: &Expr) { @@ -41,7 +48,7 @@ impl Codegen { "print" => { self.emit(format!("printf({});\n", match &args[0] { Expr::String(s) => format!("\"{}\"", s), - Expr::Ident(s) => s.to_string(), + Expr::Ident(s) => format!("\"%s\", {}", s), _ => todo!(), })); }, diff --git a/src/main.rs b/src/main.rs index 7b65804..3e269e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use std::fs; +use std::{fs, io::Write, time, process::Command}; use chumsky::{Parser, Stream}; use clap::Parser as ArgParser; @@ -16,28 +16,84 @@ use front::parse::{lexer, parser}; /// Contains code generator. pub mod back; +pub mod util; +use crate::util::log; + fn main() { let args = Args::parse(); match args.options { - Options::Compile { input: src, ast: _print_ast } => { - let src = fs::read_to_string(src).expect("Failed to read file"); + Options::Compile { input: file_name, ast: _print_ast } => { + // Get file contents. + let src = fs::read_to_string(&file_name).expect("Failed to read file"); + + // Lex the file. let (tokens, lex_error) = lexer().parse_recovery(src.as_str()); let len = src.chars().count(); + + // Parse the file. let (ast, parse_error) = parser().parse_recovery(Stream::from_iter(len..len + 1, tokens.clone().unwrap().into_iter())); + if lex_error.is_empty() { + if parse_error.is_empty() { + match ast { + // If there is some AST then generate code. Some(ast) => { - // println!("{}", ast.iter().map(|e| e.to_sexpr()).collect::>().join("\n\n")); - let mut codegen = back::c::Codegen::new(); - codegen.gen(&ast); - print!("{}", codegen.emitted); + let start = time::Instant::now(); + + let mut compiler = back::c::Codegen::new(); + compiler.gen(&ast); + + let out_file_name = file_name.file_stem().unwrap().to_str().unwrap().to_string() + ".c"; + let mut out_file = fs::File::create(&out_file_name).expect("Failed to create file"); + write!(out_file, "{}", compiler.emitted).expect("Failed to write to file"); + + let compile_elapsed = start.elapsed(); + + log(0, format!("Compiled successfully to {} in {}s", &out_file_name, compile_elapsed.as_secs_f64())); + log(0, "Running clang-format..."); + let mut clang_format_status = Command::new("clang-format") + .arg("-i") + .arg(&out_file_name) + .spawn() + .expect("Failed to run clang-format, make sure you have it installed"); + match clang_format_status.wait() { + Ok(status) => { + match status.success() { + true => log(0, "Successfully run clang-format"), + false => log(2, "Failed to run clang-format"), + } + }, + Err(e) => log(2, format!("Failed to wait on clang-format: {}", e)), + } + + log(0, "Running clang..."); + let mut clang_status = Command::new("clang") + .arg(&out_file_name) + .spawn() + .expect("Failed to run clang, make sure you have it installed"); + match clang_status.wait() { + Ok(status) => { + match status.success() { + true => log(0, "Successfully run clang"), + false => log(2, "Failed to run clang"), + } + }, + Err(e) => log(2, format!("Failed to wait on clang: {}", e)), + } + + let all_elapsed = start.elapsed(); + log(0, format!("Done in {}s", all_elapsed.as_secs_f64())); }, + // If there is no AST, then notify the user. None => println!("no ast :("), }; + } else { eprintln!("{:#?}\n(Parser error)", parse_error); } + } else { eprintln!("{:#?}\n(Lexer error)", lex_error); } diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..d4a82a1 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,10 @@ +use std::fmt::Display; + +pub fn log(level: i8, msg: T) { + match level { + 0 => println!("\x1b[92m[INFO]\x1b[0m {}", msg), + 1 => println!("[WARN] {}", msg), + 2 => println!("[ERRO] {}", msg), + _ => println!("{}", msg), + } +} \ No newline at end of file