Skip to content

Commit 0966628

Browse files
committed
updated interactive mode
switched to clap for command parsing added breakpoints added memory range printing now it is possible to print certain range of memory added pretty table print for memory printing
1 parent 2fca220 commit 0966628

File tree

6 files changed

+267
-118
lines changed

6 files changed

+267
-118
lines changed

src/interactive.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
use std::io;
2+
3+
use clap::{Error, Parser, Subcommand};
4+
5+
6+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
7+
pub enum InteractiveState {
8+
DISABLED,
9+
ENABLED,
10+
WAITING_FOR_BREAKPOINT,
11+
}
12+
13+
impl InteractiveState {
14+
pub fn is_enabled(&self) -> bool { return *self == Self::ENABLED }
15+
pub fn is_disabled(&self) -> bool { return *self == Self::DISABLED }
16+
pub fn is_waiting_bp(&self) -> bool { return *self == Self::WAITING_FOR_BREAKPOINT }
17+
}
18+
19+
#[derive(Parser, Debug)]
20+
#[command(name = ">", about = "An interactive debuging tool", long_about = None)]
21+
pub struct InteractiveCli {
22+
#[command(subcommand)]
23+
pub cmd: Command,
24+
}
25+
26+
#[derive(Subcommand, Debug)]
27+
pub enum Command {
28+
/// Proceed to the next instruction (alias: n)
29+
#[command(alias = "n")]
30+
NEXT,
31+
32+
/// Continue until the next breakpoint (alias: nb)
33+
#[command(alias = "nb")]
34+
NEXT_BREAKPOINT,
35+
36+
/// Add a breakpoint at a specified line (alias: ab)
37+
#[command(alias = "ab")]
38+
ADD_BREAKPOINT {
39+
/// Line number for the breakpoint
40+
line: usize,
41+
},
42+
43+
/// Delete a breakpoint at a specified line if exists (alias: db)
44+
#[command(alias = "db")]
45+
DELETE_BREAKPOINT {
46+
/// Line number of the breakpoint to delete
47+
line: usize,
48+
},
49+
50+
/// List all breakpoints (alias: lb)
51+
#[command(alias = "lb")]
52+
LIST_BREAKPOINTS,
53+
54+
/// Aborts execution (alias: q)
55+
#[command(alias = "q")]
56+
QUIT,
57+
58+
/// Disables interactive mode and finishes execution (alias: f)
59+
#[command(alias = "f")]
60+
FINISH,
61+
62+
/// Print memory from a start address to an end address (alias: m)
63+
#[command(alias = "m")]
64+
MEM {
65+
/// Inclusive start address of memory
66+
#[arg(short = 'f', long = "from", short, default_value_t = 0)]
67+
from: usize,
68+
/// Exclusive end address of memory
69+
#[arg(short, long, default_value_t = 512)]
70+
to: usize,
71+
/// File where u want to store a snapshot
72+
#[arg(long = "file")]
73+
file: Option<String>
74+
},
75+
}
76+
77+
impl InteractiveCli {
78+
79+
pub fn read() -> Result<InteractiveCli, Error> {
80+
let mut input = String::new();
81+
io::stdin().read_line(&mut input).expect("Failed to read line");
82+
let mut args: Vec<&str> = input.trim().split_whitespace().collect();
83+
args.insert(0, "");
84+
InteractiveCli::try_parse_from(args)
85+
}
86+
87+
pub fn print_start_baner() {
88+
println!("_________ ________ _ ____ ___");
89+
println!("| ___ \\ \\/ / __ \\ | | | | \\/ |");
90+
println!("| |_/ / . . | / \\/ | | | | . . |");
91+
println!("| __/| |\\/| | | | | | | |\\/| |");
92+
println!("| | | | | | \\__/\\ \\ \\_/ / | | |");
93+
println!("\\_| \\_| |_\\/____/ \\___/|_| |_| by poneciak");
94+
println!("Welcome to interactive mode type 'help' for more info");
95+
println!("Every instruction is displayed and then you can type your command");
96+
println!("");
97+
}
98+
}

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
pub mod parser;
22
pub mod instruction;
3-
pub mod processor;
3+
pub mod processor;
4+
pub mod mem;
5+
pub mod interactive;

src/main.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::{fs, path::PathBuf};
22

33
use clap::{command, Parser};
4-
use pmc_interpreter::{parser::parse, processor::PROC};
4+
use pmc_interpreter::{interactive::InteractiveState, parser::parse, processor::PROC};
55

66
/// A simple PMC
77
#[derive(Parser, Debug)]
@@ -23,7 +23,11 @@ fn main() {
2323
let mut mem = parse(&content);
2424
let mut proc = PROC::new();
2525
// mem.print_range(0..30);
26-
proc.run(&mut mem, cli.interactive);
27-
mem.dump_all(Some("mem.out".to_string()));
26+
let interactive_state = if cli.interactive {
27+
InteractiveState::ENABLED
28+
} else {
29+
InteractiveState::DISABLED
30+
};
31+
proc.run(&mut mem, interactive_state);
2832
//mem.dump_all();
2933
}

src/mem.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
use std::fs::OpenOptions;
2+
use std::io::{self, Write};
3+
4+
5+
use crate::instruction::Instruction;
6+
7+
pub struct MEM {
8+
pub(crate) inner: [Instruction; 512],
9+
}
10+
11+
impl MEM {
12+
13+
pub(crate) fn new(inner: [Instruction; 512]) -> Self {
14+
Self { inner }
15+
}
16+
17+
pub(crate) fn set(&mut self, i: u16, val: u16, interactive: bool) {
18+
if i >= 512 {
19+
panic!("Adress out of bounds. Tried to access memory at index: {}", i);
20+
}
21+
if interactive { println!("{:<2}Modified MEM[{}] = {}", "", i, val); }
22+
self.inner[i as usize] = Instruction { raw: val };
23+
}
24+
25+
pub(crate) fn get(&self, i: u16) -> Instruction {
26+
if i >= 512 {
27+
panic!("Adress out of bounds. Tried to access memory at index: {}", i);
28+
}
29+
self.inner[i as usize]
30+
}
31+
32+
pub(crate) fn get_raw(&self, i: u16) -> u16 {
33+
unsafe { self.get(i).raw }
34+
}
35+
36+
37+
pub fn write_to_file(&self, filename: String, range: std::ops::Range<usize>) {
38+
let mut file = OpenOptions::new()
39+
.write(true)
40+
.append(false)
41+
.create(true)
42+
.open(&filename)
43+
.expect("Expected output file creation");
44+
self.print_table(&mut file, range)
45+
.expect("Expected successfull write to file");
46+
println!("{:<2}Written memory snapshot to {}", "", filename);
47+
return;
48+
}
49+
50+
pub fn print(&self, range: std::ops::Range<usize>) {
51+
self.print_table(&mut io::stdout(), range)
52+
.expect("Expected successfull print to stdout");
53+
}
54+
55+
fn print_table<W: Write>(&self, out: &mut W, range: std::ops::Range<usize>) -> io::Result<()> {
56+
let headers = ["ID", "Binary repr", "Instruction repr", "Number repr"];
57+
let col_widths = [4, 17, 20, 15];
58+
59+
// headers
60+
for (header, &width) in headers.iter().zip(&col_widths) {
61+
write!(out, "{:<width$} ", header, width = width)?;
62+
}
63+
writeln!(out)?;
64+
65+
// separator line
66+
for &width in &col_widths {
67+
write!(out, "{:-<width$}", "", width = width)?;
68+
}
69+
writeln!(out)?;
70+
71+
// rows
72+
for i in range {
73+
let row: [String; 4];
74+
unsafe {
75+
let inner = self.inner[i as usize].inner;
76+
let sgn = if inner.sign() == 1 { '-' } else { '+' };
77+
78+
let binary_raw = format!("{:0>15b}", self.inner[i as usize].raw);
79+
let instruction = format!("{} {:?} {:?} {}", sgn, inner.code(), inner.adrt(), inner.adr());
80+
let number = format!("{}", self.inner[i as usize].raw);
81+
row = [
82+
i.to_string(),
83+
binary_raw,
84+
instruction,
85+
number
86+
];
87+
}
88+
for (cell, &width) in row.iter().zip(&col_widths) {
89+
write!(out, "{:<width$} ", cell, width = width)?;
90+
}
91+
writeln!(out)?;
92+
}
93+
writeln!(out)?;
94+
Ok(())
95+
}
96+
}

src/parser.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{instruction::{Adrt, Code, InnerInstruction, Instruction}, processor::MEM};
1+
use crate::{instruction::{Adrt, Code, InnerInstruction, Instruction}, mem::MEM};
22

33

44

0 commit comments

Comments
 (0)