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:
parent
d13e7a5faf
commit
d5c48df9bc
10 changed files with 1242 additions and 1144 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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, ' ');
|
||||
|
|
|
|||
Loading…
Reference in a new issue