#ifndef __NASAL_LEXER_H__ #define __NASAL_LEXER_H__ #include #include #ifdef _MSC_VER #define S_ISREG(m) (((m)&0xF000)==0x8000) #endif #define ID(c) ((c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z')||(c<0)) #define HEX(c) (('0'<=c&&c<='9')||('a'<=c&&c<='f')||('A'<=c && c<='F')) #define OCT(c) ('0'<=c&&c<='7') #define DIGIT(c) ('0'<=c&&c<='9') #define STR(c) (c=='\''||c=='\"'||c=='`') // single operators have only one character #define SINGLE_OPERATOR(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 CALC_OPERATOR(c) (c=='='||c=='+'||c=='-'||c=='*'||c=='!'||c=='/'||c=='<'||c=='>'||c=='~') #define NOTE(c) (c=='#') enum tok:u32{ tok_null=0, // null token (default token type) tok_num, // number literal tok_str, // string literal tok_id, // identifier tok_for, // loop keyword for tok_forindex,// loop keyword forindex tok_foreach, // loop keyword foreach tok_while, // loop keyword while tok_var, // keyword for definition tok_func, // keyword for definition of function tok_break, // loop keyword break tok_continue,// loop keyword continue tok_ret, // function keyword return tok_if, // condition expression keyword if tok_elsif, // condition expression keyword elsif tok_else, // condition expression keyword else tok_nil, // nil literal tok_lcurve,tok_rcurve, tok_lbracket,tok_rbracket, tok_lbrace,tok_rbrace, tok_semi,tok_and,tok_or,tok_comma,tok_dot,tok_ellipsis,tok_quesmark, tok_colon,tok_add,tok_sub,tok_mult,tok_div,tok_link,tok_not, 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 // end of token list }; struct{ const char* str; const u32 type; }tok_table[]={ {"for" ,tok_for }, {"forindex",tok_forindex }, {"foreach" ,tok_foreach }, {"while" ,tok_while }, {"var" ,tok_var }, {"func" ,tok_func }, {"break" ,tok_break }, {"continue",tok_continue }, {"return" ,tok_ret }, {"if" ,tok_if }, {"elsif" ,tok_elsif }, {"else" ,tok_else }, {"nil" ,tok_nil }, {"(" ,tok_lcurve }, {")" ,tok_rcurve }, {"[" ,tok_lbracket }, {"]" ,tok_rbracket }, {"{" ,tok_lbrace }, {"}" ,tok_rbrace }, {";" ,tok_semi }, {"and" ,tok_and }, {"or" ,tok_or }, {"," ,tok_comma }, {"." ,tok_dot }, {"..." ,tok_ellipsis }, {"?" ,tok_quesmark }, {":" ,tok_colon }, {"+" ,tok_add }, {"-" ,tok_sub }, {"*" ,tok_mult }, {"/" ,tok_div }, {"~" ,tok_link }, {"!" ,tok_not }, {"=" ,tok_eq }, {"+=" ,tok_addeq }, {"-=" ,tok_subeq }, {"*=" ,tok_multeq }, {"/=" ,tok_diveq }, {"~=" ,tok_lnkeq }, {"==" ,tok_cmpeq }, {"!=" ,tok_neq }, {"<" ,tok_less }, {"<=" ,tok_leq }, {">" ,tok_grt }, {">=" ,tok_geq }, {nullptr ,0 } }; struct token { u32 line; u32 col; u32 type; string str; token(u32 l=0,u32 c=0,u32 t=tok_null,const string& s=""):str(s) { line=l; col=c; type=t; } }; class lexer { private: u32 line; u32 column; usize ptr; string res; error& err; std::vector tokens; u32 get_type(const string&); void die(const string& info){err.err("lexer",line,column,info);} void open(const string&); string utf8_gen(); string id_gen(); string num_gen(); string str_gen(); public: lexer(error& e): line(1),column(0), ptr(0),res(""), err(e){} void scan(const string&); void print(); const std::vector& result() const {return tokens;} }; void lexer::open(const string& file) { struct stat buffer; if(stat(file.c_str(),&buffer)==0 && !S_ISREG(buffer.st_mode)) { err.err("lexer","<"+file+"> is not a regular file"); err.chkerr(); } std::ifstream fin(file,std::ios::binary); if(fin.fail()) err.err("lexer","failed to open <"+file+">"); else err.load(file); std::stringstream ss; ss< [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*) string str=""; while(ptr=res.size()) { die("get EOF when generating string"); return str; } ++column; if(begin=='`' && str.length()!=1) die("\'`\' is used for string that includes one character"); return str; } void lexer::scan(const string& file) { line=1; column=0; ptr=0; open(file); string str; while(ptr=res.size()) break; if(ID(res[ptr])) { str=id_gen(); u32 type=get_type(str); tokens.push_back({line,column,type?type:tok_id,str}); } else if(DIGIT(res[ptr])) { str=num_gen(); // make sure column is correct tokens.push_back({line,column,tok_num,str}); } else if(STR(res[ptr])) { str=str_gen(); // make sure column is correct tokens.push_back({line,column,tok_str,str}); } else if(SINGLE_OPERATOR(res[ptr])) { str=res[ptr]; ++column; u32 type=get_type(str); if(!type) die("invalid operator `"+str+"`"); tokens.push_back({line,column,type,str}); ++ptr; } else if(res[ptr]=='.') { str="."; if(ptr+2