Added support for MACRO-10 literal collapsing; it's not super-aggressive, but it's more than adequate for what DEC's diagnostics require

This commit is contained in:
Jeff 2017-03-28 15:22:17 -07:00 committed by Jeff Parsons
commit d5c48df9bc
10 changed files with 1242 additions and 1144 deletions

File diff suppressed because it is too large Load diff

View file

@ -378,19 +378,70 @@ class Macro10 {
this.error("open scope from line " + this.stackScopes[0].nLine);
}
for (let i = 0; i < this.aLiterals.length; i++) {
let lit = this.aLiterals[i];
this.addSymbol(lit.name, this.nLocation, Macro10.SYMTYPE.LABEL);
lit.aWords.forEach(function(w, nLocation) {
macro10.genWord(w, lit.aFixups[nLocation]);
});
let nLocationLiterals = this.nLocation;
for (let i = 0; i < this.aLiterals.length; i++) {
/*
* TODO: Add support for "literal collapsing"; ie, if two or more literals generate the same
* set of values, then all instances after the first should refer back to the first (subject to
* exceptions identified by MACRO-10: eg, "literals that contain errors, undefined expressions,
* or EXTERNAL symbols.")
* Apparently, the time has come to implement "literal collapsing"; I was treating it as just
* a nice optimization, but it turns out that DEC has written tests that actually DEPEND on it:
*
* C26300: HRRZI [135531,,246642] ;PRELOAD AC0 WITH 0,, LITERAL ADDRESS
* JRA .+1 ;*JRA SHOULD PLACE C(AC0) INTO AC0
* CAIE [135531,,246642] ;PASS IF JRA PLACED C(AC0) INTO AC0
* STOP
*
* If the HRRZI and CAIE instructions don't refer to the same exact literal, the test will fail.
* For purposes of this particular test, the values they stuffed into the literals are essentially
* gibberish, but the same literal may be used in another test where the values are significant.
*
* However, I'm still going to keep it simple. In this example from p. 2-8 of the April 1978
* MACRO-10 manual, I will NOT be attempting to collapse null words at the end of ASCIZ sequences
* with other null words, especially if they were defined before the ASCIZ:
*
* Literals having the same value are collapsed in MACRO's literal pool.
* Thus for the statements:
*
* PUSH P,[0]
* PUSH P,[0]
* MOVEI 1,[ASCIZ /TEST1/]
*
* the same address is shared by the two literals [0], and by the null word
* generated at the end of [ASCIZ /TEST1/].
*/
let lit = this.aLiterals[i];
/*
* First things first: verify that the literal is one contiguous set of words (I'm not sure how
* it couldn't be, but better safe than sorry).
*/
let aWords = [];
let nWords = 0;
lit.aWords.forEach(function(w, nLocation) {
if (nLocation === aWords.length) aWords.push(w);
nWords++;
});
if (nWords == aWords.length) {
/*
* So far, so good. Now we'll simply brute-force-search our way through the existing set of
* literals, looking for a complete match.
*/
for (let nLocation = nLocationLiterals; nLocation + nWords <= this.nLocation; nLocation++) {
let n;
for (n = 0; n < nWords; n++) {
if (aWords[n] !== this.aWords[nLocation + n] || lit.aFixups[n] != this.aFixups[nLocation]) break;
}
if (n == nWords) {
this.addSymbol(lit.name, nLocation, Macro10.SYMTYPE.LABEL);
lit = null;
break;
}
}
}
if (lit) {
this.addSymbol(lit.name, this.nLocation, Macro10.SYMTYPE.LABEL);
lit.aWords.forEach(function(w, nLocation) {
macro10.genWord(w, lit.aFixups[nLocation]);
});
}
}
for (let i = 0; i < this.aVariables.length; i++) {
@ -701,9 +752,14 @@ class Macro10 {
*/
pushScope(name)
{
this.stackScopes.push(
{name, aWords: this.aWords, aFixups: this.aFixups, nLocation: this.nLocation, nLocationScope: this.nLocationScope, nLine: this.nLine}
);
this.stackScopes.push({
name,
aWords: this.aWords,
aFixups: this.aFixups,
nLocation: this.nLocation,
nLocationScope: this.nLocationScope,
nLine: this.nLine
});
this.aWords = [];
this.aFixups = [];
this.nLocationScope = this.nLocation;

View file

@ -872,26 +872,30 @@ class Debugger extends Component
*
* Although I started listing the operators in the RegExp in "precedential" order, that's not important;
* what IS important is listing operators than contain shorter operators first. For example, bitwise
* shift operators must be listed BEFORE the logical less-than or greater-than operators.
* shift operators must be listed BEFORE the logical less-than or greater-than operators. aBinOpPrecedence
* is what determines precedence.
*
* Also, to better accommodate MACRO-10 syntax, I've replaced the single '^' for XOR with '^!' (since
* MACRO-10 uses prefixes like "^D", "^O" and "^B" with numeric constants to indicate a base override).
* Similarly, I've added '!' as an alias for '|' (bitwise inclusive-or), '^-' as an alias for '~' (unary
* complement "not" operator), and '_' as a shift operator.
* Also, to better accommodate MACRO-10 syntax, I've replaced the single '^' for XOR with '^!', and I've
* added '!' as an alias for '|' (bitwise inclusive-or), '^-' as an alias for '~' (one's complement operator),
* and '_' as a shift operator (+/- values specify a left/right shift, and the count is not limited to 32).
*
* 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 ('^_').
*
* Note that Str.parseInt(), which parseValue() relies on, supports both the MACRO-10 base prefix overrides
* and the binary shifting suffix. But since the B suffix can also be a bracketed expression, we have to
* and the binary shifting suffix ('B'), but since that suffix can also be a bracketed expression, we have to
* support it here as well.
*
* MACRO-10 supports only a subset of all the PCjs operators; for example, MACRO-10 doesn't support bitwise
* exclusive-or, shift operators, or any of the boolean logical/compare operators. But unless we run into
* conflicts, I prefer sticking with this common set of operators.
* MACRO-10 supports only a subset of all the PCjs operators; for example, MACRO-10 doesn't support any of
* the boolean logical/compare operators. But unless we run into conflicts, I prefer sticking with this
* common set of operators.
*
* WARNING: Whenever you make changes to this RegExp, make sure you update aBinOpPrecedence as needed, too.
* All whitespace in the expression is collapsed to single spaces, and space has been added to the list
* of "operators", but its sole function is as a separator, not as an operator. parseArray() will ignore
* single spaces as long as they are preceded and/or followed by a "real" operator. It would be dangerous
* to remove spaces entirely, because if an operator-less expression like "A B" was passed in, we would want
* that to generate an error; if we converted it to "AB", evaluation might inadvertently succeed.
*/
var regExp = /(\{|}|\|\||&&|\||\^!|\^B|\^O|\^D|\^L|\^-|~|\^_|_|&|!=|!|==|>=|>>>|>>|>|<=|<<|<|-|\+|%|\/|\*| )/;
sExp = sExp.replace(/(^|[^A-Z0-9$%.])([0-9]+)B/, "$1$2^_").replace(/\s+/g, ' ');