Merge branch 'mplamann' into run_vm

Conflicts:
	public/vm/index.js
This commit is contained in:
2015-04-13 23:12:40 -04:00
48 changed files with 1678 additions and 291 deletions

View File

@@ -1,5 +1,4 @@
var ByteStream = function (byte_array) {
console.log("Instance created.");
this.byte_array = byte_array;
this.index = 0;
};

110
public/vm/c0ffi.js Normal file
View File

@@ -0,0 +1,110 @@
exports.NATIVE_FADD = 0
exports.NATIVE_FDIV = 1
exports.NATIVE_FLESS = 2
exports.NATIVE_FMUL = 3
exports.NATIVE_FSUB = 4
exports.NATIVE_FTOI = 5
exports.NATIVE_ITOF = 6
exports.NATIVE_PRINT_FPT = 7
exports.NATIVE_PRINT_HEX = 8
exports.NATIVE_PRINT_INT = 9
/* args */
exports.NATIVE_ARGS_FLAG = 10
exports.NATIVE_ARGS_INT = 11
exports.NATIVE_ARGS_PARSE = 12
exports.NATIVE_ARGS_STRING = 13
/* conio */
exports.NATIVE_EOF = 14
exports.NATIVE_FLUSH = 15
exports.NATIVE_PRINT = 16
exports.NATIVE_PRINTBOOL = 17
exports.NATIVE_PRINTCHAR = 18
exports.NATIVE_PRINTINT = 19
exports.NATIVE_PRINTLN = 20
exports.NATIVE_READLINE = 21
/* curses */
exports.NATIVE_C_ADDCH = 22
exports.NATIVE_C_CBREAK = 23
exports.NATIVE_C_CURS_SET = 24
exports.NATIVE_C_DELCH = 25
exports.NATIVE_C_ENDWIN = 26
exports.NATIVE_C_ERASE = 27
exports.NATIVE_C_GETCH = 28
exports.NATIVE_C_INITSCR = 29
exports.NATIVE_C_KEYPAD = 30
exports.NATIVE_C_MOVE = 31
exports.NATIVE_C_NOECHO = 32
exports.NATIVE_C_REFRESH = 33
exports.NATIVE_C_SUBWIN = 34
exports.NATIVE_C_WADDCH = 35
exports.NATIVE_C_WADDSTR = 36
exports.NATIVE_C_WCLEAR = 37
exports.NATIVE_C_WERASE = 38
exports.NATIVE_C_WMOVE = 39
exports.NATIVE_C_WREFRESH = 40
exports.NATIVE_C_WSTANDEND = 41
exports.NATIVE_C_WSTANDOUT = 42
exports.NATIVE_CC_GETBEGX = 43
exports.NATIVE_CC_GETBEGY = 44
exports.NATIVE_CC_GETMAXX = 45
exports.NATIVE_CC_GETMAXY = 46
exports.NATIVE_CC_GETX = 47
exports.NATIVE_CC_GETY = 48
exports.NATIVE_CC_HIGHLIGHT = 49
exports.NATIVE_CC_KEY_IS_BACKSPACE = 50
exports.NATIVE_CC_KEY_IS_DOWN = 51
exports.NATIVE_CC_KEY_IS_ENTER = 52
exports.NATIVE_CC_KEY_IS_LEFT = 53
exports.NATIVE_CC_KEY_IS_RIGHT = 54
exports.NATIVE_CC_KEY_IS_UP = 55
exports.NATIVE_CC_WBOLDOFF = 56
exports.NATIVE_CC_WBOLDON = 57
exports.NATIVE_CC_WDIMOFF = 58
exports.NATIVE_CC_WDIMON = 59
exports.NATIVE_CC_WREVERSEOFF = 60
exports.NATIVE_CC_WREVERSEON = 61
exports.NATIVE_CC_WUNDEROFF = 62
exports.NATIVE_CC_WUNDERON = 63
/* file */
exports.NATIVE_FILE_CLOSE = 64
exports.NATIVE_FILE_CLOSED = 65
exports.NATIVE_FILE_EOF = 66
exports.NATIVE_FILE_READ = 67
exports.NATIVE_FILE_READLINE = 68
/* img */
exports.NATIVE_IMAGE_CLONE = 69
exports.NATIVE_IMAGE_CREATE = 70
exports.NATIVE_IMAGE_DATA = 71
exports.NATIVE_IMAGE_DESTROY = 72
exports.NATIVE_IMAGE_HEIGHT = 73
exports.NATIVE_IMAGE_LOAD = 74
exports.NATIVE_IMAGE_SAVE = 75
exports.NATIVE_IMAGE_SUBIMAGE = 76
exports.NATIVE_IMAGE_WIDTH = 77
/* parse */
exports.NATIVE_PARSE_BOOL = 78
exports.NATIVE_PARSE_INT = 79
/* string */
exports.NATIVE_CHAR_CHR = 80
exports.NATIVE_CHAR_ORD = 81
exports.NATIVE_STRING_CHARAT = 82
exports.NATIVE_STRING_COMPARE = 83
exports.NATIVE_STRING_EQUAL = 84
exports.NATIVE_STRING_FROM_CHARARRAY = 85
exports.NATIVE_STRING_FROMBOOL = 86
exports.NATIVE_STRING_FROMCHAR = 87
exports.NATIVE_STRING_FROMINT = 88
exports.NATIVE_STRING_JOIN = 89
exports.NATIVE_STRING_LENGTH = 90
exports.NATIVE_STRING_SUB = 91
exports.NATIVE_STRING_TERMINATED = 92
exports.NATIVE_STRING_TO_CHARARRAY = 93
exports.NATIVE_STRING_TOLOWER = 94

View File

@@ -1,234 +1,464 @@
op = require("./opcodes");
var ProgramState = function(parsed_file) {
var main_function = parsed_file.function_pool[0];
this.stack = []
this.pc = 0;
this.program = main_function.code;
this.variables = [];
for (var i = 0; i < main_function.num_vars; i++)
variables.push(0);
this.file = parsed_file;
var INT_MIN = 0x80000000;
var INT_MAX = 0x7FFFFFFF;
var verbose = false;
function log(message) {
if (verbose) console.log(message);
}
function c0_assertion_failure(val) {
throw ("c0 assertion failure: " + val);
}
ProgramState.prototype.doIf = function(shouldJump) {
if (shouldJump) {
var address_offset = (this.program[this.pc+1] * 0x1000) +
this.program[this.pc+2];
this.pc += address_offset;
function c0_memory_error(val) {
throw ("c0 memory error: " + val);
}
function i32_to_array(i32) {
return [(i32 & 0xFF),
((i32 >> 8) & 0xFF),
((i32 >> 16) & 0xFF),
((i32 >> 24) & 0xFF)];
}
function array_to_i32(array) {
return array[0] +
(array[1] << 8) +
(array[2] << 16) +
(array[3] << 24);
}
var StackFrame = function(file, f) {
log("Creating stack frame");
this.stack = [];
this.pc = 0;
this.program = f.code;
this.variables = [];
for (var i = 0; i < f.num_vars; i++)
this.variables.push(0);
this.file = file;
}
var ProgramState = function(parsed_file, callback_dict) {
log("Creating program state with file " + parsed_file);
var main_function = parsed_file.function_pool[0];
this.frame = new StackFrame(parsed_file, parsed_file.function_pool[0]);
this.call_stack = [];
this.file = parsed_file;
this.natives = {};
for (var i = 0; i < 95; i++) {
try {
this.natives[i] = callback_dict[i];
} catch (key_not_found) {
this.natives[i] = function (arg) {
console.log("Native function " + name + " called, ran method stub.");
return 0;
};
}
}
// Memory is just a big array of bytes, right?
// "Allocation" is appending onto this array
// A pointer to memory is an index into this array.
// Structs are stored as themselves
// Arrays are stored as an entry for the number of elements
// and then the array, byte-by-byte
this.heap = [];
}
ProgramState.prototype.push = function(val) {
this.frame.stack.push(val);
}
ProgramState.prototype.pop = function() {
return this.frame.stack.pop();
}
ProgramState.prototype.goto_offset = function() {
var c1 = this.frame.program[this.frame.pc+1];
var c2 = this.frame.program[this.frame.pc+2]
var address_offset = (c1 << 8) + c2;
// Handle negative values
if ((address_offset & 0x8000) != 0)
address_offset = -0x8000 + (address_offset & 0x7FFF);
this.frame.pc += address_offset;
}
ProgramState.prototype.doIf = function(f) {
var y = this.pop();
var x = this.pop();
if (f(x,y)) {
this.goto_offset();
} else {
this.pc += 3;
this.frame.pc += 3;
}
}
ProgramState.prototype.step = function() {
console.log("Running opcode " + op.lookup_table[this.program[this.pc]]);
switch (this.program[this.pc]) {
var opcode = this.frame.program[this.frame.pc]
log("0x" + this.frame.pc.toString(16) + " Running opcode " +
op.lookup_table[opcode]);
switch (opcode) {
// Stack manipulation
case op.POP:
this.pc++;
this.stack.pop();
this.frame.pc++;
this.pop();
break;
case op.DUP:
this.pc++;
var v = this.stack.pop();
this.stack.push(v);
this.stack.push(v);
this.frame.pc++;
var v = this.pop();
this.push(v);
this.push(v);
break;
case op.SWAP:
this.pc++;
var v1 = this.stack.pop();
var v2 = this.stack.pop();
this.stack.push(v1);
this.stack.push(v2);
this.frame.pc++;
var v1 = this.pop();
var v2 = this.pop();
this.push(v1);
this.push(v2);
break;
case op.BIPUSH:
this.pc += 2;
var val = this.program[this.pc-1];
this.frame.pc += 2;
var val = this.frame.program[this.frame.pc-1];
// Do sign extension if necessary
if (val & 0x80 != 0)
if ((val & 0x80) != 0)
val = -0x80 + (val & 0x7F);
this.stack.push(val);
this.push(val);
break;
// Returning from a function
case op.RETURN:
var retVal = this.stack.pop();
throw retVal;
var retVal = this.pop();
if (this.call_stack.length == 0)
return retVal;
this.frame = this.call_stack.pop();
this.push(retVal);
break;
// Arithmetic
case op.IADD:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
console.log("Adding " + x + " and " + y);
this.stack.push((x+y) % 0x100000000);
this.frame.pc++;
var y = this.pop();
var x = this.pop();
log("Adding " + x + " and " + y);
this.push((x+y) % 0x100000000);
break;
case op.ISUB:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.stack.push((x-y) % 0x100000000);
this.frame.pc++;
var y = this.pop();
var x = this.pop();
this.push((x-y) % 0x100000000);
break;
case op.IMUL:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.stack.push((x*y) % 0x100000000);
this.frame.pc++;
var y = this.pop();
var x = this.pop();
this.push((x*y) % 0x100000000);
break;
case op.IDIV:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.frame.pc++;
var y = this.pop();
var x = this.pop();
if (y == 0) c0_arith_error("Divide by zero");
if (x == INT_MIN && y == -1) c0_arith_error("Arithmetic overflow");
// This does int division.
// As I understand it, the ~~ is treated as the identity on integers
// which forces the type to int, not float
this.stack.push(~~(x/y));
this.push(~~(x/y));
break;
case op.IREM:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.frame.pc++;
var y = this.pop();
var x = this.pop();
if (y == 0) c0_arith_error("Divide by zero");
if (x == INT_MIN && y == -1) c0_arith_error("Arithmetic overflow");
this.stack.push(x%y);
this.push(x%y);
break;
case op.IAND:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.stack.push(x&y);
this.frame.pc++;
var y = this.pop();
var x = this.pop();
this.push(x&y);
break;
case op.IOR:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.stack.push(x|y);
this.frame.pc++;
var y = this.pop();
var x = this.pop();
this.push(x|y);
break;
case op.IXOR:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.stack.push(x^y);
this.frame.pc++;
var y = this.pop();
var x = this.pop();
this.push(x^y);
break;
case op.ISHL:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.frame.pc++;
var y = this.pop();
var x = this.pop();
if (y < 0 || y > 31) c0_arith_error("Shifting by too many bits");
this.stack.push(x<<y);
this.push(x<<y);
break;
case op.ISHR:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.frame.pc++;
var y = this.pop();
var x = this.pop();
if (y < 0 || y > 31) c0_arith_error("Shifting by too many bits");
this.stack.push(x>>y);
this.push(x>>y);
break;
// Operations on local variables
case op.VLOAD:
this.pc += 2;
var index = this.program[this.pc-1];
this.stack.push(this.variables[index]);
this.frame.pc += 2;
var index = this.frame.program[this.frame.pc-1];
this.push(this.frame.variables[index]);
break;
case op.VSTORE:
this.pc += 2;
var index = this.program[this.pc-1];
this.variables[index] = this.stack.pop();
this.frame.pc += 2;
var index = this.frame.program[this.frame.pc-1];
this.frame.variables[index] = this.pop();
break;
case op.ACONST_NULL:
this.pc++;
this.stack.push(0);
this.frame.pc++;
this.push(0);
break;
case op.ILDC:
this.pc += 3;
var c1 = this.program[this.pc-2];
var c2 = this.program[this.pc-1];
this.frame.pc += 3;
var c1 = this.frame.program[this.frame.pc-2];
var c2 = this.frame.program[this.frame.pc-1];
var index = (c1 * 0x1000) + c2;
this.stack.push(this.file.int_pool[index]);
this.push(this.file.int_pool[index]);
break;
case op.ALDC:
console.log("Error: I don't know how to handle ALDC yet");
throw "Error - can't handle ALDC";
this.frame.pc += 3;
var c1 = this.frame.program[this.frame.pc-2];
var c2 = this.frame.program[this.frame.pc-1];
var index = (c1 * 0x1000) + c2;
this.push(this.file.string_pool[index]);
break;
// Control flow
case op.NOP:
this.pc++;
this.frame.pc++;
break;
case op.IF_CMPEQ:
var y = this.stack.pop();
var x = this.stack.pop();
this.doIf(y == x);
this.doIf(function (x,y) {return y == x;});
break;
case op.IF_CMPNE:
var y = this.stack.pop();
var x = this.stack.pop();
this.doIf(y != x);
this.doIf(function (x,y) {return y != x;});
break;
case op.IF_CMPLT:
var y = this.stack.pop();
var x = this.stack.pop();
this.doIf(y > x);
case op.IF_ICMPLT:
this.doIf(function (x,y) {return y > x;});
break;
case op.IF_CMPGE:
var y = this.stack.pop();
var x = this.stack.pop();
this.doIf(y <= x);
case op.IF_ICMPGE:
this.doIf(function (x,y) {return y <= x;});
break;
case op.IF_CMPGT:
var y = this.stack.pop();
var x = this.stack.pop();
this.doIf(y < x);
case op.IF_ICMPGT:
this.doIf(function (x,y) {return y < x;});
break;
case op.IF_CMPLE:
var y = this.stack.pop();
var x = this.stack.pop();
this.doIf(y >= x);
case op.IF_ICMPLE:
this.doIf(function (x,y) {return y >= x;});
break;
case op.GOTO:
this.doIf(true);
this.goto_offset();
break;
case op.ATHROW:
this.pc++;
c0_user_error(this.stack.pop());
this.frame.pc++;
c0_user_error(this.pop());
break;
case op.ASSERT:
this.pc++;
var a = this.stack.pop();
if (this.stack.pop() == 0)
this.frame.pc++;
var a = this.pop();
if (this.pop() == 0)
c0_assertion_failure(a);
break;
// Function call operations
case op.INVOKESTATIC:
var c1 = this.frame.program[this.frame.pc+1];
var c2 = this.frame.program[this.frame.pc+2];
this.frame.pc += 3;
var index = (c1 << 8) + c2;
var f = this.file.function_pool[index];
var newFrame = new StackFrame(this.file, f);
for (var i = f.num_args - 1; i >= 0; i--) {
newFrame.variables[i] = this.pop();
}
this.call_stack.push(this.frame);
this.frame = newFrame;
break;
case op.INVOKENATIVE:
var c1 = this.frame.program[this.frame.pc+1];
var c2 = this.frame.program[this.frame.pc+2];
this.frame.pc += 3;
var index = (c1 << 8) + c2;
var f = this.file.native_pool[index];
var arg_array = [];
for (var i = f.num_args - 1; i >= 0; i--)
arg_array[i] = this.pop();
var native_function = this.natives[f.function_table_index];
if (native_function === undefined) {
native_function = function (ignored) {
console.log("Could not find native function with index " +
f.function_table_index);
return 0;
};
console.log("Unknown native function index " + f.function_table_index);
}
this.push(native_function(arg_array));
break;
// Memory allocation operations:
case op.NEW:
var size = this.frame.program[this.frame.pc+1];
var address = this.heap.length;
for (var i = 0; i < size; i++) this.heap.push(0);
this.push(address);
this.frame.pc += 2;
break;
case op.NEWARRAY:
var size = this.frame.program[this.frame.pc+1];
var address = this.heap.length;
var num_elements = this.pop();
if (num_elements < 0) c0_memory_error("Array size must be nonnegative");
this.heap.push(num_elements);
this.heap.push(size);
for (var i = 0; i < num_elements; i++) {
for (var j = 0; j < size; j++)
this.heap.push(0);
}
this.push(address);
this.frame.pc += 2;
break;
case op.ARRAYLENGTH:
var pointer = this.pop();
this.push(this.heap[pointer]);
break;
// Memory access operations:
case op.AADDF:
// Read offset into a struct
var offset = this.frame.program[this.frame.pc + 1];
var index = this.pop();
this.push(this.heap[index + offset]);
this.frame.pc += 2;
break;
case op.AADDS:
// Read offset into an array
var elt_index = this.pop();
var index = this.pop();
var array_length = this.heap[index];
var elt_size = this.heap[index+1];
if (elt_index >= array_length) c0_memory_error("Array index out of bounds.");
this.push(this.heap[index + 2 + elt_size*elt_index]);
this.frame.pc++;
break;
case op.IMLOAD:
var addr = this.pop();
// Get int32 from bytes
var c1 = this.heap[addr];
var c2 = this.heap[addr+1];
var c3 = this.heap[addr+2];
var c4 = this.heap[addr+3];
var combined = array_to_i32([c1, c2, c3, c4]);
this.push(combined);
this.frame.pc++;
break;
case op.IMSTORE:
var value = this.pop();
var addr = this.pop();
var array = i32_to_array(value);
for (var i = 0; i < 4; i++)
this.heap[addr + i] = array[i];
this.frame.pc++;
case op.AMLOAD:
var addr = this.pop();
this.push(this.heap[addr]);
this.frame.pc++;
break;
case op.AMSTORE:
var value = this.pop();
var addr = this.pop();
this.heap[addr] = value;
this.frame.pc++;
break;
case op.CMLOAD:
var addr = this.pop();
this.push(this.heap[addr]);
this.frame.pc++;
break;
case op.CMSTORE:
var value = this.pop();
var addr = this.pop();
this.heap[addr] = value;
this.frame.pc++;
break;
default:
console.log("Error: Unknown opcode\n");
var opcode_name;
try {
opcode_name = op.lookup_table[opcode];
} catch (ignored) {
opcode_name = "UNKNOWN";
}
console.log("Error: Unknown opcode: 0x" + opcode.toString(16) +
" (" + opcode_name + ")\n");
throw "Error - unknown opcode";
}
return false;
}
// Takes in a parsed .bc0 file and runs it
function execute(f) {
console.log("Beginning execution of file " + f);
function execute(file, callbacks, v) {
verbose = typeof v !== 'undefined' ? v : true;
log("Initializing with file " + file);
var state = new ProgramState(f);
var state = new ProgramState(file, callbacks);
log("Beginning execution");
while (true) {
// I'm not sure how to structure this control flow yet,
// so if anyone has a better idea, let me know
try {
state.step();
} catch (val) {
return val;
}
var val = state.step();
if (val !== undefined) return val;
// if (at_breakpoint) {
// save state (maybe in a global in this file?)
@@ -238,6 +468,3 @@ function execute(f) {
}
exports.execute = execute;
// opcode definitions

View File

@@ -1,5 +1,6 @@
parser = require("./bytecode-parser");
c0vm = require("./c0vm.js");
c0ffi = require("./c0ffi.js");
// console.log("Reading in sample bytecode file:");
// console.log(parser.getBytes("../test/test.bc0"));
@@ -9,8 +10,28 @@ c0vm = require("./c0vm.js");
// console.log(file);
// console.log(file.function_pool[0].code);
// UI interaction functions
function print(arg) {
$("#output").append(arg);
}
callbacks = {};
callbacks[c0ffi.NATIVE_PRINT] = function(args) {
print(args[0]);
print("<br />");
}
callbacks[c0ffi.NATIVE_PRINTINT] = function(args) {
print(args[0]);
print("<br />");
}
console.log(callbacks);
$("#run").click(function() {
var input = $("#bytecode").html().replace(/(\r\n|\n|\r)/gm,"");
var file = parser.parse($("#bytecode").text());
$("#output").text(c0vm.execute(file));
print("<br />");
print(c0vm.execute(file, callbacks));
});

View File

@@ -90,12 +90,12 @@ exports.lookup_table = {
0x13: "ILDC",
0x14: "ALDC",
0x00: "NOP",
0x9F: "IF",
0xA0: "IF",
0xA1: "IF",
0xA2: "IF",
0xA3: "IF",
0xA4: "IF",
0x9F: "IF_CMPEQ",
0xA0: "IF_CMPNE",
0xA1: "IF_ICMPLT",
0xA2: "IF_ICMPGE",
0xA3: "IF_ICMPGT",
0xA4: "IF_ICMPLE",
0xA7: "GOTO",
0xBF: "ATHROW",
0xCF: "ASSERT",

View File

@@ -1,6 +1,5 @@
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var ByteStream = function (byte_array) {
console.log("Instance created.");
this.byte_array = byte_array;
this.index = 0;
};
@@ -147,238 +146,580 @@ function parse(filename) {
exports.getBytes = getBytes;
exports.parse = parse;
},{"./byte-stream":1,"fs":6}],3:[function(require,module,exports){
},{"./byte-stream":1,"fs":7}],3:[function(require,module,exports){
exports.NATIVE_FADD = 0
exports.NATIVE_FDIV = 1
exports.NATIVE_FLESS = 2
exports.NATIVE_FMUL = 3
exports.NATIVE_FSUB = 4
exports.NATIVE_FTOI = 5
exports.NATIVE_ITOF = 6
exports.NATIVE_PRINT_FPT = 7
exports.NATIVE_PRINT_HEX = 8
exports.NATIVE_PRINT_INT = 9
/* args */
exports.NATIVE_ARGS_FLAG = 10
exports.NATIVE_ARGS_INT = 11
exports.NATIVE_ARGS_PARSE = 12
exports.NATIVE_ARGS_STRING = 13
/* conio */
exports.NATIVE_EOF = 14
exports.NATIVE_FLUSH = 15
exports.NATIVE_PRINT = 16
exports.NATIVE_PRINTBOOL = 17
exports.NATIVE_PRINTCHAR = 18
exports.NATIVE_PRINTINT = 19
exports.NATIVE_PRINTLN = 20
exports.NATIVE_READLINE = 21
/* curses */
exports.NATIVE_C_ADDCH = 22
exports.NATIVE_C_CBREAK = 23
exports.NATIVE_C_CURS_SET = 24
exports.NATIVE_C_DELCH = 25
exports.NATIVE_C_ENDWIN = 26
exports.NATIVE_C_ERASE = 27
exports.NATIVE_C_GETCH = 28
exports.NATIVE_C_INITSCR = 29
exports.NATIVE_C_KEYPAD = 30
exports.NATIVE_C_MOVE = 31
exports.NATIVE_C_NOECHO = 32
exports.NATIVE_C_REFRESH = 33
exports.NATIVE_C_SUBWIN = 34
exports.NATIVE_C_WADDCH = 35
exports.NATIVE_C_WADDSTR = 36
exports.NATIVE_C_WCLEAR = 37
exports.NATIVE_C_WERASE = 38
exports.NATIVE_C_WMOVE = 39
exports.NATIVE_C_WREFRESH = 40
exports.NATIVE_C_WSTANDEND = 41
exports.NATIVE_C_WSTANDOUT = 42
exports.NATIVE_CC_GETBEGX = 43
exports.NATIVE_CC_GETBEGY = 44
exports.NATIVE_CC_GETMAXX = 45
exports.NATIVE_CC_GETMAXY = 46
exports.NATIVE_CC_GETX = 47
exports.NATIVE_CC_GETY = 48
exports.NATIVE_CC_HIGHLIGHT = 49
exports.NATIVE_CC_KEY_IS_BACKSPACE = 50
exports.NATIVE_CC_KEY_IS_DOWN = 51
exports.NATIVE_CC_KEY_IS_ENTER = 52
exports.NATIVE_CC_KEY_IS_LEFT = 53
exports.NATIVE_CC_KEY_IS_RIGHT = 54
exports.NATIVE_CC_KEY_IS_UP = 55
exports.NATIVE_CC_WBOLDOFF = 56
exports.NATIVE_CC_WBOLDON = 57
exports.NATIVE_CC_WDIMOFF = 58
exports.NATIVE_CC_WDIMON = 59
exports.NATIVE_CC_WREVERSEOFF = 60
exports.NATIVE_CC_WREVERSEON = 61
exports.NATIVE_CC_WUNDEROFF = 62
exports.NATIVE_CC_WUNDERON = 63
/* file */
exports.NATIVE_FILE_CLOSE = 64
exports.NATIVE_FILE_CLOSED = 65
exports.NATIVE_FILE_EOF = 66
exports.NATIVE_FILE_READ = 67
exports.NATIVE_FILE_READLINE = 68
/* img */
exports.NATIVE_IMAGE_CLONE = 69
exports.NATIVE_IMAGE_CREATE = 70
exports.NATIVE_IMAGE_DATA = 71
exports.NATIVE_IMAGE_DESTROY = 72
exports.NATIVE_IMAGE_HEIGHT = 73
exports.NATIVE_IMAGE_LOAD = 74
exports.NATIVE_IMAGE_SAVE = 75
exports.NATIVE_IMAGE_SUBIMAGE = 76
exports.NATIVE_IMAGE_WIDTH = 77
/* parse */
exports.NATIVE_PARSE_BOOL = 78
exports.NATIVE_PARSE_INT = 79
/* string */
exports.NATIVE_CHAR_CHR = 80
exports.NATIVE_CHAR_ORD = 81
exports.NATIVE_STRING_CHARAT = 82
exports.NATIVE_STRING_COMPARE = 83
exports.NATIVE_STRING_EQUAL = 84
exports.NATIVE_STRING_FROM_CHARARRAY = 85
exports.NATIVE_STRING_FROMBOOL = 86
exports.NATIVE_STRING_FROMCHAR = 87
exports.NATIVE_STRING_FROMINT = 88
exports.NATIVE_STRING_JOIN = 89
exports.NATIVE_STRING_LENGTH = 90
exports.NATIVE_STRING_SUB = 91
exports.NATIVE_STRING_TERMINATED = 92
exports.NATIVE_STRING_TO_CHARARRAY = 93
exports.NATIVE_STRING_TOLOWER = 94
},{}],4:[function(require,module,exports){
op = require("./opcodes");
var ProgramState = function(parsed_file) {
var main_function = parsed_file.function_pool[0];
this.stack = []
this.pc = 0;
this.program = main_function.code;
this.variables = [];
for (var i = 0; i < main_function.num_vars; i++)
variables.push(0);
this.file = parsed_file;
var INT_MIN = 0x80000000;
var INT_MAX = 0x7FFFFFFF;
var verbose = false;
function log(message) {
if (verbose) console.log(message);
}
function c0_assertion_failure(val) {
throw ("c0 assertion failure: " + val);
}
ProgramState.prototype.doIf = function(shouldJump) {
if (shouldJump) {
var address_offset = (this.program[this.pc+1] * 0x1000) +
this.program[this.pc+2];
this.pc += address_offset;
function c0_memory_error(val) {
throw ("c0 memory error: " + val);
}
function i32_to_array(i32) {
return [(i32 & 0xFF),
((i32 >> 8) & 0xFF),
((i32 >> 16) & 0xFF),
((i32 >> 24) & 0xFF)];
}
function array_to_i32(array) {
return array[0] +
(array[1] << 8) +
(array[2] << 16) +
(array[3] << 24);
}
var StackFrame = function(file, f) {
log("Creating stack frame");
this.stack = [];
this.pc = 0;
this.program = f.code;
this.variables = [];
for (var i = 0; i < f.num_vars; i++)
this.variables.push(0);
this.file = file;
}
var ProgramState = function(parsed_file, callback_dict) {
log("Creating program state with file " + parsed_file);
var main_function = parsed_file.function_pool[0];
this.frame = new StackFrame(parsed_file, parsed_file.function_pool[0]);
this.call_stack = [];
this.file = parsed_file;
this.natives = {};
for (var i = 0; i < 95; i++) {
try {
this.natives[i] = callback_dict[i];
} catch (key_not_found) {
this.natives[i] = function (arg) {
console.log("Native function " + name + " called, ran method stub.");
return 0;
};
}
}
// Memory is just a big array of bytes, right?
// "Allocation" is appending onto this array
// A pointer to memory is an index into this array.
// Structs are stored as themselves
// Arrays are stored as an entry for the number of elements
// and then the array, byte-by-byte
this.heap = [];
}
ProgramState.prototype.push = function(val) {
this.frame.stack.push(val);
}
ProgramState.prototype.pop = function() {
return this.frame.stack.pop();
}
ProgramState.prototype.goto_offset = function() {
var c1 = this.frame.program[this.frame.pc+1];
var c2 = this.frame.program[this.frame.pc+2]
var address_offset = (c1 << 8) + c2;
// Handle negative values
if ((address_offset & 0x8000) != 0)
address_offset = -0x8000 + (address_offset & 0x7FFF);
this.frame.pc += address_offset;
}
ProgramState.prototype.doIf = function(f) {
var y = this.pop();
var x = this.pop();
if (f(x,y)) {
this.goto_offset();
} else {
this.pc += 3;
this.frame.pc += 3;
}
}
ProgramState.prototype.step = function() {
console.log("Running opcode " + op.lookup_table[this.program[this.pc]]);
switch (this.program[this.pc]) {
var opcode = this.frame.program[this.frame.pc]
log("0x" + this.frame.pc.toString(16) + " Running opcode " +
op.lookup_table[opcode]);
switch (opcode) {
// Stack manipulation
case op.POP:
this.pc++;
this.stack.pop();
this.frame.pc++;
this.pop();
break;
case op.DUP:
this.pc++;
var v = this.stack.pop();
this.stack.push(v);
this.stack.push(v);
this.frame.pc++;
var v = this.pop();
this.push(v);
this.push(v);
break;
case op.SWAP:
this.pc++;
var v1 = this.stack.pop();
var v2 = this.stack.pop();
this.stack.push(v1);
this.stack.push(v2);
this.frame.pc++;
var v1 = this.pop();
var v2 = this.pop();
this.push(v1);
this.push(v2);
break;
case op.BIPUSH:
this.pc += 2;
var val = this.program[this.pc-1];
this.frame.pc += 2;
var val = this.frame.program[this.frame.pc-1];
// Do sign extension if necessary
if (val & 0x80 != 0)
if ((val & 0x80) != 0)
val = -0x80 + (val & 0x7F);
this.stack.push(val);
this.push(val);
break;
// Returning from a function
case op.RETURN:
var retVal = this.stack.pop();
throw retVal;
var retVal = this.pop();
if (this.call_stack.length == 0)
return retVal;
this.frame = this.call_stack.pop();
this.push(retVal);
break;
// Arithmetic
case op.IADD:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
console.log("Adding " + x + " and " + y);
this.stack.push((x+y) % 0x100000000);
this.frame.pc++;
var y = this.pop();
var x = this.pop();
log("Adding " + x + " and " + y);
this.push((x+y) % 0x100000000);
break;
case op.ISUB:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.stack.push((x-y) % 0x100000000);
this.frame.pc++;
var y = this.pop();
var x = this.pop();
this.push((x-y) % 0x100000000);
break;
case op.IMUL:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.stack.push((x*y) % 0x100000000);
this.frame.pc++;
var y = this.pop();
var x = this.pop();
this.push((x*y) % 0x100000000);
break;
case op.IDIV:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.frame.pc++;
var y = this.pop();
var x = this.pop();
if (y == 0) c0_arith_error("Divide by zero");
if (x == INT_MIN && y == -1) c0_arith_error("Arithmetic overflow");
// This does int division.
// As I understand it, the ~~ is treated as the identity on integers
// which forces the type to int, not float
this.stack.push(~~(x/y));
this.push(~~(x/y));
break;
case op.IREM:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.frame.pc++;
var y = this.pop();
var x = this.pop();
if (y == 0) c0_arith_error("Divide by zero");
if (x == INT_MIN && y == -1) c0_arith_error("Arithmetic overflow");
this.stack.push(x%y);
this.push(x%y);
break;
case op.IAND:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.stack.push(x&y);
this.frame.pc++;
var y = this.pop();
var x = this.pop();
this.push(x&y);
break;
case op.IOR:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.stack.push(x|y);
this.frame.pc++;
var y = this.pop();
var x = this.pop();
this.push(x|y);
break;
case op.IXOR:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.stack.push(x^y);
this.frame.pc++;
var y = this.pop();
var x = this.pop();
this.push(x^y);
break;
case op.ISHL:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.frame.pc++;
var y = this.pop();
var x = this.pop();
if (y < 0 || y > 31) c0_arith_error("Shifting by too many bits");
this.stack.push(x<<y);
this.push(x<<y);
break;
case op.ISHR:
this.pc++;
var y = this.stack.pop();
var x = this.stack.pop();
this.frame.pc++;
var y = this.pop();
var x = this.pop();
if (y < 0 || y > 31) c0_arith_error("Shifting by too many bits");
this.stack.push(x>>y);
this.push(x>>y);
break;
// Operations on local variables
case op.VLOAD:
this.pc += 2;
var index = this.program[this.pc-1];
this.stack.push(this.variables[index]);
this.frame.pc += 2;
var index = this.frame.program[this.frame.pc-1];
this.push(this.frame.variables[index]);
break;
case op.VSTORE:
this.pc += 2;
var index = this.program[this.pc-1];
this.variables[index] = this.stack.pop();
this.frame.pc += 2;
var index = this.frame.program[this.frame.pc-1];
this.frame.variables[index] = this.pop();
break;
case op.ACONST_NULL:
this.pc++;
this.stack.push(0);
this.frame.pc++;
this.push(0);
break;
case op.ILDC:
this.pc += 3;
var c1 = this.program[this.pc-2];
var c2 = this.program[this.pc-1];
this.frame.pc += 3;
var c1 = this.frame.program[this.frame.pc-2];
var c2 = this.frame.program[this.frame.pc-1];
var index = (c1 * 0x1000) + c2;
this.stack.push(this.file.int_pool[index]);
this.push(this.file.int_pool[index]);
break;
case op.ALDC:
console.log("Error: I don't know how to handle ALDC yet");
throw "Error - can't handle ALDC";
this.frame.pc += 3;
var c1 = this.frame.program[this.frame.pc-2];
var c2 = this.frame.program[this.frame.pc-1];
var index = (c1 * 0x1000) + c2;
this.push(this.file.string_pool[index]);
break;
// Control flow
case op.NOP:
this.pc++;
this.frame.pc++;
break;
case op.IF_CMPEQ:
var y = this.stack.pop();
var x = this.stack.pop();
this.doIf(y == x);
this.doIf(function (x,y) {return y == x;});
break;
case op.IF_CMPNE:
var y = this.stack.pop();
var x = this.stack.pop();
this.doIf(y != x);
this.doIf(function (x,y) {return y != x;});
break;
case op.IF_CMPLT:
var y = this.stack.pop();
var x = this.stack.pop();
this.doIf(y > x);
case op.IF_ICMPLT:
this.doIf(function (x,y) {return y > x;});
break;
case op.IF_CMPGE:
var y = this.stack.pop();
var x = this.stack.pop();
this.doIf(y <= x);
case op.IF_ICMPGE:
this.doIf(function (x,y) {return y <= x;});
break;
case op.IF_CMPGT:
var y = this.stack.pop();
var x = this.stack.pop();
this.doIf(y < x);
case op.IF_ICMPGT:
this.doIf(function (x,y) {return y < x;});
break;
case op.IF_CMPLE:
var y = this.stack.pop();
var x = this.stack.pop();
this.doIf(y >= x);
case op.IF_ICMPLE:
this.doIf(function (x,y) {return y >= x;});
break;
case op.GOTO:
this.doIf(true);
this.goto_offset();
break;
case op.ATHROW:
this.pc++;
c0_user_error(this.stack.pop());
this.frame.pc++;
c0_user_error(this.pop());
break;
case op.ASSERT:
this.pc++;
var a = this.stack.pop();
if (this.stack.pop() == 0)
this.frame.pc++;
var a = this.pop();
if (this.pop() == 0)
c0_assertion_failure(a);
break;
// Function call operations
case op.INVOKESTATIC:
var c1 = this.frame.program[this.frame.pc+1];
var c2 = this.frame.program[this.frame.pc+2];
this.frame.pc += 3;
var index = (c1 << 8) + c2;
var f = this.file.function_pool[index];
var newFrame = new StackFrame(this.file, f);
for (var i = f.num_args - 1; i >= 0; i--) {
newFrame.variables[i] = this.pop();
}
this.call_stack.push(this.frame);
this.frame = newFrame;
break;
case op.INVOKENATIVE:
var c1 = this.frame.program[this.frame.pc+1];
var c2 = this.frame.program[this.frame.pc+2];
this.frame.pc += 3;
var index = (c1 << 8) + c2;
var f = this.file.native_pool[index];
var arg_array = [];
for (var i = f.num_args - 1; i >= 0; i--)
arg_array[i] = this.pop();
var native_function = this.natives[f.function_table_index];
if (native_function === undefined) {
native_function = function (ignored) {
console.log("Could not find native function with index " +
f.function_table_index);
return 0;
};
console.log("Unknown native function index " + f.function_table_index);
}
this.push(native_function(arg_array));
break;
// Memory allocation operations:
case op.NEW:
var size = this.frame.program[this.frame.pc+1];
var address = this.heap.length;
for (var i = 0; i < size; i++) this.heap.push(0);
this.push(address);
this.frame.pc += 2;
break;
case op.NEWARRAY:
var size = this.frame.program[this.frame.pc+1];
var address = this.heap.length;
var num_elements = this.pop();
if (num_elements < 0) c0_memory_error("Array size must be nonnegative");
this.heap.push(num_elements);
this.heap.push(size);
for (var i = 0; i < num_elements; i++) {
for (var j = 0; j < size; j++)
this.heap.push(0);
}
this.push(address);
this.frame.pc += 2;
break;
case op.ARRAYLENGTH:
var pointer = this.pop();
this.push(this.heap[pointer]);
break;
// Memory access operations:
case op.AADDF:
// Read offset into a struct
var offset = this.frame.program[this.frame.pc + 1];
var index = this.pop();
this.push(this.heap[index + offset]);
this.frame.pc += 2;
break;
case op.AADDS:
// Read offset into an array
var elt_index = this.pop();
var index = this.pop();
var array_length = this.heap[index];
var elt_size = this.heap[index+1];
if (elt_index >= array_length) c0_memory_error("Array index out of bounds.");
this.push(this.heap[index + 2 + elt_size*elt_index]);
this.frame.pc++;
break;
case op.IMLOAD:
var addr = this.pop();
// Get int32 from bytes
var c1 = this.heap[addr];
var c2 = this.heap[addr+1];
var c3 = this.heap[addr+2];
var c4 = this.heap[addr+3];
var combined = array_to_i32([c1, c2, c3, c4]);
this.push(combined);
this.frame.pc++;
break;
case op.IMSTORE:
var value = this.pop();
var addr = this.pop();
var array = i32_to_array(value);
for (var i = 0; i < 4; i++)
this.heap[addr + i] = array[i];
this.frame.pc++;
case op.AMLOAD:
var addr = this.pop();
this.push(this.heap[addr]);
this.frame.pc++;
break;
case op.AMSTORE:
var value = this.pop();
var addr = this.pop();
this.heap[addr] = value;
this.frame.pc++;
break;
case op.CMLOAD:
var addr = this.pop();
this.push(this.heap[addr]);
this.frame.pc++;
break;
case op.CMSTORE:
var value = this.pop();
var addr = this.pop();
this.heap[addr] = value;
this.frame.pc++;
break;
default:
console.log("Error: Unknown opcode\n");
var opcode_name;
try {
opcode_name = op.lookup_table[opcode];
} catch (ignored) {
opcode_name = "UNKNOWN";
}
console.log("Error: Unknown opcode: 0x" + opcode.toString(16) +
" (" + opcode_name + ")\n");
throw "Error - unknown opcode";
}
return false;
}
// Takes in a parsed .bc0 file and runs it
function execute(f) {
console.log("Beginning execution of file " + f);
function execute(file, callbacks, v) {
verbose = typeof v !== 'undefined' ? v : true;
log("Initializing with file " + file);
var state = new ProgramState(f);
var state = new ProgramState(file, callbacks);
log("Beginning execution");
while (true) {
// I'm not sure how to structure this control flow yet,
// so if anyone has a better idea, let me know
try {
state.step();
} catch (val) {
return val;
}
var val = state.step();
if (val !== undefined) return val;
// if (at_breakpoint) {
// save state (maybe in a global in this file?)
@@ -388,13 +729,11 @@ function execute(f) {
}
exports.execute = execute;
// opcode definitions
},{"./opcodes":5}],4:[function(require,module,exports){
},{"./opcodes":6}],5:[function(require,module,exports){
parser = require("./bytecode-parser");
c0vm = require("./c0vm.js");
c0ffi = require("./c0ffi.js");
// console.log("Reading in sample bytecode file:");
// console.log(parser.getBytes("../test/test.bc0"));
@@ -404,13 +743,33 @@ c0vm = require("./c0vm.js");
// console.log(file);
// console.log(file.function_pool[0].code);
// UI interaction functions
function print(arg) {
$("#output").append(arg);
}
callbacks = {};
callbacks[c0ffi.NATIVE_PRINT] = function(args) {
print(args[0]);
print("<br />");
}
callbacks[c0ffi.NATIVE_PRINTINT] = function(args) {
print(args[0]);
print("<br />");
}
console.log(callbacks);
$("#run").click(function() {
var input = $("#bytecode").html().replace(/(\r\n|\n|\r)/gm,"");
var file = parser.parse($("#bytecode").text());
$("#output").text(c0vm.execute(file));
print("<br />");
print(c0vm.execute(file, callbacks));
});
},{"./bytecode-parser":2,"./c0vm.js":3}],5:[function(require,module,exports){
},{"./bytecode-parser":2,"./c0ffi.js":3,"./c0vm.js":4}],6:[function(require,module,exports){
/* arithmetic operations */
exports.IADD = 0x60;
exports.IAND = 0x7E;
@@ -503,12 +862,12 @@ exports.lookup_table = {
0x13: "ILDC",
0x14: "ALDC",
0x00: "NOP",
0x9F: "IF",
0xA0: "IF",
0xA1: "IF",
0xA2: "IF",
0xA3: "IF",
0xA4: "IF",
0x9F: "IF_CMPEQ",
0xA0: "IF_CMPNE",
0xA1: "IF_ICMPLT",
0xA2: "IF_ICMPGE",
0xA3: "IF_ICMPGT",
0xA4: "IF_ICMPLE",
0xA7: "GOTO",
0xBF: "ATHROW",
0xCF: "ASSERT",
@@ -517,6 +876,6 @@ exports.lookup_table = {
0xB0: "RETURN"
};
},{}],6:[function(require,module,exports){
},{}],7:[function(require,module,exports){
},{}]},{},[3,2,1,5,4]);
},{}]},{},[4,2,1,6,5]);

110
src/c0ffi.js Normal file
View File

@@ -0,0 +1,110 @@
exports.NATIVE_FADD = 0
exports.NATIVE_FDIV = 1
exports.NATIVE_FLESS = 2
exports.NATIVE_FMUL = 3
exports.NATIVE_FSUB = 4
exports.NATIVE_FTOI = 5
exports.NATIVE_ITOF = 6
exports.NATIVE_PRINT_FPT = 7
exports.NATIVE_PRINT_HEX = 8
exports.NATIVE_PRINT_INT = 9
/* args */
exports.NATIVE_ARGS_FLAG = 10
exports.NATIVE_ARGS_INT = 11
exports.NATIVE_ARGS_PARSE = 12
exports.NATIVE_ARGS_STRING = 13
/* conio */
exports.NATIVE_EOF = 14
exports.NATIVE_FLUSH = 15
exports.NATIVE_PRINT = 16
exports.NATIVE_PRINTBOOL = 17
exports.NATIVE_PRINTCHAR = 18
exports.NATIVE_PRINTINT = 19
exports.NATIVE_PRINTLN = 20
exports.NATIVE_READLINE = 21
/* curses */
exports.NATIVE_C_ADDCH = 22
exports.NATIVE_C_CBREAK = 23
exports.NATIVE_C_CURS_SET = 24
exports.NATIVE_C_DELCH = 25
exports.NATIVE_C_ENDWIN = 26
exports.NATIVE_C_ERASE = 27
exports.NATIVE_C_GETCH = 28
exports.NATIVE_C_INITSCR = 29
exports.NATIVE_C_KEYPAD = 30
exports.NATIVE_C_MOVE = 31
exports.NATIVE_C_NOECHO = 32
exports.NATIVE_C_REFRESH = 33
exports.NATIVE_C_SUBWIN = 34
exports.NATIVE_C_WADDCH = 35
exports.NATIVE_C_WADDSTR = 36
exports.NATIVE_C_WCLEAR = 37
exports.NATIVE_C_WERASE = 38
exports.NATIVE_C_WMOVE = 39
exports.NATIVE_C_WREFRESH = 40
exports.NATIVE_C_WSTANDEND = 41
exports.NATIVE_C_WSTANDOUT = 42
exports.NATIVE_CC_GETBEGX = 43
exports.NATIVE_CC_GETBEGY = 44
exports.NATIVE_CC_GETMAXX = 45
exports.NATIVE_CC_GETMAXY = 46
exports.NATIVE_CC_GETX = 47
exports.NATIVE_CC_GETY = 48
exports.NATIVE_CC_HIGHLIGHT = 49
exports.NATIVE_CC_KEY_IS_BACKSPACE = 50
exports.NATIVE_CC_KEY_IS_DOWN = 51
exports.NATIVE_CC_KEY_IS_ENTER = 52
exports.NATIVE_CC_KEY_IS_LEFT = 53
exports.NATIVE_CC_KEY_IS_RIGHT = 54
exports.NATIVE_CC_KEY_IS_UP = 55
exports.NATIVE_CC_WBOLDOFF = 56
exports.NATIVE_CC_WBOLDON = 57
exports.NATIVE_CC_WDIMOFF = 58
exports.NATIVE_CC_WDIMON = 59
exports.NATIVE_CC_WREVERSEOFF = 60
exports.NATIVE_CC_WREVERSEON = 61
exports.NATIVE_CC_WUNDEROFF = 62
exports.NATIVE_CC_WUNDERON = 63
/* file */
exports.NATIVE_FILE_CLOSE = 64
exports.NATIVE_FILE_CLOSED = 65
exports.NATIVE_FILE_EOF = 66
exports.NATIVE_FILE_READ = 67
exports.NATIVE_FILE_READLINE = 68
/* img */
exports.NATIVE_IMAGE_CLONE = 69
exports.NATIVE_IMAGE_CREATE = 70
exports.NATIVE_IMAGE_DATA = 71
exports.NATIVE_IMAGE_DESTROY = 72
exports.NATIVE_IMAGE_HEIGHT = 73
exports.NATIVE_IMAGE_LOAD = 74
exports.NATIVE_IMAGE_SAVE = 75
exports.NATIVE_IMAGE_SUBIMAGE = 76
exports.NATIVE_IMAGE_WIDTH = 77
/* parse */
exports.NATIVE_PARSE_BOOL = 78
exports.NATIVE_PARSE_INT = 79
/* string */
exports.NATIVE_CHAR_CHR = 80
exports.NATIVE_CHAR_ORD = 81
exports.NATIVE_STRING_CHARAT = 82
exports.NATIVE_STRING_COMPARE = 83
exports.NATIVE_STRING_EQUAL = 84
exports.NATIVE_STRING_FROM_CHARARRAY = 85
exports.NATIVE_STRING_FROMBOOL = 86
exports.NATIVE_STRING_FROMCHAR = 87
exports.NATIVE_STRING_FROMINT = 88
exports.NATIVE_STRING_JOIN = 89
exports.NATIVE_STRING_LENGTH = 90
exports.NATIVE_STRING_SUB = 91
exports.NATIVE_STRING_TERMINATED = 92
exports.NATIVE_STRING_TO_CHARARRAY = 93
exports.NATIVE_STRING_TOLOWER = 94

12
test/arrays.c0 Normal file
View File

@@ -0,0 +1,12 @@
#use <conio>
int main() {
int[] A = alloc_array(int, -2);
A[3] = 0;
A[3] = 1;
A[3] = 2;
A[3] = 3;
printint(A[3]);
return 0;
}

52
test/arrays.c0.bc0 Normal file
View File

@@ -0,0 +1,52 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 00 # int pool count
# int pool
00 00 # string pool total size
# string pool
00 01 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 01 # number of local variables = 1
00 33 # code length = 51 bytes
10 FE # bipush -2 # -2
BC 04 # newarray 4 # alloc_array(int, -(2))
36 00 # vstore 0 # A = alloc_array(int, -(2));
15 00 # vload 0 # A
10 03 # bipush 3 # 3
63 # aadds # &A[3]
10 00 # bipush 0 # 0
4E # imstore # A[3] = 0;
15 00 # vload 0 # A
10 03 # bipush 3 # 3
63 # aadds # &A[3]
10 01 # bipush 1 # 1
4E # imstore # A[3] = 1;
15 00 # vload 0 # A
10 03 # bipush 3 # 3
63 # aadds # &A[3]
10 02 # bipush 2 # 2
4E # imstore # A[3] = 2;
15 00 # vload 0 # A
10 03 # bipush 3 # 3
63 # aadds # &A[3]
10 03 # bipush 3 # 3
4E # imstore # A[3] = 3;
15 00 # vload 0 # A
10 03 # bipush 3 # 3
63 # aadds # &A[3]
2E # imload # A[3]
B7 00 00 # invokenative 0 # printint(A[3])
57 # pop # (ignore result)
10 00 # bipush 0 # 0
B0 # return #
00 01 # native count
# native pool
00 01 00 09 # printint

1
test/arrays.c0.bc0out Normal file
View File

@@ -0,0 +1 @@
30

0
test/arrays.c0.c0out Normal file
View File

BIN
test/arrays.c0.ex Executable file

Binary file not shown.

23
test/dsquared.c0 Normal file
View File

@@ -0,0 +1,23 @@
int dsquared(int x, int y)
{
return x*x + y*y;
}
int main ()
{
int a1 = 15;
int b1 = 122;
int a2 = 42;
int b2 = 0;
int a3 = -7;
int b3 = -11;
int a4 = -4;
int b4 = 3;
int sum = 0;
sum = sum + dsquared(a1,b1);
sum = sum + dsquared(a2,b2);
sum = sum + dsquared(a3,b3);
sum = sum + dsquared(a4,b4);
return sum;
}

78
test/dsquared.c0.bc0 Normal file
View File

@@ -0,0 +1,78 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 00 # int pool count
# int pool
00 00 # string pool total size
# string pool
00 02 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 09 # number of local variables = 9
00 57 # code length = 87 bytes
10 0F # bipush 15 # 15
36 00 # vstore 0 # a1 = 15;
10 7A # bipush 122 # 122
36 01 # vstore 1 # b1 = 122;
10 2A # bipush 42 # 42
36 02 # vstore 2 # a2 = 42;
10 00 # bipush 0 # 0
36 03 # vstore 3 # b2 = 0;
10 F9 # bipush -7 # -7
36 04 # vstore 4 # a3 = -(7);
10 F5 # bipush -11 # -11
36 05 # vstore 5 # b3 = -(11);
10 FC # bipush -4 # -4
36 06 # vstore 6 # a4 = -(4);
10 03 # bipush 3 # 3
36 07 # vstore 7 # b4 = 3;
10 00 # bipush 0 # 0
36 08 # vstore 8 # sum = 0;
15 08 # vload 8 # sum
15 00 # vload 0 # a1
15 01 # vload 1 # b1
B8 00 01 # invokestatic 1 # dsquared(a1, b1)
60 # iadd # (sum + dsquared(a1, b1))
36 08 # vstore 8 # sum = (sum + dsquared(a1, b1));
15 08 # vload 8 # sum
15 02 # vload 2 # a2
15 03 # vload 3 # b2
B8 00 01 # invokestatic 1 # dsquared(a2, b2)
60 # iadd # (sum + dsquared(a2, b2))
36 08 # vstore 8 # sum = (sum + dsquared(a2, b2));
15 08 # vload 8 # sum
15 04 # vload 4 # a3
15 05 # vload 5 # b3
B8 00 01 # invokestatic 1 # dsquared(a3, b3)
60 # iadd # (sum + dsquared(a3, b3))
36 08 # vstore 8 # sum = (sum + dsquared(a3, b3));
15 08 # vload 8 # sum
15 06 # vload 6 # a4
15 07 # vload 7 # b4
B8 00 01 # invokestatic 1 # dsquared(a4, b4)
60 # iadd # (sum + dsquared(a4, b4))
36 08 # vstore 8 # sum = (sum + dsquared(a4, b4));
15 08 # vload 8 # sum
B0 # return #
#<dsquared>
00 02 # number of arguments = 2
00 02 # number of local variables = 2
00 0C # code length = 12 bytes
15 00 # vload 0 # x
15 00 # vload 0 # x
68 # imul # (x * x)
15 01 # vload 1 # y
15 01 # vload 1 # y
68 # imul # (y * y)
60 # iadd # ((x * x) + (y * y))
B0 # return #
00 00 # native count
# native pool

1
test/dsquared.c0.bc0out Normal file
View File

@@ -0,0 +1 @@
17068

1
test/dsquared.c0.c0out Normal file
View File

@@ -0,0 +1 @@
17068

BIN
test/dsquared.c0.ex Executable file

Binary file not shown.

3
test/ishr.c0 Normal file
View File

@@ -0,0 +1,3 @@
int main () {
return -1 >> 1; /* should return -1 */
}

24
test/ishr.c0.bc0 Normal file
View File

@@ -0,0 +1,24 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 00 # int pool count
# int pool
00 00 # string pool total size
# string pool
00 01 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 00 # number of local variables = 0
00 06 # code length = 6 bytes
10 FF # bipush -1 # -1
10 01 # bipush 1 # 1
7A # ishr # (-(1) >> 1)
B0 # return #
00 00 # native count
# native pool

1
test/ishr.c0.bc0out Normal file
View File

@@ -0,0 +1 @@
-1

1
test/ishr.c0.c0out Normal file
View File

@@ -0,0 +1 @@
-1

BIN
test/ishr.c0.ex Executable file

Binary file not shown.

10
test/isqrt.c0 Normal file
View File

@@ -0,0 +1,10 @@
int main () {
int n = 15122;
int i = 0; int k = 0;
while (k <= n) {
k += 2*i + 1;
i++;
}
return i-1;
}

51
test/isqrt.c0.bc0 Normal file
View File

@@ -0,0 +1,51 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 01 # int pool count
# int pool
00 00 3B 12
00 00 # string pool total size
# string pool
00 01 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 03 # number of local variables = 3
00 34 # code length = 52 bytes
13 00 00 # ildc 0 # c[0] = 15122
36 00 # vstore 0 # n = 15122;
10 00 # bipush 0 # 0
36 01 # vstore 1 # i = 0;
10 00 # bipush 0 # 0
36 02 # vstore 2 # k = 0;
# <00:loop>
15 02 # vload 2 # k
15 00 # vload 0 # n
A4 00 06 # if_icmple +6 # if (k <= n) goto <01:body>
A7 00 1A # goto +26 # goto <02:exit>
# <01:body>
15 02 # vload 2 # k
10 02 # bipush 2 # 2
15 01 # vload 1 # i
68 # imul # (2 * i)
10 01 # bipush 1 # 1
60 # iadd # ((2 * i) + 1)
60 # iadd #
36 02 # vstore 2 # k += ((2 * i) + 1);
15 01 # vload 1 # i
10 01 # bipush 1 # 1
60 # iadd #
36 01 # vstore 1 # i += 1;
A7 FF E2 # goto -30 # goto <00:loop>
# <02:exit>
15 01 # vload 1 # i
10 01 # bipush 1 # 1
64 # isub # (i - 1)
B0 # return #
00 00 # native count
# native pool

0
test/isqrt.c0.bc0out Normal file
View File

1
test/isqrt.c0.c0out Normal file
View File

@@ -0,0 +1 @@
122

BIN
test/isqrt.c0.ex Executable file

Binary file not shown.

10
test/mid.c0 Normal file
View File

@@ -0,0 +1,10 @@
int main()
{
int low = 0x15;
int high = 0x122;
int mid;
mid = low + (high - low)/2;
return mid;
}

35
test/mid.c0.bc0 Normal file
View File

@@ -0,0 +1,35 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 01 # int pool count
# int pool
00 00 01 22
00 00 # string pool total size
# string pool
00 01 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 03 # number of local variables = 3
00 19 # code length = 25 bytes
10 15 # bipush 21 # 21
36 00 # vstore 0 # low = 21;
13 00 00 # ildc 0 # c[0] = 290
36 01 # vstore 1 # high = 290;
15 00 # vload 0 # low
15 01 # vload 1 # high
15 00 # vload 0 # low
64 # isub # (high - low)
10 02 # bipush 2 # 2
6C # idiv # ((high - low) / 2)
60 # iadd # (low + ((high - low) / 2))
36 02 # vstore 2 # mid = (low + ((high - low) / 2));
15 02 # vload 2 # mid
B0 # return #
00 00 # native count
# native pool

1
test/mid.c0.bc0out Normal file
View File

@@ -0,0 +1 @@
155

1
test/mid.c0.c0out Normal file
View File

@@ -0,0 +1 @@
155

BIN
test/mid.c0.ex Executable file

Binary file not shown.

7
test/sample2.5.c0 Normal file
View File

@@ -0,0 +1,7 @@
int main () {
int i; int sum = 0;
for (i = 15; i <= 122; i++)
sum += i;
assert(sum == 0);
return sum;
}

55
test/sample2.5.c0.bc0 Normal file
View File

@@ -0,0 +1,55 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 00 # int pool count
# int pool
00 25 # string pool total size
# string pool
73 61 6D 70 6C 65 32 2E 35 2E 63 30 3A 35 2E 32 2D 35 2E 31 39 3A 20 61 73 73 65 72 74 20 66 61 69 6C 65 64 00 # "sample2.5.c0:5.2-5.19: assert failed"
00 01 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 02 # number of local variables = 2
00 3B # code length = 59 bytes
10 00 # bipush 0 # 0
36 01 # vstore 1 # sum = 0;
10 0F # bipush 15 # 15
36 00 # vstore 0 # i = 15;
# <00:loop>
15 00 # vload 0 # i
10 7A # bipush 122 # 122
A4 00 06 # if_icmple +6 # if (i <= 122) goto <01:body>
A7 00 14 # goto +20 # goto <02:exit>
# <01:body>
15 01 # vload 1 # sum
15 00 # vload 0 # i
60 # iadd #
36 01 # vstore 1 # sum += i;
15 00 # vload 0 # i
10 01 # bipush 1 # 1
60 # iadd #
36 00 # vstore 0 # i += 1;
A7 FF E8 # goto -24 # goto <00:loop>
# <02:exit>
15 01 # vload 1 # sum
10 00 # bipush 0 # 0
9F 00 06 # if_cmpeq +6 # if (sum == 0) goto <03:cond_true>
A7 00 08 # goto +8 # goto <04:cond_false>
# <03:cond_true>
10 01 # bipush 1 # true
A7 00 05 # goto +5 # goto <05:cond_end>
# <04:cond_false>
10 00 # bipush 0 # false
# <05:cond_end>
14 00 00 # aldc 0 # s[0] = "sample2.5.c0:5.2-5.19: assert failed"
CF # assert # assert(sum == 0) [failure message on stack]
15 01 # vload 1 # sum
B0 # return #
00 00 # native count
# native pool

0
test/sample2.5.c0.bc0out Normal file
View File

0
test/sample2.5.c0.c0out Normal file
View File

BIN
test/sample2.5.c0.ex Executable file

Binary file not shown.

18
test/structs.c0 Normal file
View File

@@ -0,0 +1,18 @@
#use <conio>
struct test {
int a;
string b;
int c;
};
int main() {
struct test* t = alloc(struct test);
t->a = 1;
t->b = "potato chip";
t->c = 23;
print(t->b);
printint(t->a);
printint(t->c);
return 0;
}

54
test/structs.c0.bc0 Normal file
View File

@@ -0,0 +1,54 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 00 # int pool count
# int pool
00 0C # string pool total size
# string pool
70 6F 74 61 74 6F 20 63 68 69 70 00 # "potato chip"
00 01 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 01 # number of local variables = 1
00 38 # code length = 56 bytes
BB 18 # new 24 # alloc(struct test)
36 00 # vstore 0 # t = alloc(struct test);
15 00 # vload 0 # t
62 00 # aaddf 0 # &t->a
10 01 # bipush 1 # 1
4E # imstore # t->a = 1;
15 00 # vload 0 # t
62 08 # aaddf 8 # &t->b
14 00 00 # aldc 0 # s[0] = "potato chip"
4F # amstore # t->b = "potato chip";
15 00 # vload 0 # t
62 10 # aaddf 16 # &t->c
10 17 # bipush 23 # 23
4E # imstore # t->c = 23;
15 00 # vload 0 # t
62 08 # aaddf 8 # &t->b
2F # amload # t->b
B7 00 00 # invokenative 0 # print(t->b)
57 # pop # (ignore result)
15 00 # vload 0 # t
62 00 # aaddf 0 # &t->a
2E # imload # t->a
B7 00 01 # invokenative 1 # printint(t->a)
57 # pop # (ignore result)
15 00 # vload 0 # t
62 10 # aaddf 16 # &t->c
2E # imload # t->c
B7 00 01 # invokenative 1 # printint(t->c)
57 # pop # (ignore result)
10 00 # bipush 0 # 0
B0 # return #
00 02 # native count
# native pool
00 01 00 10 # print
00 01 00 13 # printint

1
test/structs.c0.bc0out Normal file
View File

@@ -0,0 +1 @@
potato chip1230

1
test/structs.c0.c0out Normal file
View File

@@ -0,0 +1 @@
potato chip1230

BIN
test/structs.c0.ex Executable file

Binary file not shown.

8
test/testif.c0 Normal file
View File

@@ -0,0 +1,8 @@
int main() {
int x = 4;
if (x < 3)
x = 23;
else
x = 32;
return x;
}

36
test/testif.c0.bc0 Normal file
View File

@@ -0,0 +1,36 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 00 # int pool count
# int pool
00 00 # string pool total size
# string pool
00 01 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 01 # number of local variables = 1
00 1C # code length = 28 bytes
10 04 # bipush 4 # 4
36 00 # vstore 0 # x = 4;
15 00 # vload 0 # x
10 03 # bipush 3 # 3
A1 00 06 # if_icmplt +6 # if (x < 3) goto <00:then>
A7 00 0A # goto +10 # goto <01:else>
# <00:then>
10 17 # bipush 23 # 23
36 00 # vstore 0 # x = 23;
A7 00 07 # goto +7 # goto <02:endif>
# <01:else>
10 20 # bipush 32 # 32
36 00 # vstore 0 # x = 32;
# <02:endif>
15 00 # vload 0 # x
B0 # return #
00 00 # native count
# native pool

1
test/testif.c0.bc0out Normal file
View File

@@ -0,0 +1 @@
32

1
test/testif.c0.c0out Normal file
View File

@@ -0,0 +1 @@
32

BIN
test/testif.c0.ex Executable file

Binary file not shown.

73
test/tests.js Normal file
View File

@@ -0,0 +1,73 @@
parser = require("../src/bytecode-parser.js");
c0vm = require("../src/c0vm.js");
c0ffi = require("../src/c0ffi.js");
var callbacks = {}
var printout = "";
callbacks[c0ffi.NATIVE_PRINT] = function(args) {
printout += args[0];
}
callbacks[c0ffi.NATIVE_PRINTINT] = function(args) {
printout += args[0];
}
callbacks[c0ffi.NATIVE_PRINTLN] = function(args) {
printout += (args[0] + "\n");
}
function doTest(filename, expected_result) {
return function(test) {
var result = c0vm.execute(parser.parse(filename), callbacks, false);
test.ok(result == expected_result,
filename + " - did not get expected result " + expected_result +
", instead got " + result);
test.done();
}
}
exports.testIADD = doTest("iadd.c0.bc0", -2);
exports.testPrint = function(test) {
printout = "";
var result = c0vm.execute(parser.parse("test.bc0"), callbacks, false);
test.ok(printout == "Hello, world.\nYou don't look so good.\n",
"test.bc0 - Did not print to screen correctly: output was " + printout);
test.done();
}
exports.testISHR = doTest("ishr.c0.bc0", -1);
exports.testISQRT = doTest("isqrt.c0.bc0", 122);
exports.testMID = doTest("mid.c0.bc0", 155);
// This one should throw an exception because an assertion fails
exports.testSample25 = function(test) {
test.throws(function () {
c0vm.execute(parser.parse("sample2.5.c0.bc0"), callbacks, false)
});
test.done();
}
exports.testIF = doTest("testif.c0.bc0", 32);
exports.testDSQUARED = doTest("dsquared.c0.bc0", 17068);
exports.testArrays = function(test) {
test.throws(function () {
c0vm.execute(parser.parse("arrays.c0.bc0"), callbacks, true)
});
test.done();
}
exports.testStructs = function(test) {
printout = "";
var result = c0vm.execute(parser.parse("structs.c0.bc0"), callbacks, false);
test.ok(printout == "potato chip123",
"structs.c0.bc0 - Did not print to screen correctly, result was " +
printout);
test.done();
}