use same indentation

This commit is contained in:
ValKmjolnir 2021-08-09 21:30:18 +08:00
parent 90ac468aa9
commit 638ec1c3a3
4 changed files with 415 additions and 415 deletions

258
main.cpp
View File

@ -2,153 +2,153 @@
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]\n" <<"nasal [option]\n"
<<"option:\n" <<"option:\n"
<<" -h, --help | get help.\n" <<" -h, --help | get help.\n"
<<" -v, --version | get version of nasal interpreter.\n\n" <<" -v, --version | get version of nasal interpreter.\n\n"
<<"nasal [file]\n" <<"nasal [file]\n"
<<"file:\n" <<"file:\n"
<<" input file name to execute script file.\n\n" <<" input file name to execute script file.\n\n"
<<"nasal [option] [file]\n" <<"nasal [option] [file]\n"
<<"option:\n" <<"option:\n"
<<" -l, --lex | view token info.\n" <<" -l, --lex | view token info.\n"
<<" -a, --ast | view abstract syntax tree.\n" <<" -a, --ast | view abstract syntax tree.\n"
<<" -c, --code | view bytecode.\n" <<" -c, --code | view bytecode.\n"
<<" -e, --exec | execute script file.\n" <<" -e, --exec | execute script file.\n"
<<" -t, --time | execute and get the running time.\n" <<" -t, --time | execute and get the running time.\n"
<<" -o, --opcnt | count operands while running.\n" <<" -o, --opcnt | count operands while running.\n"
<<"file:\n" <<"file:\n"
<<" input file name to execute script file.\n"; <<" input file name to execute script file.\n";
return; return;
} }
void logo() void logo()
{ {
std::cout std::cout
<<" __ _ \n" <<" __ _ \n"
<<" /\\ \\ \\__ _ ___ __ _| | \n" <<" /\\ \\ \\__ _ ___ __ _| | \n"
<<" / \\/ / _` / __|/ _` | | \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" <<"thanks to : https://github.com/andyross/nasal\n"
<<"code repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n" <<"code repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
<<"code repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n" <<"code repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
<<"lang info : http://wiki.flightgear.org/Nasal_scripting_language\n" <<"lang info : http://wiki.flightgear.org/Nasal_scripting_language\n"
<<"input \"nasal -h\" to get help .\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;
nasal_parse parse; nasal_parse parse;
nasal_import import; nasal_import import;
nasal_codegen codegen; nasal_codegen codegen;
nasal_vm vm; nasal_vm vm;
lexer.openfile(file); lexer.openfile(file);
lexer.scanner(); lexer.scanner();
if(lexer.get_error()) if(lexer.get_error())
{ {
die("lexer",file); die("lexer",file);
return; return;
} }
if(command=="--lex" || command=="-l") if(command=="--lex" || command=="-l")
{ {
lexer.print_token(); lexer.print_token();
return; 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" || command=="-a") if(command=="--ast" || command=="-a")
{ {
parse.get_root().print_ast(0); parse.get_root().print_ast(0);
return; return;
} }
// first used file is itself // first used file is itself
import.link(parse.get_root(),file); import.link(parse.get_root(),file);
if(import.get_error()) if(import.get_error())
{ {
die("import",file); die("import",file);
return; return;
} }
codegen.main_progress(import.get_root(),import.get_file()); codegen.main_progress(import.get_root(),import.get_file());
if(codegen.get_error()) if(codegen.get_error())
{ {
die("codegen",file); die("codegen",file);
return; return;
} }
if(command=="--code" || command=="-c") if(command=="--code" || command=="-c")
{ {
codegen.print_byte_code(); codegen.print_byte_code();
return; return;
} }
vm.init( vm.init(
codegen.get_str_table(), codegen.get_str_table(),
codegen.get_num_table(), codegen.get_num_table(),
import.get_file() import.get_file()
); );
if(command=="--exec" || command=="-e" || command=="--opcnt" || command=="-o") if(command=="--exec" || command=="-e" || command=="--opcnt" || command=="-o")
vm.run(codegen.get_exec_code(),command=="--opcnt" || command=="-o"); vm.run(codegen.get_exec_code(),command=="--opcnt" || command=="-o");
else if(command=="--time" || command=="-t") else if(command=="--time" || command=="-t")
{ {
clock_t begin=clock(); clock_t begin=clock();
vm.run(codegen.get_exec_code(),false); vm.run(codegen.get_exec_code(),false);
std::cout<<"process exited after "<<((double)(clock()-begin))/CLOCKS_PER_SEC<<"s.\n"; std::cout<<"process exited after "<<((double)(clock()-begin))/CLOCKS_PER_SEC<<"s.\n";
} }
vm.clear(); vm.clear();
return; return;
} }
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==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"--version"))) 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="-e"; command="-e";
execute(file,command); execute(file,command);
} }
else if(argc==3 && else if(argc==3 &&
(!strcmp(argv[1],"--lex") || (!strcmp(argv[1],"--lex") ||
!strcmp(argv[1],"-l") || !strcmp(argv[1],"-l") ||
!strcmp(argv[1],"--ast") || !strcmp(argv[1],"--ast") ||
!strcmp(argv[1],"-a") || !strcmp(argv[1],"-a") ||
!strcmp(argv[1],"--code") || !strcmp(argv[1],"--code") ||
!strcmp(argv[1],"-c") || !strcmp(argv[1],"-c") ||
!strcmp(argv[1],"--exec") || !strcmp(argv[1],"--exec") ||
!strcmp(argv[1],"-e") || !strcmp(argv[1],"-e") ||
!strcmp(argv[1],"--opcnt")|| !strcmp(argv[1],"--opcnt")||
!strcmp(argv[1],"-o") || !strcmp(argv[1],"-o") ||
!strcmp(argv[1],"--time") || !strcmp(argv[1],"--time") ||
!strcmp(argv[1],"-t"))) !strcmp(argv[1],"-t")))
{ {
file=argv[2]; file=argv[2];
command=argv[1]; command=argv[1];
execute(file,command); execute(file,command);
} }
else else
{ {
std::cout std::cout
<<"invalid argument(s).\n" <<"invalid argument(s).\n"
<<"use nasal -h to get help.\n"; <<"use nasal -h to get help.\n";
} }
return 0; return 0;
} }

168
nasal.h
View File

@ -23,108 +23,108 @@
#include <unordered_map> #include <unordered_map>
/* /*
check if a string can be converted to a number check if a string can be converted to a number
if this string cannot be converted to a number,it will return nan if this string cannot be converted to a number,it will return nan
*/ */
inline double hex_to_double(const char* str) inline double hex_to_double(const char* str)
{ {
double ret=0; double ret=0;
for(;*str;++str) for(;*str;++str)
{ {
ret*=16; ret*=16;
if('0'<=*str && *str<='9') if('0'<=*str && *str<='9')
ret+=(*str-'0'); ret+=(*str-'0');
else if('a'<=*str && *str<='f') else if('a'<=*str && *str<='f')
ret+=(*str-'a'+10); ret+=(*str-'a'+10);
else if('A'<=*str && *str<='F') else if('A'<=*str && *str<='F')
ret+=(*str-'A'+10); ret+=(*str-'A'+10);
else else
return nan(""); return nan("");
} }
return ret; return ret;
} }
inline double oct_to_double(const char* str) inline double oct_to_double(const char* str)
{ {
double ret=0; double ret=0;
for(;*str;++str) for(;*str;++str)
{ {
ret*=8; ret*=8;
if('0'<=*str && *str<'8') if('0'<=*str && *str<'8')
ret+=(*str-'0'); ret+=(*str-'0');
else else
return nan(""); return nan("");
} }
return ret; return ret;
} }
inline double dec_to_double(const char* str) inline double dec_to_double(const char* str)
{ {
double ret=0,negative=1,num_pow=0; double ret=0,negative=1,num_pow=0;
while('0'<=*str && *str<='9') while('0'<=*str && *str<='9')
ret=ret*10+(*str++-'0'); ret=ret*10+(*str++-'0');
if(!*str) return ret; if(!*str) return ret;
if(*str=='.') if(*str=='.')
{ {
if(!*++str) return nan(""); if(!*++str) return nan("");
num_pow=0.1; num_pow=0.1;
while('0'<=*str && *str<='9') while('0'<=*str && *str<='9')
{ {
ret+=num_pow*(*str++-'0'); ret+=num_pow*(*str++-'0');
num_pow*=0.1; num_pow*=0.1;
} }
if(!*str) return ret; if(!*str) return ret;
} }
if(*str!='e' && *str!='E') if(*str!='e' && *str!='E')
return nan(""); return nan("");
if(!*++str) return nan(""); if(!*++str) return nan("");
if(*str=='-' || *str=='+') if(*str=='-' || *str=='+')
negative=(*str++=='-'? -1:1); negative=(*str++=='-'? -1:1);
if(!*str) return nan(""); if(!*str) return nan("");
num_pow=0; num_pow=0;
for(;*str;++str) for(;*str;++str)
{ {
if('0'<=*str && *str<='9') if('0'<=*str && *str<='9')
num_pow=num_pow*10+(*str-'0'); num_pow=num_pow*10+(*str-'0');
else else
return nan(""); return nan("");
} }
return ret*std::pow(10,negative*num_pow); return ret*std::pow(10,negative*num_pow);
} }
double str2num(const char* str) double str2num(const char* str)
{ {
bool is_negative=false; bool is_negative=false;
double ret_num=0; double ret_num=0;
if(*str=='-' || *str=='+') if(*str=='-' || *str=='+')
is_negative=(*str++=='-'); is_negative=(*str++=='-');
if(!*str) if(!*str)
return nan(""); return nan("");
if(str[0]=='0' && str[1]=='x') if(str[0]=='0' && str[1]=='x')
ret_num=hex_to_double(str+2); ret_num=hex_to_double(str+2);
else if(str[0]=='0' && str[1]=='o') else if(str[0]=='0' && str[1]=='o')
ret_num=oct_to_double(str+2); ret_num=oct_to_double(str+2);
else else
ret_num=dec_to_double(str); ret_num=dec_to_double(str);
return is_negative?-ret_num:ret_num; return is_negative?-ret_num:ret_num;
} }
/* /*
show raw string show raw string
*/ */
void raw_string(std::string& str) void raw_string(std::string& str)
{ {
for(auto i:str) for(auto i:str)
switch(i) switch(i)
{ {
case '\a': std::cout<<"\\a";break; case '\a': std::cout<<"\\a";break;
case '\b': std::cout<<"\\b";break; case '\b': std::cout<<"\\b";break;
case '\f': std::cout<<"\\f";break; case '\f': std::cout<<"\\f";break;
case '\n': std::cout<<"\\n";break; case '\n': std::cout<<"\\n";break;
case '\r': std::cout<<"\\r";break; case '\r': std::cout<<"\\r";break;
case '\t': std::cout<<"\\t";break; case '\t': std::cout<<"\\t";break;
case '\v': std::cout<<"\\v";break; case '\v': std::cout<<"\\v";break;
case '\0': std::cout<<"\\0";break; case '\0': std::cout<<"\\0";break;
default: std::cout<<i; break; default: std::cout<<i; break;
} }
return; return;
} }
#include "nasal_lexer.h" #include "nasal_lexer.h"
#include "nasal_ast.h" #include "nasal_ast.h"

View File

@ -678,7 +678,7 @@ nasal_val* builtin_die(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
builtin_err("die","\"str\" must be string"); builtin_err("die","\"str\" must be string");
return nullptr; return nullptr;
} }
std::cout<<">> [vm] error: "<<*str_addr->ptr.str<<'\n'; std::cout<<"[vm] error: "<<*str_addr->ptr.str<<'\n';
return nullptr; return nullptr;
} }
nasal_val* builtin_type(std::vector<nasal_val*>& local_scope,nasal_gc& gc) nasal_val* builtin_type(std::vector<nasal_val*>& local_scope,nasal_gc& gc)

View File

@ -8,7 +8,7 @@
#define IS_STRING(c) (c=='\''||c=='\"'||c=='`') #define IS_STRING(c) (c=='\''||c=='\"'||c=='`')
// single operators have only one character // single operators have only one character
#define IS_SINGLE_OPERATOR(c) (c=='('||c==')'||c=='['||c==']'||c=='{'||c=='}'||c==','||c==';'||c=='|'||c==':'||\ #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: += -= *= /= ~= != == >= <= // calculation operators may have two chars, for example: += -= *= /= ~= != == >= <=
#define IS_CALC_OPERATOR(c) (c=='='||c=='+'||c=='-'||c=='*'||c=='!'||c=='/'||c=='<'||c=='>'||c=='~') #define IS_CALC_OPERATOR(c) (c=='='||c=='+'||c=='-'||c=='*'||c=='!'||c=='/'||c=='<'||c=='>'||c=='~')
#define IS_NOTE(c) (c=='#') #define IS_NOTE(c) (c=='#')
@ -28,7 +28,7 @@ enum token_type
tok_eq, tok_eq,
tok_addeq,tok_subeq,tok_multeq,tok_diveq,tok_lnkeq, tok_addeq,tok_subeq,tok_multeq,tok_diveq,tok_lnkeq,
tok_cmpeq,tok_neq,tok_less,tok_leq,tok_grt,tok_geq, tok_cmpeq,tok_neq,tok_less,tok_leq,tok_grt,tok_geq,
tok_eof tok_eof
}; };
struct struct
@ -70,7 +70,7 @@ struct
{"/" ,tok_div }, {"/" ,tok_div },
{"~" ,tok_link }, {"~" ,tok_link },
{"!" ,tok_not }, {"!" ,tok_not },
{"=" ,tok_eq }, {"=" ,tok_eq },
{"+=" ,tok_addeq }, {"+=" ,tok_addeq },
{"-=" ,tok_subeq }, {"-=" ,tok_subeq },
{"*=" ,tok_multeq }, {"*=" ,tok_multeq },
@ -79,10 +79,10 @@ struct
{"==" ,tok_cmpeq }, {"==" ,tok_cmpeq },
{"!=" ,tok_neq }, {"!=" ,tok_neq },
{"<" ,tok_less }, {"<" ,tok_less },
{"<=" ,tok_leq }, {"<=" ,tok_leq },
{">" ,tok_grt }, {">" ,tok_grt },
{">=" ,tok_geq }, {">=" ,tok_geq },
{nullptr ,-1 } {nullptr ,-1 }
}; };
struct token struct token
@ -90,49 +90,49 @@ struct token
int line; int line;
int type; int type;
std::string str; 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 class nasal_lexer
{ {
private: private:
int error; int error;
int res_size; int res_size;
int line; int line;
int ptr; int ptr;
std::string line_code; std::string line_code;
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(const char*); 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();
public: public:
void openfile(std::string&); void openfile(std::string&);
void scanner(); void scanner();
void print_token(); void print_token();
int get_error(){return error;} 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) void nasal_lexer::openfile(std::string& filename)
{ {
error=0; error=0;
res.clear(); res.clear();
std::ifstream fin(filename,std::ios::binary); std::ifstream fin(filename,std::ios::binary);
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;
} }
while(!fin.eof()) while(!fin.eof())
{ {
char c=fin.get(); char c=fin.get();
if(fin.eof()) if(fin.eof())
break; break;
res.push_back(c); res.push_back(c);
} }
fin.close(); fin.close();
@ -141,189 +141,189 @@ void nasal_lexer::openfile(std::string& filename)
int nasal_lexer::get_tok_type(std::string& tk_str) int nasal_lexer::get_tok_type(std::string& tk_str)
{ {
for(int i=0;token_table[i].str;++i) for(int i=0;token_table[i].str;++i)
if(tk_str==token_table[i].str) if(tk_str==token_table[i].str)
return token_table[i].tok_type; return token_table[i].tok_type;
return tok_null; return tok_null;
} }
void nasal_lexer::die(const char* error_info) 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;
} }
std::string nasal_lexer::id_gen() std::string nasal_lexer::id_gen()
{ {
std::string token_str=""; std::string token_str="";
while(ptr<res_size && (IS_IDENTIFIER(res[ptr])||IS_DIGIT(res[ptr]))) while(ptr<res_size && (IS_IDENTIFIER(res[ptr])||IS_DIGIT(res[ptr])))
token_str+=res[ptr++]; token_str+=res[ptr++];
line_code+=token_str; line_code+=token_str;
return token_str; return token_str;
// after running this process, ptr will point to the next token's beginning character // after running this process, ptr will point to the next token's beginning character
} }
std::string nasal_lexer::num_gen() std::string nasal_lexer::num_gen()
{ {
// 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')
{ {
std::string 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.");
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')
{ {
std::string 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.");
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=""; 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++];
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."); 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++];
if(ptr<res_size && (res[ptr]=='-' || res[ptr]=='+')) if(ptr<res_size && (res[ptr]=='-' || res[ptr]=='+'))
token_str+=res[ptr++]; token_str+=res[ptr++];
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."); die("incorrect number.");
return "0"; return "0";
} }
} }
line_code+=token_str; line_code+=token_str;
return token_str; return token_str;
} }
std::string nasal_lexer::str_gen() std::string nasal_lexer::str_gen()
{ {
std::string token_str=""; std::string token_str="";
char str_begin=res[ptr]; char str_begin=res[ptr];
line_code+=str_begin; line_code+=str_begin;
while(++ptr<res_size && res[ptr]!=str_begin) while(++ptr<res_size && res[ptr]!=str_begin)
{ {
line_code+=res[ptr]; line_code+=res[ptr];
if(res[ptr]=='\n') if(res[ptr]=='\n')
{ {
line_code=""; line_code="";
++line; ++line;
} }
if(res[ptr]=='\\' && ptr+1<res_size) if(res[ptr]=='\\' && ptr+1<res_size)
{ {
line_code+=res[++ptr]; line_code+=res[++ptr];
switch(res[ptr]) switch(res[ptr])
{ {
case 'a': token_str.push_back('\a');break; case 'a': token_str.push_back('\a');break;
case 'b': token_str.push_back('\b');break; case 'b': token_str.push_back('\b');break;
case 'f': token_str.push_back('\f');break; case 'f': token_str.push_back('\f');break;
case 'n': token_str.push_back('\n');break; case 'n': token_str.push_back('\n');break;
case 'r': token_str.push_back('\r');break; case 'r': token_str.push_back('\r');break;
case 't': token_str.push_back('\t');break; case 't': token_str.push_back('\t');break;
case 'v': token_str.push_back('\v');break; case 'v': token_str.push_back('\v');break;
case '?': token_str.push_back('\?');break; case '?': token_str.push_back('\?');break;
case '0': token_str.push_back('\0');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; 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; default: token_str.push_back(res[ptr]);break;
} }
continue; continue;
} }
token_str+=res[ptr]; token_str+=res[ptr];
} }
// 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."); 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."); die("\'`\' is used for string that includes one character.");
return token_str; return token_str;
} }
void nasal_lexer::scanner() void nasal_lexer::scanner()
{ {
token_list.clear(); token_list.clear();
line=1; line=1;
ptr=0; ptr=0;
line_code=""; line_code="";
res_size=res.size(); res_size=res.size();
std::string token_str; std::string token_str;
while(ptr<res_size) while(ptr<res_size)
{ {
while(ptr<res_size && (res[ptr]==' ' || res[ptr]=='\n' || res[ptr]=='\t' || res[ptr]=='\r' || res[ptr]<0)) 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 // these characters will be ignored, and '\n' will cause ++line
line_code+=res[ptr]; line_code+=res[ptr];
if(res[ptr++]=='\n') if(res[ptr++]=='\n')
{ {
++line; ++line;
line_code=""; line_code="";
} }
} }
if(ptr>=res_size) break; if(ptr>=res_size) break;
if(IS_IDENTIFIER(res[ptr])) if(IS_IDENTIFIER(res[ptr]))
{ {
token_str=id_gen(); token_str=id_gen();
token new_token(line,get_tok_type(token_str),token_str); token new_token(line,get_tok_type(token_str),token_str);
if(!new_token.type) if(!new_token.type)
new_token.type=tok_id; new_token.type=tok_id;
token_list.push_back(new_token); token_list.push_back(new_token);
} }
else if(IS_DIGIT(res[ptr])) else if(IS_DIGIT(res[ptr]))
{ {
token_str=num_gen(); token_str=num_gen();
token_list.push_back({line,tok_num,token_str}); token_list.push_back({line,tok_num,token_str});
} }
else if(IS_STRING(res[ptr])) else if(IS_STRING(res[ptr]))
{ {
token_str=str_gen(); token_str=str_gen();
token_list.push_back({line,tok_str,token_str}); token_list.push_back({line,tok_str,token_str});
} }
else if(IS_SINGLE_OPERATOR(res[ptr])) else if(IS_SINGLE_OPERATOR(res[ptr]))
{ {
token_str=res[ptr]; token_str=res[ptr];
line_code+=res[ptr]; line_code+=res[ptr];
int type=get_tok_type(token_str); int type=get_tok_type(token_str);
if(!type) if(!type)
die("incorrect operator."); die("incorrect operator.");
token_list.push_back({line,type,token_str}); token_list.push_back({line,type,token_str});
++ptr; ++ptr;
} }
else if(res[ptr]=='.') else if(res[ptr]=='.')
{ {
if(ptr+2<res_size && res[ptr+1]=='.' && res[ptr+2]=='.') if(ptr+2<res_size && res[ptr+1]=='.' && res[ptr+2]=='.')
@ -336,29 +336,29 @@ void nasal_lexer::scanner()
token_str="."; token_str=".";
++ptr; ++ptr;
} }
line_code+=token_str; line_code+=token_str;
token_list.push_back({line,get_tok_type(token_str),token_str}); token_list.push_back({line,get_tok_type(token_str),token_str});
} }
else if(IS_CALC_OPERATOR(res[ptr])) else if(IS_CALC_OPERATOR(res[ptr]))
{ {
// get calculation operator // get calculation operator
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++];
line_code+=token_str; line_code+=token_str;
token_list.push_back({line,get_tok_type(token_str),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 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."); die("unknown character.");
} }
} }
token_list.push_back({line,tok_eof,""}); token_list.push_back({line,tok_eof,""});
res.clear(); res.clear();
return; return;
} }
void nasal_lexer::print_token() void nasal_lexer::print_token()