Big commit: barely functional version. Added syntax highlighting in the browser, parsing errors being highlighted, cpu errors being displayed (not highlighted yet), minor backend improvements, massive frontend improvements.

This commit is contained in:
Raphael Jacobs 2022-10-12 14:36:23 +02:00
parent 0ed779ae3a
commit 2851e78e7e
15 changed files with 478 additions and 114 deletions

View File

@ -1,8 +1,64 @@
mark.goodcode {
background-color: #deffff
}
mark.error {
background-color: #f58782
}
mark.comment {
background-color: #e0e0e0
}
.container {
position: relative;
width: 320px;
height: 440px;
}
#editing, #highlighting {
/* Both elements need the same text and space styling so they are directly on top of each other */
margin: 0px;
padding: 10px;
border: 2px solid black;
width: 300px;
height: 400px;
position: absolute;
top: 0;
left: 0;
overflow: scroll;
white-space: nowrap; /* Allows textarea to scroll horizontally */
}
#editing {
z-index: 1;
resize: none;
background: transparent;
}
#highlighting {
z-index: 0;
color: transparent;
}
#editing, #highlighting, #highlighting * {
/* Also add text styles to highlighting tokens */
font-size: 10pt;
font-family: monospace;
white-space: pre-wrap;
}
.centred {
text-align: center;
/* text-align: center; */
margin: auto;
max-width: 70vw;
max-width: 70%;
}
.spaced {
/* justify-content: space-between; */
gap: 30px;
}
.vertical {
@ -14,3 +70,8 @@
display: flex;
flex-direction: row;
}
table, th, td {
border: 2px solid black;
border-collapse: collapse;
}

View File

@ -4,26 +4,83 @@
<meta charset="utf-8" />
<title>JUMP!! HALT!! CATCH FIRE!!</title>
<link rel="stylesheet" href="css/style.css">
<script src="js/bundle.js"></script>
<script defer src="js/bundle.js"></script></head>
<link rel="stylesheet" href="css/style.css" />
<script defer src="js/bundle.js"></script>
</head>
<body>
<div class="centred">
<h3>L'incredibile interprete di RJ</h3>
<div class="interpreter vertical">
<div class="programbox">
</div>
<div class="inputbox">
</div>
<div class="memory">
<div class="vertical centred">
<div class="interpreter spaced horizontal">
<div class="vertical">
<div class="container">
<textarea id="editing" col="60" row="80">
# This is a sample program that reads two numbers from input, computes their sum, and writes it to output. Read below to learn more about the machine and the syntax.
READ 1
READ 2
LOAD 1
ADD 2
STORE 3
WRITE 3
HALT
</textarea
>
<pre id="highlighting" aria-hidden="true"></pre>
</div>
</div>
<div class="right-container vertical">
<div class="inputcontainter">
<h3>INPUT:</h3>
<input type="text" id="inputqueue" value="" />
</div>
<div class="outputcontainer">
<h3>OUTPUT:</h3>
<div class="outputbox">
<p id="outputqueue"></p>
</div>
<!-- <input type="text" name="inputqueue" value="" /> -->
</div>
<h3>MEMORY:</h3>
<table id="memtable">
<tr>
<th>r0</th>
<th>r1</th>
<th>r2</th>
<th>r3</th>
<th>r4</th>
<th>r5</th>
<th>r6</th>
<th>r7</th>
<th>r8</th>
<th>r9</th>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
</table>
<p id="errormessage"></p>
</div>
</div>
<div class="errorbox"></div>
<div class="buttons centred">
<button id="load" type="button">Load</button>
<button id="run" type="button">Run</button>
<button id="run1" type="button">Run single step</button>
<button id="reset" type="button">Reset memory</button>
<!-- <button id="run1" type="button">Reset </button> -->
</div>
</div>
</div>
</body>
</html>

View File

@ -9,6 +9,8 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@types/jquery": "^3.5.14",
"jquery": "^3.6.1",
"ts-loader": "^9.4.1",
"typescript": "^4.1.3",
"webpack-cli": "^4.10.0"

57
rammodel/Cargo.lock generated
View File

@ -17,6 +17,12 @@ version = "3.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -30,6 +36,7 @@ dependencies = [
"js-sys",
"regex",
"wasm-bindgen",
"wee_alloc",
]
[[package]]
@ -41,13 +48,19 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.134"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb"
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@ -56,6 +69,12 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memory_units"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3"
[[package]]
name = "once_cell"
version = "1.15.0"
@ -120,7 +139,7 @@ version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"wasm-bindgen-macro",
]
@ -167,3 +186,37 @@ name = "wasm-bindgen-shared"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
[[package]]
name = "wee_alloc"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e"
dependencies = [
"cfg-if 0.1.10",
"libc",
"memory_units",
"winapi",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -19,6 +19,7 @@ regex = "1.6.0"
js-sys = "0.3.60"
# lazy_static = "1.4.0"
wasm-bindgen = "0.2"
wee_alloc = "0.4.5"
[[bin]]
name = "cli"

View File

@ -29,7 +29,7 @@ use Instruction::*;
type InstructionNumber = usize;
#[derive(Debug, Clone)]
pub enum CpuErrors {
pub enum CpuError {
EndOfInput(InstructionNumber),
BadRegister(InstructionNumber, Register),
OverFlow(InstructionNumber),
@ -38,7 +38,7 @@ pub enum CpuErrors {
ProgramIsOver(InstructionNumber),
}
use CpuErrors::*;
use CpuError::*;
pub struct CPU {
pc: Register, // Which register is the program counter?
@ -50,6 +50,7 @@ pub struct CPU {
acc_access: bool, // can we access the acc register? Defaults to no.
pub stopped: bool,
steps: u32, // how many steps did the program take to run?
}
impl Default for CPU {
@ -63,6 +64,7 @@ impl Default for CPU {
output_filo: vec![].into(),
stopped: false,
acc_access: false,
steps: 0,
}
}
}
@ -99,8 +101,8 @@ impl CPU {
}
/// Used internally, retrives one number from the input queue.
/// Returns an error if the queue is empty.
fn getinput(&mut self) -> Result<Word, CpuErrors> {
/// Returns an EndOfInput error if the queue is empty.
fn getinput(&mut self) -> Result<Word, CpuError> {
match self.input_filo.pop_back() {
Some(w) => return Ok(w),
None => {
@ -117,53 +119,56 @@ impl CPU {
/// Increases the program counter by one.
/// If the program counter ever reaches the end of
/// the program (no HALT instruction), returns an error.
fn pc_increase(&mut self) -> Result<(), CpuErrors> {
/// the program (no HALT instruction), returns a ProgramIsOver error.
fn pc_increase(&mut self) -> Result<(), CpuError> {
self.regmemory[self.pc] += 1;
if self.regmemory[self.pc] >= self.program.len() as u32 {
return Err(ProgramIsOver(self.pc));
let n = self.readmemory(&self.pc.clone()).unwrap();
return Err(ProgramIsOver(n as usize));
}
Ok(())
}
/// Check if an address is the accumulator.
/// Used to check if we're trying to access the accumulator.
/// Returns an error in case. If acc_access is set to true, does nothing.
fn acc_access_check(&self, addr: &Register) -> Result<(), CpuErrors> {
/// Returns an AccAccess error in case. If acc_access is set to true, does nothing.
fn acc_access_check(&mut self, addr: &Register) -> Result<(), CpuError> {
if !self.acc_access {
if *addr == self.acc {
return Err(AccAccess(self.pc));
let n = self.readmemory(&self.pc.clone()).unwrap();
return Err(AccAccess(n as usize));
}
}
return Ok(());
}
/// Check if a jump instruction will take the program to a
/// non-existing instruction. Returns an error in case.
fn jump_check(&self, dest: &Word) -> Result<(), CpuErrors> {
if *dest >= self.program.len() as u32 {
return Err(BadJump(self.pc));
/// non-existing instruction. Returns a BadJump error in case.
fn jump_check(&mut self, dest: &Word) -> Result<(), CpuError> {
if *dest > self.program.len() as u32 {
let n = self.readmemory(&self.pc.clone()).unwrap();
return Err(BadJump(n as usize));
} else {
return Ok(());
}
}
/// Retrives the value of some register. If the register doesn't
/// exist, returns an error.
fn readmemory(&mut self, addr: &Register) -> Result<Word, CpuErrors> {
/// exist, returns a BadRegister error.
fn readmemory(&mut self, addr: &Register) -> Result<Word, CpuError> {
if addr >= &self.regmemory.len() {
let n = &self.readmemory(&self.pc.clone()).unwrap();
return Err(BadRegister(*n as usize, *addr));
let n = self.readmemory(&self.pc.clone()).unwrap();
return Err(BadRegister(n as usize, *addr));
}
return Ok(self.regmemory[*addr]);
}
/// Writes a value to a register. If the register doesn't exist, returns an error.
fn writememory(&mut self, addr: &Register, w: Word) -> Result<(), CpuErrors> {
/// Writes a value to a register. If the register doesn't exist, returns a BadRegister.
fn writememory(&mut self, addr: &Register, w: Word) -> Result<(), CpuError> {
if addr >= &self.regmemory.len() {
let n = &self.readmemory(&self.pc.clone()).unwrap();
return Err(BadRegister(*n as usize, *addr));
let n = self.readmemory(&self.pc.clone()).unwrap();
return Err(BadRegister(n as usize, *addr));
}
self.regmemory[*addr] = w;
@ -171,45 +176,42 @@ impl CPU {
}
/// Executes a single statement.
pub fn execone(&mut self) -> Result<(), CpuErrors> {
pub fn execone(&mut self) -> Result<(), CpuError> {
let acc = &self.acc.clone(); // constant
let pc = &self.pc.clone(); // constant
let pc_val = self.readmemory(pc)?;
let op = &self.program[pc_val as usize]; // fetch
// println!("{:?}, {}", *op, pc_val);
match *op {
READ(r) => {
self.acc_access_check(&r)?;
let k = self.getinput()?;
self.writememory(&r, k)?;
self.pc_increase()?;
}
WRITE(r) => {
self.acc_access_check(&r)?;
let k = self.readmemory(&r)?;
self.writeoutput(&k);
self.pc_increase()?;
}
LOAD(r) => {
self.acc_access_check(&r)?;
let k = self.readmemory(&r)?;
self.writememory(acc, k)?;
self.pc_increase()?;
}
LOADI(w) => {
self.writememory(acc, w)?;
self.pc_increase()?;
}
STORE(r) => {
self.acc_access_check(&r)?;
let k = self.readmemory(acc)?;
self.writememory(&r, k)?;
self.pc_increase()?;
}
ADD(r) => {
@ -217,13 +219,11 @@ impl CPU {
let k = &self.readmemory(&r)?;
let acc_current = self.readmemory(acc)?;
self.writememory(acc, acc_current + k)?;
self.pc_increase()?;
}
ADDI(w) => {
let acc_current = self.readmemory(acc)?;
self.writememory(acc, acc_current + w)?;
self.pc_increase()?;
}
SUB(r) => {
@ -231,18 +231,17 @@ impl CPU {
let k = &self.readmemory(&r)?;
let acc_current = self.readmemory(acc)?;
self.writememory(acc, acc_current - k)?;
self.pc_increase()?;
}
SUBI(w) => {
let acc_current = self.readmemory(acc)?;
self.writememory(acc, acc_current - w)?;
self.pc_increase()?;
}
JUMP(u) => {
self.jump_check(&u)?;
self.writememory(pc, u - 1)?;
return Ok(());
}
JZERO(u) => {
@ -250,9 +249,8 @@ impl CPU {
let accval = self.readmemory(acc)?;
if accval == 0 {
self.writememory(pc, u - 1)?;
} else {
self.pc_increase();
}
return Ok(());
}
}
JGTZ(u) => {
@ -260,9 +258,8 @@ impl CPU {
let accval = self.readmemory(acc)?;
if accval > 0 {
self.writememory(pc, u - 1)?;
} else {
self.pc_increase();
}
return Ok(());
}
}
// NON DOCUMENTED!
@ -270,18 +267,21 @@ impl CPU {
let u = self.readmemory(&w)?;
self.jump_check(&u)?;
self.writememory(pc, u)?;
return Ok(());
}
HALT => self.stopped = true,
HALT => {self.stopped = true; return Ok(())}
};
self.pc_increase()?;
return Ok(());
}
/// Executes the whole program, calling execone multiple times
/// until a HALT instruction is found.
pub fn exec(&mut self) -> Result<(), CpuErrors> {
pub fn exec(&mut self) -> Result<(), CpuError> {
while !self.stopped {
self.execone()?;
self.steps+=1;
}
return Ok(());

View File

@ -3,10 +3,20 @@ use js_sys::Uint32Array;
use wasm_bindgen::prelude::*;
use super::cpu::*;
use super::cpu::CpuError::*;
#[wasm_bindgen]
extern "C" {
fn signalerror(s: &str);
#[wasm_bindgen(js_namespace = CPUEMU)]
fn signalerror(msg: &str, l: Option<u32>);
}
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = CPUEMU)]
fn signalparseerr(l: u32);
}
#[wasm_bindgen]
@ -46,18 +56,36 @@ impl WrapCpu {
pub fn one_step(&mut self) {
match self.cpu.execone() {
Ok(()) => {}
Err(k) => signalerror(&format!("{:?}", k)),
Err(k) => cpuErrDispatch(k),
};
}
pub fn run(&mut self) {
match self.cpu.exec() {
Ok(()) => {}
Err(k) => cpuErrDispatch(k),
};
}
pub fn load_program(&mut self, prg: &str) {
match parse_program(prg) {
Ok(p) => self.cpu.load_new(&p),
Err(_) => {}
Err(ParseError::ErrorAtLine(l)) => {signalparseerr(l as u32)}
}
}
pub fn test(&self) {
signalerror("yolo")
}
}
fn cpuErrDispatch(err: CpuError) {
match err {
EndOfInput(n) => {signalerror("End of input! Add more input?", Some(n as u32))}
BadRegister(n, r) => {signalerror(&format!("The register {} doesn't exist!", r), Some(n as u32))}
OverFlow(n) => {signalerror("Overflow! Did you go into the negative numbers?", Some(n as u32))}
AccAccess(n) => {signalerror("Tried to access register 0. That's illegal!", Some(n as u32))}
BadJump(n) => {signalerror("Bad jump instruction!", Some(n as u32))}
ProgramIsOver(n) => {signalerror("The program is over! Forgot to HALT?", Some(n as u32))}
}
}

View File

@ -32,27 +32,34 @@ pub fn main() {
println!("Executing...\n");
match processor.exec() {
Err(CpuErrors::BadRegister(l, r)) => {
Err(CpuError::BadRegister(l, r)) => {
println!(
"Error, register {} does not exist! Program counter at: {}",
r, l
)
}
Err(CpuErrors::OverFlow(l)) => {
Err(CpuError::OverFlow(l)) => {
println!("Error, Overflow! Program counter at: {}", l)
}
Err(CpuErrors::EndOfInput(l)) => {
Err(CpuError::EndOfInput(l)) => {
println!("Error, end of input! Did you forget to add enough input numbers? Program counter at {}", l)
}
Err(CpuErrors::BadJump(l)) => {
Err(CpuError::BadJump(l)) => {
println!("Error, bad jump instruction! Program counter was {}", l)
}
Err(CpuErrors::AccAccess(l)) => {
Err(CpuError::AccAccess(l)) => {
println!(
"Error, tried to access the accumulator! Program counter at {}",
l
)
}
Err(CpuError::ProgramIsOver(l)) => {
println!(
"Error, program is over! Did you forget to HALT? Program counter at {}",
l
)
}
Ok(()) => {}
}

View File

@ -82,21 +82,21 @@ pub fn parse_line(line: &str) -> Option<Instruction> {
// COULD BE BETTER!!!!!!!!!
let patternspairs = [
(FnWrap::new(|x| READ(x.parse().unwrap())), r"READ\s+(\d+)"),
(FnWrap::new(|x| WRITE(x.parse().unwrap())), r"WRITE\s+(\d+)"),
(FnWrap::new(|x| LOAD(x.parse().unwrap())), r"LOAD\s+(\d+)"),
(FnWrap::new(|x| READ(x.parse().unwrap())), r"READ\s+(\d+)\s*#?.*"),
(FnWrap::new(|x| WRITE(x.parse().unwrap())), r"WRITE\s+(\d+)\s*#?.*"),
(FnWrap::new(|x| LOAD(x.parse().unwrap())), r"LOAD\s+(\d+)\s*#?.*"),
(
FnWrap::new(|x| LOADI(x.parse().unwrap())),
r"LOAD\s+=\s*(\d+)",
r"LOAD\s+=\s*(\d+)\s*#?.*",
),
(FnWrap::new(|x| STORE(x.parse().unwrap())), r"STORE\s+(\d+)"),
(FnWrap::new(|x| ADD(x.parse().unwrap())), r"ADD\s+(\d+)"),
(FnWrap::new(|x| ADDI(x.parse().unwrap())), r"ADD\s=\s*(\d+)"),
(FnWrap::new(|x| SUB(x.parse().unwrap())), r"SUB\s+(\d+)"),
(FnWrap::new(|x| SUBI(x.parse().unwrap())), r"SUB\s=\s*(\d+)"),
(FnWrap::new(|x| JUMP(x.parse().unwrap())), r"JUMP\s+(\d+)"),
(FnWrap::new(|x| JZERO(x.parse().unwrap())), r"JZERO\s+(\d+)"),
(FnWrap::new(|x| JGTZ(x.parse().unwrap())), r"JGTZ\s+(\d+)"),
(FnWrap::new(|x| STORE(x.parse().unwrap())), r"STORE\s+(\d+)\s*#?.*"),
(FnWrap::new(|x| ADD(x.parse().unwrap())), r"ADD\s+(\d+)\s*#?.*"),
(FnWrap::new(|x| ADDI(x.parse().unwrap())), r"ADD\s=\s*(\d+)\s*#?.*"),
(FnWrap::new(|x| SUB(x.parse().unwrap())), r"SUB\s+(\d+)\s*#?.*"),
(FnWrap::new(|x| SUBI(x.parse().unwrap())), r"SUB\s=\s*(\d+)\s*#?.*"),
(FnWrap::new(|x| JUMP(x.parse().unwrap())), r"JUMP\s+(\d+)\s*#?.*"),
(FnWrap::new(|x| JZERO(x.parse().unwrap())), r"JZERO\s+(\d+)\s*#?.*"),
(FnWrap::new(|x| JGTZ(x.parse().unwrap())), r"JGTZ\s+(\d+)\s*#?.*"),
(FnWrap::new(|_| HALT), r"HALT"),
];
@ -136,7 +136,7 @@ fn single_line_test() {
#[test]
fn program_test() {
let code = "READ 1\nLOAD 1\nJZERO 8\nSUB =1\nREAD 1\nWRITE 1\nJUMP 3\nHALT";
let code = "# this is a comment. \nREAD 1 # this is another comment.\nLOAD 1\nJZERO 8\nSUB =1\nREAD 1\nWRITE 1\nJUMP 3\nHALT";
let program = vec![
READ(1),

View File

@ -1,4 +1,9 @@
#![cfg(target_arch = "wasm32")]
extern crate wee_alloc;
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
mod cpu;
mod jswrap;
mod parser;

View File

@ -5,9 +5,9 @@
READ 1
LOAD 1
JZERO 8
JZERO 8 # if the acc is zero, jump to end
SUB =1
READ 1
WRITE 1
JUMP 3
JUMP 3 # jump to the branching operator (jzero)
HALT

View File

@ -1,26 +0,0 @@
// const rust = import('../pkg/');
import { WrapCpu } from 'cpuemulator';
// const rust = import('../pkg/');
export function signalerror(x: string) {
let box = document.getElementById("errorbox")
if (box) {
box.innerHTML = x
}
}
export class Main {
main() {
let k = new WrapCpu;
let mem = k.showmem();
console.log(mem);
k.test();
}
}

View File

@ -1 +1,39 @@
import('./index').catch(e => console.error('Error importing **index.ts**:', e));
import("./index").catch((e) =>
console.error("Error importing **index.ts**:", e)
);
// poor's man jquery:
function $(x: string) {
return document.getElementById(x);
}
// error signaling:
export function signalerror(msg: string, _l: number | null) {
let errbox = $("errormessage");
if (errbox) {
errbox.innerHTML = msg;
}
}
export function signalparseerr(x: number) {
console.log("hey!", x);
// $("#errormessage").val("Parser error at line " + x.toString() + "!");
let errmsg = $("errormessage");
if (errmsg) {
errmsg.innerHTML = "Parser error at line " + x.toString() + "!";
}
highlightError(x);
}
function highlightError(x: number) {
let highlights = $("highlighting");
let text = highlights?.innerHTML;
if (text != null && highlights != null) {
let lines = text.toString().split("\n");
lines[x] = lines[x] + '<mark class="error"><-- error here</mark>';
var newtext = lines.join("\n");
highlights.innerHTML = newtext;
}
}

View File

@ -1,6 +1,142 @@
import { Main, signalerror } from "./Main"
import { WrapCpu } from "cpuemulator";
import $ from "jquery";
export { Main, signalerror}
// creating the cpu object. Yeah.
let cpu = new WrapCpu();
let k = new Main;
k.main();
// setting up the "interactive" editor
let textarea = $("#editing");
let highlights = $("#highlighting");
textarea.on({
input: handleInput,
scroll: handleScroll,
});
handleInput(); // immediately calling this the first time to highlight the sample code.
function handleInput() {
var text = textarea.val();
if (text) {
var highlightedText = applyHighlights(text.toString());
highlights.html(highlightedText);
}
}
function applyHighlights(text: string) {
let res = text
.replace(/(READ\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(WRITE\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(LOAD\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(LOAD\s+=\s*\d+)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(STORE\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(ADD\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(ADD\s=\s*\d+)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(SUB\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(SUB\s=\s*\d+)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(JUMP\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(JZERO\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(JGTZ\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(HALT)/gi, '<mark class="goodcode">$1</mark>')
.replace(/(#.*\n?\$?)/gi, '<mark class="comment">$1</mark>');
return res;
}
function handleScroll() {
var scrollTop = textarea.scrollTop();
var scrollLeft = textarea.scrollLeft();
if (null != scrollTop && null != scrollLeft) {
highlights.scrollTop(scrollTop);
highlights.scrollLeft(scrollLeft);
}
}
// setting up buttons.
let load = $("#load");
let run = $("#run");
let run1 = $("#run1");
load.on({
click: function () {
loadPrg();
loadInput();
writeMem();
},
});
run.on({
click: function () {
cpu.run();
writeMem();
writeOutput();
writeInput();
},
});
run1.on({
click: function () {
cpu.one_step();
writeMem();
writeOutput();
writeInput();
},
});
function writeMem() {
let mem = cpu.showmem();
let memtable = $("td");
for (let index = 0; index < mem.length; index++) {
memtable[index].innerHTML = mem[index].toString();
}
}
function writeOutput() {
let out = cpu.showoutput();
// console.log(out);
let outputbox = $("#outputqueue");
for (let index = 0; index < out.length; index++) {
outputbox.html(outputbox.html() + " " + out[index].toString());
}
}
function writeInput() {
let input = cpu.showinput();
let inputbox = $("#inputqueue");
for (let index = 0; index < input.length; index++) {
inputbox.val(inputbox.val() + " " + input[index].toString());
}
}
function loadInput() {
// let input = cpu.showinput();
let inputbox = $("#inputqueue");
let inputboxtext = $("#inputqueue").val();
if (typeof inputboxtext == "string") {
// let inputqueue = inputboxtext.split(" ").filter(function (x) {
// x != " ";
let inputqueue = inputboxtext.split(" ");
console.log(inputqueue);
for (let index = 0; index < inputqueue.length; index++) {
cpu.add_input(Number(inputqueue[index].trim()));
}
}
}
function loadPrg() {
let prg = textarea.val();
if (typeof prg == "string") {
cpu.load_program(prg);
}
}

View File

@ -9,6 +9,8 @@ module.exports = {
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'js'),
libraryTarget: 'var',
library: 'CPUEMU'
},
experiments: {
syncWebAssembly: true