Нe получается никак решить проблему с замыканием.
<script>
String.prototype.x = function(n, j) {var s = this, buf = ""; while(n > 0) { if(n&1) buf+=s; s+=(j?j:"")+s; n >>= 1; } return buf; }
Number.prototype.toHex = function(n) {
return (n < 0 ? "0x" : "") + ((((this >> 16) & 0x0000FFFF) | 0x00010000).toString(16) + ((this & 0x0000FFFF) | 0x00010000).toString(16).substr(1)).substr(-Math.abs(n)).toUpperCase();
}
Number.prototype.hi = function(n) {
if(isFinite(n))
return (this & 255) | ((n & 255) << 8);
return (this >> 8) & 255;
}
Number.prototype.lo = function(n) {
if(isFinite(n))
return (this & 0xFF00) | (n & 255);
return this & 255;
}
var CPU =
function(pattern) {
var matrix = {
actions : [], // Instructions set
commands : [], // Assembly commands
};
var user = {
instructions : null,
logs : null,
};
var Logging = [];
// Отображение таблицы команд
this.showCommands = function(e) {
user.instructions = e;
};
function command_set(ic, ib) {
var large = false,
white = "<b style=background-color:white><u style=color:black>",
cols = 7,
dump = [],
Acts = [],
opers = [];
for(code = 0; code < 256; ++ code) {
var Action = matrix.actions[code];
var Act = Action.command + " ".x(cols),
Regs = Action.operand,
len = Regs.length - cols;
if(len > 0)
Act = Act.substr(0, cols - len) + Regs,
Regs = Regs.substr(-cols);
Act += " ",
Regs += " ";
html = "<span class=CPU_Group_" + Action.color + ">#</span>";
Act = Act.substr(0, cols);
Regs = Regs.substr(0, cols);
Acts.push(html.replace("#", (ic == code ? white + Act + "</u></b>" : Act)));
opers.push(html.replace("#", (ic == code ? white + Regs.replace("IB", ib.toHex(2)) + "</u></b>" : Regs)));
if((code & 15) == 15)
dump.push("║" + ("<span style=text-decoration:overline>" + (code >> 4).toHex(1) + "║" + Acts.join("│") + "</span>║<br />")
+ ("║ ║"+ opers.join("│") + "║").replace(/(IB|XX)/g, "<b style=color:cyan>$1</b>")),
Acts = [], opers = [];
}
for(code = 0; code < 16; ++ code)
opers.push("╝" + code.toHex(1) + "╚════");
user.instructions.innerHTML = (isFinite(ic) ? ic.toHex(2) + " " : "___") + "╔═╗ ".x(16) + "<br />" +
"╔═╦" + opers.join("╤") + "╗<br />" +
dump.join(large ? "<br />╟─╫" + "─".x(cols).x(16, "┼") + "╢<br />" : "<br />") +
"<br />╚═╩" + "═".x(cols).x(16, "╧") + "╝";
}
this.command_set = command_set;
// Начало инициализации
if(pattern) {
var res, tmp, id;
// Коллекция битов дешифратора
var pins = [],
pinex = /^([A-Z_]+)\?$/gm,
pinexp = [];
// Коллекция набора операндов
var opers = [],
operex = /^([^\s]{1,13})\t(.*)$/gm,
operexp = [],
operact = [],
operem = [];
// Коллекция командной модели
var models = [],
modelex = /^([0X1_]+)([A-Z_])\t([^:\t]+)\t*([^:\t]*?)\t*:(.*?)((?:\/\/)(.*))?$/gm;
// Начинаем разбирать представленный шаблом
if(!(res = pattern.match(pinex)))
return alert("Where the pins?");
// Разбираем битовые поля инструкций
res[0].replace(/[_?]/g, "").split("").reverse()
.forEach
(function(id, x, whole) {
(((pins[id]) || (pins[id] = [])) && pins[id]).push("(((x >> " + x + ") & 1) << " + pins[id].length + ")");
});
// Объявляем функциональное считывание
for(id in pins)
pinexp.push("$" + id),
pins["$" + id] = new Function("x", "return " + pins[id].join(" | ")),
delete pins[id];
// Собираем имена полей в выражение
pinexp = new RegExp("(" + pinexp.join("|").replace(/(\$)/g, "\\$1") + ")", "g");
if(!(res = pattern.match(operex)))
return alert("Where the operands?");
// Разбираемся с операндами
res.forEach
(function(str) {
var str = str.split(/\t+/);
operexp.push(str[0]);
opers[str[0]] = str[1];
operact[str[0]] = str[2];
operem[str[0]] = str[3] || str[1];
});
// Собираем имена операндов в выражение
operexp = new RegExp("(" + operexp.join("|").replace(/(\$)/g, "\\$1") + ")", "g");
if(!(res = pattern.match(modelex)))
return alert("Where the model???");
// Разбираемся и строим полную командную модель
res.forEach
(function(desc) {
desc.replace(modelex,
function(str, mask, group, command, operand, action, description) {
mask = mask.replace(/_/g, "");
var $D, commands, operands, actions, descriptions;
base = parseInt(mask.replace(/X/g, "0"), 2), // 0XX1X0X1XX -> 0001000100
over = parseInt(mask.replace(/X/g, "1"), 2), // 0XX1X0X1XX -> 0111101111
last = parseInt(mask.replace(/./g, "1"), 2), // 0XX1X0X1XX -> 1111111111
mix = base ^ over ^ last; // 1001010100
// Пробегаем по всем комбинациям неопределённых битов
for($D = base; $D <= over; $D = ((($D | mix) + 1) & ~mix) | base) {
if(matrix.actions[$D])
continue;
// Корректируем объявления шаблона с подстановкой конкретных числовых величин
commands = command .replace(pinexp ,function($id) {return pins[$id]($D); });
operands = operand .replace(pinexp ,function($id) {return pins[$id]($D); });
actions = action .replace(pinexp ,function($id) {return pins[$id]($D); });
descriptions = description .replace(pinexp ,function($id) {return pins[$id]($D); });
// Проходимся второй раз с подстановкой перечисленных имён шаблона конкретными ссылками
commands = commands .replace(operexp,function($id) {return opers[$id]; });
operands = operands .replace(operexp,function($id) {return opers[$id]; });
actions = actions .replace(operexp,function($id) {return operact[$id]; });
descriptions = descriptions .replace(operexp,function($id) {return operem[$id]; });
Logging.push($D.toHex(2) + "#" + group + "|" + commands + "\t" + operands + "\t{" + actions + "}" + descriptions);
// Строим функциональную матрицу системы команд для эмуляции и дизассемблера
matrix.actions[$D] = {
color : group, // Цвет группы, к которой относится операция
command : commands, // Название команды
operand : operands, // Операнды команды
action : actions, // Функциональное описание действия команды
remark : descriptions, // Краткое описание инструкции
};
if(!matrix.commands[commands])
matrix.commands[commands] = [];
// Строим обратную матрицу для ассемблера
operands.split("/")
.forEach(function(operands) {
if(!(operand in matrix.commands[commands]))
matrix.commands[commands][operands] = $D;
});
};
});
});
/**/document.getElementById("Logging").innerText = Logging.join("\r\n");
}
};
var cpu = null;
function main() {
cpu = new CPU(document.getElementById("Pattern").textContent);
cpu.showCommands(document.getElementById("Commands"));
cpu.command_set(0x55, 1);
}
</script>
<style>
pre#Commands {
color : lightgreen;
cursor : default;
}
span.CPU_Group__{
background-color: #012;
cursor : pointer;
}
span.CPU_Group_A{
background-color: #772; <!--ALU-->
}
span.CPU_Group_B{
background-color: #764; <!--JMP-->
}
span.CPU_Group_C{
background-color: #888; <!--HLT-->
}
span.CPU_Group_D{
background-color: #663; <!--INX-->
}
span.CPU_Group_E{
background-color: #363; <!--POP-->
}
span.CPU_Group_F{
background-color: #367; <!--MOV-->
}
span.CPU_Group_X{
background-color: #437; <!--???-->
}
var {
display :none
}
</style>
</head>
<body onload='main()'>
<var id=Pattern
>P0 BC reg.bc B and C
P2 DE reg.de D and E
P4 HL reg.hl H and L
P6 PSW reg.acc Status
Q0 B reg.bc B
Q1 C reg.bc C
Q2 D reg.de D
Q3 E reg.de E
Q4 H reg.hl H
Q5 L reg.hl L
Q6 M reg.m Memory
Q7 A reg.acc Accumulator
R0 B reg.bc.hi B
R1 C reg.bc.lo C
R2 D reg.de.hi D
R3 E reg.de.lo E
R4 H reg.hl.hi H
R5 L reg.hl.lo L
R6 M reg.mem Memory
R7 A reg.acc.lo Accumulator
ALU0 ADD 0 Addition
ALU1 ADC 0 Addition with carry
ALU2 SUB 0 Subtraction
ALU3 SBB 0 Subtraction with borrow
ALU4 ANA 0 Bitwise conjunction
ALU5 XRA 0 Bitwise exclude disjunction
ALU6 ORA 0 Bitwise disjunction
ALU7 CMP 0 Comparation
ZZ_YYY_XXX_?
00_000_000_C NOP : //No operation
00_110_001_B LXI SP,IW :reg.sp=$IW() //
00_XX0_001_B LXI P$Y,IW :P$Y=$IW() //Load address into P$Y
00_XXX_110_F MVI R$Y,IB :Q$X=$IB() //Flip-flop translation byte to R$Y
01_110_110_F HLT :reg.pc -- //Halting
01_XXX_XXX_F MOV R$Y,R$X :Q$X=R$Y(R$X()) //Flip-flop translation R$X to R$Y
10_XXX_XXX_A ALU$Y R$Y :ALU$Y(R$Y()) //ALU$Y
11_XX0_001_E POP P$Y :P$Y=STACK() //Pop P$Y from stack
11_XX0_101_E PUSH P$Y :STACK(P$Y) //Push P$Y to stack
XX_XXX_XXX_X ??? : //
</var>
<pre id=Commands></pre>
<pre id=Logging></pre>
</body>
Нe думал, что придётся просить помощи в элементарном.
Мне нужно организовать всё так, чтобы анонимные функции видели локальные переменные.
Спасибо!
P.S.: Пример выше - очень абстрактный. И я здорово запутался в проблеме видимости локальных переменных.
Пришлось явно всё передавать, да ещё и with(...) встроить...