🐛 fix compilation error
in windows mingw-w64 win32 thread model, but we do not suggest you to use this, please use posix thread model
This commit is contained in:
parent
94f7c941f6
commit
c858afbb76
|
@ -74,6 +74,8 @@ Use g++/clang++ on `Linux/macOS/Unix` platform (we suggest `clang`).
|
|||
|
||||
On `Windows (MinGW-w64)`:
|
||||
|
||||
Make sure your MinGW thread model is `posix thread model`, otherwise it may not have the thread library.
|
||||
|
||||
> mingw32-make nasal.exe
|
||||
|
||||
You could create project in `Visual Studio` by this way: [__Click__](./doc/vs.md).
|
||||
|
|
|
@ -65,6 +65,8 @@ __注意__: 如果你想直接下载发行版提供的zip/tar.gz压缩包来构
|
|||
|
||||
`Windows` 平台(`MinGW-w64`):
|
||||
|
||||
一定要确保您的 MinGW thread model 是 `posix thread model`, 否则可能存在没有 thread 库的问题。
|
||||
|
||||
> mingw32-make nasal.exe
|
||||
|
||||
你也可以在`Visual Studio`中用这种方式来创建项目:[__点击跳转__](../doc/vs.md)。
|
||||
|
|
325
main.cpp
325
main.cpp
|
@ -1,163 +1,164 @@
|
|||
#include "nasal.h"
|
||||
#include "nasal_err.h"
|
||||
#include "nasal_lexer.h"
|
||||
#include "nasal_ast.h"
|
||||
#include "nasal_parse.h"
|
||||
#include "nasal_import.h"
|
||||
#include "nasal_opt.h"
|
||||
#include "nasal_gc.h"
|
||||
#include "nasal_builtin.h"
|
||||
#include "nasal_codegen.h"
|
||||
#include "nasal_vm.h"
|
||||
#include "nasal_dbg.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
const u32 VM_AST =0x01;
|
||||
const u32 VM_CODE =0x02;
|
||||
const u32 VM_TIME =0x04;
|
||||
const u32 VM_EXEC =0x08;
|
||||
const u32 VM_DETAIL=0x10;
|
||||
const u32 VM_DEBUG =0x20;
|
||||
|
||||
std::ostream& help(std::ostream& out) {
|
||||
out
|
||||
<<" ,--#-,\n"
|
||||
<<"<3 / \\____\\ <3\n"
|
||||
<<" |_|__A_|\n"
|
||||
#ifdef _WIN32
|
||||
<<"use command <chcp 65001> to use unicode.\n"
|
||||
#endif
|
||||
<<"\nnasal <option>\n"
|
||||
<<"option:\n"
|
||||
<<" -h, --help | get help.\n"
|
||||
<<"\nnasal [option] <file> [argv]\n"
|
||||
<<"option:\n"
|
||||
<<" -a, --ast | view abstract syntax tree.\n"
|
||||
<<" -c, --code | view bytecode.\n"
|
||||
<<" -e, --exec | execute.\n"
|
||||
<<" -t, --time | show execute time.\n"
|
||||
<<" -d, --detail | get detail info.\n"
|
||||
<<" -dbg, --debug | debug mode.\n"
|
||||
<<"file:\n"
|
||||
<<" <filename> | execute file.\n"
|
||||
<<"argv:\n"
|
||||
<<" <args> | cmd arguments used in program.\n";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& logo(std::ostream& out) {
|
||||
out
|
||||
<<" __ _\n"
|
||||
<<" /\\ \\ \\__ _ ___ __ _| |\n"
|
||||
<<" / \\/ / _` / __|/ _` | |\n"
|
||||
<<" / /\\ / (_| \\__ \\ (_| | |\n"
|
||||
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
||||
<<"ver : "<<__nasver<<" ("<<__DATE__<<" "<<__TIME__<<")\n"
|
||||
<<"std : c++ "<<__cplusplus<<"\n"
|
||||
<<"repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
||||
<<"repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
|
||||
<<"wiki : https://wiki.flightgear.org/Nasal_scripting_language\n"
|
||||
<<"input <nasal -h> to get help .\n";
|
||||
return out;
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
void err() {
|
||||
std::cerr
|
||||
<<"invalid argument(s).\n"
|
||||
<<"use <nasal -h> to get help.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
void execute(const string& file,const std::vector<string>& argv,const u32 cmd) {
|
||||
using clk=std::chrono::high_resolution_clock;
|
||||
|
||||
error err;
|
||||
lexer lex(err);
|
||||
parse parse(err);
|
||||
linker ld(err);
|
||||
codegen gen(err);
|
||||
vm ctx;
|
||||
|
||||
// lexer scans file to get tokens
|
||||
lex.scan(file).chkerr();
|
||||
|
||||
// parser gets lexer's token list to compile
|
||||
parse.compile(lex).chkerr();
|
||||
|
||||
// linker gets parser's ast and load import files to this ast
|
||||
ld.link(parse,file,cmd&VM_DETAIL).chkerr();
|
||||
|
||||
// optimizer does simple optimization on ast
|
||||
optimize(parse.tree());
|
||||
if (cmd&VM_AST) {
|
||||
parse.tree().dump();
|
||||
}
|
||||
|
||||
// code generator gets parser's ast and linker's import file list to generate code
|
||||
gen.compile(parse,ld).chkerr();
|
||||
if (cmd&VM_CODE) {
|
||||
gen.print();
|
||||
}
|
||||
|
||||
// run
|
||||
if (cmd&VM_DEBUG) {
|
||||
dbg(err).run(gen,ld,argv);
|
||||
} else if (cmd&VM_TIME) {
|
||||
auto start=clk::now();
|
||||
ctx.run(gen,ld,argv,cmd&VM_DETAIL);
|
||||
auto end=clk::now();
|
||||
std::clog<<"process exited after "<<(end-start).count()*1.0/clk::duration::period::den<<"s.\n\n";
|
||||
} else if (cmd&VM_EXEC) {
|
||||
ctx.run(gen,ld,argv,cmd&VM_DETAIL);
|
||||
}
|
||||
}
|
||||
|
||||
i32 main(i32 argc,const char* argv[]) {
|
||||
// output version info
|
||||
if (argc<=1) {
|
||||
std::clog<<logo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// run directly or show help
|
||||
if (argc==2) {
|
||||
string s(argv[1]);
|
||||
if (s=="-h" || s=="--help") {
|
||||
std::clog<<help;
|
||||
} else if (s[0]!='-') {
|
||||
execute(s,{},VM_EXEC);
|
||||
} else {
|
||||
err();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// execute with arguments
|
||||
std::unordered_map<string,u32> cmdlst={
|
||||
{"--ast",VM_AST},{"-a",VM_AST},
|
||||
{"--code",VM_CODE},{"-c",VM_CODE},
|
||||
{"--exec",VM_EXEC},{"-e",VM_EXEC},
|
||||
{"--time",VM_TIME|VM_EXEC},{"-t",VM_TIME|VM_EXEC},
|
||||
{"--detail",VM_DETAIL|VM_EXEC},{"-d",VM_DETAIL|VM_EXEC},
|
||||
{"--debug",VM_DEBUG},{"-dbg",VM_DEBUG}
|
||||
};
|
||||
u32 cmd=0;
|
||||
string filename="";
|
||||
std::vector<string> vm_argv;
|
||||
for(i32 i=1;i<argc;++i) {
|
||||
if (cmdlst.count(argv[i])) {
|
||||
cmd|=cmdlst[argv[i]];
|
||||
} else if (!filename.length()) {
|
||||
filename=argv[i];
|
||||
} else {
|
||||
vm_argv.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
if (!filename.length()) {
|
||||
err();
|
||||
}
|
||||
execute(filename,vm_argv,cmd?cmd:VM_EXEC);
|
||||
return 0;
|
||||
#include "nasal.h"
|
||||
#include "nasal_err.h"
|
||||
#include "nasal_lexer.h"
|
||||
#include "nasal_ast.h"
|
||||
#include "nasal_parse.h"
|
||||
#include "nasal_import.h"
|
||||
#include "nasal_opt.h"
|
||||
#include "nasal_gc.h"
|
||||
#include "nasal_builtin.h"
|
||||
#include "nasal_codegen.h"
|
||||
#include "nasal_vm.h"
|
||||
#include "nasal_dbg.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
const u32 VM_AST =0x01;
|
||||
const u32 VM_CODE =0x02;
|
||||
const u32 VM_TIME =0x04;
|
||||
const u32 VM_EXEC =0x08;
|
||||
const u32 VM_DETAIL=0x10;
|
||||
const u32 VM_DEBUG =0x20;
|
||||
|
||||
std::ostream& help(std::ostream& out) {
|
||||
out
|
||||
<<" ,--#-,\n"
|
||||
<<"<3 / \\____\\ <3\n"
|
||||
<<" |_|__A_|\n"
|
||||
#ifdef _WIN32
|
||||
<<"use command <chcp 65001> to use unicode.\n"
|
||||
#endif
|
||||
<<"\nnasal <option>\n"
|
||||
<<"option:\n"
|
||||
<<" -h, --help | get help.\n"
|
||||
<<"\nnasal [option] <file> [argv]\n"
|
||||
<<"option:\n"
|
||||
<<" -a, --ast | view abstract syntax tree.\n"
|
||||
<<" -c, --code | view bytecode.\n"
|
||||
<<" -e, --exec | execute.\n"
|
||||
<<" -t, --time | show execute time.\n"
|
||||
<<" -d, --detail | get detail info.\n"
|
||||
<<" -dbg, --debug | debug mode.\n"
|
||||
<<"file:\n"
|
||||
<<" <filename> | execute file.\n"
|
||||
<<"argv:\n"
|
||||
<<" <args> | cmd arguments used in program.\n";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& logo(std::ostream& out) {
|
||||
out
|
||||
<<" __ _\n"
|
||||
<<" /\\ \\ \\__ _ ___ __ _| |\n"
|
||||
<<" / \\/ / _` / __|/ _` | |\n"
|
||||
<<" / /\\ / (_| \\__ \\ (_| | |\n"
|
||||
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
||||
<<"ver : "<<__nasver<<" ("<<__DATE__<<" "<<__TIME__<<")\n"
|
||||
<<"std : c++ "<<__cplusplus<<"\n"
|
||||
<<"repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
||||
<<"repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
|
||||
<<"wiki : https://wiki.flightgear.org/Nasal_scripting_language\n"
|
||||
<<"input <nasal -h> to get help .\n";
|
||||
return out;
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
void err() {
|
||||
std::cerr
|
||||
<<"invalid argument(s).\n"
|
||||
<<"use <nasal -h> to get help.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
void execute(const string& file,const std::vector<string>& argv,const u32 cmd) {
|
||||
using clk=std::chrono::high_resolution_clock;
|
||||
const auto den=clk::duration::period::den;
|
||||
|
||||
error err;
|
||||
lexer lex(err);
|
||||
parse parse(err);
|
||||
linker ld(err);
|
||||
codegen gen(err);
|
||||
vm ctx;
|
||||
|
||||
// lexer scans file to get tokens
|
||||
lex.scan(file).chkerr();
|
||||
|
||||
// parser gets lexer's token list to compile
|
||||
parse.compile(lex).chkerr();
|
||||
|
||||
// linker gets parser's ast and load import files to this ast
|
||||
ld.link(parse,file,cmd&VM_DETAIL).chkerr();
|
||||
|
||||
// optimizer does simple optimization on ast
|
||||
optimize(parse.tree());
|
||||
if (cmd&VM_AST) {
|
||||
parse.tree().dump();
|
||||
}
|
||||
|
||||
// code generator gets parser's ast and linker's import file list to generate code
|
||||
gen.compile(parse,ld).chkerr();
|
||||
if (cmd&VM_CODE) {
|
||||
gen.print();
|
||||
}
|
||||
|
||||
// run
|
||||
auto start=clk::now();
|
||||
if (cmd&VM_DEBUG) {
|
||||
dbg(err).run(gen,ld,argv);
|
||||
} else if (cmd&VM_TIME || cmd&VM_EXEC) {
|
||||
ctx.run(gen,ld,argv,cmd&VM_DETAIL);
|
||||
}
|
||||
if (cmd&VM_TIME) {
|
||||
f64 tm=(clk::now()-start).count()*1.0/den;
|
||||
std::clog<<"process exited after "<<tm<<"s.\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
i32 main(i32 argc,const char* argv[]) {
|
||||
// output version info
|
||||
if (argc<=1) {
|
||||
std::clog<<logo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// run directly or show help
|
||||
if (argc==2) {
|
||||
string s(argv[1]);
|
||||
if (s=="-h" || s=="--help") {
|
||||
std::clog<<help;
|
||||
} else if (s[0]!='-') {
|
||||
execute(s,{},VM_EXEC);
|
||||
} else {
|
||||
err();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// execute with arguments
|
||||
const std::unordered_map<string,u32> cmdlst={
|
||||
{"--ast",VM_AST},{"-a",VM_AST},
|
||||
{"--code",VM_CODE},{"-c",VM_CODE},
|
||||
{"--exec",VM_EXEC},{"-e",VM_EXEC},
|
||||
{"--time",VM_TIME|VM_EXEC},{"-t",VM_TIME|VM_EXEC},
|
||||
{"--detail",VM_DETAIL|VM_EXEC},{"-d",VM_DETAIL|VM_EXEC},
|
||||
{"--debug",VM_DEBUG},{"-dbg",VM_DEBUG}
|
||||
};
|
||||
u32 cmd=0;
|
||||
string filename="";
|
||||
std::vector<string> vm_argv;
|
||||
for(i32 i=1;i<argc;++i) {
|
||||
if (cmdlst.count(argv[i])) {
|
||||
cmd|=cmdlst.at(argv[i]);
|
||||
} else if (!filename.length()) {
|
||||
filename=argv[i];
|
||||
} else {
|
||||
vm_argv.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
if (!filename.length()) {
|
||||
err();
|
||||
}
|
||||
execute(filename,vm_argv,cmd?cmd:VM_EXEC);
|
||||
return 0;
|
||||
}
|
|
@ -777,7 +777,13 @@ var builtin_sleep(var* local,gc& ngc) {
|
|||
if (val.type!=vm_num) {
|
||||
return nil;
|
||||
}
|
||||
#if defined(_WIN32) && !defined(_GLIBCXX_HAS_GTHREADS)
|
||||
// mingw-w64 win32 thread model has no std::this_thread
|
||||
// also msvc will use this
|
||||
Sleep(i64(val.num()*1e3));
|
||||
#else
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(i64(val.num()*1e6)));
|
||||
#endif
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ private:
|
|||
string res;
|
||||
error& err;
|
||||
std::vector<token> toks;
|
||||
std::unordered_map<string,tok> typetbl {
|
||||
const std::unordered_map<string,tok> typetbl {
|
||||
{"true" ,tok::tktrue },
|
||||
{"false" ,tok::tkfalse },
|
||||
{"for" ,tok::rfor },
|
||||
|
|
450
nasal_opcode.h
450
nasal_opcode.h
|
@ -1,219 +1,233 @@
|
|||
#pragma once
|
||||
|
||||
#include "nasal.h"
|
||||
#include "nasal_builtin.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
enum op_code_type:u8 {
|
||||
op_exit, // stop the virtual machine
|
||||
op_intg, // global scope size, set stack top
|
||||
op_intl, // local scope size
|
||||
op_loadg, // load global value
|
||||
op_loadl, // load local value
|
||||
op_loadu, // load upvalue
|
||||
op_pnum, // push constant number to the stack
|
||||
op_pnil, // push constant nil to the stack
|
||||
op_pstr, // push constant string to the stack
|
||||
op_newv, // push new vector with initial values from stack
|
||||
op_newh, // push new hash to the stack
|
||||
op_newf, // push new function to the stack
|
||||
op_happ, // hash append
|
||||
op_para, // normal parameter
|
||||
op_deft, // default parameter
|
||||
op_dyn, // dynamic parameter
|
||||
op_lnot, // ! logical negation
|
||||
op_usub, // - negation
|
||||
op_bnot, // ~ bitwise not static_cast<i32>
|
||||
op_btor, // | bitwise or
|
||||
op_btxor, // ^ bitwise xor
|
||||
op_btand, // & bitwise and
|
||||
op_add, // +
|
||||
op_sub, // -
|
||||
op_mul, // *
|
||||
op_div, // /
|
||||
op_lnk, // ~
|
||||
op_addc, // + const
|
||||
op_subc, // - const
|
||||
op_mulc, // * const
|
||||
op_divc, // / const
|
||||
op_lnkc, // ~ const
|
||||
op_addeq, // += maybe pop stack top
|
||||
op_subeq, // -= maybe pop stack top
|
||||
op_muleq, // *= maybe pop stack top
|
||||
op_diveq, // /= maybe pop stack top
|
||||
op_lnkeq, // ~= maybe pop stack top
|
||||
op_btandeq,// &= maybe pop stack top
|
||||
op_btoreq, // |= maybe pop stack top
|
||||
op_btxoreq,// ^= maybe pop stack top
|
||||
op_addeqc, // += const don't pop stack top
|
||||
op_subeqc, // -= const don't pop stack top
|
||||
op_muleqc, // *= const don't pop stack top
|
||||
op_diveqc, // /= const don't pop stack top
|
||||
op_lnkeqc, // ~= const don't pop stack top
|
||||
op_addecp, // += const and pop stack top
|
||||
op_subecp, // -= const and pop stack top
|
||||
op_mulecp, // *= const and pop stack top
|
||||
op_divecp, // /= const and pop stack top
|
||||
op_lnkecp, // ~= concat const string and pop stack top
|
||||
op_meq, // = maybe pop stack top
|
||||
op_eq, // ==
|
||||
op_neq, // !=
|
||||
op_less, // <
|
||||
op_leq, // <=
|
||||
op_grt, // >
|
||||
op_geq, // >=
|
||||
op_lessc, // < const
|
||||
op_leqc, // <= const
|
||||
op_grtc, // > const
|
||||
op_geqc, // >= const
|
||||
op_pop, // pop a value out of stack top
|
||||
op_jmp, // jump absolute address with no condition
|
||||
op_jt, // used in operator and/or,jmp when condition is true and DO NOT POP
|
||||
op_jf, // used in conditional/loop,jmp when condition is false and POP STACK
|
||||
op_cnt, // add counter for forindex/foreach
|
||||
op_findex, // index counter on the top of forindex_stack plus 1
|
||||
op_feach, // index counter on the top of forindex_stack plus 1 and get the value in vector
|
||||
op_callg, // get value in global scope
|
||||
op_calll, // get value in local scope
|
||||
op_upval, // get upvalue in closure, high 16 as the index of upval, low 16 as the index of local
|
||||
op_callv, // call vec[index]
|
||||
op_callvi, // call vec[immediate] (used in multi-assign/multi-define)
|
||||
op_callh, // call hash.label
|
||||
op_callfv, // call function(vector as parameters)
|
||||
op_callfh, // call function(hash as parameters)
|
||||
op_callb, // call builtin-function
|
||||
op_slcbeg, // begin of slice like: vec[1,2,3:6,0,-1]
|
||||
op_slcend, // end of slice
|
||||
op_slc, // slice like vec[1]
|
||||
op_slc2, // slice like vec[nil:10]
|
||||
op_mcallg, // get memory space of value in global scope
|
||||
op_mcalll, // get memory space of value in local scope
|
||||
op_mupval, // get memory space of value in closure
|
||||
op_mcallv, // get memory space of vec[index]
|
||||
op_mcallh, // get memory space of hash.label
|
||||
op_ret // return
|
||||
};
|
||||
|
||||
const char* opname[]={
|
||||
"exit ","intg ","intl ","loadg ",
|
||||
"loadl ","loadu ","pnum ","pnil ",
|
||||
"pstr ","newv ","newh ","newf ",
|
||||
"happ ","para ","def ","dyn ",
|
||||
"lnot ","usub ","bnot ","btor ",
|
||||
"btxor ","btand ","add ","sub ",
|
||||
"mult ","div ","lnk ","addc ",
|
||||
"subc ","multc ","divc ","lnkc ",
|
||||
"addeq ","subeq ","muleq ","diveq ",
|
||||
"lnkeq ","bandeq","boreq ","bxoreq",
|
||||
"addeqc","subeqc","muleqc","diveqc",
|
||||
"lnkeqc","addecp","subecp","mulecp",
|
||||
"divecp","lnkecp","meq ","eq ",
|
||||
"neq ","less ","leq ","grt ",
|
||||
"geq ","lessc ","leqc ","grtc ",
|
||||
"geqc ","pop ","jmp ","jt ",
|
||||
"jf ","cnt ","findx ","feach ",
|
||||
"callg ","calll ","upval ","callv ",
|
||||
"callvi","callh ","callfv","callfh",
|
||||
"callb ","slcbeg","slcend","slc ",
|
||||
"slc2 ","mcallg","mcalll","mupval",
|
||||
"mcallv","mcallh","ret "
|
||||
};
|
||||
|
||||
struct opcode {
|
||||
u8 op; // opcode
|
||||
u16 fidx; // source code file index
|
||||
u32 num; // immediate num
|
||||
u32 line; // location line of source code
|
||||
opcode() = default;
|
||||
opcode(const opcode&) = default;
|
||||
opcode& operator=(const opcode&) = default;
|
||||
};
|
||||
|
||||
class codestream {
|
||||
private:
|
||||
opcode code;
|
||||
const u32 index;
|
||||
static const f64* nums;
|
||||
static const string* strs;
|
||||
static const string* files;
|
||||
public:
|
||||
codestream(const opcode& c,const u32 i):code(c),index(i) {}
|
||||
static void set(const f64*,const string*,const string*);
|
||||
void dump(std::ostream&) const;
|
||||
};
|
||||
|
||||
const f64* codestream::nums=nullptr;
|
||||
const string* codestream::strs=nullptr;
|
||||
const string* codestream::files=nullptr;
|
||||
|
||||
void codestream::set(const f64* numbuff,const string* strbuff,const string* filelist=nullptr) {
|
||||
nums=numbuff;
|
||||
strs=strbuff;
|
||||
files=filelist;
|
||||
}
|
||||
|
||||
void codestream::dump(std::ostream& out) const {
|
||||
using std::setw;
|
||||
using std::setfill;
|
||||
using std::hex;
|
||||
using std::dec;
|
||||
auto op=code.op;
|
||||
auto num=code.num;
|
||||
out<<hex<<"0x"
|
||||
<<setw(6)<<setfill('0')<<index<<" "
|
||||
<<setw(2)<<setfill('0')<<(u32)op<<" "
|
||||
<<setw(2)<<setfill('0')<<((num>>16)&0xff)<<" "
|
||||
<<setw(2)<<setfill('0')<<((num>>8)&0xff)<<" "
|
||||
<<setw(2)<<setfill('0')<<(num&0xff)<<" "
|
||||
<<opname[op]<<" "<<dec;
|
||||
switch(op) {
|
||||
case op_addeq: case op_subeq: case op_muleq: case op_diveq:
|
||||
case op_lnkeq: case op_meq: case op_btandeq: case op_btoreq:
|
||||
case op_btxoreq:
|
||||
out<<hex<<"0x"<<num<<dec<<" sp-"<<num;break;
|
||||
case op_addeqc:case op_subeqc: case op_muleqc:case op_diveqc:
|
||||
out<<hex<<"0x"<<num<<dec<<" ("<<nums[num]<<")";break;
|
||||
case op_lnkeqc:
|
||||
out<<hex<<"0x"<<num<<dec<<" ("<<rawstr(strs[num],16)<<")";break;
|
||||
case op_addecp:case op_subecp:case op_mulecp:case op_divecp:
|
||||
out<<hex<<"0x"<<num<<dec<<" ("<<nums[num]<<") sp-1";break;
|
||||
case op_lnkecp:
|
||||
out<<hex<<"0x"<<num<<dec<<" ("<<rawstr(strs[num],16)<<") sp-1";break;
|
||||
case op_addc: case op_subc: case op_mulc: case op_divc:
|
||||
case op_lessc: case op_leqc: case op_grtc: case op_geqc:
|
||||
case op_pnum:
|
||||
out<<hex<<"0x"<<num<<dec<<" ("<<nums[num]<<")";break;
|
||||
case op_callvi:case op_newv: case op_callfv:
|
||||
case op_intg: case op_intl:
|
||||
case op_findex:case op_feach:
|
||||
case op_newf: case op_jmp: case op_jt: case op_jf:
|
||||
case op_callg: case op_mcallg: case op_loadg:
|
||||
case op_calll: case op_mcalll: case op_loadl:
|
||||
out<<hex<<"0x"<<num<<dec;break;
|
||||
case op_callb:
|
||||
out<<hex<<"0x"<<num<<" <"<<builtin[num].name
|
||||
<<"@0x"<<(u64)builtin[num].func<<dec<<">";break;
|
||||
case op_upval: case op_mupval: case op_loadu:
|
||||
out<<hex<<"0x"<<((num>>16)&0xffff)
|
||||
<<"[0x"<<(num&0xffff)<<"]"<<dec;break;
|
||||
case op_happ: case op_pstr:
|
||||
case op_lnkc:
|
||||
case op_callh: case op_mcallh:
|
||||
case op_para: case op_deft: case op_dyn:
|
||||
out<<hex<<"0x"<<num<<dec<<" ("<<rawstr(strs[num],16)<<")";break;
|
||||
default:
|
||||
if (files) {
|
||||
out<<hex<<"0x"<<num<<dec;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (files) {
|
||||
out<<"("<<files[code.fidx]<<":"<<code.line<<")";
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out,const codestream& ins) {
|
||||
ins.dump(out);
|
||||
return out;
|
||||
#pragma once
|
||||
|
||||
#include "nasal.h"
|
||||
#include "nasal_builtin.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
enum op_code_type:u8 {
|
||||
op_exit, // stop the virtual machine
|
||||
op_intg, // global scope size, set stack top
|
||||
op_intl, // local scope size
|
||||
op_loadg, // load global value
|
||||
op_loadl, // load local value
|
||||
op_loadu, // load upvalue
|
||||
op_pnum, // push constant number to the stack
|
||||
op_pnil, // push constant nil to the stack
|
||||
op_pstr, // push constant string to the stack
|
||||
op_newv, // push new vector with initial values from stack
|
||||
op_newh, // push new hash to the stack
|
||||
op_newf, // push new function to the stack
|
||||
op_happ, // hash append
|
||||
op_para, // normal parameter
|
||||
op_deft, // default parameter
|
||||
op_dyn, // dynamic parameter
|
||||
op_lnot, // ! logical negation
|
||||
op_usub, // - negation
|
||||
op_bnot, // ~ bitwise not static_cast<i32>
|
||||
op_btor, // | bitwise or
|
||||
op_btxor, // ^ bitwise xor
|
||||
op_btand, // & bitwise and
|
||||
op_add, // +
|
||||
op_sub, // -
|
||||
op_mul, // *
|
||||
op_div, // /
|
||||
op_lnk, // ~
|
||||
op_addc, // + const
|
||||
op_subc, // - const
|
||||
op_mulc, // * const
|
||||
op_divc, // / const
|
||||
op_lnkc, // ~ const
|
||||
op_addeq, // += maybe pop stack top
|
||||
op_subeq, // -= maybe pop stack top
|
||||
op_muleq, // *= maybe pop stack top
|
||||
op_diveq, // /= maybe pop stack top
|
||||
op_lnkeq, // ~= maybe pop stack top
|
||||
op_btandeq,// &= maybe pop stack top
|
||||
op_btoreq, // |= maybe pop stack top
|
||||
op_btxoreq,// ^= maybe pop stack top
|
||||
op_addeqc, // += const don't pop stack top
|
||||
op_subeqc, // -= const don't pop stack top
|
||||
op_muleqc, // *= const don't pop stack top
|
||||
op_diveqc, // /= const don't pop stack top
|
||||
op_lnkeqc, // ~= const don't pop stack top
|
||||
op_addecp, // += const and pop stack top
|
||||
op_subecp, // -= const and pop stack top
|
||||
op_mulecp, // *= const and pop stack top
|
||||
op_divecp, // /= const and pop stack top
|
||||
op_lnkecp, // ~= concat const string and pop stack top
|
||||
op_meq, // = maybe pop stack top
|
||||
op_eq, // ==
|
||||
op_neq, // !=
|
||||
op_less, // <
|
||||
op_leq, // <=
|
||||
op_grt, // >
|
||||
op_geq, // >=
|
||||
op_lessc, // < const
|
||||
op_leqc, // <= const
|
||||
op_grtc, // > const
|
||||
op_geqc, // >= const
|
||||
op_pop, // pop a value out of stack top
|
||||
op_jmp, // jump absolute address with no condition
|
||||
op_jt, // used in operator and/or,jmp when condition is true and DO NOT POP
|
||||
op_jf, // used in conditional/loop,jmp when condition is false and POP STACK
|
||||
op_cnt, // add counter for forindex/foreach
|
||||
op_findex, // index counter on the top of forindex_stack plus 1
|
||||
op_feach, // index counter on the top of forindex_stack plus 1 and get the value in vector
|
||||
op_callg, // get value in global scope
|
||||
op_calll, // get value in local scope
|
||||
op_upval, // get value in closure, high 16 as the index of upval, low 16 as the index of local
|
||||
op_callv, // call vec[index]
|
||||
op_callvi, // call vec[immediate] (used in multi-assign/multi-define)
|
||||
op_callh, // call hash.label
|
||||
op_callfv, // call function(vector as parameters)
|
||||
op_callfh, // call function(hash as parameters)
|
||||
op_callb, // call builtin-function
|
||||
op_slcbeg, // begin of slice like: vec[1,2,3:6,0,-1]
|
||||
op_slcend, // end of slice
|
||||
op_slc, // slice like vec[1]
|
||||
op_slc2, // slice like vec[nil:10]
|
||||
op_mcallg, // get memory space of value in global scope
|
||||
op_mcalll, // get memory space of value in local scope
|
||||
op_mupval, // get memory space of value in closure
|
||||
op_mcallv, // get memory space of vec[index]
|
||||
op_mcallh, // get memory space of hash.label
|
||||
op_ret // return
|
||||
};
|
||||
|
||||
const char* opname[]={
|
||||
"exit ","intg ","intl ","loadg ",
|
||||
"loadl ","loadu ","pnum ","pnil ",
|
||||
"pstr ","newv ","newh ","newf ",
|
||||
"happ ","para ","def ","dyn ",
|
||||
"lnot ","usub ","bnot ","btor ",
|
||||
"btxor ","btand ","add ","sub ",
|
||||
"mult ","div ","lnk ","addc ",
|
||||
"subc ","multc ","divc ","lnkc ",
|
||||
"addeq ","subeq ","muleq ","diveq ",
|
||||
"lnkeq ","bandeq","boreq ","bxoreq",
|
||||
"addeqc","subeqc","muleqc","diveqc",
|
||||
"lnkeqc","addecp","subecp","mulecp",
|
||||
"divecp","lnkecp","meq ","eq ",
|
||||
"neq ","less ","leq ","grt ",
|
||||
"geq ","lessc ","leqc ","grtc ",
|
||||
"geqc ","pop ","jmp ","jt ",
|
||||
"jf ","cnt ","findx ","feach ",
|
||||
"callg ","calll ","upval ","callv ",
|
||||
"callvi","callh ","callfv","callfh",
|
||||
"callb ","slcbeg","slcend","slc ",
|
||||
"slc2 ","mcallg","mcalll","mupval",
|
||||
"mcallv","mcallh","ret "
|
||||
};
|
||||
|
||||
struct opcode {
|
||||
u8 op; // opcode
|
||||
u16 fidx; // source code file index
|
||||
u32 num; // immediate num
|
||||
u32 line; // location line of source code
|
||||
opcode() = default;
|
||||
opcode(const opcode&) = default;
|
||||
opcode& operator=(const opcode&) = default;
|
||||
};
|
||||
|
||||
class codestream {
|
||||
private:
|
||||
opcode code;
|
||||
const u32 index;
|
||||
static const f64* nums;
|
||||
static const string* strs;
|
||||
static const string* files;
|
||||
public:
|
||||
codestream(const opcode& c,const u32 i):code(c),index(i) {}
|
||||
static void set(const f64*,const string*,const string*);
|
||||
void dump(std::ostream&) const;
|
||||
};
|
||||
|
||||
const f64* codestream::nums=nullptr;
|
||||
const string* codestream::strs=nullptr;
|
||||
const string* codestream::files=nullptr;
|
||||
|
||||
void codestream::set(
|
||||
const f64* numbuff,
|
||||
const string* strbuff,
|
||||
const string* filelist=nullptr
|
||||
) {
|
||||
nums=numbuff;
|
||||
strs=strbuff;
|
||||
files=filelist;
|
||||
}
|
||||
|
||||
void codestream::dump(std::ostream& out) const {
|
||||
using std::setw;
|
||||
using std::setfill;
|
||||
using std::hex;
|
||||
using std::dec;
|
||||
auto op=code.op;
|
||||
auto num=code.num;
|
||||
out<<hex<<"0x"
|
||||
<<setw(6)<<setfill('0')<<index<<" "
|
||||
<<setw(2)<<setfill('0')<<(u32)op<<" "
|
||||
<<setw(2)<<setfill('0')<<((num>>16)&0xff)<<" "
|
||||
<<setw(2)<<setfill('0')<<((num>>8)&0xff)<<" "
|
||||
<<setw(2)<<setfill('0')<<(num&0xff)<<" "
|
||||
<<opname[op]<<" "<<dec;
|
||||
switch(op) {
|
||||
case op_addeq: case op_subeq:
|
||||
case op_muleq: case op_diveq:
|
||||
case op_lnkeq: case op_meq:
|
||||
case op_btandeq: case op_btoreq:
|
||||
case op_btxoreq:
|
||||
out<<hex<<"0x"<<num<<dec<<" sp-"<<num;break;
|
||||
case op_addeqc: case op_subeqc:
|
||||
case op_muleqc:case op_diveqc:
|
||||
out<<hex<<"0x"<<num<<dec<<" ("<<nums[num]<<")";break;
|
||||
case op_lnkeqc:
|
||||
out<<hex<<"0x"<<num<<dec<<" ("<<rawstr(strs[num],16)<<")";break;
|
||||
case op_addecp: case op_subecp:
|
||||
case op_mulecp: case op_divecp:
|
||||
out<<hex<<"0x"<<num<<dec<<" ("<<nums[num]<<") sp-1";break;
|
||||
case op_lnkecp:
|
||||
out<<hex<<"0x"<<num<<dec<<" ("<<rawstr(strs[num],16)<<") sp-1";break;
|
||||
case op_addc: case op_subc:
|
||||
case op_mulc: case op_divc:
|
||||
case op_lessc: case op_leqc:
|
||||
case op_grtc: case op_geqc:
|
||||
case op_pnum:
|
||||
out<<hex<<"0x"<<num<<dec<<" ("<<nums[num]<<")";break;
|
||||
case op_callvi: case op_newv:
|
||||
case op_callfv: case op_intg:
|
||||
case op_intl: case op_findex:
|
||||
case op_feach: case op_newf:
|
||||
case op_jmp: case op_jt:
|
||||
case op_jf: case op_callg:
|
||||
case op_mcallg: case op_loadg:
|
||||
case op_calll: case op_mcalll:
|
||||
case op_loadl:
|
||||
out<<hex<<"0x"<<num<<dec;break;
|
||||
case op_callb:
|
||||
out<<hex<<"0x"<<num<<" <"<<builtin[num].name
|
||||
<<"@0x"<<(u64)builtin[num].func<<dec<<">";break;
|
||||
case op_upval: case op_mupval:
|
||||
case op_loadu:
|
||||
out<<hex<<"0x"<<((num>>16)&0xffff)
|
||||
<<"[0x"<<(num&0xffff)<<"]"<<dec;break;
|
||||
case op_happ: case op_pstr:
|
||||
case op_lnkc: case op_callh:
|
||||
case op_mcallh: case op_para:
|
||||
case op_deft: case op_dyn:
|
||||
out<<hex<<"0x"<<num<<dec<<" ("<<rawstr(strs[num],16)<<")";break;
|
||||
default:
|
||||
if (files) {
|
||||
out<<hex<<"0x"<<num<<dec;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (files) {
|
||||
out<<"("<<files[code.fidx]<<":"<<code.line<<")";
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out,const codestream& ins) {
|
||||
ins.dump(out);
|
||||
return out;
|
||||
}
|
Loading…
Reference in New Issue