Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #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. Причина: Построение генератора по шаблону
Ответить с цитированием
  #2 (permalink)  
Старый 22.02.2017, 03:02
Аватар для Paguo-86PK
Профессор
Отправить личное сообщение для Paguo-86PK Посмотреть профиль Найти все сообщения от Paguo-86PK
 
Регистрация: 16.09.2009
Сообщений: 253

Удалoсь таки заставить "славный говнокод" работать
(доработал представленное выше, но не разобрался с замыканиями)

Нa этих выходных решил попробовать написать эмулятор с нуля, руководствуясь накопленным опытом.
Основной задачей было поставлено написать некий универсальный движок, с помощью которого можно описать нужный процессор простым шаблоном, который развернётся в работающую модель с комплектом 3 в 1: Эмулятор, Дизассемблер, Ассемблер. При этом, не нужно было бы сурово переделывать сам js-текст.
В итоге, уложился в трое суток бессонных ночей отладки.
Получился компактный - 1500 строк и 60кб.

P.S.: Если браузерная совместимость не подведёт, эмулятор запустится сразу под рандомным мусором в его ОЗУ…
Необходимо нажать кнопку Reset, а затем - Start.
Клавиши тоже должны работать: F1-Шаг отладки, F4-Полный ход, F9-Брейк-пойнт.
Также, F7-Выбор настраиваемого параметра(FPS, IPC, IPS), F6/F8-Декремент/Инкремент параметра.
Пожалуйста, отпишитесь, у кого - какой результат.
Кстати, шаблон можно редактировать прямо в процессе (кнопка Matrix) и изменить всю систему команд на ходу (двойной клик по той же Matrix)…
(по идее, можно описать 6502. Для Z80 пока ещё не хватает поддержки префиксов, что довольно поправимо)
Ответить с цитированием
  #3 (permalink)  
Старый 27.02.2017, 00:00
Аватар для Paguo-86PK
Профессор
Отправить личное сообщение для Paguo-86PK Посмотреть профиль Найти все сообщения от Paguo-86PK
 
Регистрация: 16.09.2009
Сообщений: 253

Сообщение от Rise Посмотреть сообщение
локализуй проблему...
Сил уже нет. Всё перепробовал:
var	BUG	=
function(formula) {
	var	expression	=
		function() {
			return	0;
		},
		adjust		= 7,
		times		= 3;
	function	Bug(n) {
		var no = n;
		while(n > 0) {
			console.log("OUTSIDE: Adjust is " + adjust + ", N is " + n);
			*!*console.log("RESULT is " + expression.bind(self).call());*/!*
			if(no == n) {
				console.log("BUGGEST");
				n --;
			}
			no = n;
		}
		if(-- times > 0)
			setTimeout(this.Bug.bind(self), 2500);
	}
	if(!!formula)
		expression = (new Function("", formula));
	this.Bug	= Bug;
	return	this;
};

var	Bugs = new BUG(
"	console.log(\"INSIDER...\");\
	console.log(\"INSIDE: Adjust is \" + this.adjust);\
	console.log(\"INSIDE: N is \" + this.n);\
	try {\
		console.log(\"INSIDE: Adjust is \" + adjust);\
	} catch(e) {\
		console.log(\"INSIDE: Adjust is ???\");\
	}\
	try {\
		console.log(\"INSIDE: N is \" + n);\
	} catch(e) {\
		console.log(\"INSIDE: N is ???\");\
	}\
	try {\
		console.log(\"return n -- * adjust\");\
		return	n -- * adjust;\
	} catch(e) {\
	}\
	try {\
		console.log(\"return this.n -- * this.adjust\");\
		return	this.n -- * this.adjust;\
	} catch(e) {\
		console.log(\"Total Error...\");\
	}\
	return	0;"
	);

alert(Bugs.Bug(3));


P.S.: Проблема в том, что из-под eval всё работает и все переменные доступны и обновляемы.
А вот красиво обвернув в функцию никак не получается…
Выше я обновил пример - пишу эмулятор. И он пока весь держится на eval… Хотелось бы иначе

Спасибо!

Последний раз редактировалось Paguo-86PK, 02.03.2017 в 00:24.
Ответить с цитированием
  #4 (permalink)  
Старый 28.02.2017, 10:40
Аватар для Paguo-86PK
Профессор
Отправить личное сообщение для Paguo-86PK Посмотреть профиль Найти все сообщения от Paguo-86PK
 
Регистрация: 16.09.2009
Сообщений: 253

Сообщение от Rise Посмотреть сообщение
Paguo-86PK, можно сразу передавать функцию:
var BUG = function(formula) {
	var adjust = 7;
	this.Bug = function(n) {
		while (n--) {
			console.log("OUTSIDE: Adjust is " + adjust + ", N is " + n);
			console.log("RESULT is " + formula(adjust, n));
		}
		return this;
	};
};
var Bugs = new BUG(function(x, y) {
	return x * y; 
});
Bugs.Bug(5);
Eсли бы всё было так просто
Вы с эмуляторами сталкивались?
Пишу сейчас собственный под РАДИО-86РК, где нудная цепочка "switch(машинный_код) case инструкция№1 ... case инструкция№255" заменена на массив.
Т.е. имеется структура регистров
var	Register	=
	function(x) {
		return	{
			id	: "",
			fx	: 0,
			hi	: (x >> 8) & 255,
			lo	: x & 255,
			start	: x & 65535,
			get reset()	{
				this.lo = this.start & 255,
				this.hi = this.start >> 8;
				return	this.lo | (this.hi << 8);
			},
			get h()		{
				return	this.hi;
			},
			set h(x)	{
				this.fx = (x >> 8) & 1;
				this.hi = (x &= 255);
				this.fx |= (x & 128) | (!x ? 64 : 0);
				x ^= x >> 4;
				x ^= x << 2;
				x ^= x >> 1;
				this.fx |= x & 4;
				//console.log(this.id + ":" + (this.lo | (this.hi << 8)).toHex(-4));
			},
			get l()		{
				return	this.lo;
			},
			set l(x)	{
				this.fx = (x >> 8) & 1;
				this.lo = (x &= 255);
				this.fx |= (x & 128) | (!x ? 64 : 0);
				x ^= x >> 4;
				x ^= x << 2;
				x ^= x >> 1;
				this.fx |= x & 4;
				//console.log(this.id + ":" + (this.lo | (this.hi << 8)).toHex(-4));
			},
			get x()		{
				//console.log(this.id + ":" + (this.lo | (this.hi << 8)).toHex(-4));
				return	this.lo | (this.hi << 8);
			},
			set x(x)	{
				this.lo = x & 255, this.hi = (x >> 8) & 255;
				//console.log(this.id + ":" + (this.lo | (this.hi << 8)).toHex(-4));
			},
			get m()		{
				//console.log(this.id + "[" + (this.lo | (this.hi << 8)).toHex(-4) + "]:" + (ram[this.lo | (this.hi << 8)] & 255).toHex(-2));
				return	ram[this.lo | (this.hi << 8)] & 255;
			},
			set m(x)	{
				ram[this.lo | (this.hi << 8)] = x & 255;
				//console.log(this.id + "[" + (this.lo | (this.hi << 8)).toHex(-4) + "]=" + (ram[this.lo | (this.hi << 8)] & 255).toHex(-2));
			},
			get n()		{
				var	x = this.lo | (this.hi << 8);
				this.lo = (this.lo + 1) & 255;
				this.hi = !this.lo ? (this.hi + 1) & 255 : this.hi;
				return	ram[x];
			},
			set n(x)	{
				this.hi = !this.lo ? (this.hi - 1) & 255 : this.hi;
				this.lo = (this.lo - 1) & 255;
				ram[this.lo | (this.hi << 8)] = x & 255;
			},
			get w()		{
				var	x = this.lo | (this.hi << 8), d;
				this.lo = (this.lo + 2) & 255;
				this.hi = this.lo < 2 ? (this.hi + 1) & 255 : this.hi;
				d = ram[x] + 256 * ram[(x + 1) & 65535];
				//console.log("[" + x.toHex(-4) + "]:" + d.toHex(-4));
				return	d;
			},
			set w(x)	{
				this.hi = this.lo < 2 ? (this.hi - 1) & 255 : this.hi;
				this.lo = (this.lo - 2) & 255;
				ram[this.lo | (this.hi << 8)] = x & 255;
				ram[(this.lo + (this.hi << 8) + 1) & 65535] = (x >> 8) & 255;
				//console.log("[" + (this.lo | (this.hi << 8)).toHex(-4) + "]=" + x.toHex(-4));
			},
		}
	};
В основном цикле эмулятора, когда просто через eval пропускается нечто типа "r.a.h = r.b.l" - полный порядок. А если всё красиво обернуть в функции { r.a.h = r.b.l; }, то никак не получается заставить видеть r-структуру.
Вы сами понимаете, что подготовить все 256 функций к вызовам и потом их вызывать - куда быстрее, чем каждый раз интерпретировать eval'ом тысячи команд за раз.

P.S.: Сейчас нашёл более-менее работающий способ: Все 256 функций при инициализации прописываю прямо внутри операционного цикла, к которому насильно привязываю ещё и регистры с памятью.
Некрасиво, обвёрнуто в with(this), но заработало…
А передавать всё через аргументы - пробовал в прошлом году. Огороды скобок и некоторые вещи сделать нельзя.
(у меня R$1 разворачивается в r.a.l, что раньше было R$1(R$1()+R$2()) как r.a.l(r.a.l()+r.b.h()) и тяжело визуально наблюдалось. сейчас - просто R$1+=R$2 за r.a.l+=r.b.h, что коротко и понятно)
Не просил бы помощи, если бы задача была проще.
Нужно мне именно так, как я описал выше. И никак иначе

Последний раз редактировалось Paguo-86PK, 02.03.2017 в 00:22.
Ответить с цитированием
  #5 (permalink)  
Старый 28.02.2017, 17:17
Аватар для nerv_
junior
Отправить личное сообщение для nerv_ Посмотреть профиль Найти все сообщения от nerv_
 
Регистрация: 29.11.2011
Сообщений: 3,924

Не знаю, что тут у вас происходит, много разных непонятных символов

Судя по
Сообщение от Paguo-86PK
(у меня R$1 разворачивается в r.a.l, что раньше было R$1(R$1()+R$2()) как r.a.l(r.a.l()+r.b.h()) и тяжело визуально наблюдалось. сейчас - просто R$1+=R$2 за r.a.l+=r.b.h, что коротко и понятно)
Если я правильно понял, тебе нужно определить (описать) свой язык, операторы, а дальше делать то, что требуется в рамках этого языка. В прологе так можно было. Применительно к js, вероятно, что-нибудь из этого:
+ https://pegjs.org/
+ https://github.com/harc/ohm
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук
Ответить с цитированием
  #6 (permalink)  
Старый 01.03.2017, 15:12
Аватар для Paguo-86PK
Профессор
Отправить личное сообщение для Paguo-86PK Посмотреть профиль Найти все сообщения от Paguo-86PK
 
Регистрация: 16.09.2009
Сообщений: 253

Основные принципы организации шаблона
Конечнo, Спасибо за советы…
В самом начале темы я пост поправил. Вы запускали пример в нём?
Имеется конкретный эмулятор (нажмите кнопку V между Console и Full Screen, чтобы увидеть таблицу команд), который расписан классически, как можете убедиться, без выкрутасов (древом switch(код_команды) case код_nn:  ействие_nn…).
Когда переписывался с его автором и пытался чуточку подогнать его под свои фантазии, приходилось модифицировать и древо ассемблера, и древо дизассемблера, и саму визуальную таблицу, и ядро эмуляции. Что крайне сложно для отладки.
Тогда появилась мысль, разработать некий автоматический конструктор для эмуляции. Из справочника по конкретному процессору переводишь таблицу в некоторый шаблон, а библиотека сама его "переварит" и всё сделает без особого напряга со стороны пользователя. Если что-то не так работает, правится только шаблон…

В детстве изучил кучу советской справочной литературы отца на темы ПЛ/1, ПЛ/М, Ада, Фортран, Лисп, Пролог, Паскаль, Форт, Си, АПЛ и т.д. Т.е. когда сел за более-менее приветливый терминал, имел некоторые представления о том, как заставить машину делать что-то именно моё уникальное. Ассемблер был роскошью и команды писал прямо дампом.

Сейчас задуманное работает. До 512 срабатываний таймера в секунду с обработкой до 2048 инструкций (512*2048=до миллиона команд в секунду). И всё держится на eval, а разумно бы в new Function завернуть. В функцию нельзя передавать аргументы. Вернее, можно, но их будет с несколько десятков, что расходно и бессмысленно.
Тем более, на выходе - ничего нет. Процесс игнорирует результат eval и не принимает значения от function-return. Т.е. оперирование идёт со всеми окружающими структурами и массивами. Понимаете?

P.S.: Когда впервые пересел с IBM-PC/XT - DOS 3.11 за Pentium-I под Windows'98, через год изучения Visual Basic 4 написал свой первый эмулятор с кучей if-then-else/switch-case и т.д.
Теперь хочу автоматизировать всё это дело…

P.P.S.: Несколько слов о принципах шаблона и его "разворачивания"…
Аналогично оператору casex в шаблоне перечисляются все возможные комбинации битов кода для каждой операции:
Код:
1X0X - Бинарная маска шаблона: Здесь X указывает на биты с произвольным линейным содержимым
==== - Разворачивается в 2²=4 (двойка в степени количества X в строке) комбинации:
1000 - Базовая комбинация
1001 - Первая комбинация
1100 - Вторая комбинация
1101 - Третья комбинация
В шаблоне указываются также битовые поля операционных констант, закреплённых за конкретным кодом:
Код:
?XYX? - Здесь за X берутся биты 3 и 1 соответственно. Только за Y берётся бит 2,
Y???? - Затем и бит 4 - в обратном порядке. Знак вопроса в конце (?) обязателен
----- - Все перечисленные имена констант далее действуют в целом шаблоне
XXXX - Всё это дело разворачивается в
==== - следующую таблицу бинарной маски:
0000 - $X = 00, $Y = 00
0001 - $X = 01, $Y = 00
0010 - $X = 00, $Y = 10
0011 - $X = 01, $Y = 10
0100 - $X = 10, $Y = 00
0101 - $X = 11, $Y = 00
0110 - $X = 10, $Y = 10
0111 - $X = 11, $Y = 10
1000 - $X = 00, $Y = 01
1001 - $X = 01, $Y = 01
1010 - $X = 00, $Y = 11
1011 - $X = 01, $Y = 11
1100 - $X = 10, $Y = 01
1101 - $X = 11, $Y = 01
1110 - $X = 10, $Y = 11
1111 - $X = 11, $Y = 11
Тем самым, в строке конкретной операции все операционные константы при разборе шаблона подменяются на конкретные значения:
Код:
0XX1 DO R$Y+=R$X
==== - Данная выше строчка развернётся в 4:
0001 DO R0+=R1
0011 DO R2+=R1
0101 DO R0+=R3
0111 DO R2+=R3
Что значительно облегчает описание всех возможных комбинаций конкретного набора однотипных инструкций.
В шаблоне также можно описать псевдонимы для операций и регистров, закрепив за ними конкретные действия:
Код:
R0 Door Open_Door
R1 Desk Wash_Desk
R2 Cat  Make_Purr
R3 Dog  Keep_Home
Тем самым, представленный выше шаблон совсем изменится в развёртке:
Код:
0XX1 DO R$Y+=R$X :R$Y(R$X)
==== - Данная выше строчка развернётся в 4:
0001 DO Door+=Desk :Open_Door(Wash_Desk)
0011 DO Cat+=Desk  :Make_Purr(Wash_Desk)
0101 DO Door+=Dog  :Open_Door(Keep_Home)
0111 DO Cat+=Dog   :Make_Purr(Keep_Home)
Чем достигается описывание довольно сложных алгоритмических выражений с шаблонной подстановкой конкретных комбинаций за конкретными кодами.
Разрабатываемая маленькая библиотека делает всё сама. При этом, когда Вы опишете шаблон абсолютно корректно, на выходе получите полноценный функциональный инструмент:
  1. Эмулятор: Берёт последовательно коды команд из таблицы и вызывает их как конкретные функции
  2. Дизассемблер: Читает коды операций и преобразует их в колонку символьного представления
  3. Ассемблер: Читает Ваш текст программы символьных команд и преобразует их в совокупность бинарных кодов тех команд
Так, например, мы напишем следующие строчки:
Код:
    DO Door+=Dog
    DO Cat+=Desk
    DO Cat+=Dog
В таблицу памяти он упакуется кодами 0101, 0011, 0111.
Запустив данную "программу" мы заставим цикл эмуляции выполнить следующую последовательность операций:
Open_Door(Keep_Home); Make_Purr(Wash_Desk); Make_Purr(Keep_Home);

Последний раз редактировалось Paguo-86PK, 03.03.2017 в 09:21.
Ответить с цитированием
  #7 (permalink)  
Старый 08.03.2017, 08:56
Аватар для Paguo-86PK
Профессор
Отправить личное сообщение для Paguo-86PK Посмотреть профиль Найти все сообщения от Paguo-86PK
 
Регистрация: 16.09.2009
Сообщений: 253

<head><script type='text/javascript'>
var	Register = function(reg) {
	this.store	= [0x43,0x42,0x45,0x44,0x4C,0x48,0x46,0x41,0,0,0,0,0,0,0,0];
	for(var id in reg) {
		var	ptr = reg[id].split(/\s+/),
			num = ptr.length,
			gets = {
				"1"	: "return this.store[0x_0]",
				"2"	: "return this.store[0x_0] | this.store[0x_1] << 8",
				"3"	: "var tmp = this.store[0x_0] | this.store[0x_1] << 8; return 0x_2==1 ? m[tmp] : m[tmp] | m[tmp + 1] << 8"
			},
			sets = {
				"1"	: "this.store[0x_0] = x & 255",
				"2"	: "this.store[0x_0] = x & 255, this.store[0x_1] = x >> 8 & 255",
				"3"	: "var tmp = this.store[0x_0] | this.store[0x_1] << 8; 0x_2==1 ? m[tmp] = x & 255 : (m[tmp] = x & 255, m[tmp + 1] = x >> 8 & 255)"
			};
		Object.defineProperty(this, id, {
			enumerable	: true,
			get		: new Function(
				"",
				gets[num].replace(/_(\d)/g, function(s, i) {
						return ptr[i];
					}
				)
			),
			set		: new Function(
				"x",
				sets[num].replace(/_(\d)/g, function(s, i) {
						return ptr[i];
					}
				)
			)
		});
	}
	return	this;
};
var	r;
var	m = (function(n) {
		var	tmp = [];
		while(n --)
			tmp.push(Math.random() * 256 & 255);
		return	tmp;
	})(65535);
var	regs = {
		bc	: "0 1",
		b	: "1",
		c	: "0",
		de	: "2 3",
		d	: "3",
		e	: "2",
		hl	: "4 5",
		h	: "5",
		l	: "4",
		psw	: "7 6",
		f	: "6",
		a	: "7",
		m	: "4 5 1",
		cx	: "0 1",
		ch	: "1",
		cl	: "0",
		dx	: "2 3",
		dh	: "3",
		dl	: "2",
		bx	: "4 5",
		bh	: "5",
		bl	: "4",
		al	: "7"
	};
window.onload = function() {
	var	log = [];
	r = new Register(regs);
	for(var id in regs)
		log.push(id + ": " + r[id].toString(16));
	document.getElementsByTagName("pre")[0].innerHTML = log.join("<br />");
}
</script>
</head>
<body>
<pre></pre>
</body>
P.S.: Код работает…
Однако, вопрос к настоящим знатокам: Может что-то можно описать красивее?

Последний раз редактировалось Paguo-86PK, 08.03.2017 в 10:03.
Ответить с цитированием
  #8 (permalink)  
Старый 09.03.2017, 12:45
Аватар для Vlasenko Fedor
Профессор
Отправить личное сообщение для Vlasenko Fedor Посмотреть профиль Найти все сообщения от Vlasenko Fedor
 
Регистрация: 13.03.2013
Сообщений: 1,572

Сообщение от Paguo-86PK
Может что-то можно описать красивее?
Конечно можно. Просто посмотри на него через год
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
getJSON и области видимости SteelRat Javascript под браузер 1 13.11.2015 06:09
Доступ к главной области видимости Penetrator Angular.js 1 21.01.2015 23:13
Событие JS, объект выходит из области видимости браузера Z@R@ Events/DOM/Window 1 28.01.2013 07:02
Как узнать находится ли DOM элемент в области видимости? phgrey Общие вопросы Javascript 4 22.03.2011 19:05
области видимости элементов zaytsewa jQuery 14 11.01.2011 16:49