Node pdp11 utility can now load machine XML files

This commit is contained in:
Jeff Parsons 2016-12-28 14:29:13 -08:00 • committed by Jeff Parsons
commit 1543583c01

View file

@ -33,10 +33,12 @@
var path = require("path"); var path = require("path");
var fs = require("fs"); var fs = require("fs");
var repl = require("repl"); var repl = require("repl");
var xml2js = require("xml2js");
var Defines = require("../../shared/es6/defines"); var Defines = require("../../shared/es6/defines");
var Str = require("../../shared/es6/strlib"); var Str = require("../../shared/es6/strlib");
var Proc = require("../../shared/es6/proclib"); var Proc = require("../../shared/es6/proclib");
var idAttrs = '@';
var fConsole = false; var fConsole = false;
var fDebug = false; var fDebug = false;
var args = Proc.getArgs(); var args = Proc.getArgs();
@ -185,118 +187,130 @@ function getComponentByType(sType)
return component; return component;
} }
/**
* initMachine(xml)
*
* @param {Object} xml
*/
function initMachine(xml)
{
/*
* Clear any/all saved objects from any previous machine
*/
Component = dbg = null;
for (var i = 0; i < aComponents.length; i++) {
aComponents[i].objects = [];
}
var machine = xml['machine'];
var idMachine = machine[idAttrs] && machine[idAttrs]['id'] || "";
for (var iComponent = 0; iComponent < aComponents.length; iComponent++) {
var component = aComponents[iComponent], aDevices = machine[component.name];
/*
* If aDevices is undefined, then that component does not exist in this machine.
*/
if (aDevices === undefined) continue;
for (var iDevice = 0; iDevice < aDevices.length; iDevice++) {
var obj;
var device = aDevices[iDevice];
var parmsObj = device[idAttrs];
if (idMachine) parmsObj['id'] = idMachine + '.' + parmsObj['id'];
if (fDebug) {
console.log("creating " + component.name + "...");
console.log(parmsObj);
}
if (component.name == "cpu") {
parmsObj['autoStart'] = false;
}
try {
obj = new component.Create(parmsObj);
} catch (err) {
console.log("error creating " + component.name + ": " + err.message);
continue;
}
console.log(obj['id'] + " object created");
component.objects.push(obj);
if (obj.type == "Debugger") {
dbg = obj;
}
}
}
}
/** /**
* loadMachine(sFile) * loadMachine(sFile)
* *
* @param {string} sFile * @param {string} sFile
* @return {Object} representing the machine whose component objects have been loaded into aComponents * @return {boolean}
*/ */
function loadMachine(sFile) function loadMachine(sFile)
{ {
if (fDebug) console.log('loadMachine("' + sFile + '")'); if (fDebug) console.log('loadMachine("' + sFile + '")');
var xml = {_resolving: 0};
/* return readXML(xml, 'machine', sFile, null, 0, initMachine);
* Clear any/all saved objects from any previous machine }
*/
var i, j; /**
Component = dbg = null; * readXML(xml, sNode, sFile, aTags, iTag, done)
for (i = 0; i < aComponents.length; i++) { *
aComponents[i].objects = []; * @param {Object} xml
} * @param {string} sNode
* @param {string} sFile
var machine; * @param {Array|null} aTags
* @param {number} iTag
* @param {function(Object)} done
* @return {boolean}
*/
function readXML(xml, sNode, sFile, aTags, iTag, done)
{
var fLoading = false;
try { try {
/* xml._resolving++;
* Since our JSON files may contain comments, hex values, and/or other tokens deemed var sXML = fs.readFileSync(sFile, {encoding: "utf8"});
* unacceptable by the JSON Overlords, we can't use require() to load it, as we're able to var parser = new xml2js.Parser({attrkey: idAttrs});
* do with "package.json". Also note that require() assumes the same path as that of the parser.parseString(sXML, function(err, xmlNode) {
* requiring file, whereas fs.readFileSync() assumes the path reported by process.cwd(). if (!aTags) {
* xml[sNode] = xmlNode[sNode];
* TODO: I've since removed the comments from my sample "ibm5150.json" file, so we could } else {
* try to reinstate this code; however, there are still hex constants, which I find *much* aTags[iTag] = xmlNode[sNode];
* preferable to the decimal equivalents. JSON's restrictions continue to irritate me.
*
* var machine = require(lib + "../bin/" +sFile);
*/
var sMachine = fs.readFileSync(sFile, {encoding: "utf8"});
sMachine = '(' + sMachine + ')';
if (fDebug) console.log(sMachine);
machine = eval(sMachine); // jshint ignore:line
if (machine) {
/*
* Since we have a machine object, we now mimic the initialization sequence that occurs
* in the browser, by walking the list of PDPjs components we loaded above and looking for
* matches.
*/
var idMachine = "";
/*
* 'machine' is a pseudo-component that is only used to define an ID for the entire machine;
* if it exists, then that ID is prepended to every component ID, just as our XSLT code would
* do for a machine XML file. This relieves the JSON file from having to manually prepend
* a machine ID to every component ID itself.
*
* This doesn't mean I anticipate a Node environment running multiple machines, as we do in
* a browser; it only means that I'm trying to make both environments operate similarly.
*/
if (machine['machine']) {
idMachine = machine['machine']['id'];
} }
if (err) {
for (i = 0; i < aComponents.length; i++) { console.log(err.message);
}
var component = aComponents[i]; else if (xmlNode && xmlNode[sNode]) {
var parms = machine[component.name]; for (var sTag in xmlNode[sNode]) {
/* var aTagsXML = xmlNode[sNode][sTag];
* If parms is undefined, it means there is no component with that name defined in the for (var iTagXML = 0; iTagXML < aTagsXML.length; iTagXML++) {
* machine object (NOT that the component has no parms), and therefore we should skip it. var tag = aTagsXML[iTagXML];
*/ var attrs = tag[idAttrs];
if (parms === undefined) continue; if (attrs) {
/* for (var attr in attrs) {
* If parms is an Array, then we must create an object for each parms element; and yes, if (attr == "ref") {
* I'm relying on the fact that none of my parm objects use a "length" property, as a quick var sFileXML = "../../.." + attrs[attr];
* and dirty way of differentiating objects from arrays. readXML(xml, sTag, sFileXML, aTagsXML, iTagXML, done);
*/ }
var aParms = parms.length !== undefined? parms : [parms]; }
for (j = 0; j < aParms.length; j++) { }
var obj;
var parmsObj = aParms[j];
if (idMachine) parmsObj['id'] = idMachine + '.' + parmsObj['id'];
if (fDebug) {
console.log("creating " + component.name + "...");
console.log(parmsObj);
}
if (component.name == "cpu") {
parmsObj['autoStart'] = false;
}
try {
obj = new component.Create(parmsObj);
} catch(err) {
console.log("error creating " + component.name + ": " + err.message);
continue;
}
console.log(obj['id'] + " object created");
component.objects.push(obj);
if (obj.type == "Debugger") {
dbg = obj;
} }
} }
if (!--xml._resolving) done(xml);
} }
/* });
* Return the original machine object only in DEBUG mode fLoading = true;
*/
if (!fDebug) machine = true;
}
} catch(err) { } catch(err) {
console.log(err.message); console.log(err.message);
} }
return machine; return fLoading;
} }
/** /**