performance optimization of vm/lex/parse/test
This commit is contained in:
parent
ab99d2d1ed
commit
fd57e9a47c
|
@ -32,7 +32,7 @@ You could add your own built-in functions to change this interpreter to a useful
|
|||
|
||||
Better choose the latest update of the interpreter.
|
||||
|
||||
MUST USE -O2 ! pragma gcc optimize(2) seems useless when using g++
|
||||
MUST USE -O2/-O3 if want to optimize the interpreter! pragma gcc optimize(2) seems useless when using g++
|
||||
|
||||
> g++ -std=c++11 -O2 main.cpp -o nasal.exe
|
||||
|
||||
|
|
|
@ -234,7 +234,7 @@ std::string nasal_val::to_string()
|
|||
|
||||
struct nasal_gc
|
||||
{
|
||||
#define STACK_MAX_DEPTH (65536<<1)
|
||||
#define STACK_MAX_DEPTH (65536)
|
||||
nasal_val* zero_addr; // reserved address of nasal_val,type vm_num, 0
|
||||
nasal_val* one_addr; // reserved address of nasal_val,type vm_num, 1
|
||||
nasal_val* nil_addr; // reserved address of nasal_val,type vm_nil
|
||||
|
|
|
@ -104,7 +104,7 @@ private:
|
|||
std::vector<char> res;
|
||||
std::vector<token> token_list;
|
||||
int get_tok_type(std::string&);
|
||||
void die(std::string,int);
|
||||
void die(const char*);
|
||||
std::string id_gen();
|
||||
std::string num_gen();
|
||||
std::string str_gen();
|
||||
|
@ -147,13 +147,13 @@ int nasal_lexer::get_tok_type(std::string& tk_str)
|
|||
return tok_null;
|
||||
}
|
||||
|
||||
void nasal_lexer::die(std::string error_info,int line)
|
||||
void nasal_lexer::die(const char* error_info)
|
||||
{
|
||||
++error;
|
||||
std::cout<<">> [lexer] line "<<line<<" column "<<line_code.length()<<": \n"<<line_code<<"\n";
|
||||
for(auto i:line_code)
|
||||
std::cout<<(i=='\t'?'\t':' ');
|
||||
std::cout<<"^ "<<error_info<<'\n';
|
||||
std::cout<<"^"<<error_info<<'\n';
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -169,87 +169,60 @@ std::string nasal_lexer::id_gen()
|
|||
|
||||
std::string nasal_lexer::num_gen()
|
||||
{
|
||||
bool scientific_notation=false;// numbers like 1e8 are scientific_notation
|
||||
std::string token_str="";
|
||||
// generate hex number
|
||||
if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='x')
|
||||
{
|
||||
token_str="0x";
|
||||
std::string token_str="0x";
|
||||
ptr+=2;
|
||||
while(ptr<res_size && IS_HEX_NUMBER(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
if(token_str=="0x")
|
||||
{
|
||||
die("incorrect number.",line);
|
||||
return "0";
|
||||
}
|
||||
die("incorrect number.");
|
||||
return token_str;
|
||||
}
|
||||
// generate oct number
|
||||
else if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='o')
|
||||
{
|
||||
token_str="0o";
|
||||
std::string token_str="0o";
|
||||
ptr+=2;
|
||||
while(ptr<res_size && IS_OCT_NUMEBR(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
if(token_str=="0o")
|
||||
{
|
||||
die("incorrect number.",line);
|
||||
return "0";
|
||||
}
|
||||
die("incorrect number.");
|
||||
return token_str;
|
||||
}
|
||||
// generate dec number
|
||||
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
|
||||
std::string token_str="";
|
||||
while(ptr<res_size && IS_DIGIT(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
if(ptr<res_size && res[ptr]=='.')
|
||||
{
|
||||
token_str+=res[ptr++];
|
||||
// "xxxx." is not a correct number
|
||||
if(ptr>=res_size)
|
||||
{
|
||||
line_code+=token_str;
|
||||
die("incorrect number.",line);
|
||||
return "0";
|
||||
}
|
||||
while(ptr<res_size && IS_DIGIT(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
// "xxxx." is not a correct number
|
||||
if(token_str.back()=='.')
|
||||
{
|
||||
line_code+=token_str;
|
||||
die("incorrect number.",line);
|
||||
die("incorrect number.");
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
if(ptr<res_size && (res[ptr]=='e' || res[ptr]=='E'))
|
||||
{
|
||||
token_str+=res[ptr++];
|
||||
// "xxxe" is not a correct number
|
||||
if(ptr>=res_size)
|
||||
{
|
||||
line_code+=token_str;
|
||||
die("incorrect number.",line);
|
||||
return "0";
|
||||
}
|
||||
if(ptr<res_size && (res[ptr]=='-' || res[ptr]=='+'))
|
||||
token_str+=res[ptr++];
|
||||
if(ptr>=res_size)
|
||||
{
|
||||
line_code+=token_str;
|
||||
die("incorrect number.",line);
|
||||
return "0";
|
||||
}
|
||||
while(ptr<res_size && IS_DIGIT(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
// "xxxe(-|+)" is not a correct number
|
||||
if(token_str.back()=='e' || token_str.back()=='E' || token_str.back()=='-' || token_str.back()=='+')
|
||||
{
|
||||
line_code+=token_str;
|
||||
die("incorrect number.",line);
|
||||
die("incorrect number.");
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
|
@ -295,9 +268,9 @@ std::string nasal_lexer::str_gen()
|
|||
}
|
||||
// check if this string ends with a " or '
|
||||
if(ptr++>=res_size)
|
||||
die("get EOF when generating string.",line);
|
||||
if(str_begin=='`' && token_str.length()>1)
|
||||
die("\'`\' is used for string that includes one character.",line);
|
||||
die("get EOF when generating string.");
|
||||
if(str_begin=='`' && token_str.length()!=1)
|
||||
die("\'`\' is used for string that includes one character.");
|
||||
return token_str;
|
||||
}
|
||||
|
||||
|
@ -334,24 +307,21 @@ void nasal_lexer::scanner()
|
|||
else if(IS_DIGIT(res[ptr]))
|
||||
{
|
||||
token_str=num_gen();
|
||||
token new_token(line,tok_num,token_str);
|
||||
token_list.push_back(new_token);
|
||||
token_list.push_back({line,tok_num,token_str});
|
||||
}
|
||||
else if(IS_STRING(res[ptr]))
|
||||
{
|
||||
token_str=str_gen();
|
||||
token new_token(line,tok_str,token_str);
|
||||
token_list.push_back(new_token);
|
||||
token_list.push_back({line,tok_str,token_str});
|
||||
}
|
||||
else if(IS_SINGLE_OPERATOR(res[ptr]))
|
||||
{
|
||||
token_str="";
|
||||
token_str+=res[ptr];
|
||||
token_str=res[ptr];
|
||||
line_code+=res[ptr];
|
||||
token new_token(line,get_tok_type(token_str),token_str);
|
||||
if(!new_token.type)
|
||||
die("incorrect operator.",line);
|
||||
token_list.push_back(new_token);
|
||||
int type=get_tok_type(token_str);
|
||||
if(!type)
|
||||
die("incorrect operator.");
|
||||
token_list.push_back({line,type,token_str});
|
||||
++ptr;
|
||||
}
|
||||
else if(res[ptr]=='.')
|
||||
|
@ -367,8 +337,7 @@ void nasal_lexer::scanner()
|
|||
++ptr;
|
||||
}
|
||||
line_code+=token_str;
|
||||
token new_token(line,get_tok_type(token_str),token_str);
|
||||
token_list.push_back(new_token);
|
||||
token_list.push_back({line,get_tok_type(token_str),token_str});
|
||||
}
|
||||
else if(IS_CALC_OPERATOR(res[ptr]))
|
||||
{
|
||||
|
@ -377,19 +346,17 @@ void nasal_lexer::scanner()
|
|||
if(ptr<res_size && res[ptr]=='=')
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
token new_token(line,get_tok_type(token_str),token_str);
|
||||
token_list.push_back(new_token);
|
||||
token_list.push_back({line,get_tok_type(token_str),token_str});
|
||||
}
|
||||
else if(IS_NOTE(res[ptr]))// avoid note, after this process ptr will point to a '\n', so next loop line counter+1
|
||||
while(++ptr<res_size && res[ptr]!='\n');
|
||||
else
|
||||
{
|
||||
line_code+=res[ptr++];
|
||||
die("unknown character.",line);
|
||||
die("unknown character.");
|
||||
}
|
||||
}
|
||||
token tk(line,tok_eof,"");
|
||||
token_list.push_back(tk);
|
||||
token_list.push_back({line,tok_eof,""});
|
||||
res.clear();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ private:
|
|||
int in_function; // count when generating function block,used to check return-expression
|
||||
int in_loop; // count when generating loop block,used to check break/continue-expression
|
||||
void die(int,std::string);
|
||||
void match(int type,std::string err_info="");
|
||||
void match(int type,const char* err_info="");
|
||||
bool check_comma(int*);
|
||||
bool check_multi_def();
|
||||
bool check_multi_scalar();
|
||||
|
@ -126,18 +126,18 @@ void nasal_parse::main_process()
|
|||
}
|
||||
if(!error_token.size())
|
||||
return;
|
||||
std::vector<int> err_lines;
|
||||
err_lines.push_back(error_token[0].line);
|
||||
for(auto& tok:error_token)
|
||||
if(err_lines.back()!=tok.line)
|
||||
err_lines.push_back(tok.line);
|
||||
++error;
|
||||
std::cout<<">> [parse] error tokens in line";
|
||||
for(auto& line:err_lines)
|
||||
std::cout<<' '<<line;
|
||||
std::cout<<">> [parse] line";
|
||||
int err_line=0;
|
||||
for(auto& tok:error_token)
|
||||
if(err_line!=tok.line)
|
||||
{
|
||||
std::cout<<' '<<tok.line;
|
||||
err_line=tok.line;
|
||||
}
|
||||
std::cout
|
||||
<<" maybe recorded because of fatal syntax errors."
|
||||
<<"please check \'(\',\'[\',\'{\',\')\',\']\',\'}\' match or not.\n";
|
||||
<<" have fatal syntax errors."
|
||||
<<"check \'(\',\'[\',\'{\',\')\',\']\',\'}\' match or not.\n";
|
||||
return;
|
||||
}
|
||||
void nasal_parse::die(int line,std::string info)
|
||||
|
@ -146,24 +146,21 @@ void nasal_parse::die(int line,std::string info)
|
|||
std::cout<<">> [parse] line "<<line<<": "<<info<<".\n";
|
||||
return;
|
||||
}
|
||||
void nasal_parse::match(int type,std::string err_info)
|
||||
void nasal_parse::match(int type,const char* err_info)
|
||||
{
|
||||
if(tok_list[ptr].type!=type)
|
||||
{
|
||||
if(err_info.length())
|
||||
if(err_info[0])
|
||||
{
|
||||
die(error_line,err_info);
|
||||
return;
|
||||
}
|
||||
std::string s="";
|
||||
if(type>=tok_for)// token_table begins at tok_for
|
||||
s=token_table[type-tok_for].str;
|
||||
switch(type)
|
||||
{
|
||||
case tok_num:die(error_line,"expected number"); break;
|
||||
case tok_str:die(error_line,"expected string"); break;
|
||||
case tok_id: die(error_line,"expected identifier");break;
|
||||
default: die(error_line,"expected \'"+s+"\'"); break;
|
||||
default: die(error_line,"expected \'"+std::string(token_table[type-tok_for].str)+"\'"); break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -628,7 +625,7 @@ nasal_ast nasal_parse::scalar()
|
|||
if(tok_list[ptr].type==tok_nil) {node=nil_gen(); match(tok_nil);}
|
||||
else if(tok_list[ptr].type==tok_num){node=num_gen(); match(tok_num);}
|
||||
else if(tok_list[ptr].type==tok_str){node=str_gen(); match(tok_str);}
|
||||
else if(tok_list[ptr].type==tok_id) {node= id_gen(); match(tok_id );}
|
||||
else if(tok_list[ptr].type==tok_id) {node=id_gen(); match(tok_id); }
|
||||
else if(tok_list[ptr].type==tok_func)
|
||||
{
|
||||
if(tok_list[ptr+1].type==tok_id)
|
||||
|
|
336
nasal_vm.h
336
nasal_vm.h
|
@ -7,12 +7,14 @@ private:
|
|||
/* reference from nasal_gc */
|
||||
nasal_val**& stack_top;// stack top
|
||||
/* values of nasal_vm */
|
||||
int pc; // program counter
|
||||
uint32_t pc; // program counter
|
||||
bool loop_mark;// when mark is false,break the main loop
|
||||
std::stack<int> ret; // ptr stack stores address for function to return
|
||||
std::stack<int> counter; // iterator stack for forindex/foreach
|
||||
std::vector<std::string> str_table;// symbols used in process
|
||||
std::vector<opcode> exec_code;// byte codes store here
|
||||
std::vector<void (nasal_vm::*)()>
|
||||
exec_code;//function pointer
|
||||
std::vector<uint32_t> imm; // immediate number
|
||||
nasal_val** mem_addr; // used for mem_call
|
||||
nasal_gc gc; // garbage collector
|
||||
|
||||
|
@ -98,7 +100,76 @@ void nasal_vm::init(
|
|||
gc.gc_init(nums,strs);
|
||||
gc.val_stack[STACK_MAX_DEPTH-1]=nullptr;
|
||||
str_table=strs; // get constant strings & symbols
|
||||
exec_code=exec; // get bytecodes
|
||||
void (nasal_vm::*opr_table[])()=
|
||||
{
|
||||
&nasal_vm::opr_nop,
|
||||
&nasal_vm::opr_intg,
|
||||
&nasal_vm::opr_intl,
|
||||
&nasal_vm::opr_offset,
|
||||
&nasal_vm::opr_loadg,
|
||||
&nasal_vm::opr_loadl,
|
||||
&nasal_vm::opr_pnum,
|
||||
&nasal_vm::opr_pone,
|
||||
&nasal_vm::opr_pzero,
|
||||
&nasal_vm::opr_pnil,
|
||||
&nasal_vm::opr_pstr,
|
||||
&nasal_vm::opr_newv,
|
||||
&nasal_vm::opr_newh,
|
||||
&nasal_vm::opr_newf,
|
||||
&nasal_vm::opr_happ,
|
||||
&nasal_vm::opr_para,
|
||||
&nasal_vm::opr_defpara,
|
||||
&nasal_vm::opr_dynpara,
|
||||
&nasal_vm::opr_unot,
|
||||
&nasal_vm::opr_usub,
|
||||
&nasal_vm::opr_add,
|
||||
&nasal_vm::opr_sub,
|
||||
&nasal_vm::opr_mul,
|
||||
&nasal_vm::opr_div,
|
||||
&nasal_vm::opr_lnk,
|
||||
&nasal_vm::opr_addeq,
|
||||
&nasal_vm::opr_subeq,
|
||||
&nasal_vm::opr_muleq,
|
||||
&nasal_vm::opr_diveq,
|
||||
&nasal_vm::opr_lnkeq,
|
||||
&nasal_vm::opr_meq,
|
||||
&nasal_vm::opr_eq,
|
||||
&nasal_vm::opr_neq,
|
||||
&nasal_vm::opr_less,
|
||||
&nasal_vm::opr_leq,
|
||||
&nasal_vm::opr_grt,
|
||||
&nasal_vm::opr_geq,
|
||||
&nasal_vm::opr_pop,
|
||||
&nasal_vm::opr_jmp,
|
||||
&nasal_vm::opr_jt,
|
||||
&nasal_vm::opr_jf,
|
||||
&nasal_vm::opr_counter,
|
||||
&nasal_vm::opr_cntpop,
|
||||
&nasal_vm::opr_findex,
|
||||
&nasal_vm::opr_feach,
|
||||
&nasal_vm::opr_callg,
|
||||
&nasal_vm::opr_calll,
|
||||
&nasal_vm::opr_callv,
|
||||
&nasal_vm::opr_callvi,
|
||||
&nasal_vm::opr_callh,
|
||||
&nasal_vm::opr_callfv,
|
||||
&nasal_vm::opr_callfh,
|
||||
&nasal_vm::opr_callb,
|
||||
&nasal_vm::opr_slcbegin,
|
||||
&nasal_vm::opr_slcend,
|
||||
&nasal_vm::opr_slc,
|
||||
&nasal_vm::opr_slc2,
|
||||
&nasal_vm::opr_mcallg,
|
||||
&nasal_vm::opr_mcalll,
|
||||
&nasal_vm::opr_mcallv,
|
||||
&nasal_vm::opr_mcallh,
|
||||
&nasal_vm::opr_ret
|
||||
};
|
||||
for(auto& i:exec)
|
||||
{
|
||||
exec_code.push_back(opr_table[i.op]);
|
||||
imm.push_back(i.num);
|
||||
}
|
||||
loop_mark=true; // set loop mark to true
|
||||
return;
|
||||
}
|
||||
|
@ -140,32 +211,32 @@ void nasal_vm::opr_nop()
|
|||
}
|
||||
void nasal_vm::opr_intg()
|
||||
{
|
||||
gc.global.resize(exec_code[pc].num,gc.nil_addr);
|
||||
gc.global.resize(imm[pc],gc.nil_addr);
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_intl()
|
||||
{
|
||||
stack_top[0]->ptr.func->closure.resize(exec_code[pc].num,gc.nil_addr);
|
||||
stack_top[0]->ptr.func->closure.resize(imm[pc],gc.nil_addr);
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_offset()
|
||||
{
|
||||
stack_top[0]->ptr.func->offset=exec_code[pc].num;
|
||||
stack_top[0]->ptr.func->offset=imm[pc];
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_loadg()
|
||||
{
|
||||
gc.global[exec_code[pc].num]=*stack_top--;
|
||||
gc.global[imm[pc]]=(stack_top--)[0];
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_loadl()
|
||||
{
|
||||
gc.local.back()[exec_code[pc].num]=*stack_top--;
|
||||
gc.local.back()[imm[pc]]=(stack_top--)[0];
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_pnum()
|
||||
{
|
||||
(++stack_top)[0]=gc.num_addrs[exec_code[pc].num];
|
||||
(++stack_top)[0]=gc.num_addrs[imm[pc]];
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_pone()
|
||||
|
@ -185,19 +256,19 @@ void nasal_vm::opr_pnil()
|
|||
}
|
||||
void nasal_vm::opr_pstr()
|
||||
{
|
||||
(++stack_top)[0]=gc.str_addrs[exec_code[pc].num];
|
||||
(++stack_top)[0]=gc.str_addrs[imm[pc]];
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_newv()
|
||||
{
|
||||
nasal_val* vec_addr=gc.gc_alloc(vm_vec);
|
||||
nasal_val** begin=stack_top-exec_code[pc].num+1;
|
||||
auto& vec=vec_addr->ptr.vec->elems;// stack_top-exec_code[pc].num stores the vector
|
||||
vec.resize(exec_code[pc].num);
|
||||
for(int i=0;i<exec_code[pc].num;++i)
|
||||
nasal_val** begin=stack_top-imm[pc]+1;
|
||||
auto& vec=vec_addr->ptr.vec->elems;// stack_top-imm[pc] stores the vector
|
||||
vec.resize(imm[pc]);
|
||||
for(int i=0;i<imm[pc];++i)
|
||||
vec[i]=begin[i];
|
||||
begin[0]=vec_addr;
|
||||
stack_top=begin;
|
||||
stack_top[0]=vec_addr;
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_newh()
|
||||
|
@ -208,7 +279,7 @@ void nasal_vm::opr_newh()
|
|||
void nasal_vm::opr_newf()
|
||||
{
|
||||
nasal_val* val=gc.gc_alloc(vm_func);
|
||||
val->ptr.func->entry=exec_code[pc].num;
|
||||
val->ptr.func->entry=imm[pc];
|
||||
if(gc.local.empty())
|
||||
val->ptr.func->closure.push_back(gc.nil_addr);// me
|
||||
else
|
||||
|
@ -219,14 +290,14 @@ void nasal_vm::opr_newf()
|
|||
void nasal_vm::opr_happ()
|
||||
{
|
||||
nasal_val* val=stack_top[0];
|
||||
(--stack_top)[0]->ptr.hash->elems[str_table[exec_code[pc].num]]=val;
|
||||
(--stack_top)[0]->ptr.hash->elems[str_table[imm[pc]]]=val;
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_para()
|
||||
{
|
||||
nasal_func* func=stack_top[0]->ptr.func;
|
||||
int size=func->key_table.size();
|
||||
func->key_table[str_table[exec_code[pc].num]]=size;
|
||||
func->key_table[str_table[imm[pc]]]=size;
|
||||
func->default_para.push_back(nullptr);
|
||||
return;
|
||||
}
|
||||
|
@ -235,13 +306,13 @@ void nasal_vm::opr_defpara()
|
|||
nasal_val* def_val=stack_top[0];
|
||||
nasal_func* func=(--stack_top)[0]->ptr.func;
|
||||
int size=func->key_table.size();
|
||||
func->key_table[str_table[exec_code[pc].num]]=size;
|
||||
func->key_table[str_table[imm[pc]]]=size;
|
||||
func->default_para.push_back(def_val);
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_dynpara()
|
||||
{
|
||||
stack_top[0]->ptr.func->dynpara=exec_code[pc].num;
|
||||
stack_top[0]->ptr.func->dynpara=imm[pc];
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_unot()
|
||||
|
@ -380,42 +451,26 @@ void nasal_vm::opr_neq()
|
|||
}
|
||||
void nasal_vm::opr_less()
|
||||
{
|
||||
nasal_val* val2=stack_top[0];
|
||||
nasal_val* val1=(--stack_top)[0];
|
||||
if(val1->type==vm_str && val2->type==vm_str)
|
||||
stack_top[0]=(*val1->ptr.str<*val2->ptr.str)?gc.one_addr:gc.zero_addr;
|
||||
else
|
||||
stack_top[0]=(val1->to_number()<val2->to_number())?gc.one_addr:gc.zero_addr;
|
||||
--stack_top;
|
||||
stack_top[0]=(stack_top[0]->to_number()<stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_leq()
|
||||
{
|
||||
nasal_val* val2=stack_top[0];
|
||||
nasal_val* val1=(--stack_top)[0];
|
||||
if(val1->type==vm_str && val2->type==vm_str)
|
||||
stack_top[0]=(*val1->ptr.str<=*val2->ptr.str)?gc.one_addr:gc.zero_addr;
|
||||
else
|
||||
stack_top[0]=(val1->to_number()<=val2->to_number())?gc.one_addr:gc.zero_addr;
|
||||
--stack_top;
|
||||
stack_top[0]=(stack_top[0]->to_number()<=stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_grt()
|
||||
{
|
||||
nasal_val* val2=stack_top[0];
|
||||
nasal_val* val1=(--stack_top)[0];
|
||||
if(val1->type==vm_str && val2->type==vm_str)
|
||||
stack_top[0]=(*val1->ptr.str>*val2->ptr.str)?gc.one_addr:gc.zero_addr;
|
||||
else
|
||||
stack_top[0]=(val1->to_number()>val2->to_number())?gc.one_addr:gc.zero_addr;
|
||||
--stack_top;
|
||||
stack_top[0]=(stack_top[0]->to_number()>stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_geq()
|
||||
{
|
||||
nasal_val* val2=stack_top[0];
|
||||
nasal_val* val1=(--stack_top)[0];
|
||||
if(val1->type==vm_str && val2->type==vm_str)
|
||||
stack_top[0]=(*val1->ptr.str>=*val2->ptr.str)?gc.one_addr:gc.zero_addr;
|
||||
else
|
||||
stack_top[0]=(val1->to_number()>=val2->to_number())?gc.one_addr:gc.zero_addr;
|
||||
--stack_top;
|
||||
stack_top[0]=(stack_top[0]->to_number()>=stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_pop()
|
||||
|
@ -425,19 +480,19 @@ void nasal_vm::opr_pop()
|
|||
}
|
||||
void nasal_vm::opr_jmp()
|
||||
{
|
||||
pc=exec_code[pc].num-1;
|
||||
pc=imm[pc]-1;
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_jt()
|
||||
{
|
||||
if(condition(stack_top[0]))
|
||||
pc=exec_code[pc].num-1;
|
||||
pc=imm[pc]-1;
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_jf()
|
||||
{
|
||||
if(!condition(stack_top[0]))
|
||||
pc=exec_code[pc].num-1;
|
||||
pc=imm[pc]-1;
|
||||
--stack_top;
|
||||
return;
|
||||
}
|
||||
|
@ -457,12 +512,11 @@ void nasal_vm::opr_findex()
|
|||
{
|
||||
if(++counter.top()>=stack_top[0]->ptr.vec->elems.size())
|
||||
{
|
||||
pc=exec_code[pc].num-1;
|
||||
pc=imm[pc]-1;
|
||||
return;
|
||||
}
|
||||
nasal_val* res=gc.gc_alloc(vm_num);
|
||||
res->ptr.num=counter.top();
|
||||
(++stack_top)[0]=res;
|
||||
(++stack_top)[0]=gc.gc_alloc(vm_num);
|
||||
stack_top[0]->ptr.num=counter.top();
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_feach()
|
||||
|
@ -470,7 +524,7 @@ void nasal_vm::opr_feach()
|
|||
std::vector<nasal_val*>& ref=stack_top[0]->ptr.vec->elems;
|
||||
if(++counter.top()>=ref.size())
|
||||
{
|
||||
pc=exec_code[pc].num-1;
|
||||
pc=imm[pc]-1;
|
||||
return;
|
||||
}
|
||||
(++stack_top)[0]=ref[counter.top()];
|
||||
|
@ -478,12 +532,12 @@ void nasal_vm::opr_feach()
|
|||
}
|
||||
void nasal_vm::opr_callg()
|
||||
{
|
||||
(++stack_top)[0]=gc.global[exec_code[pc].num];
|
||||
(++stack_top)[0]=gc.global[imm[pc]];
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_calll()
|
||||
{
|
||||
(++stack_top)[0]=gc.local.back()[exec_code[pc].num];
|
||||
(++stack_top)[0]=gc.local.back()[imm[pc]];
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_callv()
|
||||
|
@ -493,10 +547,9 @@ void nasal_vm::opr_callv()
|
|||
int type=vec_addr->type;
|
||||
if(type==vm_vec)
|
||||
{
|
||||
nasal_val* res=vec_addr->ptr.vec->get_val(val->to_number());
|
||||
if(!res)
|
||||
die("callv: index out of range:"+val->to_string());
|
||||
stack_top[0]=res;
|
||||
stack_top[0]=vec_addr->ptr.vec->get_val(val->to_number());
|
||||
if(!stack_top[0])
|
||||
die("callv: index out of range:"+num2str(val->to_number()));
|
||||
}
|
||||
else if(type==vm_hash)
|
||||
{
|
||||
|
@ -505,15 +558,14 @@ void nasal_vm::opr_callv()
|
|||
die("callv: must use string as the key");
|
||||
return;
|
||||
}
|
||||
nasal_val* res=vec_addr->ptr.hash->get_val(*val->ptr.str);
|
||||
if(!res)
|
||||
stack_top[0]=vec_addr->ptr.hash->get_val(*val->ptr.str);
|
||||
if(!stack_top[0])
|
||||
{
|
||||
die("callv: cannot find member \""+*val->ptr.str+"\" of this hash");
|
||||
return;
|
||||
}
|
||||
if(res->type==vm_func)
|
||||
res->ptr.func->closure[0]=val;// me
|
||||
stack_top[0]=res;
|
||||
if(stack_top[0]->type==vm_func)
|
||||
stack_top[0]->ptr.func->closure[0]=val;// me
|
||||
}
|
||||
else if(type==vm_str)
|
||||
{
|
||||
|
@ -522,12 +574,11 @@ void nasal_vm::opr_callv()
|
|||
int str_size=str.length();
|
||||
if(num<-str_size || num>=str_size)
|
||||
{
|
||||
die("callv: index out of range:"+val->to_string());
|
||||
die("callv: index out of range:"+num2str(val->to_number()));
|
||||
return;
|
||||
}
|
||||
nasal_val* res=gc.gc_alloc(vm_num);
|
||||
res->ptr.num=(str[num>=0? num:num+str_size]);
|
||||
stack_top[0]=res;
|
||||
stack_top[0]=gc.gc_alloc(vm_num);
|
||||
stack_top[0]->ptr.num=(str[num>=0? num:num+str_size]);
|
||||
}
|
||||
else
|
||||
die("callv: must call a vector/hash/string");
|
||||
|
@ -542,10 +593,9 @@ void nasal_vm::opr_callvi()
|
|||
return;
|
||||
}
|
||||
// cannot use operator[],because this may cause overflow
|
||||
nasal_val* res=val->ptr.vec->get_val(exec_code[pc].num);
|
||||
if(!res)
|
||||
die("callvi: index out of range:"+num2str(exec_code[pc].num));
|
||||
(++stack_top)[0]=res;
|
||||
(++stack_top)[0]=val->ptr.vec->get_val(imm[pc]);
|
||||
if(!stack_top[0])
|
||||
die("callvi: index out of range:"+num2str(imm[pc]));
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_callh()
|
||||
|
@ -556,23 +606,22 @@ void nasal_vm::opr_callh()
|
|||
die("callh: must call a hash");
|
||||
return;
|
||||
}
|
||||
nasal_val* res=val->ptr.hash->get_val(str_table[exec_code[pc].num]);
|
||||
if(!res)
|
||||
stack_top[0]=val->ptr.hash->get_val(str_table[imm[pc]]);
|
||||
if(!stack_top[0])
|
||||
{
|
||||
die("callh: hash member \""+str_table[exec_code[pc].num]+"\" does not exist");
|
||||
die("callh: member \""+str_table[imm[pc]]+"\" does not exist");
|
||||
return;
|
||||
}
|
||||
if(res->type==vm_func)
|
||||
res->ptr.func->closure[0]=val;// me
|
||||
stack_top[0]=res;
|
||||
if(stack_top[0]->type==vm_func)
|
||||
stack_top[0]->ptr.func->closure[0]=val;// me
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_callfv()
|
||||
{
|
||||
// get parameter list and function value
|
||||
int args_size=exec_code[pc].num;
|
||||
int args_size=imm[pc];
|
||||
nasal_val** vec=stack_top-args_size+1;
|
||||
nasal_val* func_addr=*(vec-1);
|
||||
nasal_val* func_addr=vec[-1];
|
||||
if(func_addr->type!=vm_func)
|
||||
{
|
||||
die("callfv: must call a function");
|
||||
|
@ -584,10 +633,9 @@ void nasal_vm::opr_callfv()
|
|||
// load parameters
|
||||
auto& ref_default=ref_func.default_para;
|
||||
auto& ref_closure=gc.local.back();
|
||||
auto& ref_keys=ref_func.key_table;
|
||||
|
||||
int offset=ref_func.offset;
|
||||
int para_size=ref_keys.size();
|
||||
int para_size=ref_func.key_table.size();
|
||||
// load arguments
|
||||
if(args_size<para_size && !ref_default[args_size])
|
||||
{
|
||||
|
@ -597,7 +645,7 @@ void nasal_vm::opr_callfv()
|
|||
}
|
||||
// if args_size>para_size,for 0 to args_size will cause corruption
|
||||
for(int i=0;i<para_size;++i)
|
||||
ref_closure[i+offset]=(i>=args_size)?ref_default[i]:vec[i];
|
||||
ref_closure[i+offset]=(i<args_size)?vec[i]:ref_default[i];
|
||||
// load dynamic argument if args_size>=para_size
|
||||
if(ref_func.dynpara>=0)
|
||||
{
|
||||
|
@ -615,7 +663,7 @@ void nasal_vm::opr_callfv()
|
|||
void nasal_vm::opr_callfh()
|
||||
{
|
||||
// get parameter list and function value
|
||||
std::unordered_map<std::string,nasal_val*>& ref_hash=(*stack_top)->ptr.hash->elems;
|
||||
auto& ref_hash=stack_top[0]->ptr.hash->elems;
|
||||
nasal_val* func_addr=stack_top[-1];
|
||||
if(func_addr->type!=vm_func)
|
||||
{
|
||||
|
@ -628,7 +676,6 @@ void nasal_vm::opr_callfh()
|
|||
// load parameters
|
||||
auto& ref_default=ref_func.default_para;
|
||||
auto& ref_closure=gc.local.back();
|
||||
auto& ref_keys=ref_func.key_table;
|
||||
|
||||
if(ref_func.dynpara>=0)
|
||||
{
|
||||
|
@ -636,7 +683,7 @@ void nasal_vm::opr_callfh()
|
|||
return;
|
||||
}
|
||||
int offset=ref_func.offset;
|
||||
for(auto& i:ref_keys)
|
||||
for(auto& i:ref_func.key_table)
|
||||
{
|
||||
if(ref_hash.count(i.first))
|
||||
ref_closure[i.second+offset]=ref_hash[i.first];
|
||||
|
@ -656,9 +703,7 @@ void nasal_vm::opr_callfh()
|
|||
}
|
||||
void nasal_vm::opr_callb()
|
||||
{
|
||||
nasal_val* res=(*builtin_func[exec_code[pc].num].func)(gc.local.back(),gc);
|
||||
(++stack_top)[0]=res;
|
||||
loop_mark=res;
|
||||
loop_mark=(++stack_top)[0]=(*builtin_func[imm[pc]].func)(gc.local.back(),gc);
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_slcbegin()
|
||||
|
@ -676,24 +721,17 @@ void nasal_vm::opr_slcend()
|
|||
}
|
||||
void nasal_vm::opr_slc()
|
||||
{
|
||||
nasal_val* val=*stack_top--;
|
||||
int num;
|
||||
switch(val->type)
|
||||
{
|
||||
case vm_num:num=(int)val->ptr.num;break;
|
||||
case vm_str:num=(int)str2num(val->ptr.str->c_str());break;
|
||||
default:die("slc: error value type");break;
|
||||
}
|
||||
nasal_val* res=stack_top[0]->ptr.vec->get_val(num);
|
||||
nasal_val* val=(stack_top--)[0];
|
||||
nasal_val* res=stack_top[0]->ptr.vec->get_val(val->to_number());
|
||||
if(!res)
|
||||
die("slc: index out of range:"+num2str(num));
|
||||
die("slc: index out of range:"+num2str(val->to_number()));
|
||||
gc.slice_stack.back()->ptr.vec->elems.push_back(res);
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_slc2()
|
||||
{
|
||||
nasal_val* val2=*stack_top--;
|
||||
nasal_val* val1=*stack_top--;
|
||||
nasal_val* val2=(stack_top--)[0];
|
||||
nasal_val* val1=(stack_top--)[0];
|
||||
std::vector<nasal_val*>& ref=stack_top[0]->ptr.vec->elems;
|
||||
std::vector<nasal_val*>& aim=gc.slice_stack.back()->ptr.vec->elems;
|
||||
|
||||
|
@ -732,13 +770,13 @@ void nasal_vm::opr_slc2()
|
|||
}
|
||||
void nasal_vm::opr_mcallg()
|
||||
{
|
||||
mem_addr=&gc.global[exec_code[pc].num];
|
||||
mem_addr=&gc.global[imm[pc]];
|
||||
(++stack_top)[0]=mem_addr[0];
|
||||
return;
|
||||
}
|
||||
void nasal_vm::opr_mcalll()
|
||||
{
|
||||
mem_addr=&gc.local.back()[exec_code[pc].num];
|
||||
mem_addr=&gc.local.back()[imm[pc]];
|
||||
(++stack_top)[0]=mem_addr[0];
|
||||
return;
|
||||
}
|
||||
|
@ -749,16 +787,9 @@ void nasal_vm::opr_mcallv()
|
|||
int type=vec_addr->type;
|
||||
if(type==vm_vec)
|
||||
{
|
||||
int num;
|
||||
switch(val->type)
|
||||
{
|
||||
case vm_num:num=(int)val->ptr.num;break;
|
||||
case vm_str:num=(int)str2num(val->ptr.str->c_str());break;
|
||||
default:die("mcallv: error value type");break;
|
||||
}
|
||||
mem_addr=vec_addr->ptr.vec->get_mem(num);
|
||||
mem_addr=vec_addr->ptr.vec->get_mem(val->to_number());
|
||||
if(!mem_addr)
|
||||
die("mcallv: index out of range:"+num2str(num));
|
||||
die("mcallv: index out of range:"+num2str(val->to_number()));
|
||||
}
|
||||
else if(type==vm_hash)
|
||||
{
|
||||
|
@ -789,7 +820,7 @@ void nasal_vm::opr_mcallh()
|
|||
return;
|
||||
}
|
||||
nasal_hash& ref=*hash_addr->ptr.hash;
|
||||
std::string& str=str_table[exec_code[pc].num];
|
||||
std::string& str=str_table[imm[pc]];
|
||||
mem_addr=ref.get_mem(str);
|
||||
if(!mem_addr) // create a new key
|
||||
{
|
||||
|
@ -800,89 +831,20 @@ void nasal_vm::opr_mcallh()
|
|||
}
|
||||
void nasal_vm::opr_ret()
|
||||
{
|
||||
gc.local.pop_back();
|
||||
pc=ret.top();
|
||||
ret.pop();
|
||||
nasal_val* ret_val=stack_top[0];
|
||||
(--stack_top)[0]->ptr.func->closure[0]=gc.nil_addr;// set me to nil
|
||||
stack_top[0]=ret_val;
|
||||
gc.local.pop_back();// delete local scope
|
||||
pc=ret.top();ret.pop();// fetch pc
|
||||
(--stack_top)[0]->ptr.func->closure[0]=gc.nil_addr;// set 'me' to nil
|
||||
stack_top[0]=stack_top[1];// rewrite nasal_func with returned value
|
||||
return;
|
||||
}
|
||||
void nasal_vm::run()
|
||||
{
|
||||
void (nasal_vm::*opr_table[])()=
|
||||
{
|
||||
&nasal_vm::opr_nop,
|
||||
&nasal_vm::opr_intg,
|
||||
&nasal_vm::opr_intl,
|
||||
&nasal_vm::opr_offset,
|
||||
&nasal_vm::opr_loadg,
|
||||
&nasal_vm::opr_loadl,
|
||||
&nasal_vm::opr_pnum,
|
||||
&nasal_vm::opr_pone,
|
||||
&nasal_vm::opr_pzero,
|
||||
&nasal_vm::opr_pnil,
|
||||
&nasal_vm::opr_pstr,
|
||||
&nasal_vm::opr_newv,
|
||||
&nasal_vm::opr_newh,
|
||||
&nasal_vm::opr_newf,
|
||||
&nasal_vm::opr_happ,
|
||||
&nasal_vm::opr_para,
|
||||
&nasal_vm::opr_defpara,
|
||||
&nasal_vm::opr_dynpara,
|
||||
&nasal_vm::opr_unot,
|
||||
&nasal_vm::opr_usub,
|
||||
&nasal_vm::opr_add,
|
||||
&nasal_vm::opr_sub,
|
||||
&nasal_vm::opr_mul,
|
||||
&nasal_vm::opr_div,
|
||||
&nasal_vm::opr_lnk,
|
||||
&nasal_vm::opr_addeq,
|
||||
&nasal_vm::opr_subeq,
|
||||
&nasal_vm::opr_muleq,
|
||||
&nasal_vm::opr_diveq,
|
||||
&nasal_vm::opr_lnkeq,
|
||||
&nasal_vm::opr_meq,
|
||||
&nasal_vm::opr_eq,
|
||||
&nasal_vm::opr_neq,
|
||||
&nasal_vm::opr_less,
|
||||
&nasal_vm::opr_leq,
|
||||
&nasal_vm::opr_grt,
|
||||
&nasal_vm::opr_geq,
|
||||
&nasal_vm::opr_pop,
|
||||
&nasal_vm::opr_jmp,
|
||||
&nasal_vm::opr_jt,
|
||||
&nasal_vm::opr_jf,
|
||||
&nasal_vm::opr_counter,
|
||||
&nasal_vm::opr_cntpop,
|
||||
&nasal_vm::opr_findex,
|
||||
&nasal_vm::opr_feach,
|
||||
&nasal_vm::opr_callg,
|
||||
&nasal_vm::opr_calll,
|
||||
&nasal_vm::opr_callv,
|
||||
&nasal_vm::opr_callvi,
|
||||
&nasal_vm::opr_callh,
|
||||
&nasal_vm::opr_callfv,
|
||||
&nasal_vm::opr_callfh,
|
||||
&nasal_vm::opr_callb,
|
||||
&nasal_vm::opr_slcbegin,
|
||||
&nasal_vm::opr_slcend,
|
||||
&nasal_vm::opr_slc,
|
||||
&nasal_vm::opr_slc2,
|
||||
&nasal_vm::opr_mcallg,
|
||||
&nasal_vm::opr_mcalll,
|
||||
&nasal_vm::opr_mcallv,
|
||||
&nasal_vm::opr_mcallh,
|
||||
&nasal_vm::opr_ret
|
||||
};
|
||||
clock_t begin_time=clock();
|
||||
// main loop
|
||||
for(pc=0;loop_mark&&!gc.val_stack[STACK_MAX_DEPTH-1];++pc)
|
||||
(this->*opr_table[exec_code[pc].op])();
|
||||
float total_time=((double)(clock()-begin_time))/CLOCKS_PER_SEC;
|
||||
(this->*exec_code[pc])();
|
||||
if(gc.val_stack[STACK_MAX_DEPTH-1])
|
||||
die("stack overflow");
|
||||
std::cout<<">> [vm] process exited after "<<total_time<<"s.\n";
|
||||
std::cout<<">> [vm] process exited after "<<((double)(clock()-begin_time))/CLOCKS_PER_SEC<<"s.\n";
|
||||
return;
|
||||
}
|
||||
#endif
|
10
test/bp.nas
10
test/bp.nas
|
@ -123,9 +123,7 @@ var backward=func(x)
|
|||
return;
|
||||
}
|
||||
|
||||
var cnt=0;
|
||||
var show=0;
|
||||
var error=100;
|
||||
var (cnt,error)=(0,100);
|
||||
while(error>0.0005)
|
||||
{
|
||||
error=0;
|
||||
|
@ -136,12 +134,6 @@ while(error>0.0005)
|
|||
backward(i);
|
||||
}
|
||||
cnt+=1;
|
||||
show+=1;
|
||||
if(show==350)
|
||||
{
|
||||
show=0;
|
||||
print('epoch ',cnt,':',error,'\r');
|
||||
}
|
||||
}
|
||||
print('finished after ',cnt,' epoch.\n');
|
||||
foreach(var v;training_set)
|
||||
|
|
|
@ -1,31 +1,27 @@
|
|||
import("lib.nas");
|
||||
var yMin=-0.2;
|
||||
var yMax=0.2;
|
||||
var xMin=-1.5;
|
||||
var xMax=-1.0;
|
||||
var (yMin,yMax,xMin,xMax,line)=(-0.2,0.2,-1.5,-1.0,"");
|
||||
var (yDel,xDel)=(yMax-yMin,xMax-xMin);
|
||||
for(var yPixel=0;yPixel<24;yPixel+=1)
|
||||
{
|
||||
var y=(yPixel/24)*(yMax-yMin)+yMin;
|
||||
var y=(yPixel/24)*yDel+yMin;
|
||||
for(var xPixel=0;xPixel<80;xPixel+=1)
|
||||
{
|
||||
var x=(xPixel/80)*(xMax-xMin)+xMin;
|
||||
var x=(xPixel/80)*xDel+xMin;
|
||||
var pixel=" ";
|
||||
var x0=x;
|
||||
var y0=y;
|
||||
var (x0,y0)=(x,y);
|
||||
for(var iter=0;iter<80;iter+=1)
|
||||
{
|
||||
var x1=(x0*x0)-(y0*y0)+x;
|
||||
var y1=2*x0*y0+y;
|
||||
x0=x1;
|
||||
y0=y1;
|
||||
var d=(x0*x0)+(y0*y0);
|
||||
if(d>4)
|
||||
(x0,y0)=(x1,y1);
|
||||
if((x0*x0)+(y0*y0)>4)
|
||||
{
|
||||
pixel=chr(" .:;+=xX$&"[int(iter/8)]);
|
||||
pixel=chr(" .:;+=xX$&"[iter/8]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
print(pixel);
|
||||
line~=pixel;
|
||||
}
|
||||
print('\n');
|
||||
line~='\n';
|
||||
}
|
||||
print(line);
|
|
@ -1,10 +1,9 @@
|
|||
import("lib.nas");
|
||||
|
||||
var t=1;
|
||||
var res=0;
|
||||
var (t,res)=(1,0);
|
||||
for(var m=1;m<4e6;m+=2)
|
||||
{
|
||||
res+=t*1/m;
|
||||
t*=-1;
|
||||
t=-t;
|
||||
}
|
||||
println(res*4);
|
Loading…
Reference in New Issue