More MACRO-10 parsing improvements
This commit is contained in:
parent
3da33e3668
commit
fb83d1e503
8 changed files with 869 additions and 806 deletions
|
|
@ -1,3 +1,22 @@
|
|||
; From the MACR0-10 ASSEMBLER PROGRAMMER'S REFERENCE MANUAL (June 1972):
|
||||
;
|
||||
; Example 4 (Figure 7-4) shows nested macros which use IRPC. The desired operation
|
||||
; is to take an ASCII text string and store the characters four per word, left-justified,
|
||||
; with the character count stored in the first nine bits of the first word.
|
||||
;
|
||||
; The TEXT macro counts the string characters and invokes the CODE macro to store the
|
||||
; characters four per word. The CODE macro invokes a SHIFT macro which left-justifies the
|
||||
; last word if it is not already left-justified. The first part of the example shows the
|
||||
; normal listing, then SALL is set to show what code the macros are generating.
|
||||
;
|
||||
; The original listing encodes the following two lines as follows:
|
||||
;
|
||||
; IFN ZZ,<DEFINE SHIFT ;;REMAINDER LEFT
|
||||
; IFE ZZ&777B8,> ;;IF NOT LEFT JUSTIFIED
|
||||
;
|
||||
; The April 1978 MACRO-10 manual says that a macro body "must be enclosed in angle brackets",
|
||||
; so I'm not sure how the above lines make sense.
|
||||
;
|
||||
TITLE STORE TEXT CHARACTER BY CHARACTER
|
||||
SUBTTL %1 5-APR-72
|
||||
|
||||
|
|
@ -13,10 +32,10 @@
|
|||
IFN ZZ&777B8,<
|
||||
EXP ZZ ;;WORD FULL
|
||||
ZZ==0> ;;START AGAIN WITH 0
|
||||
ZZ=ZZ+9+"C"> ;;END OF IRPC
|
||||
ZZ==ZZ_9+"C"> ;;END OF IRPC
|
||||
IFN ZZ,<DEFINE SHIFT< ;;REMAINDER LEFT
|
||||
IFE ZZ&777B8,< ;;IF NOT LEFT JUSTIFIED
|
||||
ZZ=ZZ+9 ;;MOVE LEFT 9 BITS
|
||||
ZZ==ZZ_9 ;;MOVE LEFT 9 BITS
|
||||
SHIFT> ;;RECURSE
|
||||
> ;;END OF DEFINE
|
||||
SHIFT ;;START MOVING LEFT
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -492,11 +492,12 @@ class Macro10 {
|
|||
case Macro10.PSEUDO_OP.IRP:
|
||||
case Macro10.PSEUDO_OP.IRPC:
|
||||
case Macro10.PSEUDO_OP.REPEAT:
|
||||
this.addMacro(sOperator, sOperands);
|
||||
this.addMacro(sOperator, sRemainder);
|
||||
break;
|
||||
|
||||
case Macro10.PSEUDO_OP.PAGE: // TODO
|
||||
case Macro10.PSEUDO_OP.SUBTTL: // TODO
|
||||
case Macro10.PSEUDO_OP.TITLE: // TODO
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -899,7 +900,7 @@ class Macro10 {
|
|||
/*
|
||||
* This is a DEFINE (macro) block.
|
||||
*/
|
||||
match = sOperands.match(/([A-Z$%.][0-9A-Z$%.]*)\s*(\([^)]*\)|)\s*(<|)(.*)/i);
|
||||
match = sOperands.match(/([A-Z$%.][0-9A-Z$%.]*)\s*(\([^)]*\)|)\s*(<|)([\s\S]*)/i);
|
||||
if (!match) {
|
||||
this.error("unrecognized " + sOperator + ": " + sOperands);
|
||||
return sOperands;
|
||||
|
|
@ -940,7 +941,7 @@ class Macro10 {
|
|||
if (!this.macroCall) {
|
||||
this.error(sOperator + " outside of macro");
|
||||
}
|
||||
match = sOperands.match(/([A-Z$%.][0-9A-Z$%.]*)\s*,\s*(<|)(.*)/i);
|
||||
match = sOperands.match(/([A-Z$%.][0-9A-Z$%.]*)\s*,\s*(<|)([\s\S]*)/i);
|
||||
if (!match) {
|
||||
this.error("unrecognized " + sOperator + ": " + sOperands);
|
||||
return sOperands;
|
||||
|
|
@ -973,7 +974,7 @@ class Macro10 {
|
|||
}
|
||||
sOperands = sOperands.substr(sOperand.length + 1);
|
||||
sOperand = sOperand.trim();
|
||||
match = sOperands.match(/\s*(<|)(.*)/i);
|
||||
match = sOperands.match(/\s*(<|)([\s\S]*)/i);
|
||||
name = '?' + sOperator;
|
||||
/*
|
||||
* The expression is either a repeat count or a condition. Either way, we must be able to
|
||||
|
|
@ -990,24 +991,14 @@ class Macro10 {
|
|||
*/
|
||||
name = name.toUpperCase();
|
||||
this.nMacroDef = 1;
|
||||
|
||||
var sText = "";
|
||||
if (match[iMatch]) { // if there IS also an opening bracket...
|
||||
this.nMacroDef = 2; // then the macro definition has begun
|
||||
sText = match[iMatch + 1];
|
||||
if (sText.slice(-1) == this.chMacroClose) { // and if there is ALSO a closing bracket...
|
||||
this.nMacroDef = 0; // the macro definition has ended as well
|
||||
sText = sText.slice(0, -1);
|
||||
}
|
||||
}
|
||||
|
||||
this.tblMacros[name] = {name, nOperand, aParms, aDefaults, aValues, sText, nLine: this.nLine};
|
||||
|
||||
if (!this.nMacroDef) {
|
||||
this.parseMacro(name);
|
||||
} else {
|
||||
this.sMacroDef = name;
|
||||
this.tblMacros[name] = {name, nOperand, aParms, aDefaults, aValues, sText: "", nLine: this.nLine};
|
||||
|
||||
if (match[iMatch]) { // if there is an opening bracket
|
||||
this.nMacroDef = 2; // then the macro definition has started
|
||||
this.appendMacro(match[iMatch + 1]);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
|
@ -1087,7 +1078,7 @@ class Macro10 {
|
|||
addWord(sOperator, sOperands)
|
||||
{
|
||||
var w;
|
||||
var sExp = sOperator + sOperands;
|
||||
var sExp = sOperator + ' ' + sOperands;
|
||||
if (sExp.indexOf(",,") >= 0 || !sOperator && sExp.indexOf('@') < 0 && sExp.indexOf('(') < 0) {
|
||||
w = this.parseExpression(sExp, true);
|
||||
} else {
|
||||
|
|
@ -1232,6 +1223,7 @@ Macro10.PSEUDO_OP = {
|
|||
REPEAT: "REPEAT",
|
||||
SIXBIT: "SIXBIT",
|
||||
SUBTTL: "SUBTTL",
|
||||
TITLE: "TITLE",
|
||||
XWD: "XWD"
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -617,7 +617,7 @@ class Debugger extends Component
|
|||
* - - - - - - - - - - -- -- -- -- --
|
||||
* 2 * { 3 + { 4 / 2 } }
|
||||
*
|
||||
* This function takes care of recursively processing sub-expressions, by processing subsets of the array,
|
||||
* This function takes care of recursively processing grouped expressions, by processing subsets of the array,
|
||||
* as well as handling certain base overrides (eg, temporarily switching to base-10 for binary shift suffixes).
|
||||
*
|
||||
* @param {Array.<string>} asValues
|
||||
|
|
@ -720,6 +720,39 @@ class Debugger extends Component
|
|||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* parseASCII(sExp, chDelim, nBits, nMax)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {string} sExp
|
||||
* @param {string} chDelim
|
||||
* @param {number} nBits
|
||||
* @param {number} nMax
|
||||
* @return {string}
|
||||
*/
|
||||
parseASCII(sExp, chDelim, nBits, nMax)
|
||||
{
|
||||
var i;
|
||||
while ((i = sExp.indexOf(chDelim)) >= 0) {
|
||||
var v = 0;
|
||||
var n = nMax;
|
||||
var j = i + 1;
|
||||
while (n--) {
|
||||
var ch = sExp[j++];
|
||||
if (ch == chDelim) break;
|
||||
var c = ch.charCodeAt(0);
|
||||
if (nBits == 7) {
|
||||
c &= 0x7F;
|
||||
} else {
|
||||
c = (c - 0x20) & 0x3F;
|
||||
}
|
||||
v = this.truncate(v * Math.pow(2, nBits) + c, nBits * nMax, true);
|
||||
}
|
||||
sExp = sExp.substr(0, i) + this.toStrBase(v, -1) + sExp.substr(j);
|
||||
}
|
||||
return sExp;
|
||||
}
|
||||
|
||||
/**
|
||||
* parseExpression(sExp, fQuiet)
|
||||
*
|
||||
|
|
@ -754,19 +787,26 @@ class Debugger extends Component
|
|||
if (sExp) {
|
||||
|
||||
/*
|
||||
* The default grouping characters for sub-expressions are braces; they can be changed by altering
|
||||
* The default delimiting characters for grouped expressions are braces; they can be changed by altering
|
||||
* achGroup, but when that happens, instead of changing our regular expressions and operator tables,
|
||||
* we simply replace all achGroup characters with braces in the given expression.
|
||||
*
|
||||
* Why not just always use parentheses for sub-expressions? Because some debuggers use parseReference()
|
||||
* to perform parenthetical value replacements in message strings, and they don't want parentheses taking
|
||||
* on a different meaning. And for some machines, like the PDP-10, the convention is to use parentheses
|
||||
* for indexed addressing and angle brackets for sub-expressions.
|
||||
* Why not use parentheses for grouped expressions? Because some debuggers use parseReference() to perform
|
||||
* parenthetical value replacements in message strings, and they don't want parentheses taking on a different
|
||||
* meaning. And for some machines, like the PDP-10, the convention is to use parentheses for other things,
|
||||
* like indexed addressing, and to use angle brackets for grouped expressions.
|
||||
*/
|
||||
if (this.achGroup[0] != '{') {
|
||||
sExp = sExp.split(this.achGroup[0]).join('{').split(this.achGroup[1]).join('}');
|
||||
}
|
||||
|
||||
/*
|
||||
* Quoted ASCII characters can have a numeric value, too, which must be converted now, to avoid any
|
||||
* conflicts with the operators below.
|
||||
*/
|
||||
sExp = this.parseASCII(sExp, '"', 7, 5); // MACRO-10 packs up to 5 7-bit ASCII codes in the value
|
||||
sExp = this.parseASCII(sExp, "'", 6, 6); // MACRO-10 packs up to 6 6-bit ASCII (SIXBIT) codes in the value
|
||||
|
||||
/*
|
||||
* All browsers (including, I believe, IE9 and up) support the following idiosyncrasy of a RegExp split():
|
||||
* when the RegExp uses a capturing pattern, the resulting array will include entries for all the pattern
|
||||
|
|
@ -903,17 +943,24 @@ class Debugger extends Component
|
|||
} else {
|
||||
value = this.getVariable(sValue);
|
||||
if (value == null) {
|
||||
/*
|
||||
* A feature of MACRO-10 is that any single-digit number is automatically interpreted as base-10.
|
||||
*/
|
||||
var nBase = sValue.length > 1? this.nBase : 10;
|
||||
if (iNegate < 0) {
|
||||
sValue = '-' + sValue;
|
||||
iNegate = 0;
|
||||
}
|
||||
value = Str.parseInt(sValue, this.nBase);
|
||||
value = Str.parseInt(sValue, nBase);
|
||||
}
|
||||
}
|
||||
if (value != null) {
|
||||
if (iNegate < 0) {
|
||||
value = -value;
|
||||
} else if (iNegate > 0) {
|
||||
/*
|
||||
* This is easier than adding an evalNOT()....
|
||||
*/
|
||||
value = this.evalXOR(value, -1);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1101,8 +1148,8 @@ if (DEBUGGER) {
|
|||
'*': 9, // multiplication
|
||||
'_': 10, // MACRO-10 shift operator
|
||||
'^_': 10, // MACRO-10 internal shift operator (converted from 'B' suffix form that MACRO-10 uses)
|
||||
'{': 11, // open sub-expression (achGroup[0] default)
|
||||
'}': 11 // close sub-expression (achGroup[1] default)
|
||||
'{': 11, // open grouped expression (achGroup[0] default)
|
||||
'}': 11 // close grouped expression (achGroup[1] default)
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue