Показать сообщение отдельно
  #1 (permalink)  
Старый 13.12.2016, 03:06
Аватар для Paguo-86PK
Профессор
Отправить личное сообщение для Paguo-86PK Посмотреть профиль Найти все сообщения от Paguo-86PK
 
Регистрация: 16.09.2009
Сообщений: 253

Замыкания и расширение области видимости (движок эмулятора ПК)
Н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("&#x2551;" + ("<span style=text-decoration:overline>" + (code >> 4).toHex(1) + "&#x2551;" + Acts.join("&#x2502;") + "</span>&#x2551;<br />")
					+ ("&#x2551; &#x2551;"+ opers.join("&#x2502;") + "&#x2551;").replace(/(IB|XX)/g, "<b style=color:cyan>$1</b>")),
				Acts = [], opers = [];
		}
		for(code = 0; code < 16; ++ code)
			opers.push("&#x255D;" + code.toHex(1) + "&#x255A;&#x2550;&#x2550;&#x2550;&#x2550;");
		user.instructions.innerHTML = (isFinite(ic) ? ic.toHex(2) + " " : "___") + "&#x2554;&#x2550;&#x2557;     ".x(16) + "<br />" +
			"&#x2554;&#x2550;&#x2566;" + opers.join("&#x2564;") + "&#x2557;<br />" +
			dump.join(large ? "<br />&#x255F;&#x2500&#x256B;" + "&#x2500;".x(cols).x(16, "&#x253C;") + "&#x2562;<br />" : "<br />") +
			"<br />&#x255A;&#x2550;&#x2569" + "&#x2550".x(cols).x(16, "&#x2567") + "&#x255D";
	}
	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(...) встроить...

Последний раз редактировалось Paguo-86PK, 02.03.2017 в 00:51. Причина: Построение генератора по шаблону
Ответить с цитированием