Skip to content

Commit

Permalink
feat: cli api impovement & compile function
Browse files Browse the repository at this point in the history
closes #32
  • Loading branch information
MilkeeyCat committed Aug 4, 2024
1 parent abb6b43 commit 2d47290
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 45 deletions.
2 changes: 1 addition & 1 deletion src/archs/amd64/amd64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ impl Amd64 {
scope: &Scope,
) -> Result<(), ArchError> {
self.mov_impl(
(&literal, literal.type_(scope)?.size(self, scope)?),
(&literal, 8),
(&dest, dest.size()),
literal.type_(scope)?.signed(),
);
Expand Down
9 changes: 2 additions & 7 deletions src/codegen/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,17 +351,12 @@ impl<'a> CodeGen<'a> {
Ok(())
}

pub fn compile(&mut self, program: Vec<Stmt>, path: &str) -> Result<(), CodeGenError> {
let mut file = File::create(path).expect(&format!("Failed to open a file {}", path));

pub fn compile(&mut self, program: Vec<Stmt>) -> Result<Vec<u8>, CodeGenError> {
for stmt in program {
self.stmt(stmt)?;
}

file.write_all(&self.arch.finish())
.expect("Failed to write generated code to output file");

Ok(())
Ok(self.arch.finish())
}

fn populate_offsets(&mut self, stmts: &Vec<Stmt>) -> Result<usize, CodeGenError> {
Expand Down
121 changes: 121 additions & 0 deletions src/compile.rs
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(())
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ pub mod scope;
pub mod symbol_table;
pub mod type_table;
pub mod types;
pub mod compile;
40 changes: 3 additions & 37 deletions src/main.rs
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)
}

0 comments on commit 2d47290

Please sign in to comment.