1 Star 3 Fork 0

ValKmjolnir/nas-sharp

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
nas_vm.h 15.12 KB
一键复制 编辑 原始数据 按行查看 历史
Valk Richard Li 提交于 2021-04-14 17:11 +08:00 . change scope from map to vector
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
#ifndef __NAS_VM_H__
#define __NAS_VM_H__
// loop mark
bool loop_mark;
// constant pool
std::vector<nas_val*> num_addrs;
std::vector<nas_val*> str_addrs;
std::vector<std::string> rt_str_table;
// program counter
int pc;
// memory
std::stack<nas_val**> mem_stack;
// function call
std::stack<unsigned int> return_address;
void runtime_error(std::string opname,std::string info)
{
loop_mark=false;
std::cout<<">> [vm] "<<opname<<": "<<info<<".\n";
return;
}
void opr_nop()
{
loop_mark=false;
return;
}
void opr_nil()
{
*(++stack_top)=*val_stack;
return;
}
void opr_pushn()
{
*(++stack_top)=num_addrs[exec_code[pc].num];
return;
}
void opr_pushs()
{
*(++stack_top)=str_addrs[exec_code[pc].num];
return;
}
void opr_pushv()
{
*(++stack_top)=gc_alloc(vm_vec);
return;
}
void opr_pushh()
{
*(++stack_top)=gc_alloc(vm_hash);
return;
}
void opr_pushf()
{
*(++stack_top)=gc_alloc(vm_func);
if(!local_scope.empty())
(*stack_top)->ptr.func->scope=local_scope.front();
(*stack_top)->ptr.func->entry=exec_code[pc].num;
return;
}
void opr_vapp()
{
nas_val* vec=*(stack_top-exec_code[pc].num);
for(nas_val** i=stack_top-exec_code[pc].num+1;i<=stack_top;++i)
vec->ptr.vec->elems.push_back(*i);
stack_top-=exec_code[pc].num;
return;
}
void opr_happ()
{
nas_val* tmp=*stack_top--;
(*stack_top)->ptr.hash->elems[rt_str_table[exec_code[pc].num]]=tmp;
return;
}
void opr_para()
{
(*stack_top)->ptr.func->para.push_back(exec_code[pc].num);
return;
}
void opr_dynpara()
{
(*stack_top)->ptr.func->dynpara=exec_code[pc].num;
return;
}
void opr_intg()
{
global_scope.resize(exec_code[pc].num);
// load builtin
for(int i=0;builtin_func[i].func_name;++i)
{
nas_val* new_builtin=gc_alloc(vm_func);
new_builtin->ptr.func->is_builtin=true;
new_builtin->ptr.func->entry=i;
global_scope[i]=new_builtin;
}
return;
}
void opr_intl()
{
(*stack_top)->ptr.func->scope.resize(exec_code[pc].num);
return;
}
void opr_loadg()
{
global_scope[exec_code[pc].num]=*stack_top--;
return;
}
void opr_loadl()
{
local_scope.front()[exec_code[pc].num]=*stack_top--;
return;
}
void opr_callg()
{
*(++stack_top)=global_scope[exec_code[pc].num];
return;
}
void opr_calll()
{
*(++stack_top)=local_scope.front()[exec_code[pc].num];
return;
}
void opr_callv()
{
nas_val* tmp=*stack_top--;
nas_val* res=nullptr;
if((*stack_top)->type!=vm_vec && (*stack_top)->type!=vm_hash && (*stack_top)->type!=vm_str)
{
runtime_error("callv","must call a vector,string or hash");
return;
}
if((*stack_top)->type==vm_vec || (*stack_top)->type==vm_str)
{
if(tmp->type!=vm_num)
{
runtime_error("callv[vec/str]","index must be a number");
return;
}
if((*stack_top)->type==vm_vec)
res=(*stack_top)->ptr.vec->get_val(tmp->ptr.num);
else
{
int index=tmp->ptr.num;
int len=(*stack_top)->ptr.str->length();
if(index<0 || index>=len)
{
runtime_error("callv[str]","index out of range");
return;
}
res=gc_alloc(vm_str);
*res->ptr.str=(*(*stack_top)->ptr.str)[index];
*stack_top=res;
return;
}
}
else
{
if(tmp->type!=vm_str)
{
runtime_error("callv[hash]","key must be a string");
return;
}
res=(*stack_top)->ptr.hash->get_val(*tmp->ptr.str);
}
if(!res)
{
loop_mark=false;
return;
}
*stack_top=res;
return;
}
void opr_callh()
{
if((*stack_top)->type!=vm_hash)
{
runtime_error("callh","must call a hash");
return;
}
nas_val* tmp=(*stack_top)->ptr.hash->get_val(rt_str_table[exec_code[pc].num]);
if(!tmp)
{
loop_mark=false;
return;
}
*stack_top=tmp;
return;
}
void opr_callf()
{
nas_val* vec=*stack_top;
nas_val* func=*(stack_top-1);
// reserve arg_vec and func on the stack to avoid being collected
if(func->type!=vm_func)
{
runtime_error("callf","must call a function");
return;
}
if(func->ptr.func->is_builtin)
{
nas_val* ret=builtin_func[func->ptr.func->entry].func_ptr(vec);
loop_mark=(ret!=0);
*(--stack_top)=ret;
return;
}
return_address.push(pc);
pc=func->ptr.func->entry-1;
local_scope.push_front(func->ptr.func->scope);
// load parameter
std::vector<nas_val*>& paras=vec->ptr.vec->elems;
std::vector<int>& para_index=func->ptr.func->para;
int dynpara=func->ptr.func->dynpara;
int arg_size=paras.size();
int argindex_size=para_index.size();
if(arg_size<argindex_size)
{
runtime_error("callf","lack argument(s)");
return;
}
for(int i=0;i<argindex_size;++i)
local_scope.front()[para_index[i]]=paras[i];
if(dynpara>=0)
{
nas_val* dyn=gc_alloc(vm_vec);
for(int i=argindex_size;i<arg_size;++i)
dyn->ptr.vec->elems.push_back(paras[i]);
local_scope.front()[dynpara]=dyn;
}
return;
}
void opr_mcallg()
{
mem_stack.push(&global_scope[exec_code[pc].num]);
return;
}
void opr_mcalll()
{
mem_stack.push(&local_scope.front()[exec_code[pc].num]);
return;
}
void opr_mcallv()
{
nas_val* tmp=*stack_top--;
nas_val** mem=mem_stack.top();
nas_val** res=nullptr;
if((*mem)->type!=vm_vec && (*mem)->type!=vm_hash)
{
runtime_error("mcallv","must call a vector or hash");
return;
}
if((*mem)->type==vm_vec)
{
if(tmp->type!=vm_num)
{
runtime_error("mcallv[vec]","index must be a number");
return;
}
res=(*mem)->ptr.vec->get_mem(tmp->ptr.num);
}
else
{
if(tmp->type!=vm_str)
{
runtime_error("mcallv[hash]","key must be a string");
return;
}
res=(*mem)->ptr.hash->get_mem(*tmp->ptr.str);
}
if(!res)
{
loop_mark=false;
return;
}
mem_stack.top()=res;
return;
}
void opr_mcallh()
{
nas_val** mem=mem_stack.top();
if((*mem)->type!=vm_hash)
{
runtime_error("mcallh","must call a hash");
return;
}
nas_val** res=(*mem)->ptr.hash->get_mem(rt_str_table[exec_code[pc].num]);
if(!res)
{
loop_mark=false;
return;
}
mem_stack.top()=res;
return;
}
void opr_neg()
{
nas_val* tmp=*stack_top;
double num=0;
if(tmp->type==vm_num)
num=-tmp->ptr.num;
*stack_top=gc_alloc(vm_num);
(*stack_top)->ptr.num=num;
return;
}
void opr_not()
{
nas_val* tmp=*stack_top;
double num=0;
if(tmp->type==vm_num)
num=!tmp->ptr.num;
else if(tmp->type==vm_str)
num=!tmp->ptr.str->length();
*stack_top=gc_alloc(vm_num);
(*stack_top)->ptr.num=num;
return;
}
void opr_plus()
{
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top--;
nas_val* num1=*stack_top;
res->ptr.num=num1->ptr.num+num2->ptr.num;
*stack_top=res;
return;
}
void opr_minus()
{
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top--;
nas_val* num1=*stack_top;
res->ptr.num=num1->ptr.num-num2->ptr.num;
*stack_top=res;
return;
}
void opr_mult()
{
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top--;
nas_val* num1=*stack_top;
res->ptr.num=num1->ptr.num*num2->ptr.num;
*stack_top=res;
return;
}
void opr_div()
{
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top--;
nas_val* num1=*stack_top;
res->ptr.num=num1->ptr.num/num2->ptr.num;
*stack_top=res;
return;
}
void opr_lnk()
{
nas_val* res=gc_alloc(vm_str);
nas_val* num2=*stack_top--;
nas_val* num1=*stack_top;
if(num1->type!=vm_str || num2->type!=vm_str)
{
runtime_error("lnk","only strinsg can take part in this calculation");
return;
}
*res->ptr.str=(*num1->ptr.str)+(*num2->ptr.str);
*stack_top=res;
return;
}
void opr_meq()
{
*mem_stack.top()=*stack_top;
mem_stack.pop();
return;
}
void opr_pluseq()
{
nas_val** mem=mem_stack.top();
mem_stack.pop();
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top;
nas_val* num1=*mem;
res->ptr.num=num1->ptr.num+num2->ptr.num;
*mem=res;
return;
}
void opr_minuseq()
{
nas_val** mem=mem_stack.top();
mem_stack.pop();
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top;
nas_val* num1=*mem;
res->ptr.num=num1->ptr.num-num2->ptr.num;
*mem=res;
return;
}
void opr_lnkeq()
{
nas_val** mem=mem_stack.top();
mem_stack.pop();
nas_val* res=gc_alloc(vm_str);
nas_val* num2=*stack_top;
nas_val* num1=*mem;
if(num1->type!=vm_str || num2->type!=vm_str)
{
runtime_error("lnkeq","only strinsg can take part in this calculation");
return;
}
*res->ptr.str=(*num1->ptr.str)+(*num2->ptr.str);
*mem=res;
return;
}
void opr_multeq()
{
nas_val** mem=mem_stack.top();
mem_stack.pop();
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top;
nas_val* num1=*mem;
res->ptr.num=num1->ptr.num*num2->ptr.num;
*mem=res;
return;
}
void opr_diveq()
{
nas_val** mem=mem_stack.top();
mem_stack.pop();
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top;
nas_val* num1=*mem;
res->ptr.num=num1->ptr.num/num2->ptr.num;
*mem=res;
return;
}
void opr_eq()
{
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top--;
nas_val* num1=*stack_top;
if(num1->type!=num2->type)
res->ptr.num=(0);
else if(num1->type==vm_num && num2->type==vm_num)
res->ptr.num=(num1->ptr.num==num2->ptr.num);
else if(num1->type==vm_str && num2->type==vm_str)
res->ptr.num=(*num1->ptr.str==*num2->ptr.str);
else
res->ptr.num=(num1==num2);
*stack_top=res;
return;
}
void opr_neq()
{
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top--;
nas_val* num1=*stack_top;
if(num1->type!=num2->type)
res->ptr.num=1;
else if(num1->type==vm_num && num2->type==vm_num)
res->ptr.num=(num1->ptr.num!=num2->ptr.num);
else if(num1->type==vm_str && num2->type==vm_str)
res->ptr.num=(*num1->ptr.str!=*num2->ptr.str);
else
res->ptr.num=(num1!=num2);
*stack_top=res;
return;
}
void opr_less()
{
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top--;
nas_val* num1=*stack_top;
if(num1->type==vm_num && num2->type==vm_num)
res->ptr.num=(num1->ptr.num<num2->ptr.num);
else if(num1->type==vm_str && num2->type==vm_str)
res->ptr.num=(*num1->ptr.str<*num2->ptr.str);
else
runtime_error("less","only number and string can take part in this calculation");
*stack_top=res;
return;
}
void opr_leq()
{
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top--;
nas_val* num1=*stack_top;
if(num1->type==vm_num && num2->type==vm_num)
res->ptr.num=(num1->ptr.num<=num2->ptr.num);
else if(num1->type==vm_str && num2->type==vm_str)
res->ptr.num=(*num1->ptr.str<=*num2->ptr.str);
else
runtime_error("leq","only number and string can take part in this calculation");
*stack_top=res;
return;
}
void opr_grt()
{
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top--;
nas_val* num1=*stack_top;
if(num1->type==vm_num && num2->type==vm_num)
res->ptr.num=(num1->ptr.num>num2->ptr.num);
else if(num1->type==vm_str && num2->type==vm_str)
res->ptr.num=(*num1->ptr.str>*num2->ptr.str);
else
runtime_error("grt","only number and string can take part in this calculation");
*stack_top=res;
return;
}
void opr_geq()
{
nas_val* res=gc_alloc(vm_num);
nas_val* num2=*stack_top--;
nas_val* num1=*stack_top;
if(num1->type==vm_num && num2->type==vm_num)
res->ptr.num=(num1->ptr.num>=num2->ptr.num);
else if(num1->type==vm_str && num2->type==vm_str)
res->ptr.num=(*num1->ptr.str>=*num2->ptr.str);
else
runtime_error("geq","only number and string can take part in this calculation");
*stack_top=res;
return;
}
void opr_pop()
{
--stack_top;
return;
}
void opr_jmp()
{
pc=exec_code[pc].num-1;
return;
}
void opr_jt()
{
nas_val* tmp=*stack_top--;
if(tmp->type==vm_num && tmp->ptr.num)
pc=exec_code[pc].num-1;
return;
}
void opr_jf()
{
nas_val* tmp=*stack_top--;
if(tmp->type==vm_num && !tmp->ptr.num)
pc=exec_code[pc].num-1;
else if(tmp->type==vm_nil)
pc=exec_code[pc].num-1;
return;
}
void opr_ret()
{
pc=return_address.top();
return_address.pop();
local_scope.pop_front();
nas_val* tmp=*stack_top--;
*(--stack_top)=tmp;
return;
}
void init_vm()
{
gc_init();
loop_mark=true;
stack_top=val_stack;
*stack_top=gc_alloc(vm_nil); // set nil in the beginning space to avoid errors
num_addrs.resize(number_table.size());
for(auto i=number_table.begin();i!=number_table.end();++i)
{
nas_val* num=new nas_val(vm_num);
num->ptr.num=i->first;
num_addrs[i->second]=num;
}
number_table.clear();
str_addrs.resize(string_table.size());
rt_str_table.resize(string_table.size());
for(auto i=string_table.begin();i!=string_table.end();++i)
{
nas_val* str=new nas_val(vm_str);
*str->ptr.str=i->first;
str_addrs[i->second]=str;
rt_str_table[i->second]=i->first;
}
string_table.clear();
return;
}
void clear_vm()
{
gc_clean();
while(!mem_stack.empty())
mem_stack.pop();
while(!return_address.empty())
return_address.pop();
for(auto i=num_addrs.begin();i!=num_addrs.end();++i)
delete *i;
for(auto i=str_addrs.begin();i!=str_addrs.end();++i)
delete *i;
num_addrs.clear();
str_addrs.clear();
rt_str_table.clear();
return;
}
void run_vm()
{
static void (*func[])()=
{
&opr_nop,
&opr_nil,
&opr_pushn,
&opr_pushs,
&opr_pushv,
&opr_pushh,
&opr_pushf,
&opr_vapp,
&opr_happ,
&opr_para,
&opr_dynpara,
&opr_intg,
&opr_intl,
&opr_loadg,
&opr_loadl,
&opr_callg,
&opr_calll,
&opr_callv,
&opr_callh,
&opr_callf,
&opr_mcallg,
&opr_mcalll,
&opr_mcallv,
&opr_mcallh,
&opr_neg,
&opr_not,
&opr_plus,
&opr_minus,
&opr_mult,
&opr_div,
&opr_lnk,
&opr_meq,
&opr_pluseq,
&opr_minuseq,
&opr_lnkeq,
&opr_multeq,
&opr_diveq,
&opr_eq,
&opr_neq,
&opr_less,
&opr_leq,
&opr_grt,
&opr_geq,
&opr_pop,
&opr_jmp,
&opr_jt,
&opr_jf,
&opr_ret,
};
init_vm();
clock_t begin_time=clock();
for(pc=0;loop_mark;++pc)
(*func[exec_code[pc].op])();
float total_run_time=((double)(clock()-begin_time))/CLOCKS_PER_SEC;
std::cout<<">> [vm] process exited after "<<total_run_time<<"s.\n";
clear_vm();
return;
}
#endif
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/valkmjolnir/nas-sharp.git
[email protected]:valkmjolnir/nas-sharp.git
valkmjolnir
nas-sharp
nas-sharp
master

搜索帮助