mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-15 06:58:50 +00:00
132 lines
3.4 KiB
Rust
132 lines
3.4 KiB
Rust
use std::ffi::OsStr;
|
|
use std::path::Path;
|
|
#[macro_use]
|
|
extern crate clap;
|
|
use clap::{crate_authors, crate_description, crate_version, App};
|
|
|
|
use lang_c::ast::TranslationUnit;
|
|
|
|
#[macro_use]
|
|
extern crate kecc;
|
|
|
|
use kecc::{
|
|
ir, write, Asmgen, Deadcode, Gvn, IrParse, Irgen, Mem2reg, Optimize, Parse, SimplifyCfg,
|
|
Translate, O1,
|
|
};
|
|
|
|
fn main() {
|
|
let yaml = load_yaml!("kecc_cli.yml");
|
|
#[allow(deprecated)]
|
|
let matches = App::from_yaml(yaml)
|
|
.version(crate_version!())
|
|
.about(crate_description!())
|
|
.author(crate_authors!(", "))
|
|
.get_matches();
|
|
|
|
let input = matches.value_of("INPUT").unwrap();
|
|
let input = Path::new(input);
|
|
|
|
let output = matches.value_of("output").unwrap_or_else(|| "-");
|
|
let mut output: Box<dyn ::std::io::Write> = if output == "-" {
|
|
Box::new(::std::io::stdout())
|
|
} else {
|
|
Box::new(ok_or_exit!(::std::fs::File::open(output), 1))
|
|
};
|
|
|
|
let ext = input.extension();
|
|
if ext == Some(OsStr::new("c")) {
|
|
let input = ok_or_exit!(Parse::default().translate(&input), 1);
|
|
compile_c(&input, &mut output, &matches);
|
|
} else if ext == Some(OsStr::new("ir")) {
|
|
let mut input = ok_or_exit!(IrParse::default().translate(&input), 1);
|
|
compile_ir(&mut input, &mut output, &matches);
|
|
} else {
|
|
panic!("Unsupported file extension: {:?}", ext);
|
|
}
|
|
}
|
|
|
|
fn compile_c(
|
|
input: &TranslationUnit,
|
|
output: &mut dyn ::std::io::Write,
|
|
matches: &clap::ArgMatches<'_>,
|
|
) {
|
|
if matches.is_present("parse") {
|
|
return;
|
|
}
|
|
|
|
if matches.is_present("print") {
|
|
write(input, output).unwrap();
|
|
return;
|
|
}
|
|
|
|
let mut ir = match Irgen::default().translate(input) {
|
|
Ok(ir) => ir,
|
|
Err(irgen_error) => {
|
|
println!("{}", irgen_error);
|
|
return;
|
|
}
|
|
};
|
|
|
|
if matches.is_present("irgen") {
|
|
write(&ir, output).unwrap();
|
|
return;
|
|
}
|
|
|
|
compile_ir(&mut ir, output, matches)
|
|
}
|
|
|
|
fn compile_ir(
|
|
input: &mut ir::TranslationUnit,
|
|
output: &mut dyn ::std::io::Write,
|
|
matches: &clap::ArgMatches<'_>,
|
|
) {
|
|
if matches.is_present("irparse") {
|
|
return;
|
|
}
|
|
|
|
if matches.is_present("irprint") {
|
|
write(input, output).unwrap();
|
|
return;
|
|
}
|
|
|
|
if matches.is_present("optimize") {
|
|
O1::default().optimize(input);
|
|
} else {
|
|
if matches.is_present("simplify-cfg") {
|
|
SimplifyCfg::default().optimize(input);
|
|
}
|
|
|
|
if matches.is_present("mem2reg") {
|
|
Mem2reg::default().optimize(input);
|
|
}
|
|
|
|
if matches.is_present("deadcode") {
|
|
Deadcode::default().optimize(input);
|
|
}
|
|
|
|
if matches.is_present("gvn") {
|
|
Gvn::default().optimize(input);
|
|
}
|
|
}
|
|
|
|
if matches.is_present("iroutput") {
|
|
write(input, output).unwrap();
|
|
return;
|
|
}
|
|
|
|
if matches.is_present("irrun") {
|
|
let result = ir::interp(input, Vec::new()).unwrap();
|
|
let (value, width, is_signed) = result.get_int().expect("non-integer value occurs");
|
|
assert_eq!(width, 32);
|
|
assert!(is_signed);
|
|
|
|
// When obtain status from `gcc` executable process, status value is truncated to byte size.
|
|
// So, we also truncate result value to byte size before printing it.
|
|
println!("[result] {:?}", value as u8);
|
|
return;
|
|
}
|
|
|
|
let asm = ok_or_exit!(Asmgen::default().translate(input), 1);
|
|
write(&asm, output).unwrap();
|
|
}
|