📜 ⬆️ ⬇️

Stacking JavaScript programming language in 34 lines


Information for those who do not know what a stack language is:

The next line is despicably copied from Wikipedia
A stack programming language is a programming language in which a machine model of a stack is used to transfer parameters.

About language

The language will be very simple, for example, functions can take only one parameter, but nevertheless there will be a possibility of pattern matching. There is only one type, namely a number.

The mapping function will be defined as follows:
value name = operations
Where value is a pattern to match, a operations is a function body.
')
If a function is defined without matching, it will be written as follows:
name = operations
But in the function body, you can use the constant op whose value is the operand with which the function, that is, the top of the stack, was called.

To put a value on the stack, simply enter a number.

And in order to translate the top element of the stack into a variable, you need to write:
-> name
From standard operation will be only + - * /

So for example, the function of increasing the element from the top of the stack to 1 will be written as:
++ = op 1 +

But for the implementation of the function factorial will require a comparison with the sample and the code will be:
0 ! = 1
! = op 1 - ! op *




Implementation

Only the interpreter will be written, which will be implemented as a context.
Work with this context will be carried out by a separate script. The details of which we will not go. I can only say that it displays the top of the stack or 'nil' in the "console"

The first steps

First of all, we, as it should be, describe the context as a constructor and denote it HContext

HContext = function(){
this.stack = []; //
this.vars = []; //
this.funs = []; //

}


Then we will create the most important function 'run' whose argument will be the code, and the function itself will divide it into lexemes and then if it turns out that this function definition it will call the necessary function, otherwise it will call the function of code execution.

this.run = function(code){
lexems = code.split(' ');
if(lexems.oneOf('=')){
this.define(lexems);}else{
this.exec(lexems,'');}}

Note: those who carefully read the code may have noticed the oneOf method, this is a method from the so-called extend.js that I wrote after I read the phrase “If you need something but you don’t have it, create it yourself.” further functions from this library will also be applied.

Now we write the exec function that will execute the code. At the very beginning, if the op argument is not defined, then we assign the value 3 to it.

Then we will create a loop that will walk along an array of tokens and, depending on the token, perform various operations.
If this is 'op', put the value of op on the stack.
If this number - put it on the stack.
If there is a variable with this name - put its value on the stack.
If there is a function with that name, call it. Call function
If one of the mathematical operation - call it. MathOp function
And if it is -> we will increase the counter by 1 and assign a variable whose name is the current token value from the top of the stack.

this.exec = function(code,op){
op = op || 0;
for(var cp=0;cp<code.length;cp++){
if(code[cp]=='op'){this.stack.push(op)}
else if(code[cp].isNum()){this.stack.push(parseFloat(code[cp]))}
else if(this.vars[code[cp]] != undefined){this.stack.push(this.vars[code[cp]])}
else if(this.funs[code[cp]] != undefined){this.call(code[cp])}
else if(this.mathOps.oneOf(code[cp])){this.mathOp(code[cp])}
else if(code[cp] == '->'){cp++;this.vars[code[cp]]=this.stack.pop();}}}//


Mathematical operations


Create an array with possible mathematical operations.
this.mathOps = ['+','-','*','/'];

And now we define the function. which will take the top two values ​​from the stack and put the result of the operation on top of the stack.

this.mathOp = function(op){
nums = [this.stack.pop(),this.stack.pop()];
this.stack.push(eval(nums[1] + ' ' + op + ' ' + nums[0]));}


Functions

And now let's talk about functions, as has already been said, there will be comparisons, but its implementation will be very simple due to a simple function storage model.
Functions will be stored in the list of funs, and at the same time each function will be a list in which the element with the key 'op' will be a function without a match, and all the others will be with a match and the key will be the pattern for matching.

We write a method for determining the function:

this.define = function(code){
eq = code.pos('='); //
op = code[eq-2] || 'op'; // 2 = 'op'
name = code[eq-1]; // 1
cmds = code.slice(eq+1); // 1
if(this.funs[name] == undefined){this.funs[name] = [];} // ,
this.funs[name][op] = cmds; // }


And now we will call functions, for this purpose we will select the call method (Most, and especially assembler programmers will not find the name exactly funny)

this.call = function(fun){
op = this.stack.pop(); //
cd = this.funs[fun][op] || this.funs[fun]['op']; //
this.exec(cd,op);} //


Try:

The pseudo-console is here . Examples are also located there.

Source: https://habr.com/ru/post/111151/


All Articles