use same indentation
This commit is contained in:
parent
90ac468aa9
commit
638ec1c3a3
258
main.cpp
258
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<<"["<<stage<<"] in <"<<filename<<">: error(s) occurred,stop.\n";
|
||||
return;
|
||||
std::cout<<"["<<stage<<"] in <"<<filename<<">: 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;
|
||||
}
|
168
nasal.h
168
nasal.h
|
@ -23,108 +23,108 @@
|
|||
#include <unordered_map>
|
||||
|
||||
/*
|
||||
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<<i; break;
|
||||
}
|
||||
return;
|
||||
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<<i; break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#include "nasal_lexer.h"
|
||||
#include "nasal_ast.h"
|
||||
|
|
|
@ -678,7 +678,7 @@ nasal_val* builtin_die(std::vector<nasal_val*>& 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<nasal_val*>& local_scope,nasal_gc& gc)
|
||||
|
|
402
nasal_lexer.h
402
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<char> res;
|
||||
int res_size;
|
||||
int line;
|
||||
int ptr;
|
||||
std::string line_code;
|
||||
std::vector<char> res;
|
||||
std::vector<token> 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<token>& get_token_list(){return token_list;}
|
||||
std::vector<token>& 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 <"<<filename<<">.\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 "<<line<<" column "<<line_code.length()<<": \n"<<line_code<<"\n";
|
||||
for(auto i:line_code)
|
||||
std::cout<<(i=='\t'?'\t':' ');
|
||||
std::cout<<"^"<<error_info<<'\n';
|
||||
return;
|
||||
++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';
|
||||
return;
|
||||
}
|
||||
|
||||
std::string nasal_lexer::id_gen()
|
||||
{
|
||||
std::string token_str="";
|
||||
while(ptr<res_size && (IS_IDENTIFIER(res[ptr])||IS_DIGIT(res[ptr])))
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
return token_str;
|
||||
// after running this process, ptr will point to the next token's beginning character
|
||||
std::string token_str="";
|
||||
while(ptr<res_size && (IS_IDENTIFIER(res[ptr])||IS_DIGIT(res[ptr])))
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
return token_str;
|
||||
// after running this process, ptr will point to the next token's beginning character
|
||||
}
|
||||
|
||||
std::string nasal_lexer::num_gen()
|
||||
{
|
||||
// generate hex number
|
||||
if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='x')
|
||||
{
|
||||
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.");
|
||||
return token_str;
|
||||
}
|
||||
// generate oct number
|
||||
else if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='o')
|
||||
{
|
||||
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.");
|
||||
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++];
|
||||
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.");
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
if(ptr<res_size && (res[ptr]=='e' || res[ptr]=='E'))
|
||||
{
|
||||
token_str+=res[ptr++];
|
||||
if(ptr<res_size && (res[ptr]=='-' || res[ptr]=='+'))
|
||||
token_str+=res[ptr++];
|
||||
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.");
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
line_code+=token_str;
|
||||
return token_str;
|
||||
// generate hex number
|
||||
if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='x')
|
||||
{
|
||||
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.");
|
||||
return token_str;
|
||||
}
|
||||
// generate oct number
|
||||
else if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='o')
|
||||
{
|
||||
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.");
|
||||
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++];
|
||||
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.");
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
if(ptr<res_size && (res[ptr]=='e' || res[ptr]=='E'))
|
||||
{
|
||||
token_str+=res[ptr++];
|
||||
if(ptr<res_size && (res[ptr]=='-' || res[ptr]=='+'))
|
||||
token_str+=res[ptr++];
|
||||
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.");
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
line_code+=token_str;
|
||||
return token_str;
|
||||
}
|
||||
|
||||
std::string nasal_lexer::str_gen()
|
||||
{
|
||||
std::string token_str="";
|
||||
char str_begin=res[ptr];
|
||||
line_code+=str_begin;
|
||||
while(++ptr<res_size && res[ptr]!=str_begin)
|
||||
{
|
||||
line_code+=res[ptr];
|
||||
if(res[ptr]=='\n')
|
||||
{
|
||||
line_code="";
|
||||
++line;
|
||||
}
|
||||
if(res[ptr]=='\\' && ptr+1<res_size)
|
||||
{
|
||||
line_code+=res[++ptr];
|
||||
switch(res[ptr])
|
||||
{
|
||||
case 'a': token_str.push_back('\a');break;
|
||||
case 'b': token_str.push_back('\b');break;
|
||||
case 'f': token_str.push_back('\f');break;
|
||||
case 'n': token_str.push_back('\n');break;
|
||||
case 'r': token_str.push_back('\r');break;
|
||||
case 't': token_str.push_back('\t');break;
|
||||
case 'v': token_str.push_back('\v');break;
|
||||
case '?': token_str.push_back('\?');break;
|
||||
case '0': token_str.push_back('\0');break;
|
||||
case '\\':token_str.push_back('\\');break;
|
||||
case '\'':token_str.push_back('\'');break;
|
||||
case '\"':token_str.push_back('\"');break;
|
||||
default: token_str.push_back(res[ptr]);break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
token_str+=res[ptr];
|
||||
}
|
||||
// check if this string ends with a " or '
|
||||
if(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 && res[ptr]!=str_begin)
|
||||
{
|
||||
line_code+=res[ptr];
|
||||
if(res[ptr]=='\n')
|
||||
{
|
||||
line_code="";
|
||||
++line;
|
||||
}
|
||||
if(res[ptr]=='\\' && ptr+1<res_size)
|
||||
{
|
||||
line_code+=res[++ptr];
|
||||
switch(res[ptr])
|
||||
{
|
||||
case 'a': token_str.push_back('\a');break;
|
||||
case 'b': token_str.push_back('\b');break;
|
||||
case 'f': token_str.push_back('\f');break;
|
||||
case 'n': token_str.push_back('\n');break;
|
||||
case 'r': token_str.push_back('\r');break;
|
||||
case 't': token_str.push_back('\t');break;
|
||||
case 'v': token_str.push_back('\v');break;
|
||||
case '?': token_str.push_back('\?');break;
|
||||
case '0': token_str.push_back('\0');break;
|
||||
case '\\':token_str.push_back('\\');break;
|
||||
case '\'':token_str.push_back('\'');break;
|
||||
case '\"':token_str.push_back('\"');break;
|
||||
default: token_str.push_back(res[ptr]);break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
token_str+=res[ptr];
|
||||
}
|
||||
// check if this string ends with a " or '
|
||||
if(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)
|
||||
{
|
||||
while(ptr<res_size && (res[ptr]==' ' || res[ptr]=='\n' || res[ptr]=='\t' || res[ptr]=='\r' || res[ptr]<0))
|
||||
{
|
||||
// these characters will be ignored, and '\n' will cause ++line
|
||||
line_code+=res[ptr];
|
||||
if(res[ptr++]=='\n')
|
||||
{
|
||||
++line;
|
||||
line_code="";
|
||||
}
|
||||
}
|
||||
if(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)
|
||||
{
|
||||
while(ptr<res_size && (res[ptr]==' ' || res[ptr]=='\n' || res[ptr]=='\t' || res[ptr]=='\r' || res[ptr]<0))
|
||||
{
|
||||
// these characters will be ignored, and '\n' will cause ++line
|
||||
line_code+=res[ptr];
|
||||
if(res[ptr++]=='\n')
|
||||
{
|
||||
++line;
|
||||
line_code="";
|
||||
}
|
||||
}
|
||||
if(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<res_size && res[ptr+1]=='.' && res[ptr+2]=='.')
|
||||
|
@ -336,29 +336,29 @@ void nasal_lexer::scanner()
|
|||
token_str=".";
|
||||
++ptr;
|
||||
}
|
||||
line_code+=token_str;
|
||||
token_list.push_back({line,get_tok_type(token_str),token_str});
|
||||
line_code+=token_str;
|
||||
token_list.push_back({line,get_tok_type(token_str),token_str});
|
||||
}
|
||||
else if(IS_CALC_OPERATOR(res[ptr]))
|
||||
{
|
||||
// get calculation operator
|
||||
token_str=res[ptr++];
|
||||
if(ptr<res_size && res[ptr]=='=')
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
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.");
|
||||
}
|
||||
}
|
||||
token_list.push_back({line,tok_eof,""});
|
||||
res.clear();
|
||||
return;
|
||||
else if(IS_CALC_OPERATOR(res[ptr]))
|
||||
{
|
||||
// get calculation operator
|
||||
token_str=res[ptr++];
|
||||
if(ptr<res_size && res[ptr]=='=')
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
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.");
|
||||
}
|
||||
}
|
||||
token_list.push_back({line,tok_eof,""});
|
||||
res.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
void nasal_lexer::print_token()
|
||||
|
|
Loading…
Reference in New Issue