variables can be used before definition
change program to command line change trace back info change print function of nasal_vec and nasal_hash
This commit is contained in:
parent
d0616ef028
commit
fa618eb97f
|
@ -844,5 +844,9 @@ You will get an error of 'undefined symbol', instead of nothing happening in mos
|
||||||
This change is __controversial__ among FGPRC's members.
|
This change is __controversial__ among FGPRC's members.
|
||||||
So maybe in the future i will use dynamic analysis again to cater to the habits of senior programmers.
|
So maybe in the future i will use dynamic analysis again to cater to the habits of senior programmers.
|
||||||
|
|
||||||
|
(2021/8/3 update) __Now i use scanning ast twice to reload symbols.
|
||||||
|
So this difference does not exist from this update.__
|
||||||
|
But a new difference is that if you call a variable before defining it, you'll get nil instead of 'undefined error'.
|
||||||
|
|
||||||
In this new interpreter, function doesn't put dynamic arguments into vector 'arg' automatically.
|
In this new interpreter, function doesn't put dynamic arguments into vector 'arg' automatically.
|
||||||
So if you use 'arg' without definition, you'll get an error of 'undefined symbol'.
|
So if you use 'arg' without definition, you'll get an error of 'undefined symbol'.
|
||||||
|
|
110
main.cpp
110
main.cpp
|
@ -1,42 +1,30 @@
|
||||||
#include "nasal.h"
|
#include "nasal.h"
|
||||||
|
|
||||||
void help_interact()
|
|
||||||
{
|
|
||||||
std::cout
|
|
||||||
<<">> [ ] input a file name to execute. \n"
|
|
||||||
<<">> [help ] show help. \n"
|
|
||||||
<<">> [ast ] view abstract syntax tree. \n"
|
|
||||||
<<">> [code ] view byte code. \n"
|
|
||||||
<<">> [exec ] execute program on bytecode vm.\n"
|
|
||||||
<<">> [logo ] print logo of nasal . \n"
|
|
||||||
<<">> [exit ] quit nasal interpreter. \n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
void help_cmd()
|
void help_cmd()
|
||||||
{
|
{
|
||||||
std::cout
|
std::cout
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
<<"use command \'chcp 65001\' if want to use unicode.\n"
|
<<"use command \'chcp 65001\' if want to use unicode.\n"
|
||||||
#endif
|
#endif
|
||||||
<<"nasal [option]|[file]\n"
|
<<"nasal [option]\n"
|
||||||
<<" input 0 argument to use the interactive interpreter.\n"
|
|
||||||
<<"option:\n"
|
<<"option:\n"
|
||||||
<<" -h, --help | get help.\n"
|
<<" -h, --help | get help.\n"
|
||||||
<<" -v, --version | get version of nasal interpreter.\n"
|
<<" -v, --version | get version of nasal interpreter.\n\n"
|
||||||
|
<<"nasal [file]\n"
|
||||||
|
<<"file:\n"
|
||||||
|
<<" input file name to execute script file.\n\n"
|
||||||
|
<<"nasal [option] [file]\n"
|
||||||
|
<<"option:\n"
|
||||||
|
<<" --lex | view token info.\n"
|
||||||
|
<<" --ast | view abstract syntax tree.\n"
|
||||||
|
<<" --code | view bytecode.\n"
|
||||||
|
<<" --exec | execute script file.\n"
|
||||||
|
<<" --time | execute and get the running time.\n"
|
||||||
<<"file:\n"
|
<<"file:\n"
|
||||||
<<" input file name to execute script file.\n";
|
<<" input file name to execute script file.\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void info()
|
|
||||||
{
|
|
||||||
std::cout
|
|
||||||
<<">> thanks to https://github.com/andyross/nasal\n"
|
|
||||||
<<">> code: https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
|
||||||
<<">> code: https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
|
|
||||||
<<">> info: http://wiki.flightgear.org/Nasal_scripting_language\n"
|
|
||||||
<<">> input \"help\" to get help .\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
void logo()
|
void logo()
|
||||||
{
|
{
|
||||||
std::cout
|
std::cout
|
||||||
|
@ -45,14 +33,21 @@ void logo()
|
||||||
<<" / \\/ / _` / __|/ _` | | \n"
|
<<" / \\/ / _` / __|/ _` | | \n"
|
||||||
<<" / /\\ / (_| \\__ \\ (_| | | \n"
|
<<" / /\\ / (_| \\__ \\ (_| | | \n"
|
||||||
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
||||||
<<" nasal interpreter ver 7.0 \n";
|
<<"nasal interpreter ver 7.0\n"
|
||||||
|
<<"thanks to : https://github.com/andyross/nasal\n"
|
||||||
|
<<"code repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
||||||
|
<<"code repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
|
||||||
|
<<"lang info : http://wiki.flightgear.org/Nasal_scripting_language\n"
|
||||||
|
<<"input \"nasal -h\" to get help .\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void die(const char* stage,std::string& filename)
|
void die(const char* stage,std::string& filename)
|
||||||
{
|
{
|
||||||
std::cout<<">> ["<<stage<<"] in <\""<<filename<<"\">: error(s) occurred,stop.\n";
|
std::cout<<">> ["<<stage<<"] in <"<<filename<<">: error(s) occurred,stop.\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute(std::string& file,std::string& command)
|
void execute(std::string& file,std::string& command)
|
||||||
{
|
{
|
||||||
nasal_lexer lexer;
|
nasal_lexer lexer;
|
||||||
|
@ -67,13 +62,18 @@ void execute(std::string& file,std::string& command)
|
||||||
die("lexer",file);
|
die("lexer",file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(command=="--lex")
|
||||||
|
{
|
||||||
|
lexer.print_token();
|
||||||
|
return;
|
||||||
|
}
|
||||||
parse.main_process(lexer.get_token_list());
|
parse.main_process(lexer.get_token_list());
|
||||||
if(parse.get_error())
|
if(parse.get_error())
|
||||||
{
|
{
|
||||||
die("parse",file);
|
die("parse",file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(command=="ast")
|
if(command=="--ast")
|
||||||
{
|
{
|
||||||
parse.get_root().print_ast(0);
|
parse.get_root().print_ast(0);
|
||||||
return;
|
return;
|
||||||
|
@ -91,7 +91,7 @@ void execute(std::string& file,std::string& command)
|
||||||
die("codegen",file);
|
die("codegen",file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(command=="code")
|
if(command=="--code")
|
||||||
{
|
{
|
||||||
codegen.print_byte_code();
|
codegen.print_byte_code();
|
||||||
return;
|
return;
|
||||||
|
@ -101,55 +101,45 @@ void execute(std::string& file,std::string& command)
|
||||||
codegen.get_num_table(),
|
codegen.get_num_table(),
|
||||||
import.get_file()
|
import.get_file()
|
||||||
);
|
);
|
||||||
|
if(command=="--exec")
|
||||||
vm.run(codegen.get_exec_code());
|
vm.run(codegen.get_exec_code());
|
||||||
|
else if(command=="--time")
|
||||||
|
{
|
||||||
|
clock_t begin=clock();
|
||||||
|
vm.run(codegen.get_exec_code());
|
||||||
|
std::cout<<"process exited after "<<((double)(clock()-begin))/CLOCKS_PER_SEC<<"s.\n";
|
||||||
|
}
|
||||||
vm.clear();
|
vm.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void interact()
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
// use chcp 65001 to use unicode io
|
|
||||||
system("chcp 65001");
|
|
||||||
#endif
|
|
||||||
std::string command,file="null";
|
|
||||||
logo();
|
|
||||||
info();
|
|
||||||
while(1)
|
|
||||||
{
|
|
||||||
std::cout<<">> ";
|
|
||||||
std::cin>>command;
|
|
||||||
if(command=="help")
|
|
||||||
help_interact();
|
|
||||||
else if(command=="logo")
|
|
||||||
logo();
|
|
||||||
else if(command=="exit")
|
|
||||||
return;
|
|
||||||
else if(command=="ast" || command=="code" || command=="exec")
|
|
||||||
execute(file,command);
|
|
||||||
else
|
|
||||||
file=command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int main(int argc,const char* argv[])
|
int main(int argc,const char* argv[])
|
||||||
{
|
{
|
||||||
std::string command,file="null";
|
std::string command,file="null";
|
||||||
if(argc==1)
|
if(argc==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"--version")))
|
||||||
interact();
|
|
||||||
else if(argc==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"--version")))
|
|
||||||
logo();
|
logo();
|
||||||
else if(argc==2 && (!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help")))
|
else if(argc==2 && (!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help")))
|
||||||
help_cmd();
|
help_cmd();
|
||||||
else if(argc==2 && argv[1][0]!='-')
|
else if(argc==2 && argv[1][0]!='-')
|
||||||
{
|
{
|
||||||
file=argv[1];
|
file=argv[1];
|
||||||
command="exec";
|
command="--exec";
|
||||||
|
execute(file,command);
|
||||||
|
}
|
||||||
|
else if(argc==3 &&
|
||||||
|
(!strcmp(argv[1],"--lex") ||
|
||||||
|
!strcmp(argv[1],"--ast") ||
|
||||||
|
!strcmp(argv[1],"--code") ||
|
||||||
|
!strcmp(argv[1],"--exec") ||
|
||||||
|
!strcmp(argv[1],"--time")))
|
||||||
|
{
|
||||||
|
file=argv[2];
|
||||||
|
command=argv[1];
|
||||||
execute(file,command);
|
execute(file,command);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cout
|
std::cout
|
||||||
<<"invalid command.\n"
|
<<"invalid argument(s).\n"
|
||||||
<<"use nasal -h to get help.\n";
|
<<"use nasal -h to get help.\n";
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -175,7 +175,7 @@ nasal_val* builtin_system(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
builtin_err("system","\"str\" must be string");
|
builtin_err("system","\"str\" must be string");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
ret_addr->ptr.num=(double)system(str_addr->ptr.str->data());
|
ret_addr->ptr.num=(double)system(str_addr->ptr.str->c_str());
|
||||||
return ret_addr;
|
return ret_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,37 +252,38 @@ nasal_val* builtin_fout(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
|
|
||||||
nasal_val* builtin_split(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
nasal_val* builtin_split(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
{
|
{
|
||||||
nasal_val* delimeter_val_addr=local_scope[1];
|
nasal_val* deli_val_addr=local_scope[1];
|
||||||
nasal_val* string_val_addr=local_scope[2];
|
nasal_val* str_val_addr=local_scope[2];
|
||||||
if(delimeter_val_addr->type!=vm_str)
|
if(deli_val_addr->type!=vm_str)
|
||||||
{
|
{
|
||||||
builtin_err("split","\"delimeter\" must be string");
|
builtin_err("split","\"delimeter\" must be string");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if(string_val_addr->type!=vm_str)
|
if(str_val_addr->type!=vm_str)
|
||||||
{
|
{
|
||||||
builtin_err("split","\"string\" must be string");
|
builtin_err("split","\"string\" must be string");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
std::string delimeter=*delimeter_val_addr->ptr.str;
|
std::string& delimeter=*deli_val_addr->ptr.str;
|
||||||
std::string source=*string_val_addr->ptr.str;
|
std::string& source=*str_val_addr->ptr.str;
|
||||||
int delimeter_len=delimeter.length();
|
size_t delimeter_len=delimeter.length();
|
||||||
int source_len=source.length();
|
size_t source_len=source.length();
|
||||||
nasal_val* ret_addr=gc.builtin_alloc(vm_vec);
|
|
||||||
std::vector<nasal_val*>& ref_vec=ret_addr->ptr.vec->elems;
|
|
||||||
std::string tmp="";
|
|
||||||
|
|
||||||
|
// push it to local scope to avoid being sweeped
|
||||||
|
local_scope.push_back(gc.gc_alloc(vm_vec));
|
||||||
|
|
||||||
|
std::vector<nasal_val*>& vec=local_scope.back()->ptr.vec->elems;
|
||||||
if(!delimeter_len)
|
if(!delimeter_len)
|
||||||
{
|
{
|
||||||
for(int i=0;i<source_len;++i)
|
for(int i=0;i<source_len;++i)
|
||||||
{
|
{
|
||||||
nasal_val* str_addr=gc.builtin_alloc(vm_str);
|
vec.push_back(gc.gc_alloc(vm_str));
|
||||||
*str_addr->ptr.str=source[i];
|
*vec.back()->ptr.str=source[i];
|
||||||
ref_vec.push_back(str_addr);
|
|
||||||
}
|
}
|
||||||
return ret_addr;
|
return local_scope.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string tmp="";
|
||||||
for(int i=0;i<source_len;++i)
|
for(int i=0;i<source_len;++i)
|
||||||
{
|
{
|
||||||
bool check_delimeter=false;
|
bool check_delimeter=false;
|
||||||
|
@ -298,9 +299,8 @@ nasal_val* builtin_split(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
{
|
{
|
||||||
if(tmp.length())
|
if(tmp.length())
|
||||||
{
|
{
|
||||||
nasal_val* str_addr=gc.builtin_alloc(vm_str);
|
vec.push_back(gc.gc_alloc(vm_str));
|
||||||
*str_addr->ptr.str=tmp;
|
*vec.back()->ptr.str=tmp;
|
||||||
ref_vec.push_back(str_addr);
|
|
||||||
tmp="";
|
tmp="";
|
||||||
}
|
}
|
||||||
i+=delimeter_len-1;
|
i+=delimeter_len-1;
|
||||||
|
@ -310,12 +310,11 @@ nasal_val* builtin_split(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
}
|
}
|
||||||
if(tmp.length())
|
if(tmp.length())
|
||||||
{
|
{
|
||||||
nasal_val* str_addr=gc.builtin_alloc(vm_str);
|
vec.push_back(gc.gc_alloc(vm_str));
|
||||||
*str_addr->ptr.str=tmp;
|
*vec.back()->ptr.str=tmp;
|
||||||
ref_vec.push_back(str_addr);
|
|
||||||
tmp="";
|
tmp="";
|
||||||
}
|
}
|
||||||
return ret_addr;
|
return local_scope.back();
|
||||||
}
|
}
|
||||||
nasal_val* builtin_rand(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
nasal_val* builtin_rand(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
{
|
{
|
||||||
|
@ -330,11 +329,11 @@ nasal_val* builtin_rand(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
srand((unsigned int)val_addr->ptr.num);
|
srand((unsigned int)val_addr->ptr.num);
|
||||||
return gc.nil_addr;
|
return gc.nil_addr;
|
||||||
}
|
}
|
||||||
double num=0;
|
|
||||||
for(int i=0;i<5;++i)
|
|
||||||
num=(num+rand())*(1.0/(RAND_MAX+1.0));
|
|
||||||
nasal_val* ret_addr=gc.gc_alloc(vm_num);
|
nasal_val* ret_addr=gc.gc_alloc(vm_num);
|
||||||
ret_addr->ptr.num=num;
|
ret_addr->ptr.num=0;
|
||||||
|
for(int i=0;i<5;++i)
|
||||||
|
ret_addr->ptr.num=(ret_addr->ptr.num+rand())*(1.0/(RAND_MAX+1.0));
|
||||||
return ret_addr;
|
return ret_addr;
|
||||||
}
|
}
|
||||||
nasal_val* builtin_id(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
nasal_val* builtin_id(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
|
@ -342,7 +341,7 @@ nasal_val* builtin_id(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
nasal_val* val_addr=local_scope[1];
|
nasal_val* val_addr=local_scope[1];
|
||||||
nasal_val* ret_addr=gc.gc_alloc(vm_str);
|
nasal_val* ret_addr=gc.gc_alloc(vm_str);
|
||||||
char buf[32];
|
char buf[32];
|
||||||
sprintf(buf,"0x%p",val_addr);
|
sprintf(buf,"%p",val_addr);
|
||||||
*ret_addr->ptr.str=buf;
|
*ret_addr->ptr.str=buf;
|
||||||
return ret_addr;
|
return ret_addr;
|
||||||
}
|
}
|
||||||
|
@ -652,15 +651,17 @@ nasal_val* builtin_keys(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
builtin_err("keys","\"hash\" must be hash");
|
builtin_err("keys","\"hash\" must be hash");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
nasal_val* ret_addr=gc.builtin_alloc(vm_vec);
|
|
||||||
std::vector<nasal_val*>& ref_vec=ret_addr->ptr.vec->elems;
|
// push vector into local scope to avoid being sweeped
|
||||||
|
local_scope.push_back(gc.gc_alloc(vm_vec));
|
||||||
|
std::vector<nasal_val*>& vec=local_scope.back()->ptr.vec->elems;
|
||||||
for(auto iter:hash_addr->ptr.hash->elems)
|
for(auto iter:hash_addr->ptr.hash->elems)
|
||||||
{
|
{
|
||||||
nasal_val* str_addr=gc.builtin_alloc(vm_str);
|
nasal_val* str_addr=gc.gc_alloc(vm_str);
|
||||||
*str_addr->ptr.str=iter.first;
|
*str_addr->ptr.str=iter.first;
|
||||||
ref_vec.push_back(str_addr);
|
vec.push_back(str_addr);
|
||||||
}
|
}
|
||||||
return ret_addr;
|
return local_scope.back();
|
||||||
}
|
}
|
||||||
nasal_val* builtin_import(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
nasal_val* builtin_import(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
{
|
{
|
||||||
|
@ -799,7 +800,7 @@ nasal_val* builtin_cmp(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
nasal_val* ret_addr=gc.gc_alloc(vm_num);
|
nasal_val* ret_addr=gc.gc_alloc(vm_num);
|
||||||
ret_addr->ptr.num=strcmp(a_addr->ptr.str->data(),b_addr->ptr.str->data());
|
ret_addr->ptr.num=strcmp(a_addr->ptr.str->c_str(),b_addr->ptr.str->c_str());
|
||||||
return ret_addr;
|
return ret_addr;
|
||||||
}
|
}
|
||||||
nasal_val* builtin_chr(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
nasal_val* builtin_chr(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||||
|
|
|
@ -210,6 +210,7 @@ private:
|
||||||
void die(std::string,int);
|
void die(std::string,int);
|
||||||
void regist_number(double);
|
void regist_number(double);
|
||||||
void regist_string(std::string&);
|
void regist_string(std::string&);
|
||||||
|
void find_symbol(nasal_ast&);
|
||||||
void add_sym(std::string&);
|
void add_sym(std::string&);
|
||||||
int local_find(std::string&);
|
int local_find(std::string&);
|
||||||
int global_find(std::string&);
|
int global_find(std::string&);
|
||||||
|
@ -278,6 +279,32 @@ void nasal_codegen::regist_string(std::string& str)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nasal_codegen::find_symbol(nasal_ast& node)
|
||||||
|
{
|
||||||
|
// symbol definition checked here
|
||||||
|
// if find a function, return
|
||||||
|
if(node.get_type()==ast_func)
|
||||||
|
return;
|
||||||
|
// find definition, check
|
||||||
|
else if(node.get_type()==ast_def)
|
||||||
|
{
|
||||||
|
if(node.get_children()[0].get_type()==ast_multi_id)
|
||||||
|
for(auto& i:node.get_children()[0].get_children())
|
||||||
|
add_sym(i.get_str());
|
||||||
|
else
|
||||||
|
add_sym(node.get_children()[0].get_str());
|
||||||
|
find_symbol(node.get_children()[1]);
|
||||||
|
}
|
||||||
|
// find iterator(foreach, forindex), check
|
||||||
|
else if(node.get_type()==ast_new_iter)
|
||||||
|
add_sym(node.get_children()[0].get_str());
|
||||||
|
// check children
|
||||||
|
else
|
||||||
|
for(auto& i:node.get_children())
|
||||||
|
find_symbol(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void nasal_codegen::add_sym(std::string& name)
|
void nasal_codegen::add_sym(std::string& name)
|
||||||
{
|
{
|
||||||
if(local.empty())
|
if(local.empty())
|
||||||
|
@ -419,6 +446,9 @@ void nasal_codegen::func_gen(nasal_ast& ast)
|
||||||
gen(op_jmp,0,0);
|
gen(op_jmp,0,0);
|
||||||
|
|
||||||
nasal_ast& block=ast.get_children()[1];
|
nasal_ast& block=ast.get_children()[1];
|
||||||
|
// search symbols first, must use after loading parameters
|
||||||
|
// or the location of symbols will change and cause fatal error
|
||||||
|
find_symbol(block);
|
||||||
block_gen(block);
|
block_gen(block);
|
||||||
for(auto& i:local)
|
for(auto& i:local)
|
||||||
exec_code[local_label].num+=i.size();
|
exec_code[local_label].num+=i.size();
|
||||||
|
@ -602,7 +632,6 @@ void nasal_codegen::mcall_hash(nasal_ast& ast)
|
||||||
void nasal_codegen::single_def(nasal_ast& ast)
|
void nasal_codegen::single_def(nasal_ast& ast)
|
||||||
{
|
{
|
||||||
std::string& str=ast.get_children()[0].get_str();
|
std::string& str=ast.get_children()[0].get_str();
|
||||||
add_sym(str);
|
|
||||||
calc_gen(ast.get_children()[1]);
|
calc_gen(ast.get_children()[1]);
|
||||||
local.empty()?gen(op_loadg,global_find(str),ast.get_line()):gen(op_loadl,local_find(str),ast.get_line());
|
local.empty()?gen(op_loadg,global_find(str),ast.get_line()):gen(op_loadl,local_find(str),ast.get_line());
|
||||||
return;
|
return;
|
||||||
|
@ -618,7 +647,6 @@ void nasal_codegen::multi_def(nasal_ast& ast)
|
||||||
{
|
{
|
||||||
calc_gen(vals[i]);
|
calc_gen(vals[i]);
|
||||||
std::string& str=ids[i].get_str();
|
std::string& str=ids[i].get_str();
|
||||||
add_sym(str);
|
|
||||||
local.empty()?gen(op_loadg,global_find(str),ids[i].get_line()):gen(op_loadl,local_find(str),ids[i].get_line());
|
local.empty()?gen(op_loadg,global_find(str),ids[i].get_line()):gen(op_loadl,local_find(str),ids[i].get_line());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -629,7 +657,6 @@ void nasal_codegen::multi_def(nasal_ast& ast)
|
||||||
{
|
{
|
||||||
gen(op_callvi,i,ast.get_children()[1].get_line());
|
gen(op_callvi,i,ast.get_children()[1].get_line());
|
||||||
std::string& str=ids[i].get_str();
|
std::string& str=ids[i].get_str();
|
||||||
add_sym(str);
|
|
||||||
local.empty()?gen(op_loadg,global_find(str),ids[i].get_line()):gen(op_loadl,local_find(str),ids[i].get_line());
|
local.empty()?gen(op_loadg,global_find(str),ids[i].get_line()):gen(op_loadl,local_find(str),ids[i].get_line());
|
||||||
}
|
}
|
||||||
gen(op_pop,0,ast.get_line());
|
gen(op_pop,0,ast.get_line());
|
||||||
|
@ -840,7 +867,6 @@ void nasal_codegen::forindex_gen(nasal_ast& ast)
|
||||||
if(ast.get_children()[0].get_type()==ast_new_iter)
|
if(ast.get_children()[0].get_type()==ast_new_iter)
|
||||||
{
|
{
|
||||||
std::string& str=ast.get_children()[0].get_children()[0].get_str();
|
std::string& str=ast.get_children()[0].get_children()[0].get_str();
|
||||||
add_sym(str);
|
|
||||||
local.empty()?
|
local.empty()?
|
||||||
gen(op_loadg,global_find(str),ast.get_children()[0].get_children()[0].get_line())
|
gen(op_loadg,global_find(str),ast.get_children()[0].get_children()[0].get_line())
|
||||||
:gen(op_loadl,local_find(str),ast.get_children()[0].get_children()[0].get_line());
|
:gen(op_loadl,local_find(str),ast.get_children()[0].get_children()[0].get_line());
|
||||||
|
@ -869,7 +895,6 @@ void nasal_codegen::foreach_gen(nasal_ast& ast)
|
||||||
if(ast.get_children()[0].get_type()==ast_new_iter)
|
if(ast.get_children()[0].get_type()==ast_new_iter)
|
||||||
{
|
{
|
||||||
std::string& str=ast.get_children()[0].get_children()[0].get_str();
|
std::string& str=ast.get_children()[0].get_children()[0].get_str();
|
||||||
add_sym(str);
|
|
||||||
local.empty()?
|
local.empty()?
|
||||||
gen(op_loadg,global_find(str),ast.get_children()[0].get_children()[0].get_line())
|
gen(op_loadg,global_find(str),ast.get_children()[0].get_children()[0].get_line())
|
||||||
:gen(op_loadl,local_find(str),ast.get_children()[0].get_children()[0].get_line());
|
:gen(op_loadl,local_find(str),ast.get_children()[0].get_children()[0].get_line());
|
||||||
|
@ -1148,6 +1173,9 @@ void nasal_codegen::main_progress(nasal_ast& ast)
|
||||||
|
|
||||||
global.clear();
|
global.clear();
|
||||||
local.clear();
|
local.clear();
|
||||||
|
|
||||||
|
// search symbols first
|
||||||
|
find_symbol(ast);
|
||||||
gen(op_intg,0,0);
|
gen(op_intg,0,0);
|
||||||
for(auto& tmp:ast.get_children())
|
for(auto& tmp:ast.get_children())
|
||||||
{
|
{
|
||||||
|
|
21
nasal_gc.h
21
nasal_gc.h
|
@ -96,6 +96,11 @@ nasal_val** nasal_vec::get_mem(int index)
|
||||||
}
|
}
|
||||||
void nasal_vec::print()
|
void nasal_vec::print()
|
||||||
{
|
{
|
||||||
|
if(!elems.size())
|
||||||
|
{
|
||||||
|
std::cout<<"[]";
|
||||||
|
return;
|
||||||
|
}
|
||||||
std::cout<<'[';
|
std::cout<<'[';
|
||||||
for(auto i:elems)
|
for(auto i:elems)
|
||||||
{
|
{
|
||||||
|
@ -108,20 +113,19 @@ void nasal_vec::print()
|
||||||
case vm_hash: i->ptr.hash->print(); break;
|
case vm_hash: i->ptr.hash->print(); break;
|
||||||
case vm_func: std::cout<<"func(...){...}"; break;
|
case vm_func: std::cout<<"func(...){...}"; break;
|
||||||
}
|
}
|
||||||
std::cout<<',';
|
std::cout<<",]"[i==elems.back()];
|
||||||
}
|
}
|
||||||
std::cout<<']';
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*functions of nasal_hash*/
|
/*functions of nasal_hash*/
|
||||||
nasal_val* nasal_hash::get_val(std::string& key)
|
nasal_val* nasal_hash::get_val(std::string& key)
|
||||||
{
|
{
|
||||||
nasal_val* ret_addr=nullptr;
|
|
||||||
if(elems.count(key))
|
if(elems.count(key))
|
||||||
return elems[key];
|
return elems[key];
|
||||||
else if(elems.count("parents"))
|
else if(elems.count("parents"))
|
||||||
{
|
{
|
||||||
|
nasal_val* ret_addr=nullptr;
|
||||||
nasal_val* val_addr=elems["parents"];
|
nasal_val* val_addr=elems["parents"];
|
||||||
if(val_addr->type==vm_vec)
|
if(val_addr->type==vm_vec)
|
||||||
for(auto i:val_addr->ptr.vec->elems)
|
for(auto i:val_addr->ptr.vec->elems)
|
||||||
|
@ -136,11 +140,11 @@ nasal_val* nasal_hash::get_val(std::string& key)
|
||||||
}
|
}
|
||||||
nasal_val** nasal_hash::get_mem(std::string& key)
|
nasal_val** nasal_hash::get_mem(std::string& key)
|
||||||
{
|
{
|
||||||
nasal_val** mem_addr=nullptr;
|
|
||||||
if(elems.count(key))
|
if(elems.count(key))
|
||||||
return &elems[key];
|
return &elems[key];
|
||||||
else if(elems.count("parents"))
|
else if(elems.count("parents"))
|
||||||
{
|
{
|
||||||
|
nasal_val** mem_addr=nullptr;
|
||||||
nasal_val* val_addr=elems["parents"];
|
nasal_val* val_addr=elems["parents"];
|
||||||
if(val_addr->type==vm_vec)
|
if(val_addr->type==vm_vec)
|
||||||
for(auto i:val_addr->ptr.vec->elems)
|
for(auto i:val_addr->ptr.vec->elems)
|
||||||
|
@ -155,6 +159,12 @@ nasal_val** nasal_hash::get_mem(std::string& key)
|
||||||
}
|
}
|
||||||
void nasal_hash::print()
|
void nasal_hash::print()
|
||||||
{
|
{
|
||||||
|
if(!elems.size())
|
||||||
|
{
|
||||||
|
std::cout<<"{}";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t iter=0;
|
||||||
std::cout<<'{';
|
std::cout<<'{';
|
||||||
for(auto& i:elems)
|
for(auto& i:elems)
|
||||||
{
|
{
|
||||||
|
@ -169,9 +179,8 @@ void nasal_hash::print()
|
||||||
case vm_hash: tmp->ptr.hash->print(); break;
|
case vm_hash: tmp->ptr.hash->print(); break;
|
||||||
case vm_func: std::cout<<"func(...){...}"; break;
|
case vm_func: std::cout<<"func(...){...}"; break;
|
||||||
}
|
}
|
||||||
std::cout<<',';
|
std::cout<<",}"[(++iter)==elems.size()];
|
||||||
}
|
}
|
||||||
std::cout<<'}';
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ void nasal_lexer::openfile(std::string& filename)
|
||||||
if(fin.fail())
|
if(fin.fail())
|
||||||
{
|
{
|
||||||
++error;
|
++error;
|
||||||
std::cout<<">> [lexer] cannot open file \""<<filename<<"\".\n";
|
std::cout<<">> [lexer] cannot open file <"<<filename<<">.\n";
|
||||||
fin.close();
|
fin.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
70
nasal_vm.h
70
nasal_vm.h
|
@ -18,10 +18,12 @@ private:
|
||||||
/* values used for debug */
|
/* values used for debug */
|
||||||
std::vector<opcode> bytecode; // bytecode
|
std::vector<opcode> bytecode; // bytecode
|
||||||
std::vector<std::string> files; // files
|
std::vector<std::string> files; // files
|
||||||
|
/* debug functions */
|
||||||
|
void bytecodeinfo(uint32_t);
|
||||||
void stackinfo(int);
|
void stackinfo(int);
|
||||||
void die(std::string);
|
void die(std::string);
|
||||||
void stackoverflow();
|
void stackoverflow();
|
||||||
|
/* vm calculation functions*/
|
||||||
bool condition(nasal_val*);
|
bool condition(nasal_val*);
|
||||||
void opr_intg();
|
void opr_intg();
|
||||||
void opr_intl();
|
void opr_intl();
|
||||||
|
@ -132,6 +134,14 @@ void nasal_vm::clear()
|
||||||
imm.clear();
|
imm.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
void nasal_vm::bytecodeinfo(uint32_t p)
|
||||||
|
{
|
||||||
|
printf("\t0x%.8x: %s 0x%.8x",p,code_table[bytecode[p].op].name,bytecode[p].num);
|
||||||
|
if(bytecode[p].op==op_callb)
|
||||||
|
printf(":%s",builtin_func[bytecode[p].num].name);
|
||||||
|
printf(" (%s line %d)\n",files[bytecode[p].fidx].c_str(),bytecode[p].line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
void nasal_vm::stackinfo(int limit)
|
void nasal_vm::stackinfo(int limit)
|
||||||
{
|
{
|
||||||
printf("vm stack(limit %d):\n",limit);
|
printf("vm stack(limit %d):\n",limit);
|
||||||
|
@ -143,10 +153,10 @@ void nasal_vm::stackinfo(int limit)
|
||||||
switch(stack_top[-i]->type)
|
switch(stack_top[-i]->type)
|
||||||
{
|
{
|
||||||
case vm_nil: printf("\t%p nil\n",stack_top[-i]);break;
|
case vm_nil: printf("\t%p nil\n",stack_top[-i]);break;
|
||||||
case vm_num: printf("\t%p num :%lf\n",stack_top[-i],stack_top[-i]->ptr.num);break;
|
case vm_num: printf("\t%p num:%lf\n",stack_top[-i],stack_top[-i]->ptr.num);break;
|
||||||
case vm_str: printf("\t%p str :",stack_top[-i]->ptr.str);raw_string(*stack_top[-i]->ptr.str);putchar('\n');break;
|
case vm_str: printf("\t%p str:",stack_top[-i]->ptr.str);raw_string(*stack_top[-i]->ptr.str);putchar('\n');break;
|
||||||
case vm_func: printf("\t%p func\n",stack_top[-i]->ptr.func);break;
|
case vm_func: printf("\t%p func\n",stack_top[-i]->ptr.func);break;
|
||||||
case vm_vec: printf("\t%p vec \n",stack_top[-i]->ptr.vec); break;
|
case vm_vec: printf("\t%p vec\n",stack_top[-i]->ptr.vec);break;
|
||||||
case vm_hash: printf("\t%p hash\n",stack_top[-i]->ptr.hash);break;
|
case vm_hash: printf("\t%p hash\n",stack_top[-i]->ptr.hash);break;
|
||||||
default: printf("\t%p unknown\n",stack_top[-i]);break;
|
default: printf("\t%p unknown\n",stack_top[-i]);break;
|
||||||
}
|
}
|
||||||
|
@ -156,20 +166,12 @@ void nasal_vm::stackinfo(int limit)
|
||||||
void nasal_vm::die(std::string str)
|
void nasal_vm::die(std::string str)
|
||||||
{
|
{
|
||||||
printf(">> [vm] error at 0x%.8x: %s\ntrace back:\n",pc,str.c_str());
|
printf(">> [vm] error at 0x%.8x: %s\ntrace back:\n",pc,str.c_str());
|
||||||
// add error pc into ret_stack
|
|
||||||
ret.push(pc);
|
|
||||||
// trace back will use ret_stack
|
// trace back will use ret_stack
|
||||||
|
bytecodeinfo(pc);
|
||||||
while(!ret.empty())
|
while(!ret.empty())
|
||||||
{
|
{
|
||||||
uint32_t point=ret.top();
|
bytecodeinfo(ret.top());
|
||||||
ret.pop();
|
ret.pop();
|
||||||
printf(
|
|
||||||
"\t0x%.8x: %s 0x%.8x (%s line %d)\n",
|
|
||||||
point,
|
|
||||||
code_table[bytecode[point].op].name,
|
|
||||||
bytecode[point].num,
|
|
||||||
files[bytecode[point].fidx].c_str(),
|
|
||||||
bytecode[point].line);
|
|
||||||
}
|
}
|
||||||
stackinfo(10);
|
stackinfo(10);
|
||||||
gc.val_stack[STACK_MAX_DEPTH-1]=(nasal_val*)0xffff;
|
gc.val_stack[STACK_MAX_DEPTH-1]=(nasal_val*)0xffff;
|
||||||
|
@ -177,17 +179,21 @@ void nasal_vm::die(std::string str)
|
||||||
}
|
}
|
||||||
void nasal_vm::stackoverflow()
|
void nasal_vm::stackoverflow()
|
||||||
{
|
{
|
||||||
printf(">> [vm] stack overflow\nlast called(limit 10):\n");
|
printf(">> [vm] stack overflow\ntrace back:\n");
|
||||||
for(int i=0;i<10 && !ret.empty();++i,ret.pop())
|
for(uint32_t same_cnt=0,point=0,last_point=0;!ret.empty();last_point=point,ret.pop())
|
||||||
{
|
{
|
||||||
uint32_t point=ret.top();
|
point=ret.top();
|
||||||
printf(
|
if(point!=last_point)
|
||||||
"\t0x%.8x: %s 0x%.8x (%s line %d)\n",
|
{
|
||||||
point,
|
if(same_cnt)
|
||||||
code_table[bytecode[point].op].name,
|
{
|
||||||
bytecode[point].num,
|
printf("\t0x%.8x: %d same call(s) ...\n",last_point,same_cnt);
|
||||||
files[bytecode[point].fidx].c_str(),
|
same_cnt=0;
|
||||||
bytecode[point].line);
|
}
|
||||||
|
bytecodeinfo(point);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++same_cnt;
|
||||||
}
|
}
|
||||||
stackinfo(10);
|
stackinfo(10);
|
||||||
return;
|
return;
|
||||||
|
@ -709,7 +715,7 @@ inline void nasal_vm::opr_callh()
|
||||||
inline void nasal_vm::opr_callfv()
|
inline void nasal_vm::opr_callfv()
|
||||||
{
|
{
|
||||||
// get parameter list and function value
|
// get parameter list and function value
|
||||||
int args_size=imm[pc];
|
uint32_t 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)
|
||||||
|
@ -724,8 +730,8 @@ inline void nasal_vm::opr_callfv()
|
||||||
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();
|
||||||
|
|
||||||
int offset=ref_func.offset;
|
uint32_t offset=ref_func.offset;
|
||||||
int para_size=ref_func.key_table.size();
|
uint32_t 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])
|
||||||
{
|
{
|
||||||
|
@ -734,7 +740,7 @@ inline void nasal_vm::opr_callfv()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 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
|
||||||
int min_size=std::min(para_size,args_size);
|
uint32_t min_size=std::min(para_size,args_size);
|
||||||
for(int i=0;i<min_size;++i)
|
for(int i=0;i<min_size;++i)
|
||||||
ref_closure[i+offset]=vec[i];
|
ref_closure[i+offset]=vec[i];
|
||||||
for(int i=args_size;i<para_size;++i)
|
for(int i=args_size;i<para_size;++i)
|
||||||
|
@ -775,7 +781,7 @@ inline void nasal_vm::opr_callfh()
|
||||||
die("callfh: special call cannot use dynamic argument");
|
die("callfh: special call cannot use dynamic argument");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int offset=ref_func.offset;
|
uint32_t offset=ref_func.offset;
|
||||||
for(auto& i:ref_func.key_table)
|
for(auto& i:ref_func.key_table)
|
||||||
{
|
{
|
||||||
if(ref_hash.count(i.first))
|
if(ref_hash.count(i.first))
|
||||||
|
@ -938,7 +944,7 @@ inline void nasal_vm::opr_ret()
|
||||||
}
|
}
|
||||||
void nasal_vm::run(std::vector<opcode>& exec)
|
void nasal_vm::run(std::vector<opcode>& exec)
|
||||||
{
|
{
|
||||||
uint64_t count[op_ret+1]={0};
|
//uint64_t count[op_ret+1]={0};
|
||||||
void* opr_table[]=
|
void* opr_table[]=
|
||||||
{
|
{
|
||||||
&&nop, &&intg, &&intl, &&offset,
|
&&nop, &&intg, &&intl, &&offset,
|
||||||
|
@ -970,15 +976,15 @@ void nasal_vm::run(std::vector<opcode>& exec)
|
||||||
imm.push_back(i.num);
|
imm.push_back(i.num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set canary and program counter
|
||||||
auto& canary=gc.val_stack[STACK_MAX_DEPTH-1];
|
auto& canary=gc.val_stack[STACK_MAX_DEPTH-1];
|
||||||
// clock_t begin=clock();
|
|
||||||
pc=0;
|
pc=0;
|
||||||
|
// run
|
||||||
goto *code[pc];
|
goto *code[pc];
|
||||||
|
|
||||||
nop:
|
nop:
|
||||||
if(canary && canary!=(nasal_val*)0xffff)
|
if(canary && canary!=(nasal_val*)0xffff)
|
||||||
stackoverflow();
|
stackoverflow();
|
||||||
// std::cout<<">> [vm] process exited after "<<((double)(clock()-begin))/CLOCKS_PER_SEC<<"s.\n";
|
|
||||||
// debug
|
// debug
|
||||||
// for(int i=0;i<15;++i)
|
// for(int i=0;i<15;++i)
|
||||||
// {
|
// {
|
||||||
|
|
Loading…
Reference in New Issue