performance optimization of vm/lex/parse/test

This commit is contained in:
ValKmjolnir 2021-06-24 00:26:26 +08:00
parent ab99d2d1ed
commit fd57e9a47c
8 changed files with 205 additions and 292 deletions

View File

@ -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. 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 > g++ -std=c++11 -O2 main.cpp -o nasal.exe

View File

@ -234,7 +234,7 @@ std::string nasal_val::to_string()
struct nasal_gc 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* 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* one_addr; // reserved address of nasal_val,type vm_num, 1
nasal_val* nil_addr; // reserved address of nasal_val,type vm_nil nasal_val* nil_addr; // reserved address of nasal_val,type vm_nil

View File

@ -104,7 +104,7 @@ private:
std::vector<char> res; std::vector<char> res;
std::vector<token> token_list; std::vector<token> token_list;
int get_tok_type(std::string&); int get_tok_type(std::string&);
void die(std::string,int); void die(const char*);
std::string id_gen(); std::string id_gen();
std::string num_gen(); std::string num_gen();
std::string str_gen(); std::string str_gen();
@ -147,13 +147,13 @@ int nasal_lexer::get_tok_type(std::string& tk_str)
return tok_null; return tok_null;
} }
void nasal_lexer::die(std::string error_info,int line) void nasal_lexer::die(const char* error_info)
{ {
++error; ++error;
std::cout<<">> [lexer] line "<<line<<" column "<<line_code.length()<<": \n"<<line_code<<"\n"; std::cout<<">> [lexer] line "<<line<<" column "<<line_code.length()<<": \n"<<line_code<<"\n";
for(auto i:line_code) for(auto i:line_code)
std::cout<<(i=='\t'?'\t':' '); std::cout<<(i=='\t'?'\t':' ');
std::cout<<"^ "<<error_info<<'\n'; std::cout<<"^"<<error_info<<'\n';
return; return;
} }
@ -169,87 +169,60 @@ std::string nasal_lexer::id_gen()
std::string nasal_lexer::num_gen() std::string nasal_lexer::num_gen()
{ {
bool scientific_notation=false;// numbers like 1e8 are scientific_notation
std::string token_str="";
// generate hex number // generate hex number
if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='x') if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='x')
{ {
token_str="0x"; std::string token_str="0x";
ptr+=2; ptr+=2;
while(ptr<res_size && IS_HEX_NUMBER(res[ptr])) while(ptr<res_size && IS_HEX_NUMBER(res[ptr]))
token_str+=res[ptr++]; token_str+=res[ptr++];
line_code+=token_str; line_code+=token_str;
if(token_str=="0x") if(token_str=="0x")
{ die("incorrect number.");
die("incorrect number.",line);
return "0";
}
return token_str; return token_str;
} }
// generate oct number // generate oct number
else if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='o') else if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='o')
{ {
token_str="0o"; std::string token_str="0o";
ptr+=2; ptr+=2;
while(ptr<res_size && IS_OCT_NUMEBR(res[ptr])) while(ptr<res_size && IS_OCT_NUMEBR(res[ptr]))
token_str+=res[ptr++]; token_str+=res[ptr++];
line_code+=token_str; line_code+=token_str;
if(token_str=="0o") if(token_str=="0o")
{ die("incorrect number.");
die("incorrect number.",line);
return "0";
}
return token_str; return token_str;
} }
// generate dec number // generate dec number
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*) // 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])) while(ptr<res_size && IS_DIGIT(res[ptr]))
token_str+=res[ptr++]; token_str+=res[ptr++];
if(ptr<res_size && res[ptr]=='.') if(ptr<res_size && res[ptr]=='.')
{ {
token_str+=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])) while(ptr<res_size && IS_DIGIT(res[ptr]))
token_str+=res[ptr++]; token_str+=res[ptr++];
// "xxxx." is not a correct number // "xxxx." is not a correct number
if(token_str.back()=='.') if(token_str.back()=='.')
{ {
line_code+=token_str; line_code+=token_str;
die("incorrect number.",line); die("incorrect number.");
return "0"; return "0";
} }
} }
if(ptr<res_size && (res[ptr]=='e' || res[ptr]=='E')) if(ptr<res_size && (res[ptr]=='e' || res[ptr]=='E'))
{ {
token_str+=res[ptr++]; 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]=='+')) if(ptr<res_size && (res[ptr]=='-' || res[ptr]=='+'))
token_str+=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])) while(ptr<res_size && IS_DIGIT(res[ptr]))
token_str+=res[ptr++]; token_str+=res[ptr++];
// "xxxe(-|+)" is not a correct number // "xxxe(-|+)" is not a correct number
if(token_str.back()=='e' || token_str.back()=='E' || token_str.back()=='-' || token_str.back()=='+') if(token_str.back()=='e' || token_str.back()=='E' || token_str.back()=='-' || token_str.back()=='+')
{ {
line_code+=token_str; line_code+=token_str;
die("incorrect number.",line); die("incorrect number.");
return "0"; return "0";
} }
} }
@ -295,9 +268,9 @@ std::string nasal_lexer::str_gen()
} }
// check if this string ends with a " or ' // check if this string ends with a " or '
if(ptr++>=res_size) if(ptr++>=res_size)
die("get EOF when generating string.",line); die("get EOF when generating string.");
if(str_begin=='`' && token_str.length()>1) if(str_begin=='`' && token_str.length()!=1)
die("\'`\' is used for string that includes one character.",line); die("\'`\' is used for string that includes one character.");
return token_str; return token_str;
} }
@ -334,24 +307,21 @@ void nasal_lexer::scanner()
else if(IS_DIGIT(res[ptr])) else if(IS_DIGIT(res[ptr]))
{ {
token_str=num_gen(); token_str=num_gen();
token new_token(line,tok_num,token_str); token_list.push_back({line,tok_num,token_str});
token_list.push_back(new_token);
} }
else if(IS_STRING(res[ptr])) else if(IS_STRING(res[ptr]))
{ {
token_str=str_gen(); token_str=str_gen();
token new_token(line,tok_str,token_str); token_list.push_back({line,tok_str,token_str});
token_list.push_back(new_token);
} }
else if(IS_SINGLE_OPERATOR(res[ptr])) else if(IS_SINGLE_OPERATOR(res[ptr]))
{ {
token_str=""; token_str=res[ptr];
token_str+=res[ptr];
line_code+=res[ptr]; line_code+=res[ptr];
token new_token(line,get_tok_type(token_str),token_str); int type=get_tok_type(token_str);
if(!new_token.type) if(!type)
die("incorrect operator.",line); die("incorrect operator.");
token_list.push_back(new_token); token_list.push_back({line,type,token_str});
++ptr; ++ptr;
} }
else if(res[ptr]=='.') else if(res[ptr]=='.')
@ -367,8 +337,7 @@ void nasal_lexer::scanner()
++ptr; ++ptr;
} }
line_code+=token_str; line_code+=token_str;
token new_token(line,get_tok_type(token_str),token_str); token_list.push_back({line,get_tok_type(token_str),token_str});
token_list.push_back(new_token);
} }
else if(IS_CALC_OPERATOR(res[ptr])) else if(IS_CALC_OPERATOR(res[ptr]))
{ {
@ -377,19 +346,17 @@ void nasal_lexer::scanner()
if(ptr<res_size && res[ptr]=='=') if(ptr<res_size && res[ptr]=='=')
token_str+=res[ptr++]; token_str+=res[ptr++];
line_code+=token_str; line_code+=token_str;
token new_token(line,get_tok_type(token_str),token_str); token_list.push_back({line,get_tok_type(token_str),token_str});
token_list.push_back(new_token);
} }
else if(IS_NOTE(res[ptr]))// avoid note, after this process ptr will point to a '\n', so next loop line counter+1 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'); while(++ptr<res_size && res[ptr]!='\n');
else else
{ {
line_code+=res[ptr++]; line_code+=res[ptr++];
die("unknown character.",line); die("unknown character.");
} }
} }
token tk(line,tok_eof,""); token_list.push_back({line,tok_eof,""});
token_list.push_back(tk);
res.clear(); res.clear();
return; return;
} }

View File

@ -49,7 +49,7 @@ private:
int in_function; // count when generating function block,used to check return-expression 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 int in_loop; // count when generating loop block,used to check break/continue-expression
void die(int,std::string); 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_comma(int*);
bool check_multi_def(); bool check_multi_def();
bool check_multi_scalar(); bool check_multi_scalar();
@ -126,18 +126,18 @@ void nasal_parse::main_process()
} }
if(!error_token.size()) if(!error_token.size())
return; 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; ++error;
std::cout<<">> [parse] error tokens in line"; std::cout<<">> [parse] line";
for(auto& line:err_lines) int err_line=0;
std::cout<<' '<<line; for(auto& tok:error_token)
if(err_line!=tok.line)
{
std::cout<<' '<<tok.line;
err_line=tok.line;
}
std::cout std::cout
<<" maybe recorded because of fatal syntax errors." <<" have fatal syntax errors."
<<"please check \'(\',\'[\',\'{\',\')\',\']\',\'}\' match or not.\n"; <<"check \'(\',\'[\',\'{\',\')\',\']\',\'}\' match or not.\n";
return; return;
} }
void nasal_parse::die(int line,std::string info) 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"; std::cout<<">> [parse] line "<<line<<": "<<info<<".\n";
return; 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(tok_list[ptr].type!=type)
{ {
if(err_info.length()) if(err_info[0])
{ {
die(error_line,err_info); die(error_line,err_info);
return; return;
} }
std::string s="";
if(type>=tok_for)// token_table begins at tok_for
s=token_table[type-tok_for].str;
switch(type) switch(type)
{ {
case tok_num:die(error_line,"expected number"); break; case tok_num:die(error_line,"expected number"); break;
case tok_str:die(error_line,"expected string"); break; case tok_str:die(error_line,"expected string"); break;
case tok_id: die(error_line,"expected identifier");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; return;
} }
@ -628,7 +625,7 @@ nasal_ast nasal_parse::scalar()
if(tok_list[ptr].type==tok_nil) {node=nil_gen(); match(tok_nil);} 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_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_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) else if(tok_list[ptr].type==tok_func)
{ {
if(tok_list[ptr+1].type==tok_id) if(tok_list[ptr+1].type==tok_id)

View File

@ -7,12 +7,14 @@ private:
/* reference from nasal_gc */ /* reference from nasal_gc */
nasal_val**& stack_top;// stack top nasal_val**& stack_top;// stack top
/* values of nasal_vm */ /* values of nasal_vm */
int pc; // program counter uint32_t pc; // program counter
bool loop_mark;// when mark is false,break the main loop 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> ret; // ptr stack stores address for function to return
std::stack<int> counter; // iterator stack for forindex/foreach std::stack<int> counter; // iterator stack for forindex/foreach
std::vector<std::string> str_table;// symbols used in process 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_val** mem_addr; // used for mem_call
nasal_gc gc; // garbage collector nasal_gc gc; // garbage collector
@ -98,7 +100,76 @@ void nasal_vm::init(
gc.gc_init(nums,strs); gc.gc_init(nums,strs);
gc.val_stack[STACK_MAX_DEPTH-1]=nullptr; gc.val_stack[STACK_MAX_DEPTH-1]=nullptr;
str_table=strs; // get constant strings & symbols 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 loop_mark=true; // set loop mark to true
return; return;
} }
@ -140,32 +211,32 @@ void nasal_vm::opr_nop()
} }
void nasal_vm::opr_intg() void nasal_vm::opr_intg()
{ {
gc.global.resize(exec_code[pc].num,gc.nil_addr); gc.global.resize(imm[pc],gc.nil_addr);
return; return;
} }
void nasal_vm::opr_intl() 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; return;
} }
void nasal_vm::opr_offset() void nasal_vm::opr_offset()
{ {
stack_top[0]->ptr.func->offset=exec_code[pc].num; stack_top[0]->ptr.func->offset=imm[pc];
return; return;
} }
void nasal_vm::opr_loadg() void nasal_vm::opr_loadg()
{ {
gc.global[exec_code[pc].num]=*stack_top--; gc.global[imm[pc]]=(stack_top--)[0];
return; return;
} }
void nasal_vm::opr_loadl() void nasal_vm::opr_loadl()
{ {
gc.local.back()[exec_code[pc].num]=*stack_top--; gc.local.back()[imm[pc]]=(stack_top--)[0];
return; return;
} }
void nasal_vm::opr_pnum() void nasal_vm::opr_pnum()
{ {
(++stack_top)[0]=gc.num_addrs[exec_code[pc].num]; (++stack_top)[0]=gc.num_addrs[imm[pc]];
return; return;
} }
void nasal_vm::opr_pone() void nasal_vm::opr_pone()
@ -185,19 +256,19 @@ void nasal_vm::opr_pnil()
} }
void nasal_vm::opr_pstr() void nasal_vm::opr_pstr()
{ {
(++stack_top)[0]=gc.str_addrs[exec_code[pc].num]; (++stack_top)[0]=gc.str_addrs[imm[pc]];
return; return;
} }
void nasal_vm::opr_newv() void nasal_vm::opr_newv()
{ {
nasal_val* vec_addr=gc.gc_alloc(vm_vec); nasal_val* vec_addr=gc.gc_alloc(vm_vec);
nasal_val** begin=stack_top-exec_code[pc].num+1; nasal_val** begin=stack_top-imm[pc]+1;
auto& vec=vec_addr->ptr.vec->elems;// stack_top-exec_code[pc].num stores the vector auto& vec=vec_addr->ptr.vec->elems;// stack_top-imm[pc] stores the vector
vec.resize(exec_code[pc].num); vec.resize(imm[pc]);
for(int i=0;i<exec_code[pc].num;++i) for(int i=0;i<imm[pc];++i)
vec[i]=begin[i]; vec[i]=begin[i];
begin[0]=vec_addr;
stack_top=begin; stack_top=begin;
stack_top[0]=vec_addr;
return; return;
} }
void nasal_vm::opr_newh() void nasal_vm::opr_newh()
@ -208,7 +279,7 @@ void nasal_vm::opr_newh()
void nasal_vm::opr_newf() void nasal_vm::opr_newf()
{ {
nasal_val* val=gc.gc_alloc(vm_func); 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()) if(gc.local.empty())
val->ptr.func->closure.push_back(gc.nil_addr);// me val->ptr.func->closure.push_back(gc.nil_addr);// me
else else
@ -219,14 +290,14 @@ void nasal_vm::opr_newf()
void nasal_vm::opr_happ() void nasal_vm::opr_happ()
{ {
nasal_val* val=stack_top[0]; 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; return;
} }
void nasal_vm::opr_para() void nasal_vm::opr_para()
{ {
nasal_func* func=stack_top[0]->ptr.func; nasal_func* func=stack_top[0]->ptr.func;
int size=func->key_table.size(); 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); func->default_para.push_back(nullptr);
return; return;
} }
@ -235,13 +306,13 @@ void nasal_vm::opr_defpara()
nasal_val* def_val=stack_top[0]; nasal_val* def_val=stack_top[0];
nasal_func* func=(--stack_top)[0]->ptr.func; nasal_func* func=(--stack_top)[0]->ptr.func;
int size=func->key_table.size(); 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); func->default_para.push_back(def_val);
return; return;
} }
void nasal_vm::opr_dynpara() void nasal_vm::opr_dynpara()
{ {
stack_top[0]->ptr.func->dynpara=exec_code[pc].num; stack_top[0]->ptr.func->dynpara=imm[pc];
return; return;
} }
void nasal_vm::opr_unot() void nasal_vm::opr_unot()
@ -380,42 +451,26 @@ void nasal_vm::opr_neq()
} }
void nasal_vm::opr_less() void nasal_vm::opr_less()
{ {
nasal_val* val2=stack_top[0]; --stack_top;
nasal_val* val1=(--stack_top)[0]; stack_top[0]=(stack_top[0]->to_number()<stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
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;
return; return;
} }
void nasal_vm::opr_leq() void nasal_vm::opr_leq()
{ {
nasal_val* val2=stack_top[0]; --stack_top;
nasal_val* val1=(--stack_top)[0]; stack_top[0]=(stack_top[0]->to_number()<=stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
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;
return; return;
} }
void nasal_vm::opr_grt() void nasal_vm::opr_grt()
{ {
nasal_val* val2=stack_top[0]; --stack_top;
nasal_val* val1=(--stack_top)[0]; stack_top[0]=(stack_top[0]->to_number()>stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
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;
return; return;
} }
void nasal_vm::opr_geq() void nasal_vm::opr_geq()
{ {
nasal_val* val2=stack_top[0]; --stack_top;
nasal_val* val1=(--stack_top)[0]; stack_top[0]=(stack_top[0]->to_number()>=stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
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;
return; return;
} }
void nasal_vm::opr_pop() void nasal_vm::opr_pop()
@ -425,19 +480,19 @@ void nasal_vm::opr_pop()
} }
void nasal_vm::opr_jmp() void nasal_vm::opr_jmp()
{ {
pc=exec_code[pc].num-1; pc=imm[pc]-1;
return; return;
} }
void nasal_vm::opr_jt() void nasal_vm::opr_jt()
{ {
if(condition(stack_top[0])) if(condition(stack_top[0]))
pc=exec_code[pc].num-1; pc=imm[pc]-1;
return; return;
} }
void nasal_vm::opr_jf() void nasal_vm::opr_jf()
{ {
if(!condition(stack_top[0])) if(!condition(stack_top[0]))
pc=exec_code[pc].num-1; pc=imm[pc]-1;
--stack_top; --stack_top;
return; return;
} }
@ -457,12 +512,11 @@ void nasal_vm::opr_findex()
{ {
if(++counter.top()>=stack_top[0]->ptr.vec->elems.size()) if(++counter.top()>=stack_top[0]->ptr.vec->elems.size())
{ {
pc=exec_code[pc].num-1; pc=imm[pc]-1;
return; return;
} }
nasal_val* res=gc.gc_alloc(vm_num); (++stack_top)[0]=gc.gc_alloc(vm_num);
res->ptr.num=counter.top(); stack_top[0]->ptr.num=counter.top();
(++stack_top)[0]=res;
return; return;
} }
void nasal_vm::opr_feach() 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; std::vector<nasal_val*>& ref=stack_top[0]->ptr.vec->elems;
if(++counter.top()>=ref.size()) if(++counter.top()>=ref.size())
{ {
pc=exec_code[pc].num-1; pc=imm[pc]-1;
return; return;
} }
(++stack_top)[0]=ref[counter.top()]; (++stack_top)[0]=ref[counter.top()];
@ -478,12 +532,12 @@ void nasal_vm::opr_feach()
} }
void nasal_vm::opr_callg() void nasal_vm::opr_callg()
{ {
(++stack_top)[0]=gc.global[exec_code[pc].num]; (++stack_top)[0]=gc.global[imm[pc]];
return; return;
} }
void nasal_vm::opr_calll() void nasal_vm::opr_calll()
{ {
(++stack_top)[0]=gc.local.back()[exec_code[pc].num]; (++stack_top)[0]=gc.local.back()[imm[pc]];
return; return;
} }
void nasal_vm::opr_callv() void nasal_vm::opr_callv()
@ -493,10 +547,9 @@ void nasal_vm::opr_callv()
int type=vec_addr->type; int type=vec_addr->type;
if(type==vm_vec) if(type==vm_vec)
{ {
nasal_val* res=vec_addr->ptr.vec->get_val(val->to_number()); stack_top[0]=vec_addr->ptr.vec->get_val(val->to_number());
if(!res) if(!stack_top[0])
die("callv: index out of range:"+val->to_string()); die("callv: index out of range:"+num2str(val->to_number()));
stack_top[0]=res;
} }
else if(type==vm_hash) else if(type==vm_hash)
{ {
@ -505,15 +558,14 @@ void nasal_vm::opr_callv()
die("callv: must use string as the key"); die("callv: must use string as the key");
return; return;
} }
nasal_val* res=vec_addr->ptr.hash->get_val(*val->ptr.str); stack_top[0]=vec_addr->ptr.hash->get_val(*val->ptr.str);
if(!res) if(!stack_top[0])
{ {
die("callv: cannot find member \""+*val->ptr.str+"\" of this hash"); die("callv: cannot find member \""+*val->ptr.str+"\" of this hash");
return; return;
} }
if(res->type==vm_func) if(stack_top[0]->type==vm_func)
res->ptr.func->closure[0]=val;// me stack_top[0]->ptr.func->closure[0]=val;// me
stack_top[0]=res;
} }
else if(type==vm_str) else if(type==vm_str)
{ {
@ -522,12 +574,11 @@ void nasal_vm::opr_callv()
int str_size=str.length(); int str_size=str.length();
if(num<-str_size || num>=str_size) 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; return;
} }
nasal_val* res=gc.gc_alloc(vm_num); stack_top[0]=gc.gc_alloc(vm_num);
res->ptr.num=(str[num>=0? num:num+str_size]); stack_top[0]->ptr.num=(str[num>=0? num:num+str_size]);
stack_top[0]=res;
} }
else else
die("callv: must call a vector/hash/string"); die("callv: must call a vector/hash/string");
@ -542,10 +593,9 @@ void nasal_vm::opr_callvi()
return; return;
} }
// cannot use operator[],because this may cause overflow // cannot use operator[],because this may cause overflow
nasal_val* res=val->ptr.vec->get_val(exec_code[pc].num); (++stack_top)[0]=val->ptr.vec->get_val(imm[pc]);
if(!res) if(!stack_top[0])
die("callvi: index out of range:"+num2str(exec_code[pc].num)); die("callvi: index out of range:"+num2str(imm[pc]));
(++stack_top)[0]=res;
return; return;
} }
void nasal_vm::opr_callh() void nasal_vm::opr_callh()
@ -556,23 +606,22 @@ void nasal_vm::opr_callh()
die("callh: must call a hash"); die("callh: must call a hash");
return; return;
} }
nasal_val* res=val->ptr.hash->get_val(str_table[exec_code[pc].num]); stack_top[0]=val->ptr.hash->get_val(str_table[imm[pc]]);
if(!res) 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; return;
} }
if(res->type==vm_func) if(stack_top[0]->type==vm_func)
res->ptr.func->closure[0]=val;// me stack_top[0]->ptr.func->closure[0]=val;// me
stack_top[0]=res;
return; return;
} }
void nasal_vm::opr_callfv() void nasal_vm::opr_callfv()
{ {
// get parameter list and function value // 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** vec=stack_top-args_size+1;
nasal_val* func_addr=*(vec-1); nasal_val* func_addr=vec[-1];
if(func_addr->type!=vm_func) if(func_addr->type!=vm_func)
{ {
die("callfv: must call a function"); die("callfv: must call a function");
@ -584,10 +633,9 @@ void nasal_vm::opr_callfv()
// load parameters // load parameters
auto& ref_default=ref_func.default_para; auto& ref_default=ref_func.default_para;
auto& ref_closure=gc.local.back(); auto& ref_closure=gc.local.back();
auto& ref_keys=ref_func.key_table;
int offset=ref_func.offset; int offset=ref_func.offset;
int para_size=ref_keys.size(); int para_size=ref_func.key_table.size();
// load arguments // load arguments
if(args_size<para_size && !ref_default[args_size]) 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 // if args_size>para_size,for 0 to args_size will cause corruption
for(int i=0;i<para_size;++i) 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 // load dynamic argument if args_size>=para_size
if(ref_func.dynpara>=0) if(ref_func.dynpara>=0)
{ {
@ -615,7 +663,7 @@ void nasal_vm::opr_callfv()
void nasal_vm::opr_callfh() void nasal_vm::opr_callfh()
{ {
// get parameter list and function value // 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]; nasal_val* func_addr=stack_top[-1];
if(func_addr->type!=vm_func) if(func_addr->type!=vm_func)
{ {
@ -628,7 +676,6 @@ void nasal_vm::opr_callfh()
// load parameters // load parameters
auto& ref_default=ref_func.default_para; auto& ref_default=ref_func.default_para;
auto& ref_closure=gc.local.back(); auto& ref_closure=gc.local.back();
auto& ref_keys=ref_func.key_table;
if(ref_func.dynpara>=0) if(ref_func.dynpara>=0)
{ {
@ -636,7 +683,7 @@ void nasal_vm::opr_callfh()
return; return;
} }
int offset=ref_func.offset; int offset=ref_func.offset;
for(auto& i:ref_keys) for(auto& i:ref_func.key_table)
{ {
if(ref_hash.count(i.first)) if(ref_hash.count(i.first))
ref_closure[i.second+offset]=ref_hash[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() void nasal_vm::opr_callb()
{ {
nasal_val* res=(*builtin_func[exec_code[pc].num].func)(gc.local.back(),gc); loop_mark=(++stack_top)[0]=(*builtin_func[imm[pc]].func)(gc.local.back(),gc);
(++stack_top)[0]=res;
loop_mark=res;
return; return;
} }
void nasal_vm::opr_slcbegin() void nasal_vm::opr_slcbegin()
@ -676,24 +721,17 @@ void nasal_vm::opr_slcend()
} }
void nasal_vm::opr_slc() void nasal_vm::opr_slc()
{ {
nasal_val* val=*stack_top--; nasal_val* val=(stack_top--)[0];
int num; nasal_val* res=stack_top[0]->ptr.vec->get_val(val->to_number());
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);
if(!res) 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); gc.slice_stack.back()->ptr.vec->elems.push_back(res);
return; return;
} }
void nasal_vm::opr_slc2() void nasal_vm::opr_slc2()
{ {
nasal_val* val2=*stack_top--; nasal_val* val2=(stack_top--)[0];
nasal_val* val1=*stack_top--; nasal_val* val1=(stack_top--)[0];
std::vector<nasal_val*>& ref=stack_top[0]->ptr.vec->elems; std::vector<nasal_val*>& ref=stack_top[0]->ptr.vec->elems;
std::vector<nasal_val*>& aim=gc.slice_stack.back()->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() 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]; (++stack_top)[0]=mem_addr[0];
return; return;
} }
void nasal_vm::opr_mcalll() 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]; (++stack_top)[0]=mem_addr[0];
return; return;
} }
@ -749,16 +787,9 @@ void nasal_vm::opr_mcallv()
int type=vec_addr->type; int type=vec_addr->type;
if(type==vm_vec) if(type==vm_vec)
{ {
int num; mem_addr=vec_addr->ptr.vec->get_mem(val->to_number());
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);
if(!mem_addr) 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) else if(type==vm_hash)
{ {
@ -789,7 +820,7 @@ void nasal_vm::opr_mcallh()
return; return;
} }
nasal_hash& ref=*hash_addr->ptr.hash; 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); mem_addr=ref.get_mem(str);
if(!mem_addr) // create a new key if(!mem_addr) // create a new key
{ {
@ -800,89 +831,20 @@ void nasal_vm::opr_mcallh()
} }
void nasal_vm::opr_ret() void nasal_vm::opr_ret()
{ {
gc.local.pop_back(); gc.local.pop_back();// delete local scope
pc=ret.top(); pc=ret.top();ret.pop();// fetch pc
ret.pop(); (--stack_top)[0]->ptr.func->closure[0]=gc.nil_addr;// set 'me' to nil
nasal_val* ret_val=stack_top[0]; stack_top[0]=stack_top[1];// rewrite nasal_func with returned value
(--stack_top)[0]->ptr.func->closure[0]=gc.nil_addr;// set me to nil
stack_top[0]=ret_val;
return; return;
} }
void nasal_vm::run() 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(); clock_t begin_time=clock();
// main loop
for(pc=0;loop_mark&&!gc.val_stack[STACK_MAX_DEPTH-1];++pc) for(pc=0;loop_mark&&!gc.val_stack[STACK_MAX_DEPTH-1];++pc)
(this->*opr_table[exec_code[pc].op])(); (this->*exec_code[pc])();
float total_time=((double)(clock()-begin_time))/CLOCKS_PER_SEC;
if(gc.val_stack[STACK_MAX_DEPTH-1]) if(gc.val_stack[STACK_MAX_DEPTH-1])
die("stack overflow"); 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; return;
} }
#endif #endif

View File

@ -123,9 +123,7 @@ var backward=func(x)
return; return;
} }
var cnt=0; var (cnt,error)=(0,100);
var show=0;
var error=100;
while(error>0.0005) while(error>0.0005)
{ {
error=0; error=0;
@ -136,12 +134,6 @@ while(error>0.0005)
backward(i); backward(i);
} }
cnt+=1; cnt+=1;
show+=1;
if(show==350)
{
show=0;
print('epoch ',cnt,':',error,'\r');
}
} }
print('finished after ',cnt,' epoch.\n'); print('finished after ',cnt,' epoch.\n');
foreach(var v;training_set) foreach(var v;training_set)

View File

@ -1,31 +1,27 @@
import("lib.nas"); import("lib.nas");
var yMin=-0.2; var (yMin,yMax,xMin,xMax,line)=(-0.2,0.2,-1.5,-1.0,"");
var yMax=0.2; var (yDel,xDel)=(yMax-yMin,xMax-xMin);
var xMin=-1.5;
var xMax=-1.0;
for(var yPixel=0;yPixel<24;yPixel+=1) 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) for(var xPixel=0;xPixel<80;xPixel+=1)
{ {
var x=(xPixel/80)*(xMax-xMin)+xMin; var x=(xPixel/80)*xDel+xMin;
var pixel=" "; var pixel=" ";
var x0=x; var (x0,y0)=(x,y);
var y0=y;
for(var iter=0;iter<80;iter+=1) for(var iter=0;iter<80;iter+=1)
{ {
var x1=(x0*x0)-(y0*y0)+x; var x1=(x0*x0)-(y0*y0)+x;
var y1=2*x0*y0+y; var y1=2*x0*y0+y;
x0=x1; (x0,y0)=(x1,y1);
y0=y1; if((x0*x0)+(y0*y0)>4)
var d=(x0*x0)+(y0*y0);
if(d>4)
{ {
pixel=chr(" .:;+=xX$&"[int(iter/8)]); pixel=chr(" .:;+=xX$&"[iter/8]);
break; break;
} }
} }
print(pixel); line~=pixel;
} }
print('\n'); line~='\n';
} }
print(line);

View File

@ -1,10 +1,9 @@
import("lib.nas"); import("lib.nas");
var t=1; var (t,res)=(1,0);
var res=0;
for(var m=1;m<4e6;m+=2) for(var m=1;m<4e6;m+=2)
{ {
res+=t*1/m; res+=t*1/m;
t*=-1; t=-t;
} }
println(res*4); println(res*4);