diff --git a/Cargo.toml b/Cargo.toml index 81729964..632d42eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "customasm" -version = "0.10.1" +version = "0.10.2" edition = "2018" authors = ["Henrique Lorenzi "] diff --git a/README.md b/README.md index b208ba93..ab108113 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Options: decc, hexc, logisim8, logisim16 -o, --output FILE The name of the output file. + -s, --symbol FILE The name of the output symbol file. -p, --print Print output to stdout instead of writing to a file. -q, --quiet Suppress progress reports. -v, --version Display version information. diff --git a/src/asm/assembler.rs b/src/asm/assembler.rs index db5c0108..99938c62 100644 --- a/src/asm/assembler.rs +++ b/src/asm/assembler.rs @@ -160,6 +160,43 @@ impl AssemblerState output } + + + pub fn get_symbol_output(&self) -> String + { + let mut result = String::new(); + + for global_label in &self.labels.name_to_index_map + { + let global_value = &self.labels.global_labels[*global_label.1]; + + if global_label.0 != "" + { + match global_value.value + { + ExpressionValue::Integer(ref integer) => + { + result.push_str(&format!("{} = {:#x}\n", global_label.0, integer)); + } + _ => {} + } + } + + for local_label in &global_value.local_labels + { + match local_label.1 + { + ExpressionValue::Integer(ref integer) => + { + result.push_str(&format!("{}{} = {:#x}\n", global_label.0, local_label.0, integer)); + } + _ => {} + } + } + } + + result + } } diff --git a/src/asm/label.rs b/src/asm/label.rs index f61b3467..b6657135 100644 --- a/src/asm/label.rs +++ b/src/asm/label.rs @@ -6,8 +6,8 @@ use std::collections::HashMap; pub struct LabelManager { - global_labels: Vec, - name_to_index_map: HashMap + pub global_labels: Vec, + pub name_to_index_map: HashMap } @@ -16,8 +16,8 @@ pub type LabelContext = usize; pub struct GlobalLabel { - value: ExpressionValue, - local_labels: HashMap + pub value: ExpressionValue, + pub local_labels: HashMap } diff --git a/src/driver.rs b/src/driver.rs index caa73b75..88d038ba 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,7 +1,6 @@ use crate::diagn::RcReport; use crate::util::FileServer; use crate::util::enable_windows_ansi_support; -use crate::asm::BinaryBlock; use crate::asm::AssemblerState; use std::io::stdout; use getopts; @@ -63,7 +62,7 @@ fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec, fi if matches.opt_present("v") { - print_version(); + print_info(); return Ok(()); } @@ -108,44 +107,54 @@ fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec, fi let main_asm_file = matches.free[0].clone(); + let output_symbol_requested = matches.opt_present("s"); + let output_requested = matches.opt_present("o"); + + let output_symbol_file = matches.opt_str("s"); let output_file = match matches.opt_str("o") { - Some(f) => f, + Some(f) => Some(f), None => { - match get_default_output_filename(report.clone(), &main_asm_file) + if output_symbol_requested || output_symbol_file.is_some() + { None } + else { - Ok(f) => f, - Err(_) => return Err(true) + match get_default_output_filename(report.clone(), &main_asm_file) + { + Ok(f) => Some(f), + Err(_) => None, + } } } }; - + let mut filenames = matches.opt_strs("i"); for filename in matches.free { filenames.push(filename); } let assembled = assemble(report.clone(), fileserver, &filenames, quiet).map_err(|_| false)?; - + let output = assembled.get_binary_output(); + let output_symbol_data = assembled.get_symbol_output(); let output_data = match out_format { - OutputFormat::Binary => assembled.generate_binary(0, assembled.len()), + OutputFormat::Binary => output.generate_binary(0, output.len()), - OutputFormat::BinStr => assembled.generate_binstr (0, assembled.len()).bytes().collect::>(), - OutputFormat::BinDump => assembled.generate_bindump (0, assembled.len()).bytes().collect::>(), - OutputFormat::HexStr => assembled.generate_hexstr (0, assembled.len()).bytes().collect::>(), - OutputFormat::HexDump => assembled.generate_hexdump (0, assembled.len()).bytes().collect::>(), - OutputFormat::Mif => assembled.generate_mif (0, assembled.len()).bytes().collect::>(), - OutputFormat::IntelHex => assembled.generate_intelhex(0, assembled.len()).bytes().collect::>(), - OutputFormat::DecComma => assembled.generate_comma (0, assembled.len(), 10).bytes().collect::>(), - OutputFormat::HexComma => assembled.generate_comma (0, assembled.len(), 16).bytes().collect::>(), - OutputFormat::DecC => assembled.generate_c_array (0, assembled.len(), 10).bytes().collect::>(), - OutputFormat::HexC => assembled.generate_c_array (0, assembled.len(), 16).bytes().collect::>(), - OutputFormat::LogiSim8 => assembled.generate_logisim (0, assembled.len(), 8).bytes().collect::>(), - OutputFormat::LogiSim16 => assembled.generate_logisim (0, assembled.len(), 16).bytes().collect::>(), + OutputFormat::BinStr => output.generate_binstr (0, output.len()).bytes().collect::>(), + OutputFormat::BinDump => output.generate_bindump (0, output.len()).bytes().collect::>(), + OutputFormat::HexStr => output.generate_hexstr (0, output.len()).bytes().collect::>(), + OutputFormat::HexDump => output.generate_hexdump (0, output.len()).bytes().collect::>(), + OutputFormat::Mif => output.generate_mif (0, output.len()).bytes().collect::>(), + OutputFormat::IntelHex => output.generate_intelhex(0, output.len()).bytes().collect::>(), + OutputFormat::DecComma => output.generate_comma (0, output.len(), 10).bytes().collect::>(), + OutputFormat::HexComma => output.generate_comma (0, output.len(), 16).bytes().collect::>(), + OutputFormat::DecC => output.generate_c_array (0, output.len(), 10).bytes().collect::>(), + OutputFormat::HexC => output.generate_c_array (0, output.len(), 16).bytes().collect::>(), + OutputFormat::LogiSim8 => output.generate_logisim (0, output.len(), 8).bytes().collect::>(), + OutputFormat::LogiSim16 => output.generate_logisim (0, output.len(), 16).bytes().collect::>(), - OutputFormat::AnnotatedHex => assembled.generate_annotated_hex(fileserver, 0, assembled.len()).bytes().collect::>(), - OutputFormat::AnnotatedBin => assembled.generate_annotated_bin(fileserver, 0, assembled.len()).bytes().collect::>(), + OutputFormat::AnnotatedHex => output.generate_annotated_hex(fileserver, 0, output.len()).bytes().collect::>(), + OutputFormat::AnnotatedBin => output.generate_annotated_bin(fileserver, 0, output.len()).bytes().collect::>(), }; if out_stdout @@ -155,14 +164,34 @@ fn drive_inner(report: RcReport, opts: &getopts::Options, args: &Vec, fi println!("success"); println!(""); } + + if output_requested || output_file.is_some() + { println!("{}", String::from_utf8_lossy(&output_data)); } - println!("{}", String::from_utf8_lossy(&output_data)); + if output_symbol_requested || output_symbol_file.is_some() + { println!("{}", &output_symbol_data); } } else { - println!("writing `{}`...", &output_file); - fileserver.write_bytes(report.clone(), &output_file, &output_data, None).map_err(|_| false)?; - + let mut any_files_written = false; + + if let Some(ref output_file) = output_file + { + println!("writing `{}`...", &output_file); + fileserver.write_bytes(report.clone(), &output_file, &output_data, None).map_err(|_| false)?; + any_files_written = true; + } + + if let Some(ref output_symbol_file) = output_symbol_file + { + println!("writing `{}`...", &output_symbol_file); + fileserver.write_bytes(report.clone(), &output_symbol_file, &output_symbol_data.bytes().collect::>(), None).map_err(|_| false)?; + any_files_written = true; + } + + if !any_files_written + { println!("no files written"); } + if !quiet { println!("success"); } } @@ -176,7 +205,8 @@ fn make_opts() -> getopts::Options let mut opts = getopts::Options::new(); opts.optopt("f", "format", "The format of the output file. Possible formats: binary, annotated, annotatedbin, binstr, hexstr, bindump, hexdump, mif, intelhex, deccomma, hexcomma, decc, hexc, logisim8, logisim16", "FORMAT"); opts.optmulti("i", "include", "Specifies an additional file for processing before the given . [deprecated]", "FILE"); - opts.optopt("o", "output", "The name of the output file.", "FILE"); + opts.opt("o", "output", "The name of the output file.", "FILE", getopts::HasArg::Maybe, getopts::Occur::Optional); + opts.opt("s", "symbol", "The name of the output symbol file.", "FILE", getopts::HasArg::Maybe, getopts::Occur::Optional); opts.optflag("p", "print", "Print output to stdout instead of writing to a file."); opts.optflag("q", "quiet", "Suppress progress reports."); opts.optflag("v", "version", "Display version information."); @@ -198,6 +228,8 @@ fn parse_opts(report: RcReport, opts: &getopts::Options, args: &Vec) -> fn print_usage(opts: &getopts::Options) { + print_info(); + println!(""); println!("{}", opts.usage(&format!("Usage: {} [options] ... ", env!("CARGO_PKG_NAME")))); } @@ -208,9 +240,10 @@ fn print_version() } -fn print_header() +fn print_info() { print_version(); + println!("https://github.com/hlorenzi/customasm"); } @@ -230,10 +263,10 @@ fn get_default_output_filename(report: RcReport, input_filename: &str) -> Result } -pub fn assemble(report: RcReport, fileserver: &dyn FileServer, filenames: &[String], quiet: bool) -> Result +pub fn assemble(report: RcReport, fileserver: &dyn FileServer, filenames: &[String], quiet: bool) -> Result { if !quiet - { print_header(); } + { print_version(); } let mut asm = AssemblerState::new(); @@ -248,5 +281,5 @@ pub fn assemble(report: RcReport, fileserver: &dyn FileServer, filenames: &[Stri } asm.wrapup(report)?; - Ok(asm.get_binary_output()) + Ok(asm) } \ No newline at end of file diff --git a/web/customasm.gc.wasm b/web/customasm.gc.wasm index 05d93189..c6b5e038 100644 Binary files a/web/customasm.gc.wasm and b/web/customasm.gc.wasm differ