Howto:Implementing a simple bytecode interpreter in Nasal

From FlightGear wiki
Jump to navigation Jump to search
This article is a stub. You can help the wiki by expanding it.
Note  Untested pseudo code (for now)
var push = func(ctx) {
var value = ctx.program[ ctx.ip +=1];
append(ctx.stack, value);
};

var pop = func(ctx) {
print("Calling pop");
};

var dup = func(ctx) {
print("Calling dup");
};

var jmp = func(ctx) {
 print("Calling jump");
 ctx.ip = ctx.program[ctx.ip+1];
};

var call = func(ctx) {
# push ip
# get address from stack
# jmp
# restore ip
};

var ret = func(ctx) {
# pop return address from stack
# set ip
};

var plus = func(ctx) {
print("Calling plus");
};

var minus = func(ctx) {
print("Calling minus");
};

var nop = func(ctx) {
print("Calling nop");
};

var hlt = func(ctx) {
print("HLT: Bytecode finished");
};

# set up a new environment for the interpreter (stack, program etc)
var newContext = func(code) {
 var ctx = {};
 ctx.stack = [];
 ctx.stackTop = 0;
 ctx.stackSize = 64;
 setsize(ctx.stack, ctx.stackSize);
 ctx.program = code;
 setsize(ctx.program, 512);
 ctx.ip = 0;
 return ctx;
};

# a list of supported opcodes, mapped to their implementation callbacks
var OP = {
 PLUS: plus, 
 MINUS: minus, 
 NOP: nop,
 JMP: jmp,
 HLT: nil,
};

# an actual command stream ("program") to be executed
var COMMAND_STREAM = [OP.JMP, 3, OP.PLUS, OP.PLUS, OP.MINUS, OP.NOP, OP.HLT];
var context = newContext(COMMAND_STREAM);

# our little bytecode interpreter loop
for(context.ip=0;context.ip<size(context.program);context.ip+=1) {
# get the current opcode from the program

var opcode = context.program[context.ip];

if (opcode == OP.HLT) {
 print("Terminating bytecode interpreter loop");
 break;
}

# look up the callback, and call it passing a context hash to it

opcode ( context );
} # loop

print("interpreter finished");