-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: cli api impovement & compile function
closes #32
- Loading branch information
1 parent
abb6b43
commit 2d47290
Showing
5 changed files
with
128 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
use crate::{ | ||
archs::{Amd64, Architecture}, | ||
codegen::CodeGen, | ||
lexer::Lexer, | ||
parser, | ||
}; | ||
use clap::Parser; | ||
use std::{ | ||
fs::File, | ||
io::{Read, Write}, | ||
path::{Path, PathBuf}, | ||
process::Stdio, | ||
}; | ||
|
||
#[derive(Parser, Debug)] | ||
#[command(version, about, long_about = None)] | ||
pub struct CompileArgs { | ||
/// Source code filenames | ||
#[arg(required = true, num_args = 1..)] | ||
file: PathBuf, | ||
|
||
/// Output binary file name | ||
#[arg(short, default_value = "a.out")] | ||
output: Option<PathBuf>, | ||
|
||
/// Produce assembly output | ||
#[arg(short = 'S', default_value_t = false, group = "output_t")] | ||
assembly_only: bool, | ||
|
||
/// Compile and assemble but do not link | ||
#[arg(short = 'c', default_value_t = false, group = "output_t")] | ||
object_only: bool, | ||
} | ||
|
||
pub fn compile(args: CompileArgs) -> Result<(), Box<dyn std::error::Error>> { | ||
let mut file = File::open(&args.file)?; | ||
let mut source_code = String::new(); | ||
|
||
file.read_to_string(&mut source_code)?; | ||
|
||
let lexer = Lexer::new(source_code); | ||
let (stmts, scope) = parser::Parser::new(lexer)?.into_parts()?; | ||
|
||
dbg!(&stmts); | ||
dbg!(&scope); | ||
|
||
let code = CodeGen::new(&mut Amd64::new(), scope).compile(stmts)?; | ||
|
||
if args.assembly_only { | ||
let asm_filename = args.file.with_extension("s"); | ||
let mut file = std::fs::File::create(&asm_filename)?; | ||
|
||
file.write_all(&code)?; | ||
|
||
return Ok(()); | ||
} | ||
|
||
let obj_filename = args.file.with_extension("o"); | ||
|
||
assemble(&code, &obj_filename)?; | ||
|
||
if args.object_only { | ||
return Ok(()); | ||
} | ||
|
||
let binary_filename = if let Some(output) = args.output { | ||
output | ||
} else { | ||
"a.out".into() | ||
}; | ||
|
||
link(&obj_filename, &binary_filename)?; | ||
|
||
// Remove intermediate steps file | ||
std::fs::remove_file(&obj_filename)?; | ||
|
||
Ok(()) | ||
} | ||
|
||
fn assemble(source: &[u8], output: &Path) -> std::io::Result<()> { | ||
let source = std::process::Command::new("echo") | ||
.stdout(Stdio::piped()) | ||
.arg(std::str::from_utf8(source).unwrap()) | ||
.spawn()?; | ||
|
||
let as_args = vec![ | ||
"-msyntax=intel", | ||
"-mnaked-reg", | ||
"-o", | ||
output.to_str().unwrap(), | ||
]; | ||
|
||
std::process::Command::new("as") | ||
.args(as_args) | ||
.stdin(Stdio::from(source.stdout.unwrap())) | ||
.spawn()? | ||
.wait()?; | ||
|
||
Ok(()) | ||
} | ||
|
||
fn link(input: &Path, output: &Path) -> std::io::Result<()> { | ||
const OBJ_PATH: &'static str = "/usr/lib/x86_64-linux-gnu"; | ||
|
||
std::process::Command::new("ld") | ||
.args([ | ||
"-dynamic-linker", | ||
&format!("{OBJ_PATH}/ld-linux-x86-64.so.2"), | ||
&format!("{OBJ_PATH}/crt1.o"), | ||
"-lc", | ||
input.to_str().unwrap(), | ||
"-z", | ||
"noexecstack", | ||
"-o", | ||
output.to_str().unwrap(), | ||
]) | ||
.spawn()? | ||
.wait()?; | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ pub mod scope; | |
pub mod symbol_table; | ||
pub mod type_table; | ||
pub mod types; | ||
pub mod compile; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,8 @@ | ||
use clap::Parser; | ||
use meraki::{ | ||
archs::{Amd64, Architecture}, | ||
codegen::CodeGen, | ||
lexer::Lexer, | ||
parser, | ||
}; | ||
use std::{fs::File, io::Read}; | ||
|
||
#[derive(Parser, Debug)] | ||
#[command(version, about, long_about = None)] | ||
struct Args { | ||
/// Source code filenames | ||
#[arg(required = true, num_args = 1..)] | ||
files: Vec<String>, | ||
|
||
/// Output file | ||
#[arg(short, default_value = "main.s")] | ||
output: String, | ||
} | ||
use meraki::compile::{compile, CompileArgs}; | ||
|
||
fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
let args = Args::parse(); | ||
|
||
for filename in args.files { | ||
let mut file = File::open(&filename).expect(&format!("Failed to open file: {}", filename)); | ||
let mut source_code = String::new(); | ||
|
||
file.read_to_string(&mut source_code) | ||
.expect(&format!("Failed to read contents of file: {}", filename)); | ||
|
||
let lexer = Lexer::new(source_code); | ||
let (stmts, scope) = parser::Parser::new(lexer)?.into_parts()?; | ||
|
||
dbg!(&stmts); | ||
dbg!(&scope); | ||
|
||
CodeGen::new(&mut Amd64::new(), scope).compile(stmts, &args.output)?; | ||
} | ||
let options = CompileArgs::parse(); | ||
|
||
Ok(()) | ||
compile(options) | ||
} |