From 11f0760b019dc462a0eda278966f3ce28e045c40 Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Sat, 7 Jan 2023 02:09:27 -0600 Subject: [PATCH] Vasm cli wrapper will now export a symbol table --- Cargo.lock | 24 ++++++++++++++++++++++++ vasm/Cargo.toml | 3 ++- vasm/src/main.rs | 24 +++++++++++++++++++++--- vasm_core/src/vasm_assembler.rs | 20 ++++++++++---------- vweb/4th/4th.rom.sym | 2 +- 5 files changed, 58 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15b528c..b18718e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -592,6 +592,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + [[package]] name = "jni-sys" version = "0.3.0" @@ -1203,6 +1209,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + [[package]] name = "safe_arch" version = "0.5.2" @@ -1230,6 +1242,17 @@ version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha-1" version = "0.8.2" @@ -1386,6 +1409,7 @@ version = "0.1.0" dependencies = [ "clap", "regex", + "serde_json", "vasm_core", ] diff --git a/vasm/Cargo.toml b/vasm/Cargo.toml index 0a2d5a6..a1d7773 100644 --- a/vasm/Cargo.toml +++ b/vasm/Cargo.toml @@ -8,4 +8,5 @@ edition = "2021" [dependencies] vasm_core = { path = "../vasm_core" } clap = { version = "3.1.18", features = ["derive"] } -regex = "1.7.0" \ No newline at end of file +regex = "1.7.0" +serde_json = "1.0.91" diff --git a/vasm/src/main.rs b/vasm/src/main.rs index 8196935..3b52ade 100644 --- a/vasm/src/main.rs +++ b/vasm/src/main.rs @@ -1,8 +1,10 @@ +use std::collections::BTreeMap; use std::fs::File; use std::io::Write; use clap::lazy_static::lazy_static; use clap::Parser; use regex::Regex; +use serde_json::json; /// Vulcan Assembler #[derive(Parser, Debug)] @@ -12,6 +14,10 @@ struct Args { #[clap(short, long)] output: Option, + /// Whether to generate a JSON file containing the symbol table + #[clap(short, long)] + symbols: bool, + /// Input file #[clap()] file: String, @@ -51,10 +57,22 @@ fn main() { args.deduce(); match vasm_core::assemble_file(args.file.as_str()) { - Ok(bytes) => { - //println!("We got some bytes... {} of them", bytes.len()); - let mut outfile = File::create(args.output.unwrap()).expect("Failed to open output file"); + Ok((bytes, scope)) => { + let mut outfile = File::create(args.output.as_ref().unwrap()).expect("Failed to open output file"); outfile.write(bytes.as_slice()).expect("Failed to write to output file"); + + if args.symbols { + let mut important_symbols : BTreeMap = BTreeMap::new(); + for (sym, addr) in scope { + if !sym.starts_with("__gensym") { + important_symbols.insert(sym, addr); + } + } + + let mut symfile = File::create(format!("{}.sym", args.output.unwrap())).expect("Failed to open symbol file"); + let json = json!(important_symbols).to_string(); + symfile.write(json.as_bytes()).expect("Failed to write to symbol file"); + } } Err(error) => { println!("{}", error) diff --git a/vasm_core/src/vasm_assembler.rs b/vasm_core/src/vasm_assembler.rs index eb0b417..2dba839 100644 --- a/vasm_core/src/vasm_assembler.rs +++ b/vasm_core/src/vasm_assembler.rs @@ -179,11 +179,11 @@ pub fn assemble_snippet>( }) .collect(); - assemble_line_results(line_results) + assemble_line_results(line_results).map(|(bytes, _)| { bytes }) } /// Assemble a file from the filesystem, opening other files as it includes them. -pub fn assemble_file(filename: &str) -> Result, AssembleError> { +pub fn assemble_file(filename: &str) -> Result<(Vec, Scope), AssembleError> { let lines = lines_from_file(filename)?; let line_results: Vec> = LineSource::new(filename, lines, |file| { lines_from_file(file.as_str()) @@ -195,7 +195,7 @@ pub fn assemble_file(filename: &str) -> Result, AssembleError> { fn assemble_line_results( mut line_results: Vec>, -) -> Result, AssembleError> { +) -> Result<(Vec, Scope), AssembleError> { if let Some(Err(error)) = line_results.iter().find(|line| line.is_err()) { Err(error.clone()) } else { @@ -224,7 +224,7 @@ fn lines_from_file(filename: &str) -> Result, AssembleError> { /// /// Vulcan is a little-endian architecture: multi-byte arguments / .dbs will store the /// least-significant byte at the lowest address, then the more significant bytes following. -fn generate_code>(lines: T) -> Result, AssembleError> { +fn generate_code>(lines: T) -> Result<(Vec, Scope), AssembleError> { let lines: Vec = lines.into_iter().collect(); let scope = solve_equs(&lines)?; let line_lengths = measure_instructions(&lines, &scope); @@ -276,7 +276,7 @@ fn generate_code>(lines: T) -> Result, Asse } } - Ok(code) + Ok((code, scope)) } #[cfg(test)] @@ -485,13 +485,13 @@ mod test { #[test] fn test_generate_code() { - assert_eq!(generate_code(parse(["add"])), Ok(vec![4])); + assert_eq!(generate_code(parse(["add"])).unwrap().0, vec![4]); assert_eq!( - generate_code(parse([".org 0x400", "add 7"])), - Ok(vec![5, 7]) + generate_code(parse([".org 0x400", "add 7"])).unwrap().0, + vec![5, 7] ); - assert_eq!(generate_code(parse([".db 57"])), Ok(vec![57, 0, 0])); - assert_eq!(generate_code(parse([".db \"AZ\0\""])), Ok(vec![65, 90, 0])); + assert_eq!(generate_code(parse([".db 57"])).unwrap().0, vec![57, 0, 0]); + assert_eq!(generate_code(parse([".db \"AZ\0\""])).unwrap().0, vec![65, 90, 0]); } #[test] diff --git a/vweb/4th/4th.rom.sym b/vweb/4th/4th.rom.sym index f0cb3f0..e21e6b0 100644 --- a/vweb/4th/4th.rom.sym +++ b/vweb/4th/4th.rom.sym @@ -1 +1 @@ -{"$BRNZ":28,"$BRZ":27,"$CALL":25,"$JMP":23,"$JMPR":24,"$PUSH":0,"$RET":26,"$SWAP":20,"$end":4617,"$start":1024,"advance_entry":1141,"backslash":3276,"close_paren":3267,"close_paren_stub":3275,"compare":1414,"compile_dict_start":3429,"compile_dictionary":4222,"compile_handleword":3150,"compile_instruction":1537,"compile_instruction_arg":1511,"compile_tick":1196,"cr":1067,"cursor":4210,"data_start":3340,"dict_start":3588,"dictionary":4219,"does_at_runtime":2225,"does_word":2196,"dupnz":1074,"dupnz_done":1080,"emit":1025,"emit_cursor":1042,"emit_hook":4228,"end0_pop1":1093,"end0_pop2":1092,"end1_pop2":1096,"eval":1773,"eval_word_buffer":4487,"expected_word_err":3388,"find_in_dict":1149,"find_in_dict_next":1179,"find_word":2584,"handleword_hook":4198,"heap":4195,"heap_start":4618,"hex_is_number":1280,"hex_itoa":1701,"immediate_handleword":3113,"input_number":1595,"invalid_mnemonic":3293,"invalid_mnemonic_str":3353,"is_digit":1084,"is_number":1205,"is_number_hook":4201,"itoa":1618,"itoa_hook":4204,"itoa_loop":1648,"itoa_pos":1637,"itoa_print_loop":1685,"lambda_nesting_level":4216,"lambda_start_ptr":4213,"line_len":4207,"linecomment":3209,"missing_word":3301,"missing_word_str":3340,"mnemonics":2258,"mnemonics_end":2469,"new_dict":1451,"new_dict_error":1497,"nova_asm_to":2563,"nova_bracket_tick":2634,"nova_char":2689,"nova_close_brace":3049,"nova_close_bracket":1998,"nova_colon":2146,"nova_comma":2133,"nova_compile_dotquote":2877,"nova_compile_opcode":2555,"nova_compile_open_brace":3024,"nova_compile_squote":2810,"nova_continue":2007,"nova_create":1946,"nova_dec":2660,"nova_dotquote":2856,"nova_emit":3007,"nova_exit":2099,"nova_here":2579,"nova_hex":2672,"nova_immediate":2105,"nova_immediate_open_brace":3012,"nova_literal":2654,"nova_number":1932,"nova_opcode":2550,"nova_opcode_for_word":2469,"nova_open_bracket":1990,"nova_peekr":2961,"nova_popr":2994,"nova_postpone":2017,"nova_print_stack":2907,"nova_pushr":2981,"nova_quote_string_to":2715,"nova_resolve":1568,"nova_rpick":2969,"nova_safe_opcode":2529,"nova_semicolon":2154,"nova_squote":2780,"nova_tick":2613,"nova_word":1852,"nova_word_to":1902,"nova_word_to_pad":2164,"open_paren":3250,"pad":4231,"parencomment":3211,"parse_hex_digit":1326,"pos_is_number":1234,"pos_is_number_bad":1271,"pos_is_number_done":1276,"pos_is_number_loop":1236,"print":1045,"print_number":1613,"print_stack_end":3426,"print_stack_start":3422,"push_jump":1552,"quit":3317,"quit_vector":4225,"r_stack":4522,"r_stack_ptr":4519,"skip_nonword":1388,"skip_word":1371,"stop":1024,"tick":1187,"unclosed_error":3372,"word_char":1081,"wordeq":1100} \ No newline at end of file +{"$BRNZ":28,"$BRZ":27,"$CALL":25,"$JMP":23,"$JMPR":24,"$PUSH":0,"$RET":26,"$SWAP":20,"advance_entry":1141,"backslash":3276,"close_paren":3267,"close_paren_stub":3275,"compare":1414,"compile_dict_start":3429,"compile_dictionary":4222,"compile_handleword":3150,"compile_instruction":1537,"compile_instruction_arg":1511,"compile_tick":1196,"cr":1067,"cursor":4210,"data_start":3340,"dict_start":3588,"dictionary":4219,"does_at_runtime":2225,"does_word":2196,"dupnz":1074,"dupnz_done":1080,"emit":1025,"emit_cursor":1042,"emit_hook":4228,"end0_pop1":1093,"end0_pop2":1092,"end1_pop2":1096,"eval":1773,"eval_word_buffer":4487,"expected_word_err":3388,"find_in_dict":1149,"find_in_dict_next":1179,"find_word":2584,"handleword_hook":4198,"heap":4195,"heap_start":4618,"hex_is_number":1280,"hex_itoa":1701,"immediate_handleword":3113,"input_number":1595,"invalid_mnemonic":3293,"invalid_mnemonic_str":3353,"is_digit":1084,"is_number":1205,"is_number_hook":4201,"itoa":1618,"itoa_hook":4204,"itoa_loop":1648,"itoa_pos":1637,"itoa_print_loop":1685,"lambda_nesting_level":4216,"lambda_start_ptr":4213,"line_len":4207,"linecomment":3209,"missing_word":3301,"missing_word_str":3340,"mnemonics":2258,"mnemonics_end":2469,"new_dict":1451,"new_dict_error":1497,"nova_asm_to":2563,"nova_bracket_tick":2634,"nova_char":2689,"nova_close_brace":3049,"nova_close_bracket":1998,"nova_colon":2146,"nova_comma":2133,"nova_compile_dotquote":2877,"nova_compile_opcode":2555,"nova_compile_open_brace":3024,"nova_compile_squote":2810,"nova_continue":2007,"nova_create":1946,"nova_dec":2660,"nova_dotquote":2856,"nova_emit":3007,"nova_exit":2099,"nova_here":2579,"nova_hex":2672,"nova_immediate":2105,"nova_immediate_open_brace":3012,"nova_literal":2654,"nova_number":1932,"nova_opcode":2550,"nova_opcode_for_word":2469,"nova_open_bracket":1990,"nova_peekr":2961,"nova_popr":2994,"nova_postpone":2017,"nova_print_stack":2907,"nova_pushr":2981,"nova_quote_string_to":2715,"nova_resolve":1568,"nova_rpick":2969,"nova_safe_opcode":2529,"nova_semicolon":2154,"nova_squote":2780,"nova_tick":2613,"nova_word":1852,"nova_word_to":1902,"nova_word_to_pad":2164,"open_paren":3250,"pad":4231,"parencomment":3211,"parse_hex_digit":1326,"pos_is_number":1234,"pos_is_number_bad":1271,"pos_is_number_done":1276,"pos_is_number_loop":1236,"print":1045,"print_number":1613,"print_stack_end":3426,"print_stack_start":3422,"push_jump":1552,"quit":3317,"quit_vector":4225,"r_stack":4522,"r_stack_ptr":4519,"skip_nonword":1388,"skip_word":1371,"stop":1024,"tick":1187,"unclosed_error":3372,"word_char":1081,"wordeq":1100} \ No newline at end of file