Merge branch 'master' into gh-pages

This commit is contained in:
Jeff Parsons 2017-06-15 14:39:27 -07:00
commit f2582de7b6
9 changed files with 932 additions and 690 deletions

View file

@ -0,0 +1,83 @@
---
layout: post
title: Adventures in Archiving
date: 2017-06-15 22:00:00
permalink: /blog/2017/06/15/
machines:
- type: pcx86
id: ibm5150
config: /devices/pcx86/machine/5150/cga/64kb/machine.xml
autoMount:
A:
path: /disks/pcx86/dos/ibm/1.00/PCDOS100.json
B:
path: /apps/pcx86/1983/adventmath/ADVENTMATH100.json
autoType: 8-10-81\\rb:\\ra:basica castle\\r
---
In October 1983, IBM released a game called "Adventures in Math", which apparently tried to make mathematics as
exciting as walking through a dungeon full of locked doors, treasures, spiders, and more. I had never heard of this
game, until I was recently browsing the [Internet Archive](https://archive.org/)'s
[MS-DOS Showcase](https://archive.org/details/softwarelibrary_msdos_showcase):
> This collection is a hand-picked set of selections from the MS-DOS Software Library of the Internet Archive.
They've been chosen because they represent major parts of the MS-DOS story, because they are particularly impressive,
and because they're fun. The intention is to eventually link these games to manuals and other materials as time goes on.
> Curation was done by Jason Scott, Internet Archive's Software Librarian. He can be reached at jscott@archive.org with
suggestion, questions and inquiries.
For some reason, "Adventures in Math" caught my eye. You can play it on the
[Internet Archive](https://archive.org/details/msdos_Adventures_in_Math_1983), or play it below, using PCjs. In
fact, I invite you to play it in BOTH places, and let me know what you think.
A word of warning: this is NOT a great game. I find it interesting only as an example of the challenges we face
archiving and emulating old software.
{% include machine.html id="ibm5150" %}
Hosting the software on the PCjs website was more tedious than I'd expected, but that wasn't due to technical issues.
The biggest challenge was isolating and recreating the original distribution software. You can find all the gory
details on the page I created for "[Adventures in Math](/apps/pcx86/1983/adventmath/)".
In short, although the software is archived inside multiple ZIP archives at the [Internet Archive](https://archive.org/),
none of them appeared to contain an un-mingled, un-modified, distribution-only copy of the original software.
And discovering that the software was archived inside multiple ZIP archives was a purely accidental discovery, not
something one could easily determine using the Internet Archive's own search engine.
### Emulation Challenges
There are also some fundamental problems with the Internet Archive's approach to emulation. They load sets of files,
along with custom batch files, into tightly coupled machine configurations, with no indication which files were part
of the original software distribution, and no hardware details regarding their "mystery" machine configurations.
And the Internet Archive's overall "emulation experience" is often not very faithful. Their rendering of
"Adventures in Math" gives the impression that the game ran *much* faster than it actually ran on a 4.77Mhz IBM PC.
While their emulator can be configured operate at different speeds, it's unclear which of their holdings have already
been "tuned". As a fallback, they do provide some user controls:
> "While the program is running, press CTRL-F11 to slow the program down. Pressing CTRL-F11 repeatedly will slow it
down further, until the speed is more reasonable. (Pressing CTRL-F12 repeatedly will attempt to speed things up.)"
but in general, the user has no idea what speed they have currently selected, or what the target speed should be.
For users who simply want "to play the game," that may be fine, but an historian would probably prefer to see how the
game originally operated and how each screen was painstakingly rendered, to better understand both the original user
experience and the challenges that early software developers faced.
The failure to archive software exactly as it was originally distributed, generally as one or more disk image (IMG)
files along with scanned (PDF) copies of the documentation, is the most serious problem we collectively face. I don't
blame the Internet Archive, because in most cases, they're simply archiving what someone else archived before them,
and those earlier "archivists" often didn't take the time to thoroughly preserve and document everything.
On the other hand, the Internet Archive could do a better job of cataloging its holdings, recording the provenance of
everything they have archived, maintaining a clear separation of original material from subsequent modifications
(including any modifications created solely for ease of emulation), providing more control over machine configurations,
and enabling the use of third-party emulators -- like PCjs -- which may be able to perform a more faithful rendering
of certain software packages.
In addition, I would hope that anything the Internet Archive "archives" itself (ie, from original distribution media)
is duplicated and preserved according to a *much* higher standard than any files, documents, etc, it has simply scraped
from the Internet.
*[@jeffpar](http://twitter.com/jeffpar)*
*Jun 15, 2017*

View file

@ -11,7 +11,7 @@ machines:
path: /disks/pcx86/dos/ibm/1.00/PCDOS100.json
B:
path: /apps/pcx86/1983/adventmath/ADVENTMATH100.json
autoType: 8-10-81\rb:\ra:basica castle\r
autoType: 8-10-81\\rb:\\ra:basica castle\\r
---
Adventures in Math (1983)
@ -36,12 +36,12 @@ The contents of their ZIP archive contained:
-rwxr-xr-x@ 1 Jeff staff 13 Dec 24 1996 Sn
-rwxr-xr-x@ 1 Jeff staff 369 Dec 24 1996 Topten
It's unfortunate that the archive did not contain a complete dump of the original "Adventures in Math" diskette.
It's especially disturbing that all the files in the archive are dated "Dec 24 1996", calling into question which,
if any, of these files are authentic.
It was unfortunate that the archive did not contain a complete dump of the original "Adventures in Math"
diskette, and that all the files in the archive were dated "Dec 24 1996", calling into question the authenticity
of the files.
After digging around a bit more on the Internet Archive, I discovered that
[A Large Collection of DOS Collections](https://archive.org/details/large_dos_collection_2013_08) contains:
[A Large Collection of DOS Collections](https://archive.org/details/large_dos_collection_2013_08) contained:
- DOS Collection v0.7/DVD1/Adventures In Math (1983)(Ibm).zip
- main torrent/1983/Adventures in Math (1983)(IBM) [Educational].zip
@ -78,10 +78,10 @@ And in the second ZIP file:
-rw-r--r--@ 1 Jeff staff 369 Sep 17 1999 Topten
-rw-r--r--@ 1 Jeff staff 170 Jan 22 2011 file_id.diz
I decided to start with the contents of the second ZIP file, since the timestamps of the most of the files
I decided to start with the contents of the second ZIP file, since the timestamps of most of the files
appeared to be legitimate.
One strange file common to *all* these archives is **MONOCODE.000**. Dumping that file revealed:
One strange file common to *all* the archives was **MONOCODE.000**. Dumping that file revealed:
00000c60 20 4d 4f 4e 4f 50 4f 4c 59 20 69 73 20 61 20 72 | MONOPOLY is a r|
00000c70 65 67 69 73 74 65 72 65 64 20 74 72 61 64 65 6d |egistered tradem|
@ -93,15 +93,14 @@ One strange file common to *all* these archives is **MONOCODE.000**. Dumping th
00000cd0 20 44 6f 6e 20 50 68 69 6c 6c 69 70 20 47 69 62 | Don Phillip Gib|
00000ce0 73 6f 6e 20 5b e8 96 7d 03 35 2e 31 b8 5d 00 50 |son [..}.5.1.].P|
So at some point, unrelated ("MONOPOLY") files were mingled with this game. I deleted the file.
So at some point, unrelated "MONOPOLY" files were mingled with this game. I deleted **MONOCODE.000**.
Another unexpected file is **BASICA.EXE** (54277 bytes) from 1999. It seems unlikely that IBM would have distributed
Another unexpected file was **BASICA.EXE** (54277 bytes) from 1999. It seems unlikely that IBM would have distributed
*any* BASIC binary with this game, because DOS was a prerequisite, and at the time, all versions of DOS included BASIC.
IBM's PC-DOS shipped with **BASICA.COM**, and OEM versions of DOS shipped with either **GWBASIC.EXE** or **BASIC.EXE**.
IBM's PC-DOS shipped with **BASICA.COM** and OEM versions of DOS shipped with either **GWBASIC.EXE** or **BASIC.EXE**.
The closest matching binary I'd seen up to this point was **BASICA.EXE** from [COMPAQ DOS 1.12](/disks/pcx86/dos/compaq/1.12/)
(54304 bytes). And sure enough, examining the strings contained inside this **BASICA.EXE** revealed that it was a close
relative:
(54304 bytes). And sure enough, dumping the strings inside this **BASICA.EXE** revealed that it was a close relative:
The COMPAQ Personal Computer BASIC
Version 1.13
@ -109,11 +108,8 @@ relative:
It's safe to say that IBM would not have distributed a COMPAQ binary; if IBM had distributed any BASIC binary at all,
it would have been their own **BASICA.COM**. Of course, the problem with IBM's **BASICA.COM** is that it also requires
an IBM PC with ROM BASIC installed, which is why some people would have preferred the COMPAQ version: it has no ROM
dependencies.
Anyway, I've deleted **BASICA.EXE**. The proper thing to do -- and what any purchaser of this game would have to do --
is boot a machine with an appropriate version of DOS and use the BASIC binary included with DOS to run this game.
an IBM PC with ROM BASIC installed, which is why some people would have preferred the COMPAQ binary: it had no ROM
dependencies. Anyway, I deleted **BASICA.EXE**.
Finally, there was **FILE_ID.DIZ**:
@ -147,13 +143,13 @@ and **TOPTEN**:
Z[z],55677,LARGE,07-24-81
[z],55197,LARGE,07-23-81
All those files have been deleted as well, leaving 8 files dated "Aug 11 1983". Next, I used the PCjs
[DiskDump](/modules/diskdump/) utility to create a disk image from a directory ("archive/disk") containing just
All those files were deleted as well, leaving 8 files dated "Aug 11 1983". Next, I used the PCjs
[DiskDump](/modules/diskdump/) utility to create a disk image from a directory ("archive/disk") containing
those files:
diskdump --dir=archive/disk --format=json --output=ADVENTMATH100.json --manifest
The resulting 160Kb disk image contains:
Here's a directory listing of the resulting 160Kb disk image:
Volume in drive A is PCJS ORG
Directory of A:\
@ -168,10 +164,10 @@ The resulting 160Kb disk image contains:
SN 13 8-11-83 12:00p
8 File(s) 108544 bytes free
And this disk has now been added to the PCjs [IBM PC Disk Library](/disks/pcx86/) as "Adventures in Math (1983)".
This disk has now been added to the PCjs [IBM PC Disk Library](/disks/pcx86/) as "Adventures in Math (1983)".
I originally selected an [IBM PC (Model 5150, 64Kb) with Color Display](/devices/pcx86/machine/5150/cga/64kb/),
which boots PC-DOS 2.00 by default. However, in the course of starting the game, it would crash:
To run the game, I originally selected an [IBM PC (Model 5150, 64Kb) with Color Display](/devices/pcx86/machine/5150/cga/64kb/),
which boots PC-DOS 2.00 by default. However, in the course of starting the game, it crashed:
![ADVENTMATH-CRASH](ADVENTMATH-CRASH.png)
@ -183,9 +179,28 @@ It appeared to run fine with 256Kb of RAM, but these were IBM's "System Requirem
> One diskette drive
so I reconfigured the machine to boot PC-DOS 1.00, which required less RAM than PC-DOS 2.00, and that appeared to be
sufficient. Note that the game was released in October 1983, well after the March 1983 release of PC-DOS 2.00, so
either it wasn't tested with PC-DOS 2.00 on a 64Kb machine, or the error is a PCjs anomaly.
so I reconfigured the machine to boot PC-DOS 1.00, which requires less RAM than PC-DOS 2.00, and that worked.
Note that the game was released in October 1983, well after the March 1983 release of PC-DOS 2.00, so it should
have been tested with PC-DOS 2.00 on a 64Kb machine, but perhaps it wasn't.
The machine on this page is configured with the following "autoType" sequence:
autoType: 8-10-81\\rb:\\ra:basica castle\\r
which translates to:
8-10-81 [enter an arbitrary date]
b: [switch to drive B:]
a:basica castle [run BASICA on drive A: and load CASTLE.BAS on drive B:]
This is one of the preferred methods of demonstrating software in PCjs: loading unmodified disk images into machines
that match the software's system requirements as closely as possible, powering the machine, and then automatically
executing a series of commands that an owner of that hardware and software combination would have likely executed.
The other preferred method is to use a machine state file, which restores the machine to a state where the software is
already running. This is the fastest approach, and it is useful when the software has an involved installation
process, but it takes more effort to set up. The [VisiCalc (1981)](/apps/pcx86/1981/visicalc/) demo operates this way,
but it does so purely for convenience (and because it predates the "autoType" feature).
References
----------

View file

@ -7,12 +7,80 @@ permalink: /disks/pcx86/fixed/10mb/
10Mb Hard Drive (Fixed Disk) Images
---
This folder contains the following 10Mb disk images:
This folder contains the following 10Mb fixed disk images:
* Empty formatted disk ([PCDOS200-EMPTY](PCDOS200-EMPTY.json))
* PC-DOS 2.00 with Windows 1.01 for CGA ([PCDOS200-WIN101-CGA](pcdos200-win101-cga.xml))
* PC-DOS 2.00 with Windows 1.01 for EGA ([PCDOS200-WIN101-EGA](pcdos200-win101-ega.xml))
These disk images are used by various [Model 5160](/devices/pcx86/machine/5160/) machine configurations.
These disk images are used by various IBM PC XT [Model 5160](/devices/pcx86/machine/5160/) machine configurations.
NOTE: The empty disk is *completely* empty. It was partitioned with the PC-DOS 2.00 **FDISK** utility, allocating
the entire disk to a single DOS partition, and then it was formatted with the PC-DOS 2.00 **FORMAT** utility.
Neither the **FORMAT** "/S" option nor the **SYS** command were used, so no system files were transferred, leaving
the disk completely empty and non-bootable.
After formatting, PC-DOS 2.00 reports:
10592256 bytes total disk space
10592256 bytes available on disk
As explained in the [DiskDump source code](/modules/diskdump/lib/diskdump.js), in its description of the 10Mb
BPB, a 10Mb "Type 3" PC XT fixed disk contains:
306 cylinders
4 heads
17 sectors/track
for a total of 20808 sectors or 10,653,696 bytes. However, as p.1-179 of the PC XT Technical Reference Manual
(April 1983) notes:
WARNING: The last cylinder on the fixed disk drive is reserved for diagnostic use.
Diagnostic write tests will destroy any data on this cylinder.
And this is confirmed by the PC XT BIOS, p.A-94, in the code for the "GET PARAMETERS (AH = 8)" function:
C800:03B2 268B07 MOV AX,ES:[BX] ; MAX NUMBER OF CYLINDERS
C800:03B5 2D0200 SUB AX,2 ; ADJUST FOR 0-N AND RESERVE LAST TRACK
By "RESERVE LAST TRACK", they really meant "RESERVE LAST CYLINDER", because 68 (not 17) sectors are reserved at
the end of the disk. In addition, the first sector of the disk is reserved for the Master Boot Record (MBR), so there
are a total of 69 reserved sectors. (20808 - 69) = 20739 or 0x5103, which is exactly what's stored in the "total
sectors" field of the disk's BPB, yielding a total partition size of 10,618,368 bytes.
However, that 69-sector overhead is not the end of the story. There is also overhead incurred by the FAT file system,
which, in this case, consists of:
- Boot sector (1)
- FAT sectors (2 * 8 = 16)
- Root directory sectors (32)
for a total of 49 sectors, leaving (20739 - 49) = 20690 sectors. Moreover, free space is measured in clusters,
not sectors, and the partition uses 8 sectors/cluster, leaving room for 2586.25 clusters. Since a fractional cluster
is not allowed, another 2 sectors are lost, bringing the total FAT file system overhead to 51 sectors.
Thus, actual free space is (20739 - 51) * 512, or 10,592,256 bytes, which is exactly what DOS reports as the available
space.
Some sources on the internet (eg, http://www.wikiwand.com/en/Timeline_of_DOS_operating_systems) claim that the (FAT)
file system overhead for the XT's 10Mb disk is "50 sectors". As they explain:
"The fixed disk has 10,618,880 bytes of raw space: 305 cylinders (the equivalent of tracks) × 2 platters
× 2 sides or heads per platter × 17 sectors per track = 20,740 sectors × 512 bytes per sector = 10,618,880
bytes...."
and:
"With DOS the only partition, the combined overhead is 50 sectors leaving 10,592,256 bytes for user data:
DOS's FAT is eight sectors (16 sectors for two copies) + 32 sectors for the root directory, room for 512
directory entries + 2 sectors (one master and one DOS boot sector) = 50 sectors...."
However, that's incorrect. First, the disk has 306 cylinders, not 305. Second, there are TWO overhead values:
the overhead OUTSIDE the partition (69 sectors) and the overhead INSIDE the partition (51 sectors). They failed
to account for the reserved cylinder in the first calculation and the lost fractional cluster in the second
calculation, and then they conflated the two values to produce a single (incorrect) result.
---
To use one of these disks with another machine configuration, include:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -530,15 +530,15 @@ DiskDump.aDefaultBPBs = [
/*
* Here's some useful background information on a 10Mb PC XT fixed disk, partitioned with a single DOS partition.
*
* The BPB for a 10Mb "type 3" PC XT drive specifies 0x5103 or 20739 for TOTAL_SECS, which is the partition
* The BPB for a 10Mb "type 3" PC XT hard disk specifies 0x5103 or 20739 for TOTAL_SECS, which is the partition
* size in sectors (10,618,368 bytes), whereas total disk size is 20808 sectors (10,653,696 bytes). The partition
* is 69 sectors smaller than the disk because the first sector is reserved for the MBR and 68 sectors (the entire
* last cylinder) are reserved for diagnostics, head parking, etc. This cylinder usage is confirmed by FDISK,
* which reports that 305 cylinders (not 306) are assigned to the DOS partition.
*
* That 69-sector overhead is NOT the overhead incurred by the FAT file system. That overhead is the boot sector
* That 69-sector overhead is NOT overhead incurred by the FAT file system. The FAT overhead is the boot sector
* (1), FAT sectors (2 * 8), and root directory sectors (32), for a total of 49 sectors, leaving 20739 - 49 or
* 20690 sectors. However, free space is measured in clusters, not sectors, and the partition uses 8 sectors/cluster,
* 20690 sectors. Moreover, free space is measured in clusters, not sectors, and the partition uses 8 sectors/cluster,
* leaving room for 2586.25 clusters. Since a fractional cluster is not allowed, another 2 sectors are lost, for
* a total of 51 sectors of FAT overhead. So actual free space is (20739 - 51) * 512, or 10,592,256 bytes -- which
* is exactly what is reported as the available space on a freshly formatted 10Mb PC XT fixed disk.
@ -562,7 +562,7 @@ DiskDump.aDefaultBPBs = [
* and then they conflated the two values to produce a single (incorrect) result.
*
* Even if one were to assume that the disk had only 305 cylinders, that would only change the partitioning overhead
* to 1 sector; the file system overhead would still be 51 sectors.
* to 1 sector; the FAT file system overhead would still be 51 sectors.
*/
[ // define BPB for 10Mb hard drive
0xEB, 0xFE, 0x90, // 0x00: JMP instruction, following by 8-byte OEM signature

View file

@ -35,6 +35,7 @@ if (NODE) {
var Keys = require("../../shared/lib/keys");
var State = require("../../shared/lib/state");
var PCX86 = require("./defines");
var Interrupts = require("./interrupts");
var Messages = require("./messages");
var ChipSet = require("./chipset");
var CPU = require("./cpu");
@ -59,6 +60,8 @@ class Keyboard extends Component {
* "US84"
* "US101"
*
* autoType: string of keys to automatically inject when the machine is ready (undefined if none)
*
* Its main purpose is to receive binding requests for various keyboard events, and to use those events
* to simulate the PC's keyboard hardware.
*
@ -137,7 +140,14 @@ class Keyboard extends Component {
this.msAutoRepeat = 500;
this.msNextRepeat = 100;
this.msAutoRelease = 50;
this.msInjectDelay = 300; // number of milliseconds between injected keystrokes
this.msInjectDelay = 150; // number of milliseconds between injected keystrokes
/*
* autoType records the machine's specified autoType sequence, if any. At the appropriate signal(s),
* autoType will be copied to autoInject, and injection will commence.
*/
this.autoInject = null;
this.autoType = parmsKbd['autoType'];
/*
* HACK: We set fAllDown to false to ignore all down/up events for keys not explicitly marked as ONDOWN;
@ -351,6 +361,26 @@ class Keyboard extends Component {
this.cpu = cpu;
this.dbg = dbg;
this.chipset = cmp.getMachineComponent("ChipSet");
this.autoType = cmp.getMachineParm('autoType') || this.autoType;
cpu.addIntNotify(Interrupts.DOS, this.intDOS.bind(this));
}
/**
* intDOS()
*
* Monitors selected DOS interrupts for signals to initialize 'autoType' injection.
*
* @this {Keyboard}
* @param {number} addr
* @return {boolean} true to proceed with the INT 0x21 software interrupt, false to skip
*/
intDOS(addr)
{
var AH = (this.cpu.regEAX >> 8) & 0xff;
if (AH == 0x0A) {
this.injectInit();
}
return true;
}
/**
@ -726,6 +756,7 @@ class Keyboard extends Component {
/*
* Make sure the auto-injection buffer is empty (an injection could have been in progress on any reset after the first).
*/
this.autoInject = null;
this.sInjectBuffer = "";
}
@ -833,6 +864,19 @@ class Keyboard extends Component {
}
}
/**
* injectInit()
*
* @this {Keyboard}
*/
injectInit()
{
if (!this.autoInject && this.autoType) {
this.autoInject = this.autoType;
this.injectKeys(this.autoInject);
}
}
/**
* injectKeys(sKeys, msDelay)
*
@ -857,15 +901,41 @@ class Keyboard extends Component {
*/
injectKeysFromBuffer(msDelay)
{
if (this.sInjectBuffer.length > 0) {
var ch = this.sInjectBuffer.charCodeAt(0);
var charCode = 0;
while (this.sInjectBuffer.length > 0 && !charCode) {
var ch = this.sInjectBuffer.charAt(0);
this.sInjectBuffer = this.sInjectBuffer.substr(1);
if (ch != '\\') {
charCode = ch.charCodeAt(0);
} else {
ch = this.sInjectBuffer.charAt(0);
this.sInjectBuffer = this.sInjectBuffer.substr(1);
switch (ch) {
case 'n':
charCode = 0x0A;
break;
case 'r':
charCode = 0x0D;
break;
case 't':
charCode = 0x09;
break;
default:
if (ch >= '1' && ch <= '9') {
msDelay = ch.charCodeAt(0) * 100;
break;
}
charCode = ch.charCodeAt(0);
break;
}
}
}
if (charCode) {
/*
* I could require all callers to supply CRs instead of LFs, but this is friendlier.
*/
if (ch == 0x0a) ch = 0x0d;
this.sInjectBuffer = this.sInjectBuffer.substr(1);
this.addActiveKey(ch, true);
if (charCode == 0x0A) charCode = 0x0D;
this.addActiveKey(charCode, true);
}
if (this.sInjectBuffer.length > 0) {
setTimeout(function(kbd) {
@ -1012,7 +1082,9 @@ class Keyboard extends Component {
*/
addActiveKey(simCode, fPress)
{
if (!Keyboard.SIMCODES[simCode]) {
var wCode = Keyboard.SIMCODES[simCode] || Keyboard.SIMCODES[simCode += Keys.KEYCODE.ONDOWN];
if (!wCode) {
if (!COMPILED && this.messageEnabled(Messages.KEYS)) {
this.printMessage("addActiveKey(" + simCode + "," + (fPress? "press" : "down") + "): unrecognized", true);
}

View file

@ -1461,7 +1461,7 @@ class X86CPU extends CPU {
/**
* addIntNotify(nInt, fn)
*
* Add an software interrupt notification handler to the CPU's list of such handlers.
* Add a software interrupt notification handler to the CPU's list of such handlers.
*
* TODO: Consider adding removeIntNotify(). Example use case: if the Debugger's intWindowsDebugger() function
* detects that an INT 0x41 client is loaded, it would be quite happy to uninstall itself.

View file

@ -905,8 +905,8 @@ class Debugger extends Component
* And to avoid conflicts with MACRO-10 syntax, I've replaced the original mod operator ('%') with '^/'.
*
* The MACRO-10 binary shifting suffix ('B') is a bit more problematic, since a capital B can also appear
* inside symbols. So I pre-scan for that suffix and replace all non-symbolic occurrences with an internal
* shift operator ('^_').
* inside symbols, or inside hex values. So if the default base is NOT 16, then I pre-scan for that suffix
* and replace all non-symbolic occurrences with an internal shift operator ('^_').
*
* Note that Str.parseInt(), which parseValue() relies on, supports both the MACRO-10 base prefix overrides
* and the binary shifting suffix ('B'), but since that suffix can also be a bracketed expression, we have to
@ -923,7 +923,9 @@ class Debugger extends Component
* that to generate an error; if we converted it to "AB", evaluation might inadvertently succeed.
*/
var regExp = /({|}|\|\||&&|\||\^!|\^B|\^O|\^D|\^L|\^-|~|\^_|_|&|!=|!|==|>=|>>>|>>|>|<=|<<|<|-|\+|\^\/|\/|\*|,,| )/;
if (this.nBase != 16) {
sExp = sExp.replace(/(^|[^A-Z0-9$%.])([0-9]+)B/, "$1$2^_").replace(/\s+/g, ' ');
}
var asValues = sExp.split(regExp);
value = this.parseArray(asValues, 0, asValues.length, this.nBase, aUndefined);
if (value !== undefined && fPrint) {