Add compile and compile_out options, and extended input/output options

* compile flag and compile_out argument to the driver allow the program
  to be compiled only
* if '-' is supplied to compile_out, it will output to STDOUT instead
* if '-' is supplied to input, it will read from STDIN instead

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-02-25 18:12:28 -05:00
parent d11dbbcdf5
commit bd34cdad63

View File

@@ -5,7 +5,7 @@ mod vm;
use structopt::StructOpt; use structopt::StructOpt;
use snafu::Snafu; use snafu::Snafu;
use std::{fs, process, path::PathBuf}; use std::{fs, io::{stdin, stdout, Write, Read}, process, path::PathBuf};
const DEFAULT_MAX_MEM: usize = 64 * 1024 * 1024; const DEFAULT_MAX_MEM: usize = 64 * 1024 * 1024;
@@ -57,11 +57,28 @@ fn test_bytes_size() {
struct Options { struct Options {
// maybe some other options: // maybe some other options:
// * debug // * debug
/// The input file to work with.
///
/// By default, the file will be executed. If -c is passed, it will not run and only compile.
/// Supplying - for the path will read from STDIN.
#[structopt(name = "FILE", parse(from_os_str))] #[structopt(name = "FILE", parse(from_os_str))]
input: PathBuf, input: PathBuf,
#[structopt(short, long, parse(try_from_str = from_bytes_size))] /// The maximum amount of virtual memory allowed.
#[structopt(long, parse(try_from_str = from_bytes_size))]
max_mem: Option<usize>, max_mem: Option<usize>,
/// Whether to compile the input file to an object.
#[structopt(short, long)]
compile: bool,
/// The output file for compiled files.
///
/// If not supplied, a name will be inferred from the input file. Supplying - for the path will
/// output to STDOUT.
#[structopt(short = "o", long)]
compile_out: Option<PathBuf>
} }
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>; type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
@@ -74,11 +91,21 @@ fn main() -> Result<()> {
syn::{lexer, parser}, syn::{lexer, parser},
} }
}; };
// get the object either from reading it, or from parsing an assembly file
let opt = Options::from_args(); let opt = Options::from_args();
let text = fs::read_to_string(&opt.input)?; let text = if Some("-") == opt.input.to_str() {
let mut text = String::new();
let stdin = stdin();
stdin.lock().read_to_string(&mut text)?;
text
} else {
fs::read_to_string(&opt.input)?
};
let lexerdef = lexer::lexerdef(); let lexerdef = lexer::lexerdef();
let lexer = lexerdef.lexer(&text); let lexer = lexerdef.lexer(&text);
let (res, errors) = parser::parse(&lexer); let (res, errors) = parser::parse(&lexer);
// print errors // print errors
for err in errors.iter() { for err in errors.iter() {
println!("{}", err.pp(&lexer, &parser::token_epp)); println!("{}", err.pp(&lexer, &parser::token_epp));
@@ -89,8 +116,25 @@ fn main() -> Result<()> {
let res = res.unwrap(); let res = res.unwrap();
let mut asm = Asm::default(); let mut asm = Asm::default();
let object = res.assemble(&mut asm)?; let object = res.assemble(&mut asm)?;
if opt.compile {
let outfile = opt.compile_out.clone().unwrap_or_else(|| {
let mut outfile = opt.input.clone();
assert!(outfile.set_extension("obj"));
outfile
});
let bytes = object.to_bytes();
if Some("-") == outfile.to_str() {
let stdout = stdout();
stdout.lock().write(&bytes)?;
} else {
// write compiled file here
fs::write(outfile, &bytes)?;
}
Ok(())
} else {
let mut state = State::new(); let mut state = State::new();
state.load_object(object, opt.max_mem.unwrap_or(DEFAULT_MAX_MEM))?; state.load_object(object, opt.max_mem.unwrap_or(DEFAULT_MAX_MEM))?;
let status = state.exec()?; let status = state.exec()?;
process::exit((status & 0xffff_ffff) as i32); process::exit((status & 0xffff_ffff) as i32);
}
} }