More MACRO-10 support

This commit is contained in:
Jeff 2017-03-11 23:30:06 -08:00 committed by Jeff Parsons
commit e2e018af67
8 changed files with 706 additions and 205 deletions

View file

@ -100,7 +100,9 @@ class Debugger extends Component {
* Default base used to display all values; modified with the "s base" command.
*/
this.nBase = +parmsDbg['base'] || 16;
this.fParens = false;
this.achGroup = ['{','}'];
this.achAddress = ['[',']'];
/*
* These keep track of instruction activity, but only when tracing or when Debugger checks
@ -409,19 +411,19 @@ class Debugger extends Component {
* ...
*
* We pop 1 "binop" from aOps and 2 values from aVals whenever a "binop" of lower priority than its
* predecessor is encountered, evaluate, and push the result back onto aVals.
* predecessor is encountered, evaluate, and push the result back onto aVals. Unary operators like
* '~' and ternary operators like '?:' are not supported.
*
* Unary operators like '~' and ternary operators like '?:' are not supported; neither are parentheses.
* parseReference() makes it possible to write parenthetical-style sub-expressions by using whatever
* characters achGroup contains (default is braces}. Address references are resolved using the characters
* in achAddress (default is brackets).
*
* However, parseReference() now makes it possible to write parenthetical-style sub-expressions by using
* {...} (braces), as well as address references by using [...] (brackets).
* Why not always use parentheses for sub-expressions? Because parseReference() serves multiple purposes,
* the other being reference replacement in message strings passing through replaceRegs(), and some
* Debuggers don't want parentheses taking on a new meaning in message strings.
*
* Why am I using braces instead of parentheses for sub-expressions? Because parseReference() serves
* multiple purposes, the other being reference replacement in message strings passing through replaceRegs(),
* and I didn't want parentheses taking on a new meaning in message strings.
*
* However, a Debugger can override this choice by setting fParens to true, if there's no conflict in its
* replaceRegs() implementation.
* However, a Debugger can override these choices by modifying achGroup and/or achAddress, if there's no
* conflict in its replaceRegs() implementation.
*
* @this {Debugger}
* @param {string|undefined} sExp
@ -494,8 +496,7 @@ class Debugger extends Component {
*
* Returns the given string with any "{expression}" sequences replaced with the value of the expression,
* and any "[address]" references replaced with the contents of the address. Expressions are parsed BEFORE
* addresses. Owing to this function's simplistic parsing, nested braces/brackets are not supported
* (define intermediate variables if needed).
* addresses.
*
* @this {Debugger}
* @param {string} s
@ -503,17 +504,36 @@ class Debugger extends Component {
*/
parseReference(s) {
var a;
var chOpen = this.fParens? '(' : '{';
var chClose = this.fParens? ')' : '}';
var reSubExp = new RegExp(this.fParens? "\\((.*?)\\)" : "\\{(.*?)\\}");
var chOpen = this.achGroup[0];
var chClose = this.achGroup[1];
var chEscape = (chOpen == '(' || chOpen == '{' || chOpen == '[')? '\\' : '';
var chInnerEscape = (chOpen == '['? '\\' : '');
var reSubExp = new RegExp(chEscape + chOpen + "([^" + chInnerEscape + chOpen + chInnerEscape + chClose + "]+)" + chEscape + chClose);
while (a = s.match(reSubExp)) {
if (a[1].indexOf(chOpen) >= 0) break; // unsupported nested brace(s)
var value = this.parseExpression(a[1]);
s = s.replace(chOpen + a[1] + chClose, value != null? this.toStrBase(value) : "undefined");
var sSearch = chOpen + a[1] + chClose;
var sReplace = value != null? this.toStrBase(value) : "undefined";
/*
* Note that by default, the String replace() method only replaces the FIRST occurrence,
* and there MIGHT be more than one occurrence of the expression we just parsed, so we could
* do this instead:
*
* s = s.split(sSearch).join(sReplace);
*
* However, that's knd of an expensive (slow) solution, and it's not strictly necessary, since
* any additional identical expressions will be picked up on a subsequent iteration through this loop.
*/
s = s.replace(sSearch, sReplace);
}
while (a = s.match(/\[(.*?)]/)) {
if (a[1].indexOf('[') >= 0) break; // unsupported nested bracket(s)
s = this.parseAddrReference(s, a[1]);
if (this.achAddress.length) {
chOpen = this.achAddress[0];
chClose = this.achAddress[1];
chEscape = (chOpen == '(' || chOpen == '{' || chOpen == '[')? '\\' : '';
chInnerEscape = (chOpen == '['? '\\' : '');
reSubExp = new RegExp(chEscape + chOpen + "([^" + chInnerEscape + chOpen + chInnerEscape + chClose + "]+)" + chEscape + chClose);
while (a = s.match(reSubExp)) {
s = this.parseAddrReference(s, a[1]);
}
}
return this.parseSysVars(s);
}
@ -595,6 +615,28 @@ class Debugger extends Component {
return fDefined;
}
/**
* resetVariables()
*
* @this {Debugger}
* @return {Object}
*/
resetVariables() {
var a = this.aVariables;
this.aVariables = {};
return a;
}
/**
* restoreVariables(a)
*
* @this {Debugger}
* @param {Object} a (from previous resetVariables() call)
*/
restoreVariables(a) {
this.aVariables = a;
}
/**
* printVariable(sVar)
*

View file

@ -65,6 +65,10 @@ class Str {
* to indicate octal (because such a number could also be decimal or hex). Any number of commas are
* allowed; we remove them all before calling the built-in parseInt().
*
* More recently, we've added support for "^D", "^O", and "^B" prefixes to accommodate the base overrides
* that the PDP-10's MACRO-10 assembly language supports. If this support turns out to adversely affect
* other debuggers, then it will have to be "conditionalized".
*
* To summarize our non-standard alternatives: a 'y' suffix indicates binary, a '#' prefix indicates
* octal, a '$' prefix indicates hex, and a "0b" prefix indicates binary IF at least one comma is present.
* Commas are useful for grouping binary digits, but if you don't want to use them, then you must use a
@ -110,6 +114,21 @@ class Str {
chPrefix = null;
}
}
else if (chPrefix == '^') {
chPrefix = s.charAt(1);
if (chPrefix == 'D') {
base = 10;
chPrefix = null;
}
else if (chPrefix == 'O') {
base = 8;
chPrefix = null;
}
else if (chPrefix == 'B') {
base = 2;
chPrefix = null;
}
}
if (chPrefix == null) {
s = s.substr(2);
}