Open mingodad opened 8 years ago
I'll try to write something about it, asap.
Did anything ever get written up for this? I'm trying to understand the opcode format as well and having some documentation would be helpful.
I've tried to make sense of it by adding an extra option -s
to my fork here https://github.com/mingodad/squilu:
squilu -h
usage: sq <options> <scriptpath [args]>.
Available options are:
-s compiles the file to bytecode(default output 'out.cnut')
-o specifies output file for the -c option
-c compiles only
-d generates debug infos
-v displays version infos
-p preload given script file
-i set the include_path
-D define a preprocesor named constant
-h prints help
SquiLu based on Squirrel 3.1 stable and Lua 5.1.5 Copyright (C) 2003-2017 Alberto Demichelis, Domingo Alvarez Duarte (64 bits)
Sample:
//squilu _fix-non-terminal.nut srcML-dad.g
if(vargv.len() < 2) {
print("usage:", vargv[0], " grammar_file");
os.exit(1);
}
auto cmd = "./parsertl-playground " + vargv[1] + " test.empty 2>&1";
print(cmd);
auto txt = popen(cmd, "r").read_all();
//print(txt);
txt = txt.gsub("Warning: Token \"[^\n]-\" is not used in the grammar.\n", "");
txt = txt.replace("Non-terminal '", "%token ");
txt = txt.replace("' does not have any productions.", "");
txt = txt.gsub("Warning: Token \"([^\n]-)\" does not have a lexer definiton%.", function(m) {
if(m[0] == '\'') return format("\"%s\"\t%s", m.slice(1,-1), m);
return format("%s\t%s", m, m);
});
txt = txt.gsub("Unknown token \"([^\n]-)\"%.", "%%token %1");
auto lines = txt.split('\n');
lines.sort(@(a,b) a<=>b);
auto prevLine;
foreach(line in lines) {
if(line == prevLine) continue;
prevLine = line;
print(line);
}
Output:
local bytecode = {
source_name = "_fix-non-terminal.nut",
function_name = "main",
function_return_type = null,
literals = [
/*0*/ "len",
/*1*/ "print",
/*2*/ "usage:",
/*3*/ " grammar_file",
/*4*/ "os",
/*5*/ "exit",
/*6*/ "./parsertl-playground ",
/*7*/ " test.empty 2>&1",
/*8*/ "popen",
/*9*/ "r",
/*10*/ "read_all",
/*11*/ "gsub",
/*12*/ [==[Warning: Token "[^
]-" is not used in the grammar.
]==],
/*13*/ null,
/*14*/ "replace",
/*15*/ "Non-terminal '",
/*16*/ "%token ",
/*17*/ "' does not have any productions.",
/*18*/ [==[Warning: Token "([^
]-)" does not have a lexer definiton%.]==],
/*19*/ [==[Unknown token "([^
]-)"%.]==],
/*20*/ "%%token %1",
/*21*/ "split",
/*22*/ "sort",
],
parameters = [
/*0*/ "this",
/*1*/ "vargv",
],
outervalues = [
//[type, src, name],
],
localvarinfos = [
//[pos, name, start_op, end_op, scope, type, type_name, dtype_name],
/*0*/ [0, "this", 0, 68, 1, 1, "ANY", ""],
/*1*/ [1, "vargv", 0, 68, 1, 1, "ANY", ""],
/*2*/ [2, "cmd", 20, 67, 0, 1, "ANY", "TK_LOCAL"],
/*3*/ [3, "txt", 29, 67, 0, 1, "ANY", "TK_LOCAL"],
/*4*/ [4, "lines", 53, 67, 0, 1, "ANY", "TK_LOCAL"],
/*5*/ [5, "prevLine", 57, 67, 0, 1, "ANY", "TK_LOCAL"],
/*6*/ [6, "@INDEX@", 57, 67, 1, 1, "ANY", ""],
/*7*/ [7, "line", 58, 67, 1, 1, "ANY", ""],
/*8*/ [8, "@ITERATOR@", 58, 67, 1, 1, "ANY", ""],
],
lineinfos = [
//[op, line],
/*0*/ [0, 2], /*_OP_PREPCALLK*/
/*1*/ [4, 3], /*_OP_PREPCALLK*/
/*2*/ [10, 4], /*_OP_GETK*/
/*3*/ [14, 7], /*_OP_LOAD*/
/*4*/ [20, 8], /*_OP_PREPCALLK*/
/*5*/ [23, 10], /*_OP_PREPCALLK*/
/*6*/ [29, 13], /*_OP_PREPCALLK*/
/*7*/ [33, 14], /*_OP_PREPCALLK*/
/*8*/ [37, 15], /*_OP_PREPCALLK*/
/*9*/ [41, 17], /*_OP_PREPCALLK*/
/*10*/ [46, 21], /*_OP_PREPCALLK*/
/*11*/ [50, 23], /*_OP_PREPCALLK*/
/*12*/ [53, 24], /*_OP_PREPCALLK*/
/*13*/ [56, 26], /*_OP_LOADNULLS*/
/*14*/ [57, 27], /*_OP_LOADNULLS*/
/*15*/ [60, 28], /*_OP_EQ*/
/*16*/ [63, 29], /*_OP_MOVE*/
/*17*/ [64, 30], /*_OP_PREPCALLK*/
/*18*/ [68, 33], /*_OP_RETURN*/
],
defaultparams = [],
instructions = [ /*stack*/
//[op_str, op, arg0, arg1, arg2, arg3],
/*0*/ ["_OP_PREPCALLK", 8, 2, 0, 1, 3], /* closure_at_stk[2], stk[1].get(literals[0]) -> stk[3] */
/*1*/ ["_OP_CALL", 6, 2, 2, 3, 1], /* target[2], lvi[2]("cmd"), stackbase(3), nargs(1) */
/*2*/ ["_OP_LOADINT", 2, 3, 2, 0, 0], /* stk[3] <- arg1(2) */
/*3*/ ["_OP_JCMP", 29, 3, 10, 2, 3], /* IsFalse(STK(2) CMP_L STK(3)) (ci->_ip+=(10) -> goto[14]) */
/*4*/ ["_OP_PREPCALLK", 8, 2, 1, 0, 3], /* closure_at_stk[2], stk[0].get(literals[1]) -> stk[3] */
/*5*/ ["_OP_LOAD", 1, 4, 2, 0, 0], /* stk[4] <- literals[2]("usage:") */
/*6*/ ["_OP_LOADINT", 2, 5, 0, 0, 0], /* stk[5] <- arg1(0) */
/*7*/ ["_OP_GET", 14, 5, 1, 5, 0], /* stk_at_arg0[5] = stk_at_arg1[1].get(stk_at_arg2(5)) */
/*8*/ ["_OP_LOAD", 1, 6, 3, 0, 0], /* stk[6] <- literals[3](" grammar_file") */
/*9*/ ["_OP_CALL", 6, 255, 2, 3, 4], /* target[255], lvi[2]("cmd"), stackbase(3), nargs(4) */
/*10*/ ["_OP_GETK", 9, 2, 4, 0, 0], /* stk[2] <- literals[4]("os") */
/*11*/ ["_OP_PREPCALLK", 8, 2, 5, 2, 3], /* closure_at_stk[2], stk[2].get(literals[5]) -> stk[3] */
/*12*/ ["_OP_LOADINT", 2, 4, 1, 0, 0], /* stk[4] <- arg1(1) */
/*13*/ ["_OP_CALL", 6, 255, 2, 3, 2], /* target[255], lvi[2]("cmd"), stackbase(3), nargs(2) */
/*14*/ ["_OP_LOAD", 1, 2, 6, 0, 0], /* stk[2] <- literals[6]("./parsertl-playground ") */
/*15*/ ["_OP_LOADINT", 2, 3, 1, 0, 0], /* stk[3] <- arg1(1) */
/*16*/ ["_OP_GET", 14, 3, 1, 3, 0], /* stk_at_arg0[3] = stk_at_arg1[1].get(stk_at_arg2(3)) */
/*17*/ ["_OP_ADD", 17, 2, 3, 2, 0], /* stk[2] = stk[2]("cmd") + stk[3]("txt") */
/*18*/ ["_OP_LOAD", 1, 3, 7, 0, 0], /* stk[3] <- literals[7](" test.empty 2>&1") */
/*19*/ ["_OP_ADD", 17, 2, 3, 2, 0], /* stk[2] = stk[2]("cmd") + stk[3]("txt") */
/*20*/ ["_OP_PREPCALLK", 8, 3, 1, 0, 4], /* closure_at_stk[3], stk[0].get(literals[1]) -> stk[4] */
/*21*/ ["_OP_MOVE", 10, 5, 2, 0, 0], /* stk[5] <- lvi[2]("cmd") */
/*22*/ ["_OP_CALL", 6, 255, 3, 4, 2], /* target[255], lvi[3]("txt"), stackbase(4), nargs(2) */
/*23*/ ["_OP_PREPCALLK", 8, 3, 8, 0, 4], /* closure_at_stk[3], stk[0].get(literals[8]) -> stk[4] */
/*24*/ ["_OP_MOVE", 10, 5, 2, 0, 0], /* stk[5] <- lvi[2]("cmd") */
/*25*/ ["_OP_LOAD", 1, 6, 9, 0, 0], /* stk[6] <- literals[9]("r") */
/*26*/ ["_OP_CALL", 6, 3, 3, 4, 3], /* target[3], lvi[3]("txt"), stackbase(4), nargs(3) */
/*27*/ ["_OP_PREPCALLK", 8, 3, 10, 3, 4], /* closure_at_stk[3], stk[3].get(literals[10]) -> stk[4] */
/*28*/ ["_OP_CALL", 6, 3, 3, 4, 1], /* target[3], lvi[3]("txt"), stackbase(4), nargs(1) */
/*29*/ ["_OP_PREPCALLK", 8, 4, 11, 3, 5], /* closure_at_stk[4], stk[3].get(literals[11]) -> stk[5] */
/*30*/ ["_OP_DLOAD", 4, 6, 12, 7, 13], /* stk[6] <- literals[12]("Warning: Token "[^
]-" is not used in the grammar.
") */ /* stk[7] <- literals[13] null */
/*31*/ ["_OP_CALL", 6, 4, 4, 5, 3], /* target[4], lvi[4]("lines"), stackbase(5), nargs(3) */
/*32*/ ["_OP_MOVE", 10, 3, 4, 0, 0], /* stk[3] <- lvi[4]("lines") */
/*33*/ ["_OP_PREPCALLK", 8, 4, 14, 3, 5], /* closure_at_stk[4], stk[3].get(literals[14]) -> stk[5] */
/*34*/ ["_OP_DLOAD", 4, 6, 15, 7, 16], /* stk[6] <- literals[15]("Non-terminal '") */ /* stk[7] <- literals[16] "%token " */
/*35*/ ["_OP_CALL", 6, 4, 4, 5, 3], /* target[4], lvi[4]("lines"), stackbase(5), nargs(3) */
/*36*/ ["_OP_MOVE", 10, 3, 4, 0, 0], /* stk[3] <- lvi[4]("lines") */
/*37*/ ["_OP_PREPCALLK", 8, 4, 14, 3, 5], /* closure_at_stk[4], stk[3].get(literals[14]) -> stk[5] */
/*38*/ ["_OP_DLOAD", 4, 6, 17, 7, 13], /* stk[6] <- literals[17]("' does not have any productions.") */ /* stk[7] <- literals[13] null */
/*39*/ ["_OP_CALL", 6, 4, 4, 5, 3], /* target[4], lvi[4]("lines"), stackbase(5), nargs(3) */
/*40*/ ["_OP_MOVE", 10, 3, 4, 0, 0], /* stk[3] <- lvi[4]("lines") */
/*41*/ ["_OP_PREPCALLK", 8, 4, 11, 3, 5], /* closure_at_stk[4], stk[3].get(literals[11]) -> stk[5] */
/*42*/ ["_OP_LOAD", 1, 6, 18, 0, 0], /* stk[6] <- literals[18]("Warning: Token "([^
]-)" does not have a lexer definiton%.") */
/*43*/ ["_OP_CLOSURE", 48, 7, 0, 0, 0], /* stk_at_arg0[7] <- functions[0](null), isLanbda(0) */
/*44*/ ["_OP_CALL", 6, 4, 4, 5, 3], /* target[4], lvi[4]("lines"), stackbase(5), nargs(3) */
/*45*/ ["_OP_MOVE", 10, 3, 4, 0, 0], /* stk[3] <- lvi[4]("lines") */
/*46*/ ["_OP_PREPCALLK", 8, 4, 11, 3, 5], /* closure_at_stk[4], stk[3].get(literals[11]) -> stk[5] */
/*47*/ ["_OP_DLOAD", 4, 6, 19, 7, 20], /* stk[6] <- literals[19]("Unknown token "([^
]-)"%.") */ /* stk[7] <- literals[20] "%%token %1" */
/*48*/ ["_OP_CALL", 6, 4, 4, 5, 3], /* target[4], lvi[4]("lines"), stackbase(5), nargs(3) */
/*49*/ ["_OP_MOVE", 10, 3, 4, 0, 0], /* stk[3] <- lvi[4]("lines") */
/*50*/ ["_OP_PREPCALLK", 8, 4, 21, 3, 5], /* closure_at_stk[4], stk[3].get(literals[21]) -> stk[5] */
/*51*/ ["_OP_LOADINT", 2, 6, 10, 0, 0], /* stk[6] <- arg1(10) */
/*52*/ ["_OP_CALL", 6, 4, 4, 5, 2], /* target[4], lvi[4]("lines"), stackbase(5), nargs(2) */
/*53*/ ["_OP_PREPCALLK", 8, 5, 22, 4, 6], /* closure_at_stk[5], stk[4].get(literals[22]) -> stk[6] */
/*54*/ ["_OP_CLOSURE", 48, 7, 1, 1, 0], /* stk_at_arg0[7] <- functions[1](null), isLanbda(1) */
/*55*/ ["_OP_CALL", 6, 255, 5, 6, 2], /* target[255], lvi[5]("prevLine"), stackbase(6), nargs(2) */
/*56*/ ["_OP_LOADNULLS", 24, 5, 1, 0, 0], /* stk_at_arg0[5.. (arg0 + arg1(1))] = null */
/*57*/ ["_OP_LOADNULLS", 24, 6, 3, 0, 0], /* stk_at_arg0[6.. (arg0 + arg1(3))] = null */
/*58*/ ["_OP_FOREACH", 51, 4, 9, 6, 0],
/*59*/ ["_OP_POSTFOREACH", 52, 4, 9, 6, 0],
/*60*/ ["_OP_EQ", 15, 9, 5, 7, 0], /* stk_at_arg0[9] = stk_at_arg2[7] == (arg3(0) !=0 ? literals_at_arg1[5] : stk_at_arg1[5]) */
/*61*/ ["_OP_JZ", 30, 9, 1, 0, 0], /* IsFalse(STK(9) (ci->_ip+=(1) -> goto[63]) */
/*62*/ ["_OP_JMP", 28, 0, -5, 0, 0], /* (ci->_ip+=(-5)) -> goto[58] */
/*63*/ ["_OP_MOVE", 10, 5, 7, 0, 0], /* stk[5] <- lvi[7]("line") */
/*64*/ ["_OP_PREPCALLK", 8, 9, 1, 0, 10], /* closure_at_stk[9], stk[0].get(literals[1]) -> stk[10] */
/*65*/ ["_OP_MOVE", 10, 11, 7, 0, 0], /* stk[11] <- lvi[7]("line") */
/*66*/ ["_OP_CALL", 6, 255, 9, 10, 2], /* target[255], lvi[9]("?"), stackbase(10), nargs(2) */
/*67*/ ["_OP_JMP", 28, 0, -10, 0, 0], /* (ci->_ip+=(-10)) -> goto[58] */
/*68*/ ["_OP_RETURN", 23, 255, 0, 0, 0], /* _arg0(255) != 255 ? stk[0] : null */
],
functions = [
/*function 0*/{
source_name = "_fix-non-terminal.nut",
function_name = null,
function_return_type = null,
literals = [
/*0*/ "format",
/*1*/ [==["%s" %s]==],
/*2*/ "slice",
/*3*/ -1,
/*4*/ "%s %s",
],
parameters = [
/*0*/ "this",
/*1*/ "m",
],
outervalues = [
//[type, src, name],
],
localvarinfos = [
//[pos, name, start_op, end_op, scope, type, type_name, dtype_name],
/*0*/ [0, "this", 0, 19, 1, 1, "ANY", ""],
/*1*/ [1, "m", 0, 19, 1, 1, "ANY", ""],
],
lineinfos = [
//[op, line],
/*0*/ [0, 17], /*_OP_LOADINT*/
/*1*/ [0, 18], /*_OP_LOADINT*/
/*2*/ [14, 19], /*_OP_PREPCALLK*/
/*3*/ [19, 20], /*_OP_RETURN*/
],
defaultparams = [],
instructions = [ /*stack*/
//[op_str, op, arg0, arg1, arg2, arg3],
/*0*/ ["_OP_LOADINT", 2, 2, 0, 0, 0], /* stk[2] <- arg1(0) */
/*1*/ ["_OP_GET", 14, 2, 1, 2, 0], /* stk_at_arg0[2] = stk_at_arg1[1].get(stk_at_arg2(2)) */
/*2*/ ["_OP_LOADINT", 2, 3, 39, 0, 0], /* stk[3] <- arg1(39) */
/*3*/ ["_OP_EQ", 15, 2, 3, 2, 0], /* stk_at_arg0[2] = stk_at_arg2[2] == (arg3(0) !=0 ? literals_at_arg1[3] : stk_at_arg1[3]) */
/*4*/ ["_OP_JZ", 30, 2, 9, 0, 0], /* IsFalse(STK(2) (ci->_ip+=(9) -> goto[14]) */
/*5*/ ["_OP_PREPCALLK", 8, 2, 0, 0, 3], /* closure_at_stk[2], stk[0].get(literals[0]) -> stk[3] */
/*6*/ ["_OP_DLOAD", 4, 4, 1, 5, 2], /* stk[4] <- literals[1](""%s" %s") */ /* stk[5] <- literals[2] "slice" */
/*7*/ ["_OP_PREPCALL", 7, 5, 5, 1, 6], /* closure_at_stk[5], stk[1].get(stk[5]) -> stk[6] */
/*8*/ ["_OP_LOADINT", 2, 7, 1, 0, 0], /* stk[7] <- arg1(1) */
/*9*/ ["_OP_LOAD", 1, 8, 3, 0, 0], /* stk[8] <- literals[3]("?") */
/*10*/ ["_OP_CALL", 6, 5, 5, 6, 3], /* target[5], lvi[5]("?"), stackbase(6), nargs(3) */
/*11*/ ["_OP_MOVE", 10, 6, 1, 0, 0], /* stk[6] <- lvi[1]("m") */
/*12*/ ["_OP_TAILCALL", 5, 2, 2, 3, 4],
/*13*/ ["_OP_RETURN", 23, 1, 2, 3, 0], /* _arg0(1) != 255 ? stk[2] : null */
/*14*/ ["_OP_PREPCALLK", 8, 2, 0, 0, 3], /* closure_at_stk[2], stk[0].get(literals[0]) -> stk[3] */
/*15*/ ["_OP_LOAD", 1, 4, 4, 0, 0], /* stk[4] <- literals[4]("%s %s") */
/*16*/ ["_OP_DMOVE", 27, 5, 1, 6, 1], /* stk[5] <- lvi[1]("m"), stk[6] <- lvi[1]("m") */
/*17*/ ["_OP_TAILCALL", 5, 2, 2, 3, 4],
/*18*/ ["_OP_RETURN", 23, 1, 2, 3, 0], /* _arg0(1) != 255 ? stk[2] : null */
/*19*/ ["_OP_RETURN", 23, 255, 0, 0, 0], /* _arg0(255) != 255 ? stk[0] : null */
],
functions = [
],
stacksize = 9,
bgenerator = 0,
varparams = 0,
},
/*function 1*/{
source_name = "_fix-non-terminal.nut",
function_name = null,
function_return_type = null,
literals = [
],
parameters = [
/*0*/ "this",
/*1*/ "a",
/*2*/ "b",
],
outervalues = [
//[type, src, name],
],
localvarinfos = [
//[pos, name, start_op, end_op, scope, type, type_name, dtype_name],
/*0*/ [0, "this", 0, 2, 1, 1, "ANY", ""],
/*1*/ [1, "a", 0, 2, 1, 1, "ANY", ""],
/*2*/ [2, "b", 0, 2, 1, 1, "ANY", ""],
],
lineinfos = [
//[op, line],
/*0*/ [2, 24], /*_OP_RETURN*/
],
defaultparams = [],
instructions = [ /*stack*/
//[op_str, op, arg0, arg1, arg2, arg3],
/*0*/ ["_OP_CMP", 40, 3, 2, 1, 5],
/*1*/ ["_OP_RETURN", 23, 1, 3, 0, 0], /* _arg0(1) != 255 ? stk[3] : null */
/*2*/ ["_OP_RETURN", 23, 255, 0, 0, 0], /* _arg0(255) != 255 ? stk[0] : null */
],
functions = [
],
stacksize = 4,
bgenerator = 0,
varparams = 0,
},
],
stacksize = 12,
bgenerator = 0,
varparams = 1,
}
Hello ! Is it possible to have a description of squirrel opcodes ?
I'm trying to dump the compiled code to be manipulated by a script but I'm having some trouble to understand it by looking at the compiler/sqmv files.
Cheers !
For example in lua lopcodes.h, it's also a bit crypt but better than nothing: