Updated the PDP-10 DAKAK diagnostic page, and verified the ability to assemble (but not run) all the original DAKAK source files, after making further improvements to the built-in MACRO-10 Mini-Assembler
This commit is contained in:
parent
e7988597c5
commit
afd621dc79
15 changed files with 2007 additions and 16361 deletions
|
|
@ -2536,8 +2536,14 @@ class DebuggerPDP10 extends Debugger {
|
|||
if (!nWords) {
|
||||
this.println("no data");
|
||||
} else {
|
||||
this.println(nWords + " words loaded at " + this.toStrBase(addrLo) + '-' + this.toStrBase(addrHi));
|
||||
if (addrStart != null) this.cpu.setPC(addrStart);
|
||||
var sStart = "start address ";
|
||||
if (addrStart != null) {
|
||||
this.cpu.setPC(addrStart);
|
||||
sStart += this.toStrBase(addrStart);
|
||||
} else {
|
||||
sStart += "unspecified";
|
||||
}
|
||||
this.println(nWords + " words loaded at " + this.toStrBase(addrLo) + '-' + this.toStrBase(addrHi) + ", " + sStart);
|
||||
this.updateStatus();
|
||||
}
|
||||
}
|
||||
|
|
@ -2614,10 +2620,7 @@ class DebuggerPDP10 extends Debugger {
|
|||
* assembling (multiple files must be separated by semicolons), along with any option letters that were included
|
||||
* with the "a" command; for example, if "ap" was specified, then "p" will be passed to Macro10 as an option.
|
||||
*
|
||||
* Macro10 options include:
|
||||
*
|
||||
* p: preprocess the specified resource(s) without assembling them
|
||||
* l: generate listing information (TODO)
|
||||
* See the Macro10 component for a list of supported options.
|
||||
*
|
||||
* When assembling a file, the target address determines the initial location counter for the assembly process,
|
||||
* but that can always be overridden by a LOC (or RELOC) pseudo-op in the file. The target address will also be
|
||||
|
|
|
|||
|
|
@ -125,6 +125,11 @@ class Macro10 {
|
|||
* parseExpression(), etc). This is NOT a subclass of Component, so Component services are not part
|
||||
* of this class.
|
||||
*
|
||||
* Supported options include:
|
||||
*
|
||||
* 'p': print the preprocessed resource(s) without assembling them
|
||||
* 'l': print lines as they are parsed
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {string} sURL (the URL(s) of the resource to be assembled)
|
||||
* @param {number|null} addrLoad (the absolute address to assemble the code at, if any)
|
||||
|
|
@ -264,6 +269,7 @@ class Macro10 {
|
|||
|
||||
this.iURL = 0;
|
||||
this.asURLs = sURL.split(';');
|
||||
this.anLines = []; // keeps track of the number of lines per file
|
||||
|
||||
this.loadNextResource();
|
||||
}
|
||||
|
|
@ -281,7 +287,7 @@ class Macro10 {
|
|||
}
|
||||
|
||||
var macro10 = this;
|
||||
var sURL = this.asURLs[this.iURL++];
|
||||
var sURL = this.asURLs[this.iURL];
|
||||
|
||||
this.println("loading " + Str.getBaseName(sURL));
|
||||
|
||||
|
|
@ -311,10 +317,31 @@ class Macro10 {
|
|||
sText += s;
|
||||
}
|
||||
match = sText.match(/&[a-z]+;/i);
|
||||
if (match) macro10.warning("unrecognized HTML entity: " + match[0]);
|
||||
if (match) macro10.warning("unrecognized HTML entity '" + match[0] + "'");
|
||||
}
|
||||
|
||||
macro10.asLines = macro10.asLines.concat(sText.split(/(\r?\n)/));
|
||||
/*
|
||||
* For a file containing N lines, split() will return an array of N*2+1 entries, with every even entry
|
||||
* containing the characters, if any, preceding a line-ending, and every odd entry (including the final
|
||||
* entry) containing a line-ending.
|
||||
*
|
||||
* If, for some reason, split() doesn't do that, then we try to warn and patch things up as best we can.
|
||||
*/
|
||||
var asLines = sText.split(/(\r?\n)/);
|
||||
if (asLines.length & 1) {
|
||||
s = asLines.pop();
|
||||
if (s) {
|
||||
macro10.warning("unexpected line '" + s + "'");
|
||||
asLines.push(s);
|
||||
asLines.push("");
|
||||
}
|
||||
} else {
|
||||
macro10.warning("unexpected number of lines (" + asLines.length + ")");
|
||||
}
|
||||
|
||||
macro10.asLines = macro10.asLines.concat(asLines);
|
||||
macro10.anLines[macro10.iURL] = (asLines.length >> 1);
|
||||
macro10.iURL++;
|
||||
|
||||
setTimeout(function() {
|
||||
macro10.loadNextResource();
|
||||
|
|
@ -361,7 +388,7 @@ class Macro10 {
|
|||
var macro10 = this;
|
||||
|
||||
/*
|
||||
* If the "preprocess" option is set, then just return the plain text we retrieved.
|
||||
* If the "preprocess" option is set, then print everything without assembling.
|
||||
*/
|
||||
if (this.sOptions.indexOf('p') >= 0) {
|
||||
this.println(this.asLines.join(""));
|
||||
|
|
@ -371,7 +398,16 @@ class Macro10 {
|
|||
var a = this.dbg.resetVariables();
|
||||
try {
|
||||
for (let i = 0; i < this.asLines.length; i += 2) {
|
||||
|
||||
this.nLine++;
|
||||
|
||||
/*
|
||||
* If the "line" option is set, then print all the lines as they are parsed.
|
||||
*/
|
||||
if (this.sOptions.indexOf('l') >= 0) {
|
||||
this.println(this.getLineRef() + ": " + this.asLines[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since, at this early stage, I'm not sure whether all the resources I'm interested in
|
||||
* assembling have had their original CR/LF line endings preserved (eg, some files may have
|
||||
|
|
@ -379,6 +415,7 @@ class Macro10 {
|
|||
* are in the array (stored in every OTHER entry) and insert my own uniform CR/LF sequences.
|
||||
*/
|
||||
if (!this.parseLine(this.asLines[i] + '\r\n')) break;
|
||||
|
||||
/*
|
||||
* When an END statement is encountered, addrStart will change from null to either undefined
|
||||
* or a starting address.
|
||||
|
|
@ -387,11 +424,11 @@ class Macro10 {
|
|||
}
|
||||
|
||||
if (this.nMacroDef) {
|
||||
this.error("open block from line " + this.tblMacros[this.sMacroDef].nLine);
|
||||
this.error("open block", this.tblMacros[this.sMacroDef].nLine);
|
||||
}
|
||||
|
||||
if (this.stackScopes.length) {
|
||||
this.error("open scope from line " + this.stackScopes[0].nLine);
|
||||
this.error("open scope", this.stackScopes[0].nLine);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -480,7 +517,7 @@ class Macro10 {
|
|||
/*
|
||||
* This is more of an assert(), because it should never happen, regardless of input.
|
||||
*/
|
||||
this.error("missing definition for variable: " + name);
|
||||
this.error("missing definition for variable '" + name + "'");
|
||||
continue;
|
||||
}
|
||||
this.parseText(macro.sText);
|
||||
|
|
@ -492,7 +529,7 @@ class Macro10 {
|
|||
this.aFixups.forEach(function processFixup(sValue, nLocation){
|
||||
let value = macro10.parseExpression(sValue, undefined, nLocation);
|
||||
if (value === undefined) {
|
||||
macro10.error("unable to parse expression: " + sValue);
|
||||
macro10.error("unable to parse expression '" + sValue + "'");
|
||||
return;
|
||||
}
|
||||
value += macro10.aWords[nLocation];
|
||||
|
|
@ -527,7 +564,7 @@ class Macro10 {
|
|||
this.nMacroDef++;
|
||||
sLine = sLine.substr(i+1);
|
||||
} else {
|
||||
this.error("expected " + this.sOperator + " definition: " + sLine);
|
||||
this.error("expected " + this.sOperator + " definition in '" + sLine + "'");
|
||||
}
|
||||
}
|
||||
if (this.nMacroDef > 1) {
|
||||
|
|
@ -546,7 +583,7 @@ class Macro10 {
|
|||
while (fParse) {
|
||||
var matchLine = sLine.match(this.reLine);
|
||||
if (!matchLine || matchLine[5] && matchLine[5].slice(0, 1) != ';') {
|
||||
this.error("failed to parse line: " + sLine);
|
||||
this.error("failed to parse line '" + sLine + "'");
|
||||
return false;
|
||||
}
|
||||
fParse = false;
|
||||
|
|
@ -639,6 +676,10 @@ class Macro10 {
|
|||
this.defASCII(sRemainder);
|
||||
break;
|
||||
|
||||
case Macro10.PSEUDO_OP.BLOCK:
|
||||
this.defBLOCK(sOperands);
|
||||
break;
|
||||
|
||||
case Macro10.PSEUDO_OP.END:
|
||||
this.defEND(sOperands);
|
||||
break;
|
||||
|
|
@ -661,6 +702,7 @@ class Macro10 {
|
|||
case Macro10.PSEUDO_OP.IFG:
|
||||
case Macro10.PSEUDO_OP.IFL:
|
||||
case Macro10.PSEUDO_OP.IFN:
|
||||
case Macro10.PSEUDO_OP.IFNDEF:
|
||||
case Macro10.PSEUDO_OP.IRP:
|
||||
case Macro10.PSEUDO_OP.IRPC:
|
||||
case Macro10.PSEUDO_OP.OPDEF:
|
||||
|
|
@ -728,7 +770,6 @@ class Macro10 {
|
|||
*/
|
||||
parseMacro(name, sOperands)
|
||||
{
|
||||
var i;
|
||||
var macro = this.tblMacros[name];
|
||||
if (!macro) return false;
|
||||
|
||||
|
|
@ -738,9 +779,16 @@ class Macro10 {
|
|||
* the operands and merge their bits with the OPDEF's bits.
|
||||
*/
|
||||
if (macro.nOperand == Macro10.MACRO_OP.OPDEF) {
|
||||
|
||||
var nLocation = this.nLocation;
|
||||
this.parseText(macro.sText);
|
||||
if (nLocation < this.nLocation) {
|
||||
|
||||
/*
|
||||
* An OPDEF invokation *may* have operands, but it's not required to.
|
||||
*/
|
||||
if (!sOperands) return true;
|
||||
|
||||
this.pushScope();
|
||||
this.parseText(sOperands);
|
||||
var w = this.aWords[0];
|
||||
|
|
@ -759,7 +807,11 @@ class Macro10 {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
this.error("OPDEF '" + name + "' error: " + sOperands);
|
||||
|
||||
/*
|
||||
* Either the OPDEF didn't generate any data OR the OPDEF's operands failed to evaluate.
|
||||
*/
|
||||
this.error("OPDEF '" + name + "' (" + sOperands + ") failed");
|
||||
return false;
|
||||
}
|
||||
var macroPrev = this.macroCall;
|
||||
|
|
@ -782,13 +834,8 @@ class Macro10 {
|
|||
var sOperator = name.substr(1);
|
||||
|
||||
switch(sOperator) {
|
||||
case Macro10.PSEUDO_OP.IFDEF:
|
||||
if (macro.nOperand) {
|
||||
this.parseText(macro.sText);
|
||||
}
|
||||
break;
|
||||
|
||||
case Macro10.PSEUDO_OP.IFE:
|
||||
case Macro10.PSEUDO_OP.IFNDEF:
|
||||
if (!macro.nOperand) {
|
||||
this.parseText(macro.sText);
|
||||
}
|
||||
|
|
@ -807,6 +854,7 @@ class Macro10 {
|
|||
break;
|
||||
|
||||
case Macro10.PSEUDO_OP.IFN:
|
||||
case Macro10.PSEUDO_OP.IFDEF:
|
||||
if (macro.nOperand) {
|
||||
this.parseText(macro.sText);
|
||||
}
|
||||
|
|
@ -814,7 +862,7 @@ class Macro10 {
|
|||
|
||||
case Macro10.PSEUDO_OP.IRP:
|
||||
case Macro10.PSEUDO_OP.IRPC:
|
||||
for (i = 0; i < macro.aValues.length; i++) {
|
||||
for (let i = 0; i < macro.aValues.length; i++) {
|
||||
this.parseText(macro.sText, macro.aParms, [macro.aValues[i]], []);
|
||||
}
|
||||
break;
|
||||
|
|
@ -903,29 +951,6 @@ class Macro10 {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* error(sError)
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {string} sError
|
||||
*/
|
||||
error(sError)
|
||||
{
|
||||
throw new Error("error" + (this.nLine? " at line " + Str.toDec(this.nLine) : "") + ": " + sError);
|
||||
}
|
||||
|
||||
/**
|
||||
* warning(sWarning)
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {string} sWarning
|
||||
*/
|
||||
warning(sWarning)
|
||||
{
|
||||
this.println("warning" + (this.nLine? " at line " + Str.toDec(this.nLine) : "") + ": " + sWarning);
|
||||
}
|
||||
|
||||
/**
|
||||
* getExpression(sOperands, sDelim)
|
||||
*
|
||||
|
|
@ -955,7 +980,7 @@ class Macro10 {
|
|||
cNesting++;
|
||||
} else if (ch == '>') {
|
||||
if (--cNesting < 0) {
|
||||
this.error("missing bracket(s): " + sOperands);
|
||||
this.error("missing bracket(s) in '" + sOperands + "'");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -964,7 +989,7 @@ class Macro10 {
|
|||
sOperand = sOperands.substr(0, i);
|
||||
}
|
||||
else if (cNesting > 0) {
|
||||
this.error("extra bracket(s): " + sOperands);
|
||||
this.error("extra bracket(s) in '" + sOperands + "'");
|
||||
}
|
||||
return sOperand;
|
||||
}
|
||||
|
|
@ -998,23 +1023,33 @@ class Macro10 {
|
|||
/*
|
||||
* The SIXBIT (and presumably ASCII; not sure about ASCIZ) pseudo-ops can also be used in expressions
|
||||
* (or at least assignments), so we check for those in the given expression and convert them to quoted
|
||||
* sequences that the debugger's parseExpression() understands.
|
||||
* sequences that the Debugger's parseExpression() understands.
|
||||
*/
|
||||
sOperand = sOperand.replace(/SIXBIT\s*(\S)(.*?)\1/g, "'$2'").replace(/ASCII\s*(\S)(.*?)\1/g, '"$2"');
|
||||
/*
|
||||
* Check for the "period" syntax that MACRO-10 uses to represent the value of the current location.
|
||||
* The Debugger's parseInstruction() method understands that syntax, but its parseExpression() method
|
||||
* does not.
|
||||
*
|
||||
* Note that the Debugger's parseInstruction() replaces any period not PRECEDED by a decimal
|
||||
* digit with the current address, because our Debuggers' only other interpretation of a period
|
||||
* is as the suffix of a decimal integer, whereas MACRO-10's only other interpretation of a period
|
||||
* is (I think) as the decimal point within a floating-point number, so here we only replace
|
||||
* periods that are not FOLLOWED by a decimal digit.
|
||||
*/
|
||||
result = this.dbg.parseExpression(sOperand.replace(/\.([^0-9]|$)/g, this.dbg.toStrBase(nLocation, -1) + "$1"), fPass1);
|
||||
if (result === undefined) {
|
||||
this.error("error parsing expression: " + sOperand);
|
||||
|
||||
var sOperator = "";
|
||||
var sOperands = sOperand;
|
||||
if (match = sOperand.match(/^([^\s]+)\s+(.+?)\s*$/)) {
|
||||
sOperator = match[1];
|
||||
sOperands = match[2];
|
||||
}
|
||||
result = this.dbg.parseInstruction(sOperator, sOperands, nLocation, true);
|
||||
if (result < 0) {
|
||||
/*
|
||||
* Check for the "period" syntax that MACRO-10 uses to represent the value of the current location.
|
||||
* The Debugger's parseInstruction() method understands that syntax, but its parseExpression() method
|
||||
* does not.
|
||||
*
|
||||
* Note that the Debugger's parseInstruction() replaces any period not PRECEDED by a decimal
|
||||
* digit with the current address, because our Debuggers' only other interpretation of a period
|
||||
* is as the suffix of a decimal integer, whereas MACRO-10's only other interpretation of a period
|
||||
* is (I think) as the decimal point within a floating-point number, so here we only replace
|
||||
* periods that are not FOLLOWED by a decimal digit.
|
||||
*/
|
||||
result = this.dbg.parseExpression(sOperand.replace(/\.([^0-9]|$)/g, this.dbg.toStrBase(nLocation, -1) + "$1"), fPass1);
|
||||
if (result === undefined) {
|
||||
this.error("unable to parse expression '" + sOperand + "'");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var wLeft = match[1]? this.parseExpression(match[1], fPass1, nLocation) : 0;
|
||||
|
|
@ -1058,7 +1093,7 @@ class Macro10 {
|
|||
}
|
||||
}
|
||||
if (cNesting < 0) {
|
||||
this.error("missing bracket(s): " + sOperands);
|
||||
this.error("missing bracket(s) in '" + sOperands + "'");
|
||||
}
|
||||
if (iBegin >= 0) {
|
||||
sLiteral = sOperands.substr(iBegin, iEnd - iBegin);
|
||||
|
|
@ -1090,6 +1125,27 @@ class Macro10 {
|
|||
return aDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* getLineRef(nLine)
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {number|undefined} [nLine]
|
||||
* @return {string}
|
||||
*/
|
||||
getLineRef(nLine = this.nLine)
|
||||
{
|
||||
var iURL = 0;
|
||||
while (nLine > this.anLines[iURL]) {
|
||||
nLine -= this.anLines[iURL];
|
||||
if (iURL < this.asURLs.length - 1) {
|
||||
iURL++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Str.getBaseName(this.asURLs[iURL] + " line " + nLine);
|
||||
}
|
||||
|
||||
/**
|
||||
* getReserved(sOperands)
|
||||
*
|
||||
|
|
@ -1337,7 +1393,7 @@ class Macro10 {
|
|||
*/
|
||||
match = sOperands.match(/([A-Z$%.][0-9A-Z$%.]*)\s*(\([^)]*\)|)\s*,?\s*(<|)([\s\S]*)/i);
|
||||
if (!match) {
|
||||
this.error("unrecognized " + sOperator + ": " + sOperands);
|
||||
this.error("unrecognized " + sOperator + " in '" + sOperands + "'");
|
||||
return sOperands;
|
||||
}
|
||||
name = match[1];
|
||||
|
|
@ -1362,7 +1418,7 @@ class Macro10 {
|
|||
this.chMacroClose = ']';
|
||||
match = sOperands.match(/([A-Z$%.][0-9A-Z$%.]*)\s*(\[)([\s\S]*)/i);
|
||||
if (!match) {
|
||||
this.error("unrecognized " + sOperator + ": " + sOperands);
|
||||
this.error("unrecognized " + sOperator + " in '" + sOperands + "'");
|
||||
return sOperands;
|
||||
}
|
||||
name = match[1];
|
||||
|
|
@ -1377,7 +1433,7 @@ class Macro10 {
|
|||
this.chMacroClose = ']';
|
||||
name = '?' + Str.toDec(++this.nLiteral, 5);
|
||||
if (this.tblMacros[name] !== undefined) {
|
||||
this.error("literal symbol redefined: " + name);
|
||||
this.error("literal symbol '" + name + "' redefined");
|
||||
}
|
||||
match = [sOperands[0], sOperands.substr(1)];
|
||||
nOperand = Macro10.MACRO_OP.LITERAL;
|
||||
|
|
@ -1395,14 +1451,14 @@ class Macro10 {
|
|||
}
|
||||
match = sOperands.match(/([A-Z$%.][0-9A-Z$%.]*)\s*,\s*(<|)([\s\S]*)/i);
|
||||
if (!match) {
|
||||
this.error("unrecognized " + sOperator + ": " + sOperands);
|
||||
this.error("unrecognized " + sOperator + " operands '" + sOperands + "'");
|
||||
return sOperands;
|
||||
}
|
||||
for (i = 0; i < this.macroCall.aParms.length; i++) {
|
||||
if (match[1] == this.macroCall.aParms[i]) break;
|
||||
}
|
||||
if (i == this.macroCall.aParms.length) {
|
||||
this.error("invalid " + sOperator + " parameter: " + match[1]);
|
||||
this.error("invalid " + sOperator + " parameter '" + match[1] + "'");
|
||||
return sOperands;
|
||||
}
|
||||
name = '?' + sOperator;
|
||||
|
|
@ -1421,7 +1477,7 @@ class Macro10 {
|
|||
*/
|
||||
var sOperand = this.getExpression(sOperands);
|
||||
if (!sOperand) {
|
||||
this.error("missing " + sOperator + " expression: " + sOperands);
|
||||
this.error("missing " + sOperator + " expression '" + sOperands + "'");
|
||||
return sOperands;
|
||||
}
|
||||
sOperands = sOperands.substr(sOperand.length + 1);
|
||||
|
|
@ -1429,7 +1485,7 @@ class Macro10 {
|
|||
match = sOperands.match(/\s*(<|)([\s\S]*)/i);
|
||||
name = '?' + sOperator;
|
||||
|
||||
if (sOperator == Macro10.PSEUDO_OP.IFDEF) {
|
||||
if (sOperator == Macro10.PSEUDO_OP.IFDEF || sOperator == Macro10.PSEUDO_OP.IFNDEF) {
|
||||
nOperand = this.isDefined(sOperand)? 1 : 0;
|
||||
} else {
|
||||
/*
|
||||
|
|
@ -1503,16 +1559,22 @@ class Macro10 {
|
|||
{
|
||||
name = name.toUpperCase().substr(0, 6);
|
||||
if ((nType & Macro10.SYMTYPE.LABEL) && this.tblSymbols[name] !== undefined) {
|
||||
this.error("label " + name + " redefined");
|
||||
this.error("label '" + name + "' redefined");
|
||||
return;
|
||||
}
|
||||
var sUndefined = null;
|
||||
if (typeof value == 'string') {
|
||||
var v = this.parseExpression(value);
|
||||
/*
|
||||
* We now pass true to parseExpression() to allow at least one undefined symbol to exist in the expression,
|
||||
* which we will record alongside the variable.
|
||||
*/
|
||||
var v = this.parseExpression(value, true);
|
||||
if (v === undefined) {
|
||||
this.error("parseExpression(" + value + ")");
|
||||
this.error("parseExpression(" + value + ") failed");
|
||||
return;
|
||||
}
|
||||
value = v;
|
||||
sUndefined = this.dbg.sUndefined;
|
||||
}
|
||||
var sym = this.tblSymbols[name];
|
||||
if (sym) {
|
||||
|
|
@ -1522,7 +1584,25 @@ class Macro10 {
|
|||
} else {
|
||||
this.tblSymbols[name] = {name, value, nType, nLine: this.nLine};
|
||||
}
|
||||
this.dbg.setVariable(name, value);
|
||||
this.dbg.setVariable(name, value, sUndefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* defBLOCK()
|
||||
*
|
||||
* Processes the BLOCK pseudo-op.
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {string} sOperands
|
||||
*/
|
||||
defBLOCK(sOperands)
|
||||
{
|
||||
var w = this.parseExpression(sOperands);
|
||||
if (w !== undefined && this.dbg.sUndefined == null && w >= 0 && w <= 0o777777) {
|
||||
this.nLocation += w; // while (w--) this.genWord(0);
|
||||
} else {
|
||||
this.error("unrecognized BLOCK expression '" + sOperands + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1540,7 +1620,7 @@ class Macro10 {
|
|||
} else {
|
||||
this.addrStart = this.parseExpression(sOperands, true);
|
||||
if (this.addrStart === undefined) {
|
||||
this.error("unrecognized expression: " + sOperands);
|
||||
this.error("unrecognized END expression '" + sOperands + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1559,7 +1639,7 @@ class Macro10 {
|
|||
if (w !== undefined) {
|
||||
this.genWord(w, this.dbg.sUndefined);
|
||||
} else {
|
||||
this.error("unrecognized expression: " + sOperands);
|
||||
this.error("unrecognized EXP expression '" + sOperands + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1602,23 +1682,14 @@ class Macro10 {
|
|||
*/
|
||||
defWord(sOperator, sSeparator, sOperands)
|
||||
{
|
||||
var w = -1;
|
||||
|
||||
var sExp = (sOperator + sSeparator + sOperands).trim();
|
||||
|
||||
if (sOperands.indexOf(",,") < 0) {
|
||||
var nLocation = this.nLocationScope >= 0? this.nLocationScope : this.nLocation;
|
||||
w = this.dbg.parseInstruction(sOperator, sOperands, nLocation, true);
|
||||
}
|
||||
|
||||
if (w < 0) {
|
||||
w = this.parseExpression(sExp, true);
|
||||
}
|
||||
var w = this.parseExpression(sExp, true);
|
||||
|
||||
if (w !== undefined) {
|
||||
this.genWord(w, this.dbg.sUndefined);
|
||||
} else {
|
||||
this.error("unrecognized expression: " + sExp);
|
||||
this.error("unrecognized word expression '" + sExp + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1698,6 +1769,31 @@ class Macro10 {
|
|||
return w;
|
||||
}
|
||||
|
||||
/**
|
||||
* error(sError, nLine)
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {string} sError
|
||||
* @param {number} [nLine]
|
||||
* @throws {Error}
|
||||
*/
|
||||
error(sError, nLine)
|
||||
{
|
||||
throw new Error("error in " + this.getLineRef(nLine) + ": " + sError);
|
||||
}
|
||||
|
||||
/**
|
||||
* warning(sWarning, nLine)
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {string} sWarning
|
||||
* @param {number} [nLine]
|
||||
*/
|
||||
warning(sWarning, nLine)
|
||||
{
|
||||
this.println("warning in " + this.getLineRef(nLine) + ": " + sWarning);
|
||||
}
|
||||
|
||||
/**
|
||||
* println(s)
|
||||
*
|
||||
|
|
@ -1723,6 +1819,7 @@ Macro10.SYMTYPE = {
|
|||
Macro10.PSEUDO_OP = {
|
||||
ASCII: "ASCII",
|
||||
ASCIZ: "ASCIZ",
|
||||
BLOCK: "BLOCK",
|
||||
DEFINE: "DEFINE",
|
||||
END: "END",
|
||||
EXP: "EXP",
|
||||
|
|
@ -1731,10 +1828,11 @@ Macro10.PSEUDO_OP = {
|
|||
IFG: "IFG",
|
||||
IFL: "IFL",
|
||||
IFN: "IFN",
|
||||
IFNDEF: "IFNDEF",
|
||||
IRP: "IRP",
|
||||
IRPC: "IRPC",
|
||||
LALL: "LALL",
|
||||
LITERAL: "LITERAL", // this is a pseudo-pseudo-op, used for internal purposes
|
||||
LITERAL: "LITERAL", // this is a pseudo-pseudo-op, for internal use only
|
||||
LIST: "LIST",
|
||||
LOC: "LOC",
|
||||
NOSYM: "NOSYM",
|
||||
|
|
|
|||
|
|
@ -151,9 +151,9 @@ class Debugger extends Component
|
|||
/*
|
||||
* aVariables is an object with properties that grow as setVariable() assigns more variables;
|
||||
* each property corresponds to one variable, where the property name is the variable name (ie,
|
||||
* a string beginning with a letter or underscore, followed by zero or more additional letters,
|
||||
* digits, or underscores) and the property value is the variable's numeric value. See doVar()
|
||||
* and setVariable() for details.
|
||||
* a string beginning with a non-digit, followed by zero or more symbol characters and/or digits)
|
||||
* and the property value is the variable's numeric value. See doVar() and setVariable() for
|
||||
* details.
|
||||
*
|
||||
* Note that parseValue() parses variables before numbers, so any variable that looks like a
|
||||
* unprefixed hex value (eg, "a5" as opposed to "0xa5") will trump the numeric value. Unprefixed
|
||||
|
|
@ -1019,7 +1019,20 @@ class Debugger extends Component
|
|||
value = this.getRegValue(iReg);
|
||||
} else {
|
||||
value = this.getVariable(sValue);
|
||||
if (value == null) {
|
||||
if (value != null) {
|
||||
var sUndefined = this.getVariableFixup(sValue);
|
||||
if (sUndefined) {
|
||||
if (!this.sUndefined) {
|
||||
this.sUndefined = sUndefined;
|
||||
} else {
|
||||
if (!fQuiet) {
|
||||
this.println(sValue + " has too many undefined values (" + sUndefined + ',' + this.sUndefined + ")");
|
||||
fQuiet = true;
|
||||
}
|
||||
value = undefined;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* A feature of MACRO-10 is that any single-digit number is automatically interpreted as base-10.
|
||||
*/
|
||||
|
|
@ -1119,11 +1132,11 @@ class Debugger extends Component
|
|||
printVariable(sVar)
|
||||
{
|
||||
if (sVar) {
|
||||
return this.printValue(sVar, this.aVariables[sVar]);
|
||||
return this.printValue(sVar, this.aVariables[sVar].value);
|
||||
}
|
||||
var cVariables = 0;
|
||||
for (sVar in this.aVariables) {
|
||||
this.printValue(sVar, this.aVariables[sVar]);
|
||||
this.printValue(sVar, this.aVariables[sVar].value);
|
||||
cVariables++;
|
||||
}
|
||||
return cVariables > 0;
|
||||
|
|
@ -1149,7 +1162,19 @@ class Debugger extends Component
|
|||
*/
|
||||
getVariable(sVar)
|
||||
{
|
||||
return this.aVariables[sVar];
|
||||
return this.aVariables[sVar] && this.aVariables[sVar].value;
|
||||
}
|
||||
|
||||
/**
|
||||
* getVariableFixup(sVar)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {string} sVar
|
||||
* @return {string|undefined}
|
||||
*/
|
||||
getVariableFixup(sVar)
|
||||
{
|
||||
return this.aVariables[sVar] && this.aVariables[sVar].sUndefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1165,15 +1190,16 @@ class Debugger extends Component
|
|||
}
|
||||
|
||||
/**
|
||||
* setVariable(sVar, value)
|
||||
* setVariable(sVar, value, sUndefined)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {string} sVar
|
||||
* @param {number} value
|
||||
* @param {string|null} [sUndefined]
|
||||
*/
|
||||
setVariable(sVar, value)
|
||||
setVariable(sVar, value, sUndefined)
|
||||
{
|
||||
this.aVariables[sVar] = value;
|
||||
this.aVariables[sVar] = {value, sUndefined};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue