🐛 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:
ValKmjolnir 2023-04-23 00:02:39 +08:00
parent 94f7c941f6
commit c858afbb76
6 changed files with 406 additions and 381 deletions

View File

@ -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).

View File

@ -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
View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 },

View File

@ -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;
}