Стековый вычислитель -- вычислительное устройство выполняющее операций над элементами стека. Данные ВычМ удобны для вычисления выражений в постфиксной форме, так как на прямую интерпретируют выражения, и не требуют дополнительных регистров для хранения промежуточных результатов.

Рассмотрим описание стекового интерпретатора с таблицей символов и переходами.

   


Интерпретатор состоит из следующих частей.

STACK -- стек. Для реализации достаточно массива чисел с операциями push, pop, top.

SYMTAB -- таблица символов. Реализуется хеш-таблицей или массивом чисел, хранящим значение символа по соответствующему индексу

!!! Переход от имен к индексам осуществляет компилятор.

PROG -- программа. Массив чисел, где каждый элемент обозначает: число, символ или операцию, в зависимости от места.

!!! Так как символы и операции можно закодировать числами, то для представления программы достаточно числового вектора.

POS -- курсор. Индекс очередного интерпретируемого элемента.

Набор операций выполняемой интерпретатором:

!!! В скобках указано выталкиваемое содержимое стека, слева направо

  - nop (<val>) -- не выполнять операцию, вытолкнуть содержимое стека,
  - lit, <val> -- интерпретировать следующий элемент как литерал и добавить его в стек,
  - set (sym, val) -- интерпретировать первый элемент стека как символ и в SYMTAB установить его значение равное второму элементу,
  - get (sym) -- интерпретировать верхний элемент как символ и заменить его на его значение из SYMTAB
  - if (else, then, cond) -- если третий элемент не равен 0, то оставить в стеке второй элемент, иначе первый
  - jmp (pos) -- изменить значение POS на значение элемента стека
  - add/sub/mul/div/mod (<val1>, <val2>) -- арифметические операции, первого элемента над вторым
  - not/and/or/xor -- побитовые операции
  - eq/ne/gt/lt/ge/le -- сравнения первого операнда со вторым

  - halt -- остановка машины, если оператор не распознан.

   


Реализация на javascript

Код:

var prog = [
	1,0x48, 1,0, 3,
	1,0x65, 1,0, 3,
	1,0x6c, 1,0, 3,
	1,0x6c, 1,0, 3,
	1,0x6f, 1,0, 3,
	-1];//программа выводящая hello


function run(){
	var stack= new Array();
	var symtab = new Array();
	var pos=0;

run:while(true){
    let b = prog[pos++];
    if(b === undefined) break;

    switch(b){
    case 0:{//nop (<val>)
    	stack.pop();
    }break;
    case 1:{//lit <val>
    	stack.push(prog[pos++]);
    }break;
    case 2:{//cp (<val>)
    	stack.push(stack[stack.length-1]);
    }break;
    case 3:{//set (<sym>,<val>)
    	let sym = stack.pop();
    	let val = stack.pop();
    	if(sym == 0) console.log(val+"\t("+ String.fromCharCode(val) +")");//OUT
    	else symtab[sym] = val;
    }break;
    case 4:{//get (<sym>)
    	let sym = stack.pop();
    	if(sym == 0) stack.push(parseInt(prompt()));//IN
    	else stack.push(symtab[sym]);
    }break;
    case 6:{//ifr (<else>, <then>, <cond>)
    	let els = stack.pop();
    	let thn = stack.pop();
    	let cond = stack.pop();
    	if(cond != 0) stack.push(thn);
    	else stack.push(els);
    }break;
    case 7:{//jmp (<pos>)
    	pos = stack.pop();
    }break;

    case 11:{//add (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	stack.push(a+b);
    }break;
    case 12:{//sub (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	stack.push(b-a);
    }break;
    case 13:{//mul (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	stack.push(a*b);
    }break;
    case 14:{//div (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	stack.push(b/a);
    }break;
    case 15:{//add (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	stack.push(a % b);
    }break;

    case 21:{//not (<opn1>)
    	let a = stack.pop();
    	stack.push(~a);
    }break;
    case 22:{//and (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	stack.push(a & b);
    }break;
    case 23:{//or (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	stack.push(a | b);
    }break;
    case 24:{//xor (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	stack.push(a ^ b);
    }break;

    case 31:{//eq (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	if(a == b)
        stack.push(1);
    	else
        stack.push(0);
    }break;
    case 32:{//ne (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	if(a != b)
        stack.push(1);
    	else
        stack.push(0);
    }break;
    case 33:{//gt (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	if(a > b)
        stack.push(1);
    	else
        stack.push(0);
    }break;
    case 34:{//lt (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	if(a < b)
        stack.push(1);
    	else
        stack.push(0);
    }break;
    case 35:{//ge (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	if(a >= b)
        stack.push(1);
    	else
        stack.push(0);
    }break;
    case 36:{//le (<opn1>, <opn2>)
    	let a = stack.pop();
    	let b = stack.pop();
    	if(a <= b)
        stack.push(1);
    	else
        stack.push(0);
    }break;
    default: break run;//halt
    }

	}

}