|
Nojotalk Byte Code
[ Home ]
Nojotalk source code is converted into byte code at compile-time. Every function body (as well as main, or top level) corresponds to a string of 16-bit characters. The most significant bit is the operator bit, which is zero for operators and keywords. The next most significant bit is zero for local variables and parameters, and one for global variables. The low order 14 bits for local variables and parameters encode the stack offset. The low order 14 bits for global variables/functions encode the offset value. The following JavaScript code is a sneak preview of the byte code processor, which will eventually be written in Python.
var stack;
var stkbase;
var funcarray;
var glbarray;
var currfunc;
var currpos;
var currbody;
var parmcount;
var varcount;
function mainloop() {
stack = [];
stkbase = 0;
callfunc(0, 0);
initfuncs();
initops();
do {
token = currbody.charCodeAt(currpos);
if (token < 32768) {
operator = operators[token];
operator();
}
else {
offset = token - 32768;
push(offset);
}
currpos += 1;
}
while (stack.length > 0);
}
function push(val) {
stack.push(val);
}
function pop() {
return stack.pop();
}
function jump(addr) {
currpos = addr;
}
function callfunc(funcidx, posidx) {
currfunc = funcidx;
currpos = posidx;
funcobj = funcarray[currfunc];
currbody = funcobj.body;
parmcount = funcobj.parmcount;
varcount = funcobj.varcount;
}
function assign(addr, val) {
addr -= 32768;
if (addr < 16384) {
stack[stkbase + addr] = val;
}
else {
addr -= 16384;
glbarray[addr] = val;
}
}
function getval(addr) {
addr -= 32768;
if (addr < 16384) {
val = stack[stkbase + addr];
}
else {
addr -= 16384;
val = glbarray[addr];
}
return val;
}
function initfuncs() {
typeof_fn = function() {
push(typeof(pop()));
};
to_number = function() {
push(+pop());
};
negate = function() {
push(-pop());
};
not = function() {
push(!pop());
};
multiply = function() {
push(pop() * pop());
};
divide = function() {
temp = pop();
push(pop() / temp);
};
remainder = function() {
temp = pop();
push(pop() % temp);
};
add = function() {
temp = pop();
push(pop() + pop());
};
subtract = function() {
temp = pop();
push(pop() - pop());
};
greater_or_equal = function() {
temp = pop();
push(pop() >= pop());
};
less_or_equal = function() {
temp = pop();
push(pop() <= pop());
};
greater = function() {
temp = pop();
push(pop() > pop());
};
less = function() {
temp = pop();
push(pop() < pop());
};
equal = function() {
push(pop() === pop());
};
not_equal = function() {
push(pop() !== pop());
};
refinement = function() {
expr = pop();
obj = pop();
push(obj[expr]);
};
logical_or = function() {
addr = pop();
flag = pop();
if (flag) {
push(true);
jump(addr);
}
};
logical_and = function() {
addr = pop();
flag = pop();
if (!flag) {
push(false);
jump(addr);
}
};
asst = function() {
addr = pop();
expr = pop();
assign(addr, expr);
};
plus_asst = function() {
addr = pop();
expr = pop();
val = getval(addr);
assign(addr, val + expr);
};
minus_asst = function() {
addr = pop();
expr = pop();
val = getval(addr);
assign(addr, val - expr);
};
jump_local = function() {
jump(pop());
};
branch_true = function() {
addr = pop();
if (pop()) {
jump(addr);
}
};
branch_false = function() {
// (same as ternary)
addr = pop();
if (!pop()) {
jump(addr);
}
};
call = function() {
addr = pop();
push(catchaddr);
push(stkbase);
push(currfunc);
push(currpos);
callfunc(addr, 0);
};
post_call = function() {
rtnpos = pop();
rtnfunc = pop();
stkbase = stack.length - parmcount
push(varcount);
push(rtnfunc);
push(rtnpos);
};
return_no_val = function() {
rtnpos = pop();
rtnfunc = pop();
varcount = pop();
for (i = 1; i <= varcount; i += 1) {
pop();
}
stkbase = pop();
callfunc(rtnfunc, rtnpos);
pop();
};
return_val = function() {
rtnval = pop();
rtnpos = pop();
rtnfunc = pop();
varcount = pop();
for (i = 1; i <= varcount; i += 1) {
pop();
}
stkbase = pop();
push(rtnval);
callfunc(rtnfunc, rtnpos);
pop();
};
array_literal = function() {
count = pop();
array = [];
for (i = 1; i <= count; i += 1) {
array.push(pop());
};
array.reverse();
push(array);
};
object_literal = function() {
count = pop();
object = {};
for (i = 1; i <= count; i += 1) {
expr = pop();
key = pop();
object[key] = expr;
};
push(object);
};
throw_in_try = function() {
jump(pop());
};
catch_clause = function() {
expr = pop();
assign(offset, expr);
};
throw_not_try = function() {
expr = pop();
do {
rtnpos = pop();
rtnfunc = pop();
varcount = pop();
for (i = 1; i <= varcount; i += 1) {
pop();
}
stkbase = pop();
callfunc(rtnfunc, rtnpos);
catchaddr = pop();
}
while (!catchaddr);
jump(catchaddr);
push(expr);
};
call_self = function() {
push(catchaddr);
push(stkbase);
push(currfunc);
push(currpos);
callfunc(currfunc, 0);
};
}
function initops() {
operators = [
defun,
begin,
end,
typeof_fn,
to_number,
negate,
not,
multiply,
divide,
remainder,
add,
subtract,
greater_or_equal,
less_or_equal,
greater,
less,
equal,
not_equal,
refinement,
logical_or,
logical_and,
asst,
plus_asst,
minus_asst,
jump_local,
branch_true,
branch_false,
call,
post_call,
return_no_val,
return_val,
array_literal,
object_literal,
throw_in_try,
catch_clause,
throw_not_try,
call_self
];
}
Sample Byte Code
Token Name Examples:
- Operator: opadd
- Definition: opdef myvar
- Variable reference: opvar myvar
- Global integer constant: opdef -123
- Global float constant: opdef 3.1416E-12
- Global string literal: opdef "xyz&ABC DEF_123"
Nojotalk Code:
// set label to 'Hello, world!'
(= myFunction (func () (
(= (: ($ (: document getElementById) 'myLabel') innerHTML) 'Hello, world!')
)))
Equivalent Byte Code:
Token / Overhead
- op_post_call / 6
- loc_func1
- loc_label1
- loc_func2
- str_getElementById
- str_myLabel
- str_Hello_world
- str_innerHTML
- glb_document
- str_getElementById
- op_refinement / 3
- loc_func1
- op_asst / 3 + 3
- str_myLabel
- loc_func1
- op_call / 6 + 6
- loc_label1
- op_asst / 3 + 3
- str_Hello_world
- loc_label1
- str_innerHTML
- op_refinement / 3
- op_asst / 3 + 4
- op_return_no_val / 22
Total:
65
Main Loop:
144 = 24 tokens x 6
Grand Total:
209 lines of JavaScript code executed
[ Back to Top ]
|
|
|