assembler and examples
This commit is contained in:
parent
f4c78f2b05
commit
6c1cf0f620
|
@ -2,6 +2,344 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is-terminal",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34d21f9bf1b425d2968943631ec91202fe5e837264063503708b83013f8fc938"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"bitflags",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"io-lifetimes",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "parse_int"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d695b79916a2c08bcff7be7647ab60d1402885265005a6658ffe6d763553c5a"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.37.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tmcpu"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"parse_int",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
|
|
@ -6,3 +6,5 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.2.7", features = ["derive"] }
|
||||
parse_int = { version = "0.6.0" }
|
|
@ -1,15 +1,42 @@
|
|||
nop
|
||||
nop
|
||||
|
||||
ldi ra, 0x01
|
||||
ldi rb, 0x02
|
||||
add rc, ra rb ; should be 3
|
||||
out 0x02, rc ; displays 03 on the numeric display
|
||||
|
||||
ldi ra, 0b10100000 ; load the num for red and blue into ra
|
||||
mrm ra, 0x001
|
||||
mrm ra, 0x003
|
||||
mrm ra, 0x01e
|
||||
mrm ra, 0x02e
|
||||
mrm ra, 0x02f
|
||||
mrm ra, 0x030
|
||||
mrm ra, 0x031
|
||||
mrm ra, 0x023
|
||||
; Draw a smiley face
|
||||
mrm 0x001, ra
|
||||
mrm 0x003, ra
|
||||
mrm 0x01e, ra
|
||||
mrm 0x02e, ra
|
||||
mrm 0x02f, ra
|
||||
mrm 0x030, ra
|
||||
mrm 0x031, ra
|
||||
mrm 0x023, ra
|
||||
; Draw a smiley face
|
||||
|
||||
; Test the normalizer
|
||||
ldi ra, 0b10100101
|
||||
lsh rb, ra
|
||||
; Expands to:
|
||||
; add rb, ra ra
|
||||
|
||||
cmp ra rb
|
||||
; Expands to:
|
||||
; sub ra, ra rb
|
||||
|
||||
cpy rc, rb
|
||||
; Expands to:
|
||||
; ldi r0, 0
|
||||
; add rc, rb r0
|
||||
|
||||
not rd, rc
|
||||
; Expands to:
|
||||
; ldi r0, 0
|
||||
; nor rd, rc r0
|
||||
|
||||
; test validation
|
||||
in ra, 0x02
|
||||
out 0x03, rb
|
Binary file not shown.
|
@ -0,0 +1,4 @@
|
|||
ldi ra, 0x01 ; set ra = 0x01
|
||||
ldi rb, 0x02 ; set rb = 0x02
|
||||
add rc, ra rb ; set rc = ra + rb
|
||||
out 0x02, rc ; send rc to the numerical display
|
Binary file not shown.
|
@ -0,0 +1,11 @@
|
|||
ldi ra, 0b10100000 ; load the num for red and blue into ra
|
||||
mrm 0x001, ra
|
||||
mrm 0x003, ra
|
||||
mrm 0x01e, ra
|
||||
mrm 0x02e, ra
|
||||
mrm 0x02f, ra
|
||||
mrm 0x030, ra
|
||||
mrm 0x031, ra
|
||||
mrm 0x023, ra
|
||||
; Draw a teal smiley face in the top left corner of the framebuffer
|
||||
; See the spreadsheet (Memory Mapped Framebuffer) for the chart I used to get these values
|
Binary file not shown.
|
@ -0,0 +1,36 @@
|
|||
use std::error::Error;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use crate::opt_sim_asm::SimpleAssemblySimulator;
|
||||
|
||||
pub fn assemble(processed: String, out: PathBuf) -> Result<(), Box<dyn Error>> {
|
||||
let mut simple_sim = SimpleAssemblySimulator {
|
||||
rom: [0u8; 4096],
|
||||
ram: [0u8; 4096],
|
||||
r0: 0,
|
||||
ra: 0,
|
||||
rb: 0,
|
||||
rc: 0,
|
||||
rd: 0,
|
||||
re: 0,
|
||||
pc: 0,
|
||||
flg: 0,
|
||||
};
|
||||
|
||||
let mut asm = vec![];
|
||||
|
||||
for (line_no, line) in processed.lines().enumerate() {
|
||||
match simple_sim.line(line) {
|
||||
Ok(mut d) => asm.append(&mut d),
|
||||
Err(e) => {
|
||||
eprintln!("{} | {}", line_no, line);
|
||||
eprintln!("Error on {}: {}", line_no, e);
|
||||
return Err(e)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fs::write(out, asm)?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
use std::error::Error;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn disassemble(file: PathBuf, out: PathBuf) -> Result<(), Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
86
src/main.rs
86
src/main.rs
|
@ -1,5 +1,89 @@
|
|||
use std::path::PathBuf;
|
||||
use clap::{Parser, ArgAction};
|
||||
use crate::asm::assemble;
|
||||
use crate::disasm::disassemble;
|
||||
use crate::normalizer::normalize;
|
||||
use crate::preprocessor::preprocess;
|
||||
|
||||
pub mod ops;
|
||||
pub mod disasm;
|
||||
pub mod normalizer;
|
||||
pub mod asm;
|
||||
pub mod preprocessor;
|
||||
pub mod opt_sim_asm;
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct Cli {
|
||||
// The input assembly file to assemble
|
||||
pub input: PathBuf,
|
||||
// The file to write the output to
|
||||
pub output: PathBuf,
|
||||
/// Only run the normalizer, and write the normalized code to the output file instead.
|
||||
#[clap(short, long, action = ArgAction::SetTrue)]
|
||||
pub normalize_only: bool,
|
||||
/// Only run up to the preprocessor, and write the normalized and preprocessed code to the output file instead.
|
||||
#[clap(short, long, action = ArgAction::SetTrue)]
|
||||
pub preprocess_only: bool,
|
||||
#[clap(short, long, action = ArgAction::SetTrue)]
|
||||
pub disassemble: bool
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
let args = Cli::parse();
|
||||
|
||||
if args.disassemble {
|
||||
match disassemble(args.input.clone(), args.output) {
|
||||
Ok(_) => std::process::exit(0),
|
||||
Err(e) => {
|
||||
eprintln!("{}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let normalized = match normalize(args.input) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
eprintln!("Normalizer error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
if args.normalize_only {
|
||||
match std::fs::write(args.output, normalized) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
eprintln!("Error writing output: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
let preprocessed = match preprocess(normalized) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
eprintln!("Preprocessor error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
if args.preprocess_only {
|
||||
match std::fs::write(args.output, preprocessed) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
eprintln!("Error writing output: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
match assemble(preprocessed, args.output) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
eprintln!("Error assembling: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
use std::error::Error;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn normalize(file: PathBuf) -> Result<String, Box<dyn Error>> {
|
||||
let file_str = fs::read_to_string(file)?;
|
||||
|
||||
let mut normalized = "; This file has only been normalized. It has not been processed or optimized.\n; This code cannot yet directly be passed into the assembler.\n".to_string();
|
||||
normalized += "; t+normalizer:tmCPU t+preprocessor:none t+optimizer:none @generated\n";
|
||||
|
||||
for (line_num, line) in file_str.lines().enumerate() {
|
||||
let line_split: Vec<&str> = line.split(' ').collect();
|
||||
|
||||
match line_split[0] {
|
||||
"lsh" => {
|
||||
if line_split.len() != 3 {
|
||||
return Err(format!("line {}: expected exactly 2 arguments to 'lsh', instead got {}", line_num, line_split.len() - 1).into());
|
||||
}
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') {
|
||||
return Err(format!("line {}: arg 1 to 'lsh' must end in ','", line_num).into());
|
||||
}
|
||||
let dest = &dest[..dest.len()-1];
|
||||
let rg = line_split[2];
|
||||
|
||||
normalized += &format!("add {}, {} {} ; normalizer: originally '{}'\n", dest, rg, rg, line);
|
||||
|
||||
},
|
||||
"cmp" => {
|
||||
if line_split.len() != 3 {
|
||||
return Err(format!("line {}: expected exactly 2 arguments to 'cmp', instead got {}", line_num, line_split.len() - 1).into());
|
||||
}
|
||||
let a = line_split[1];
|
||||
let b = line_split[2];
|
||||
|
||||
normalized += &format!("sub r0, {} {} ; normalizer: originally '{}'\n", a, b, line);
|
||||
},
|
||||
"cpy" => {
|
||||
if line_split.len() != 3 {
|
||||
return Err(format!("line {}: expected exactly 2 arguments to 'cpy', instead got {}", line_num, line_split.len() - 1).into());
|
||||
}
|
||||
let dest = line_split[1];
|
||||
let a = line_split[2];
|
||||
|
||||
if !dest.ends_with(',') {
|
||||
return Err(format!("line {}: arg 1 to 'lsh' must end in ','", line_num).into());
|
||||
}
|
||||
|
||||
normalized += "ldi r0, 0 ; normalizer: originally below\n";
|
||||
normalized += &format!("add {}, {} r0 ; normalizer: originally '{}'\n", &dest[..dest.len()-1], a, line);
|
||||
},
|
||||
"not" => {
|
||||
if line_split.len() != 3 {
|
||||
return Err(format!("line {}: expected exactly 2 arguments to 'not', instead got {}", line_num, line_split.len() - 1).into());
|
||||
}
|
||||
let dest = line_split[1];
|
||||
let a = line_split[2];
|
||||
|
||||
if !dest.ends_with(',') {
|
||||
return Err(format!("line {}: arg 1 to 'not' must end in ','", line_num).into());
|
||||
}
|
||||
|
||||
normalized += "ldi r0, 0 ; normalizer: originally below\n";
|
||||
normalized += &format!("nor {}, {} r0 ; normalizer: originally '{}'\n", &dest[..dest.len()-1], a, line);
|
||||
}
|
||||
_ => {
|
||||
normalized += line;
|
||||
normalized += "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(normalized)
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
pub fn nop() -> Vec<u8> {
|
||||
vec![0b1111_1111]
|
||||
vec![0b1111_1111, 0b0000_0000, 0b0000_0000, 0b0000_0000]
|
||||
}
|
||||
pub fn hcf() -> Vec<u8> {
|
||||
vec![0b1111_1110]
|
||||
vec![0b1111_1110, 0b0000_0000, 0b0000_0000, 0b0000_0000]
|
||||
}
|
||||
|
||||
pub enum Register {
|
||||
|
@ -183,12 +183,12 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_nop() {
|
||||
assert_eq!(nop(), vec![0b1111_1111]);
|
||||
assert_eq!(nop(), vec![0b1111_1111, 0, 0, 0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hcf() {
|
||||
assert_eq!(hcf(), vec![0b1111_1110]);
|
||||
assert_eq!(hcf(), vec![0b1111_1110, 0, 0, 0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -0,0 +1,466 @@
|
|||
use std::error::Error;
|
||||
use crate::ops::{add, and, hcf, ldi, mmr, mrm, nop, nor, or, out, r#in, Register, rmmr, rsh, sub, xor};
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub struct SimpleAssemblySimulator {
|
||||
pub rom: [u8; 4096],
|
||||
pub ram: [u8; 4096],
|
||||
|
||||
pub r0: u8,
|
||||
pub ra: u8,
|
||||
pub rb: u8,
|
||||
pub rc: u8,
|
||||
pub rd: u8,
|
||||
pub re: u8,
|
||||
pub pc: u16,
|
||||
pub flg: u8
|
||||
}
|
||||
impl SimpleAssemblySimulator {
|
||||
pub fn line(&mut self, line: &str) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
let line_split: Vec<&str> = line.split(' ').collect();
|
||||
|
||||
match line_split[0] {
|
||||
"nop" => Ok(nop()),
|
||||
"hcf" => Ok(hcf()), // ignored for the simulator
|
||||
"add" => {
|
||||
if line_split.len() != 4 { return Err("add requires exactly 3 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of add must end in , ".into()) }
|
||||
let dest = to_reg(&dest[..dest.len() - 1])?;
|
||||
let a = to_reg(line_split[2])?;
|
||||
|
||||
let a_val = match a {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
let b = to_reg(line_split[3])?;
|
||||
|
||||
let b_val = match b {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
let mut val = (a_val as u16) + (b_val as u16);
|
||||
if val > u8::MAX as u16 {
|
||||
val = u8::MAX as u16; // ignore overflow
|
||||
}
|
||||
|
||||
match dest {
|
||||
Register::R0 => self.r0 = val as u8,
|
||||
Register::RA => self.ra = val as u8,
|
||||
Register::RB => self.rb = val as u8,
|
||||
Register::RC => self.rc = val as u8,
|
||||
Register::RD => self.rd = val as u8,
|
||||
Register::RE => self.re = val as u8,
|
||||
Register::PC => self.pc = (val as u8) as u16,
|
||||
Register::FLG => self.flg = val as u8
|
||||
}
|
||||
|
||||
Ok(add(dest, a, b))
|
||||
},
|
||||
"sub" => {
|
||||
if line_split.len() != 4 { return Err("sub requires exactly 3 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of sub must end in , ".into()) }
|
||||
let dest = to_reg(&dest[..dest.len() - 1])?;
|
||||
let a = to_reg(line_split[2])?;
|
||||
|
||||
let a_val = match a {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
let b = to_reg(line_split[3])?;
|
||||
|
||||
let b_val = match b {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
let val;
|
||||
if b_val > a_val {
|
||||
val = 0;
|
||||
} else {
|
||||
val = a_val - b_val;
|
||||
}
|
||||
|
||||
match dest {
|
||||
Register::R0 => self.r0 = val,
|
||||
Register::RA => self.ra = val,
|
||||
Register::RB => self.rb = val,
|
||||
Register::RC => self.rc = val,
|
||||
Register::RD => self.rd = val,
|
||||
Register::RE => self.re = val,
|
||||
Register::PC => self.pc = (val) as u16,
|
||||
Register::FLG => self.flg = val
|
||||
}
|
||||
|
||||
Ok(sub(dest, a, b))
|
||||
},
|
||||
"or" => {
|
||||
if line_split.len() != 4 { return Err("or requires exactly 3 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of or must end in , ".into()) }
|
||||
let dest = to_reg(&dest[..dest.len() - 1])?;
|
||||
let a = to_reg(line_split[2])?;
|
||||
|
||||
let a_val = match a {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
let b = to_reg(line_split[3])?;
|
||||
|
||||
let b_val = match b {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
match dest {
|
||||
Register::R0 => self.r0 = a_val | b_val,
|
||||
Register::RA => self.ra = a_val | b_val,
|
||||
Register::RB => self.rb = a_val | b_val,
|
||||
Register::RC => self.rc = a_val | b_val,
|
||||
Register::RD => self.rd = a_val | b_val,
|
||||
Register::RE => self.re = a_val | b_val,
|
||||
Register::PC => self.pc = (a_val | b_val) as u16,
|
||||
Register::FLG => self.flg = a_val | b_val
|
||||
}
|
||||
|
||||
Ok(or(dest, a, b))
|
||||
},
|
||||
"nor" => {
|
||||
if line_split.len() != 4 { return Err("nor requires exactly 3 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of nor must end in , ".into()) }
|
||||
let dest = to_reg(&dest[..dest.len() - 1])?;
|
||||
let a = to_reg(line_split[2])?;
|
||||
|
||||
let a_val = match a {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
let b = to_reg(line_split[3])?;
|
||||
|
||||
let b_val = match b {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
match dest {
|
||||
Register::R0 => self.r0 = !(a_val | b_val),
|
||||
Register::RA => self.ra = !(a_val | b_val),
|
||||
Register::RB => self.rb = !(a_val | b_val),
|
||||
Register::RC => self.rc = !(a_val | b_val),
|
||||
Register::RD => self.rd = !(a_val | b_val),
|
||||
Register::RE => self.re = !(a_val | b_val),
|
||||
Register::PC => self.pc = !(a_val | b_val) as u16,
|
||||
Register::FLG => self.flg = !(a_val | b_val)
|
||||
}
|
||||
|
||||
Ok(nor(dest, a, b))
|
||||
},
|
||||
"and" => {
|
||||
if line_split.len() != 4 { return Err("and requires exactly 3 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of and must end in , ".into()) }
|
||||
let dest = to_reg(&dest[..dest.len() - 1])?;
|
||||
let a = to_reg(line_split[2])?;
|
||||
|
||||
let a_val = match a {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
let b = to_reg(line_split[3])?;
|
||||
|
||||
let b_val = match b {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
match dest {
|
||||
Register::R0 => self.r0 = a_val & b_val,
|
||||
Register::RA => self.ra = a_val & b_val,
|
||||
Register::RB => self.rb = a_val & b_val,
|
||||
Register::RC => self.rc = a_val & b_val,
|
||||
Register::RD => self.rd = a_val & b_val,
|
||||
Register::RE => self.re = a_val & b_val,
|
||||
Register::PC => self.pc = (a_val & b_val) as u16,
|
||||
Register::FLG => self.flg = a_val & b_val
|
||||
}
|
||||
|
||||
Ok(and(dest, a, b))
|
||||
},
|
||||
"xor" => {
|
||||
if line_split.len() != 4 { return Err("xor requires exactly 3 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of xor must end in , ".into()) }
|
||||
let dest = to_reg(&dest[..dest.len() - 1])?;
|
||||
let a = to_reg(line_split[2])?;
|
||||
|
||||
let a_val = match a {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
let b = to_reg(line_split[3])?;
|
||||
|
||||
let b_val = match b {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
match dest {
|
||||
Register::R0 => self.r0 = a_val ^ b_val,
|
||||
Register::RA => self.ra = a_val ^ b_val,
|
||||
Register::RB => self.rb = a_val ^ b_val,
|
||||
Register::RC => self.rc = a_val ^ b_val,
|
||||
Register::RD => self.rd = a_val ^ b_val,
|
||||
Register::RE => self.re = a_val ^ b_val,
|
||||
Register::PC => self.pc = (a_val ^ b_val) as u16,
|
||||
Register::FLG => self.flg = a_val ^ b_val
|
||||
}
|
||||
|
||||
Ok(xor(dest, a, b))
|
||||
},
|
||||
"rsh" => {
|
||||
if line_split.len() != 3 { return Err("rsh requires exactly 2 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of rsh must end in , ".into()) }
|
||||
let dest = to_reg(&dest[..dest.len() - 1])?;
|
||||
let a = to_reg(line_split[2])?;
|
||||
|
||||
let a_val = match a {
|
||||
Register::R0 => self.r0,
|
||||
Register::RA => self.ra,
|
||||
Register::RB => self.rb,
|
||||
Register::RC => self.rc,
|
||||
Register::RD => self.rd,
|
||||
Register::RE => self.re,
|
||||
Register::PC => return Err("Cannot use program counter as a register".into()),
|
||||
Register::FLG => self.flg
|
||||
};
|
||||
|
||||
match dest {
|
||||
Register::R0 => self.r0 = a_val >> 1,
|
||||
Register::RA => self.ra = a_val >> 1,
|
||||
Register::RB => self.rb = a_val >> 1,
|
||||
Register::RC => self.rc = a_val >> 1,
|
||||
Register::RD => self.rd = a_val >> 1,
|
||||
Register::RE => self.re = a_val >> 1,
|
||||
Register::PC => self.pc = (a_val >> 1) as u16,
|
||||
Register::FLG => self.flg = a_val >> 1
|
||||
}
|
||||
|
||||
Ok(rsh(dest, a))
|
||||
},
|
||||
"ldi" => {
|
||||
if line_split.len() != 3 { return Err("rsh requires exactly 2 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of rsh must end in , ".into()) }
|
||||
let dest = to_reg(&dest[..dest.len() - 1])?;
|
||||
let data: u8 = parse_int::parse(line_split[2])?;
|
||||
|
||||
match dest {
|
||||
Register::R0 => self.r0 = data,
|
||||
Register::RA => self.ra = data,
|
||||
Register::RB => self.rb = data,
|
||||
Register::RC => self.rc = data,
|
||||
Register::RD => self.rd = data,
|
||||
Register::RE => self.re = data,
|
||||
Register::PC => self.pc = data as u16,
|
||||
Register::FLG => self.flg = data
|
||||
}
|
||||
|
||||
Ok(ldi(dest, data))
|
||||
},
|
||||
"mmr" => {
|
||||
if line_split.len() != 3 { return Err("mmr requires exactly 2 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of mmr must end in , ".into()) }
|
||||
let dest = to_reg(&dest[..dest.len() - 1])?;
|
||||
let address: u16 = parse_int::parse(line_split[2])?;
|
||||
|
||||
match dest {
|
||||
Register::R0 => self.r0 = self.ram[address as usize],
|
||||
Register::RA => self.ra = self.ram[address as usize],
|
||||
Register::RB => self.rb = self.ram[address as usize],
|
||||
Register::RC => self.rc = self.ram[address as usize],
|
||||
Register::RD => self.rd = self.ram[address as usize],
|
||||
Register::RE => self.re = self.ram[address as usize],
|
||||
Register::PC => self.pc = self.ram[address as usize] as u16,
|
||||
Register::FLG => self.flg = self.ram[address as usize]
|
||||
}
|
||||
|
||||
Ok(mmr(dest, address))
|
||||
},
|
||||
"mrm" => {
|
||||
if line_split.len() != 3 { return Err("mrm requires exactly 2 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of mrm must end in , ".into()) }
|
||||
|
||||
let src = line_split[2];
|
||||
let src = to_reg(src)?;
|
||||
|
||||
let address: u16 = parse_int::parse(&line_split[1][..line_split[1].len()-1])?;
|
||||
|
||||
match src {
|
||||
Register::R0 => self.ram[address as usize] = self.r0,
|
||||
Register::RA => self.ram[address as usize] = self.ra,
|
||||
Register::RB => self.ram[address as usize] = self.rb,
|
||||
Register::RC => self.ram[address as usize] = self.rc,
|
||||
Register::RD => self.ram[address as usize] = self.rd,
|
||||
Register::RE => self.ram[address as usize] = self.re,
|
||||
Register::PC => self.ram[address as usize] = self.pc.try_into().unwrap(),
|
||||
Register::FLG => self.ram[address as usize] = self.flg
|
||||
}
|
||||
|
||||
Ok(mrm(src, address))
|
||||
},
|
||||
"in" => {
|
||||
if line_split.len() != 3 { return Err("in requires exactly 2 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of in must end in , ".into()) }
|
||||
let dest = to_reg(&dest[..dest.len() - 1])?;
|
||||
let port: u8 = parse_int::parse(line_split[2])?;
|
||||
|
||||
Ok(r#in(dest, port))
|
||||
},
|
||||
"out" => {
|
||||
if line_split.len() != 3 { return Err("in requires exactly 2 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of in must end in , ".into()) }
|
||||
|
||||
let src = line_split[2];
|
||||
let src = to_reg(src)?;
|
||||
|
||||
let port: u8 = parse_int::parse(&line_split[1][..line_split[1].len()-1])?;
|
||||
|
||||
Ok(out(src, port))
|
||||
},
|
||||
"rmmr" => {
|
||||
if line_split.len() != 3 { return Err("rmmr requires exactly 2 arguments".into()) }
|
||||
|
||||
let dest = line_split[1];
|
||||
if !dest.ends_with(',') { return Err("1st argument of rmmr must end in , ".into()) }
|
||||
let dest = to_reg(&dest[..dest.len() - 1])?;
|
||||
let address: u16 = parse_int::parse(line_split[2])?;
|
||||
|
||||
match dest {
|
||||
Register::R0 => self.r0 = self.ram[address as usize],
|
||||
Register::RA => self.ra = self.ram[address as usize],
|
||||
Register::RB => self.rb = self.ram[address as usize],
|
||||
Register::RC => self.rc = self.ram[address as usize],
|
||||
Register::RD => self.rd = self.ram[address as usize],
|
||||
Register::RE => self.re = self.ram[address as usize],
|
||||
Register::PC => self.pc = self.ram[address as usize] as u16,
|
||||
Register::FLG => self.flg = self.ram[address as usize]
|
||||
}
|
||||
|
||||
Ok(rmmr(dest, address))
|
||||
}
|
||||
_ => Err(format!("Unknown instruction {}", line_split[0]).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_reg(s: &str) -> Result<Register, Box<dyn Error>> {
|
||||
match s {
|
||||
"r0" => Ok(Register::R0),
|
||||
"ra" => Ok(Register::RA),
|
||||
"rb" => Ok(Register::RB),
|
||||
"rc" => Ok(Register::RC),
|
||||
"rd" => Ok(Register::RD),
|
||||
"re" => Ok(Register::RE),
|
||||
"pc" => Ok(Register::PC),
|
||||
"flg" => Ok(Register::FLG),
|
||||
_ => Err(format!("Unknown register {}", s).into())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
use std::error::Error;
|
||||
|
||||
pub fn preprocess(normalized: String) -> Result<String, Box<dyn Error>> {
|
||||
let mut processed = String::new();
|
||||
|
||||
for (_line_num, line) in normalized.lines().enumerate() {
|
||||
let mut line_comments_removed = String::new();
|
||||
for char in line.chars() {
|
||||
if char == ';' {
|
||||
break;
|
||||
} else {
|
||||
line_comments_removed += char.to_string().as_str();
|
||||
}
|
||||
}
|
||||
|
||||
if !line_comments_removed.is_empty() {
|
||||
processed += line_comments_removed.trim_start_matches(' ').trim_end_matches(' ');
|
||||
processed += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
Ok(processed)
|
||||
}
|
Loading…
Reference in New Issue