1
1
Fork 0
mirror of https://github.com/azur1s/bobbylisp.git synced 2024-10-16 02:37:40 -05:00

bool.h, running clang and clang-format on comp

This commit is contained in:
Natapat Samutpong 2022-02-24 21:45:35 +07:00
parent 0e3cd664af
commit 39b79b8c61
6 changed files with 95 additions and 11 deletions

4
Makefile Normal file
View file

@ -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

View file

@ -1,7 +1,11 @@
# Hycron # 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. 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 # TODO
- Compliation - Compliation
- Optimization - Optimization

3
lib/bool.h Normal file
View file

@ -0,0 +1,3 @@
#define bool _Bool
#define true 1
#define false 0

View file

@ -15,12 +15,19 @@ impl Codegen {
self.emitted.push_str(s.as_str()); 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]) { pub fn gen(&mut self, exprs: &[Expr]) {
self.emit("#include <stdio.h>\n#include <stdbool.h>\nint main() {\n".to_string()); self.emit_str("#include <stdio.h>\n");
self.emit_str("#include <hycron/bool.h>\n");
self.emit_str("int main() {\n");
for expr in exprs { for expr in exprs {
self.gen_expr(expr); 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) { fn gen_expr(&mut self, expr: &Expr) {
@ -41,7 +48,7 @@ impl Codegen {
"print" => { "print" => {
self.emit(format!("printf({});\n", match &args[0] { self.emit(format!("printf({});\n", match &args[0] {
Expr::String(s) => format!("\"{}\"", s), Expr::String(s) => format!("\"{}\"", s),
Expr::Ident(s) => s.to_string(), Expr::Ident(s) => format!("\"%s\", {}", s),
_ => todo!(), _ => todo!(),
})); }));
}, },

View file

@ -1,4 +1,4 @@
use std::fs; use std::{fs, io::Write, time, process::Command};
use chumsky::{Parser, Stream}; use chumsky::{Parser, Stream};
use clap::Parser as ArgParser; use clap::Parser as ArgParser;
@ -16,28 +16,84 @@ use front::parse::{lexer, parser};
/// Contains code generator. /// Contains code generator.
pub mod back; pub mod back;
pub mod util;
use crate::util::log;
fn main() { fn main() {
let args = Args::parse(); let args = Args::parse();
match args.options { match args.options {
Options::Compile { input: src, ast: _print_ast } => { Options::Compile { input: file_name, ast: _print_ast } => {
let src = fs::read_to_string(src).expect("Failed to read file"); // 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 (tokens, lex_error) = lexer().parse_recovery(src.as_str());
let len = src.chars().count(); 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())); let (ast, parse_error) = parser().parse_recovery(Stream::from_iter(len..len + 1, tokens.clone().unwrap().into_iter()));
if lex_error.is_empty() { if lex_error.is_empty() {
if parse_error.is_empty() { if parse_error.is_empty() {
match ast { match ast {
// If there is some AST then generate code.
Some(ast) => { Some(ast) => {
// println!("{}", ast.iter().map(|e| e.to_sexpr()).collect::<Vec<String>>().join("\n\n")); let start = time::Instant::now();
let mut codegen = back::c::Codegen::new();
codegen.gen(&ast); let mut compiler = back::c::Codegen::new();
print!("{}", codegen.emitted); 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 :("), None => println!("no ast :("),
}; };
} else { } else {
eprintln!("{:#?}\n(Parser error)", parse_error); eprintln!("{:#?}\n(Parser error)", parse_error);
} }
} else { } else {
eprintln!("{:#?}\n(Lexer error)", lex_error); eprintln!("{:#?}\n(Lexer error)", lex_error);
} }

10
src/util.rs Normal file
View file

@ -0,0 +1,10 @@
use std::fmt::Display;
pub fn log<T: Display>(level: i8, msg: T) {
match level {
0 => println!("\x1b[92m[INFO]\x1b[0m {}", msg),
1 => println!("[WARN] {}", msg),
2 => println!("[ERRO] {}", msg),
_ => println!("{}", msg),
}
}