diff --git a/main.cpp b/main.cpp index b0fbb47..4d058fb 100644 --- a/main.cpp +++ b/main.cpp @@ -2,153 +2,153 @@ void help_cmd() { - std::cout + std::cout #ifdef _WIN32 - <<"use command \'chcp 65001\' if want to use unicode.\n" + <<"use command \'chcp 65001\' if want to use unicode.\n" #endif - <<"nasal [option]\n" - <<"option:\n" - <<" -h, --help | get help.\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" - <<" -l, --lex | view token info.\n" - <<" -a, --ast | view abstract syntax tree.\n" - <<" -c, --code | view bytecode.\n" - <<" -e, --exec | execute script file.\n" - <<" -t, --time | execute and get the running time.\n" - <<" -o, --opcnt | count operands while running.\n" - <<"file:\n" - <<" input file name to execute script file.\n"; - return; + <<"nasal [option]\n" + <<"option:\n" + <<" -h, --help | get help.\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" + <<" -l, --lex | view token info.\n" + <<" -a, --ast | view abstract syntax tree.\n" + <<" -c, --code | view bytecode.\n" + <<" -e, --exec | execute script file.\n" + <<" -t, --time | execute and get the running time.\n" + <<" -o, --opcnt | count operands while running.\n" + <<"file:\n" + <<" input file name to execute script file.\n"; + return; } void logo() { std::cout - <<" __ _ \n" - <<" /\\ \\ \\__ _ ___ __ _| | \n" - <<" / \\/ / _` / __|/ _` | | \n" - <<" / /\\ / (_| \\__ \\ (_| | | \n" - <<" \\_\\ \\/ \\__,_|___/\\__,_|_|\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"; + <<" __ _ \n" + <<" /\\ \\ \\__ _ ___ __ _| | \n" + <<" / \\/ / _` / __|/ _` | | \n" + <<" / /\\ / (_| \\__ \\ (_| | | \n" + <<" \\_\\ \\/ \\__,_|___/\\__,_|_|\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; } void die(const char* stage,std::string& filename) { - std::cout<<"["<: error(s) occurred,stop.\n"; - return; + std::cout<<"["<: error(s) occurred,stop.\n"; + return; } void execute(std::string& file,std::string& command) { - nasal_lexer lexer; - nasal_parse parse; - nasal_import import; - nasal_codegen codegen; - nasal_vm vm; - lexer.openfile(file); - lexer.scanner(); - if(lexer.get_error()) - { - die("lexer",file); - return; - } - if(command=="--lex" || command=="-l") - { - lexer.print_token(); - return; - } - parse.main_process(lexer.get_token_list()); - if(parse.get_error()) - { - die("parse",file); - return; - } - if(command=="--ast" || command=="-a") - { - parse.get_root().print_ast(0); - return; - } - // first used file is itself - import.link(parse.get_root(),file); - if(import.get_error()) - { - die("import",file); - return; - } - codegen.main_progress(import.get_root(),import.get_file()); - if(codegen.get_error()) - { - die("codegen",file); - return; - } - if(command=="--code" || command=="-c") - { - codegen.print_byte_code(); - return; - } - vm.init( - codegen.get_str_table(), - codegen.get_num_table(), - import.get_file() - ); - if(command=="--exec" || command=="-e" || command=="--opcnt" || command=="-o") - vm.run(codegen.get_exec_code(),command=="--opcnt" || command=="-o"); - else if(command=="--time" || command=="-t") - { - clock_t begin=clock(); - vm.run(codegen.get_exec_code(),false); - std::cout<<"process exited after "<<((double)(clock()-begin))/CLOCKS_PER_SEC<<"s.\n"; - } - vm.clear(); - return; + nasal_lexer lexer; + nasal_parse parse; + nasal_import import; + nasal_codegen codegen; + nasal_vm vm; + lexer.openfile(file); + lexer.scanner(); + if(lexer.get_error()) + { + die("lexer",file); + return; + } + if(command=="--lex" || command=="-l") + { + lexer.print_token(); + return; + } + parse.main_process(lexer.get_token_list()); + if(parse.get_error()) + { + die("parse",file); + return; + } + if(command=="--ast" || command=="-a") + { + parse.get_root().print_ast(0); + return; + } + // first used file is itself + import.link(parse.get_root(),file); + if(import.get_error()) + { + die("import",file); + return; + } + codegen.main_progress(import.get_root(),import.get_file()); + if(codegen.get_error()) + { + die("codegen",file); + return; + } + if(command=="--code" || command=="-c") + { + codegen.print_byte_code(); + return; + } + vm.init( + codegen.get_str_table(), + codegen.get_num_table(), + import.get_file() + ); + if(command=="--exec" || command=="-e" || command=="--opcnt" || command=="-o") + vm.run(codegen.get_exec_code(),command=="--opcnt" || command=="-o"); + else if(command=="--time" || command=="-t") + { + clock_t begin=clock(); + vm.run(codegen.get_exec_code(),false); + std::cout<<"process exited after "<<((double)(clock()-begin))/CLOCKS_PER_SEC<<"s.\n"; + } + vm.clear(); + return; } int main(int argc,const char* argv[]) { - std::string command,file="null"; - if(argc==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"--version"))) - logo(); - else if(argc==2 && (!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help"))) - help_cmd(); - else if(argc==2 && argv[1][0]!='-') - { - file=argv[1]; - command="-e"; - execute(file,command); - } - else if(argc==3 && - (!strcmp(argv[1],"--lex") || - !strcmp(argv[1],"-l") || - !strcmp(argv[1],"--ast") || - !strcmp(argv[1],"-a") || - !strcmp(argv[1],"--code") || - !strcmp(argv[1],"-c") || - !strcmp(argv[1],"--exec") || - !strcmp(argv[1],"-e") || - !strcmp(argv[1],"--opcnt")|| - !strcmp(argv[1],"-o") || - !strcmp(argv[1],"--time") || - !strcmp(argv[1],"-t"))) - { - file=argv[2]; - command=argv[1]; - execute(file,command); - } - else - { - std::cout - <<"invalid argument(s).\n" - <<"use nasal -h to get help.\n"; - } + std::string command,file="null"; + if(argc==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"--version"))) + logo(); + else if(argc==2 && (!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help"))) + help_cmd(); + else if(argc==2 && argv[1][0]!='-') + { + file=argv[1]; + command="-e"; + execute(file,command); + } + else if(argc==3 && + (!strcmp(argv[1],"--lex") || + !strcmp(argv[1],"-l") || + !strcmp(argv[1],"--ast") || + !strcmp(argv[1],"-a") || + !strcmp(argv[1],"--code") || + !strcmp(argv[1],"-c") || + !strcmp(argv[1],"--exec") || + !strcmp(argv[1],"-e") || + !strcmp(argv[1],"--opcnt")|| + !strcmp(argv[1],"-o") || + !strcmp(argv[1],"--time") || + !strcmp(argv[1],"-t"))) + { + file=argv[2]; + command=argv[1]; + execute(file,command); + } + else + { + std::cout + <<"invalid argument(s).\n" + <<"use nasal -h to get help.\n"; + } return 0; } \ No newline at end of file diff --git a/nasal.h b/nasal.h index 89b7f8d..ad41a6c 100644 --- a/nasal.h +++ b/nasal.h @@ -23,108 +23,108 @@ #include /* - check if a string can be converted to a number - if this string cannot be converted to a number,it will return nan + check if a string can be converted to a number + if this string cannot be converted to a number,it will return nan */ inline double hex_to_double(const char* str) { - double ret=0; - for(;*str;++str) - { - ret*=16; - if('0'<=*str && *str<='9') - ret+=(*str-'0'); - else if('a'<=*str && *str<='f') - ret+=(*str-'a'+10); - else if('A'<=*str && *str<='F') - ret+=(*str-'A'+10); - else - return nan(""); - } - return ret; + double ret=0; + for(;*str;++str) + { + ret*=16; + if('0'<=*str && *str<='9') + ret+=(*str-'0'); + else if('a'<=*str && *str<='f') + ret+=(*str-'a'+10); + else if('A'<=*str && *str<='F') + ret+=(*str-'A'+10); + else + return nan(""); + } + return ret; } inline double oct_to_double(const char* str) { - double ret=0; - for(;*str;++str) - { - ret*=8; - if('0'<=*str && *str<'8') - ret+=(*str-'0'); - else - return nan(""); - } - return ret; + double ret=0; + for(;*str;++str) + { + ret*=8; + if('0'<=*str && *str<'8') + ret+=(*str-'0'); + else + return nan(""); + } + return ret; } inline double dec_to_double(const char* str) { - double ret=0,negative=1,num_pow=0; - while('0'<=*str && *str<='9') - ret=ret*10+(*str++-'0'); - if(!*str) return ret; - if(*str=='.') - { - if(!*++str) return nan(""); - num_pow=0.1; - while('0'<=*str && *str<='9') - { - ret+=num_pow*(*str++-'0'); - num_pow*=0.1; - } - if(!*str) return ret; - } - if(*str!='e' && *str!='E') - return nan(""); - if(!*++str) return nan(""); - if(*str=='-' || *str=='+') - negative=(*str++=='-'? -1:1); - if(!*str) return nan(""); - num_pow=0; - for(;*str;++str) - { - if('0'<=*str && *str<='9') - num_pow=num_pow*10+(*str-'0'); - else - return nan(""); - } - return ret*std::pow(10,negative*num_pow); + double ret=0,negative=1,num_pow=0; + while('0'<=*str && *str<='9') + ret=ret*10+(*str++-'0'); + if(!*str) return ret; + if(*str=='.') + { + if(!*++str) return nan(""); + num_pow=0.1; + while('0'<=*str && *str<='9') + { + ret+=num_pow*(*str++-'0'); + num_pow*=0.1; + } + if(!*str) return ret; + } + if(*str!='e' && *str!='E') + return nan(""); + if(!*++str) return nan(""); + if(*str=='-' || *str=='+') + negative=(*str++=='-'? -1:1); + if(!*str) return nan(""); + num_pow=0; + for(;*str;++str) + { + if('0'<=*str && *str<='9') + num_pow=num_pow*10+(*str-'0'); + else + return nan(""); + } + return ret*std::pow(10,negative*num_pow); } double str2num(const char* str) { - bool is_negative=false; - double ret_num=0; - if(*str=='-' || *str=='+') - is_negative=(*str++=='-'); - if(!*str) - return nan(""); - if(str[0]=='0' && str[1]=='x') - ret_num=hex_to_double(str+2); - else if(str[0]=='0' && str[1]=='o') - ret_num=oct_to_double(str+2); - else - ret_num=dec_to_double(str); - return is_negative?-ret_num:ret_num; + bool is_negative=false; + double ret_num=0; + if(*str=='-' || *str=='+') + is_negative=(*str++=='-'); + if(!*str) + return nan(""); + if(str[0]=='0' && str[1]=='x') + ret_num=hex_to_double(str+2); + else if(str[0]=='0' && str[1]=='o') + ret_num=oct_to_double(str+2); + else + ret_num=dec_to_double(str); + return is_negative?-ret_num:ret_num; } /* - show raw string + show raw string */ void raw_string(std::string& str) { - for(auto i:str) - switch(i) - { - case '\a': std::cout<<"\\a";break; - case '\b': std::cout<<"\\b";break; - case '\f': std::cout<<"\\f";break; - case '\n': std::cout<<"\\n";break; - case '\r': std::cout<<"\\r";break; - case '\t': std::cout<<"\\t";break; - case '\v': std::cout<<"\\v";break; - case '\0': std::cout<<"\\0";break; - default: std::cout<& local_scope,nasal_gc& gc) builtin_err("die","\"str\" must be string"); return nullptr; } - std::cout<<">> [vm] error: "<<*str_addr->ptr.str<<'\n'; + std::cout<<"[vm] error: "<<*str_addr->ptr.str<<'\n'; return nullptr; } nasal_val* builtin_type(std::vector& local_scope,nasal_gc& gc) diff --git a/nasal_lexer.h b/nasal_lexer.h index 4ae5734..52c766c 100644 --- a/nasal_lexer.h +++ b/nasal_lexer.h @@ -8,7 +8,7 @@ #define IS_STRING(c) (c=='\''||c=='\"'||c=='`') // single operators have only one character #define IS_SINGLE_OPERATOR(c) (c=='('||c==')'||c=='['||c==']'||c=='{'||c=='}'||c==','||c==';'||c=='|'||c==':'||\ - c=='?'||c=='`'||c=='&'||c=='@'||c=='%'||c=='$'||c=='^'||c=='\\') + c=='?'||c=='`'||c=='&'||c=='@'||c=='%'||c=='$'||c=='^'||c=='\\') // calculation operators may have two chars, for example: += -= *= /= ~= != == >= <= #define IS_CALC_OPERATOR(c) (c=='='||c=='+'||c=='-'||c=='*'||c=='!'||c=='/'||c=='<'||c=='>'||c=='~') #define IS_NOTE(c) (c=='#') @@ -28,7 +28,7 @@ enum token_type tok_eq, tok_addeq,tok_subeq,tok_multeq,tok_diveq,tok_lnkeq, tok_cmpeq,tok_neq,tok_less,tok_leq,tok_grt,tok_geq, - tok_eof + tok_eof }; struct @@ -70,7 +70,7 @@ struct {"/" ,tok_div }, {"~" ,tok_link }, {"!" ,tok_not }, - {"=" ,tok_eq }, + {"=" ,tok_eq }, {"+=" ,tok_addeq }, {"-=" ,tok_subeq }, {"*=" ,tok_multeq }, @@ -79,10 +79,10 @@ struct {"==" ,tok_cmpeq }, {"!=" ,tok_neq }, {"<" ,tok_less }, - {"<=" ,tok_leq }, + {"<=" ,tok_leq }, {">" ,tok_grt }, {">=" ,tok_geq }, - {nullptr ,-1 } + {nullptr ,-1 } }; struct token @@ -90,49 +90,49 @@ struct token int line; int type; std::string str; - token(int l=0,int t=tok_null,std::string s=""){line=l;type=t;str=s;} + token(int l=0,int t=tok_null,std::string s=""){line=l;type=t;str=s;} }; class nasal_lexer { private: int error; - int res_size; - int line; - int ptr; - std::string line_code; - std::vector res; + int res_size; + int line; + int ptr; + std::string line_code; + std::vector res; std::vector token_list; - int get_tok_type(std::string&); - void die(const char*); - std::string id_gen(); + int get_tok_type(std::string&); + void die(const char*); + std::string id_gen(); std::string num_gen(); std::string str_gen(); public: - void openfile(std::string&); + void openfile(std::string&); void scanner(); void print_token(); int get_error(){return error;} - std::vector& get_token_list(){return token_list;} + std::vector& get_token_list(){return token_list;} }; void nasal_lexer::openfile(std::string& filename) { - error=0; - res.clear(); + error=0; + res.clear(); std::ifstream fin(filename,std::ios::binary); if(fin.fail()) { - ++error; + ++error; std::cout<<"[lexer] cannot open file <"<.\n"; - fin.close(); + fin.close(); return; } while(!fin.eof()) { char c=fin.get(); if(fin.eof()) - break; + break; res.push_back(c); } fin.close(); @@ -141,189 +141,189 @@ void nasal_lexer::openfile(std::string& filename) int nasal_lexer::get_tok_type(std::string& tk_str) { - for(int i=0;token_table[i].str;++i) - if(tk_str==token_table[i].str) - return token_table[i].tok_type; - return tok_null; + for(int i=0;token_table[i].str;++i) + if(tk_str==token_table[i].str) + return token_table[i].tok_type; + return tok_null; } void nasal_lexer::die(const char* error_info) { - ++error; - std::cout<<"[lexer] line "< [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*) - std::string token_str=""; - while(ptr [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*) + std::string token_str=""; + while(ptr=res_size) - 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; + std::string token_str=""; + char str_begin=res[ptr]; + line_code+=str_begin; + while(++ptr=res_size) + 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; } void nasal_lexer::scanner() { token_list.clear(); line=1; - ptr=0; - line_code=""; - res_size=res.size(); + ptr=0; + line_code=""; + res_size=res.size(); - std::string token_str; - while(ptr=res_size) break; - if(IS_IDENTIFIER(res[ptr])) - { - token_str=id_gen(); - token new_token(line,get_tok_type(token_str),token_str); + std::string token_str; + while(ptr=res_size) break; + if(IS_IDENTIFIER(res[ptr])) + { + token_str=id_gen(); + token new_token(line,get_tok_type(token_str),token_str); if(!new_token.type) new_token.type=tok_id; - token_list.push_back(new_token); - } - else if(IS_DIGIT(res[ptr])) - { - token_str=num_gen(); - token_list.push_back({line,tok_num,token_str}); - } - else if(IS_STRING(res[ptr])) - { - token_str=str_gen(); - token_list.push_back({line,tok_str,token_str}); - } - else if(IS_SINGLE_OPERATOR(res[ptr])) - { - token_str=res[ptr]; - line_code+=res[ptr]; - int type=get_tok_type(token_str); - if(!type) - die("incorrect operator."); - token_list.push_back({line,type,token_str}); - ++ptr; - } + token_list.push_back(new_token); + } + else if(IS_DIGIT(res[ptr])) + { + token_str=num_gen(); + token_list.push_back({line,tok_num,token_str}); + } + else if(IS_STRING(res[ptr])) + { + token_str=str_gen(); + token_list.push_back({line,tok_str,token_str}); + } + else if(IS_SINGLE_OPERATOR(res[ptr])) + { + token_str=res[ptr]; + line_code+=res[ptr]; + 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]=='.') { if(ptr+2