diff --git a/main.cpp b/main.cpp index 5869920..b4c9ee9 100644 --- a/main.cpp +++ b/main.cpp @@ -63,7 +63,6 @@ void err() void execute(const std::string& file,const uint32_t cmd) { - // 33kb space on stack nasal_lexer lexer; nasal_parse parse; nasal_import linker; diff --git a/makefile b/makefile index 59875ef..facafb8 100644 --- a/makefile +++ b/makefile @@ -13,6 +13,7 @@ test:nasal ./nasal test/class.nas # ./nasal test/exception.nas ./nasal -t test/fib.nas + ./nasal test/filesystem.nas ./nasal test/hexdump.nas ./nasal test/json.nas ./nasal test/leetcode1319.nas diff --git a/nasal_ast.h b/nasal_ast.h index 5cc023e..26601d6 100644 --- a/nasal_ast.h +++ b/nasal_ast.h @@ -4,32 +4,63 @@ enum ast_node { ast_null=0, - ast_root, - ast_block, - ast_file, // ast_file is only used to store which file the subtree is on,codegen will generate nothing - ast_nil,ast_num,ast_str,ast_id,ast_func,ast_hash,ast_vec, - ast_hashmember, - ast_call,ast_callh,ast_callv,ast_callf, - ast_subvec, - ast_args,ast_default,ast_dynamic, - ast_and,ast_or, - ast_equal, - ast_addeq,ast_subeq, - ast_multeq,ast_diveq, - ast_lnkeq, - ast_cmpeq,ast_neq, - ast_less,ast_leq, - ast_grt,ast_geq, - ast_add,ast_sub, - ast_mult,ast_div, - ast_link, - ast_neg,ast_not, - ast_trino, - ast_for,ast_forindex,ast_foreach,ast_while,ast_new_iter, - ast_conditional,ast_if,ast_elsif,ast_else, - ast_multi_id,ast_multi_scalar, - ast_def,ast_multi_assign, - ast_continue,ast_break,ast_ret + ast_root, // mark the root node of ast + ast_block, // expression block + ast_file, // used to store which file the sub-tree is on + ast_nil, // nil keyword + ast_num, // number, basic value type + ast_str, // string, basic value type + ast_id, // identifier + ast_func, // func keyword + ast_hash, // hash, basic value type + ast_vec, // vector, basic value type + ast_hashmember,// elements in hashmap + ast_call, // mark a sub-tree of calling an identifier + ast_callh, // id.name + ast_callv, // id[index] + ast_callf, // id() + ast_subvec, // id[index:index] + ast_args, // mark a sub-tree of function parameters + ast_default, // default parameter + ast_dynamic, // dynamic parameter + ast_and, // and keyword + ast_or, // or keyword + ast_equal, // = + ast_addeq, // += + ast_subeq, // -= + ast_multeq, // *= + ast_diveq, // /= + ast_lnkeq, // ~= + ast_cmpeq, // == + ast_neq, // != + ast_less, // < + ast_leq, // <= + ast_grt, // > + ast_geq, // >= + ast_add, // + + ast_sub, // - + ast_mult, // * + ast_div, // / + ast_link, // ~ + ast_neg, // - + ast_not, // ~ + ast_trino, // ?: + ast_for, // for keyword + ast_forindex,// forindex keyword + ast_foreach, // foreach keyword + ast_while, // while + ast_new_iter,// iterator, used in forindex/foreach + ast_conditional,// mark a sub-tree of conditional expression + ast_if, // if keyword + ast_elsif, // elsif keyword + ast_else, // else keyword + ast_multi_id,// multi identifiers sub-tree + ast_multi_scalar,// multi value sub-tree + ast_def, // definition + ast_multi_assign,// multi assignment sub-tree + ast_continue,// continue keyword + ast_break, // break keyword + ast_ret // return keyword }; const char* ast_name[]= @@ -38,29 +69,61 @@ const char* ast_name[]= "root", "block", "file", - "nil","num","str","id","func","hash","vec", + "nil", + "num", + "str", + "id", + "func", + "hash", + "vec", "hashmember", - "call","callh","callv","callf", + "call", + "callh", + "callv", + "callf", "subvec", - "args","default","dynamic", - "and","or", + "args", + "default", + "dynamic", + "and", + "or", "=", - "+=","-=", - "*=","/=", + "+=", + "-=", + "*=", + "/=", "~=", - "==","!=", - "<","<=", - ">",">=", - "+","-", - "*","/", + "==", + "!=", + "<", + "<=", + ">", + ">=", + "+", + "-", + "*", + "/", "~", - "unary-","unary!", + "unary-", + "unary!", "trino", - "for","forindex","foreach","while","iter", - "conditional","if","elsif","else", - "multi_id","multi_scalar", - "def","multi_assign", - "continue","break","return" + "for", + "forindex", + "foreach", + "while", + "iter", + "conditional", + "if", + "elsif", + "else", + "multi_id", + "multi_scalar", + "def", + "multi_assign", + "continue", + "break", + "return", + nullptr }; class nasal_ast diff --git a/nasal_codegen.h b/nasal_codegen.h index b901ef0..40fd460 100644 --- a/nasal_codegen.h +++ b/nasal_codegen.h @@ -197,11 +197,11 @@ private: uint16_t fileindex; uint32_t in_forindex; uint32_t in_foreach; + const std::string* file; std::unordered_map num_table; std::unordered_map str_table; std::vector num_res; std::vector str_res; - std::vector file; std::vector code; std::list> continue_ptr; std::list> break_ptr; @@ -1146,20 +1146,9 @@ void nasal_codegen::ret_gen(const nasal_ast& ast) void nasal_codegen::compile(const nasal_parse& parse,const nasal_import& import) { - error=0; - in_foreach=0; - in_forindex=0; + error=in_foreach=in_forindex=0; fileindex=0; - - num_table.clear(); - str_table.clear(); - num_res.clear(); - str_res.clear(); - file=import.get_file(); - code.clear(); - - global.clear(); - local.clear(); + file=import.get_file().data(); // search symbols first find_symbol(parse.ast()); @@ -1263,7 +1252,7 @@ void nasal_codegen::print_op(uint32_t index) void nasal_codegen::print() { - for(auto num:num_res) + for(auto& num:num_res) std::cout<<".number "< files; void die(const std::string&,const char*); bool check_import(const nasal_ast&); @@ -67,6 +65,8 @@ void nasal_import::linker(nasal_ast& root,nasal_ast&& add_root) nasal_ast nasal_import::file_import(nasal_ast& node) { + nasal_lexer lex; + nasal_parse par; // get filename and set node to ast_null std::string filename=node[1][0].str(); node.clear(); diff --git a/nasal_lexer.h b/nasal_lexer.h index 2cebc88..b8f36f6 100644 --- a/nasal_lexer.h +++ b/nasal_lexer.h @@ -101,10 +101,10 @@ private: uint32_t error; uint32_t line; uint32_t ptr; - size_t size; std::string code; std::string res; std::vector tokens; + uint32_t get_type(const std::string&); void die(const char*); void open(const std::string&); @@ -120,7 +120,6 @@ public: void nasal_lexer::open(const std::string& file) { - error=0; std::ifstream fin(file,std::ios::binary); if(fin.fail()) { @@ -152,7 +151,7 @@ void nasal_lexer::die(const char* info) std::string nasal_lexer::id_gen() { std::string str=""; - while(ptr [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*) std::string str=""; - while(ptr=size) + if(ptr++>=res.size()) { die("get EOF when generating string."); return str; @@ -272,16 +271,13 @@ std::string nasal_lexer::str_gen() void nasal_lexer::scan(const std::string& file) { open(file); - tokens.clear(); line=1; - ptr=0; - code=""; - size=res.size(); + error=ptr=0; std::string str; - while(ptr=size) break; + if(ptr>=res.size()) break; if(ID(res[ptr])) { str=id_gen(); @@ -315,7 +311,7 @@ void nasal_lexer::scan(const std::string& file) else if(res[ptr]=='.') { str="."; - if(ptr+2 tokens; - std::vector error_token; - + void die(uint32_t,const std::string&); void match(uint32_t type,const char* info=nullptr); bool check_comma(const uint32_t*); @@ -84,8 +83,8 @@ private: nasal_ast callf(); nasal_ast subvec(); nasal_ast definition(); - nasal_ast var_incurve_def(); - nasal_ast var_outcurve_def(); + nasal_ast incurve_def(); + nasal_ast outcurve_def(); nasal_ast multi_id(); nasal_ast multi_scalar(bool); nasal_ast multi_assgin(); @@ -107,38 +106,19 @@ public: }; void nasal_parse::compile(const nasal_lexer& lexer) { - tokens=lexer.get_tokens(); + tokens=lexer.get_tokens().data(); ptr=in_func=in_loop=error=0; - error_token.clear(); root={1,ast_root}; while(tokens[ptr].type!=tok_eof) { - uint32_t err_tok_size=error_token.size(); root.add(expr()); if(tokens[ptr].type==tok_semi) match(tok_semi); - // if detect error token, avoid checking semicolon - else if(error_token.size()>err_tok_size) - continue; // the last expression can be recognized without semi else if(need_semi_check(root.child().back()) && tokens[ptr].type!=tok_eof) die(error_line,"expected \";\""); } - if(!error_token.size()) - return; - ++error; - std::cout<<"[parse] line"; - uint32_t err_line=0; - for(auto& tok:error_token) - if(err_line!=tok.line) - { - std::cout<<' '<"); + ++ptr; + break; } return {tokens[ptr].line,ast_null}; } @@ -493,13 +476,9 @@ nasal_ast nasal_parse::exprs() match(tok_lbrace); while(tokens[ptr].type!=tok_rbrace && tokens[ptr].type!=tok_eof) { - uint32_t err_tok_size=error_token.size(); node.add(expr()); if(tokens[ptr].type==tok_semi) match(tok_semi); - // if detect error token, avoid checking semicolon - else if(error_token.size()>err_tok_size) - continue; // the last expression can be recognized without semi else if(need_semi_check(node.child().back()) && tokens[ptr].type!=tok_rbrace) die(error_line,"expected \";\""); @@ -766,12 +745,12 @@ nasal_ast nasal_parse::definition() switch(tokens[ptr].type) { case tok_id: node.add(id());match(tok_id);break; - case tok_lcurve: node.add(var_outcurve_def());break; + case tok_lcurve: node.add(outcurve_def());break; default: die(error_line,"expected identifier");break; } } else if(tokens[ptr].type==tok_lcurve) - node.add(var_incurve_def()); + node.add(incurve_def()); match(tok_eq); if(tokens[ptr].type==tok_lcurve) node.add(check_multi_scalar()?multi_scalar(false):calc()); @@ -784,7 +763,7 @@ nasal_ast nasal_parse::definition() die(node[0].line(),"too much or lack values in multi-definition"); return node; } -nasal_ast nasal_parse::var_incurve_def() +nasal_ast nasal_parse::incurve_def() { match(tok_lcurve); match(tok_var); @@ -792,7 +771,7 @@ nasal_ast nasal_parse::var_incurve_def() match(tok_rcurve); return node; } -nasal_ast nasal_parse::var_outcurve_def() +nasal_ast nasal_parse::outcurve_def() { match(tok_lcurve); nasal_ast node=multi_id(); diff --git a/nasal_vm.h b/nasal_vm.h index 9b6e94d..51a6e65 100644 --- a/nasal_vm.h +++ b/nasal_vm.h @@ -7,18 +7,18 @@ private: /* values of nasal_vm */ uint32_t pc; // program counter uint32_t offset; // used to load default parameters to a new function + const double* num_table;// const numbers, ref from nasal_codegen + const std::string* str_table;// const symbols, ref from nasal_codegen std::stack ret; // stack to store return pc std::stack func_stk; // stack to store function, used to get upvalues std::stack counter; // iterator stack for forindex/foreach - const double* num_table;// const numbers - std::vector str_table;// const symbols std::vector imm; // immediate number nasal_ref* mem_addr; // used for mem_call /* garbage collector */ nasal_gc gc; /* values used for debug */ - std::vector bytecode; - std::vector files; + const opcode* bytecode; // ref from nasal_codegen + const std::string* files; // ref from nasal_import void init( const std::vector&, @@ -130,8 +130,8 @@ void nasal_vm::init( { gc.init(strs); num_table=nums.data(); - str_table=strs; - files=filenames; + str_table=strs.data(); + files=filenames.data(); } void nasal_vm::clear() { @@ -140,7 +140,6 @@ void nasal_vm::clear() ret.pop(); while(!counter.empty()) counter.pop(); - str_table.clear(); imm.clear(); } void nasal_vm::valinfo(nasal_ref& val) @@ -804,7 +803,7 @@ inline void nasal_vm::opr_mcallh() if(hash.type!=vm_hash) die("mcallh: must call a hash"); nasal_hash& ref=*hash.hash(); - std::string& str=str_table[imm[pc]]; + const std::string& str=str_table[imm[pc]]; mem_addr=ref.get_mem(str); if(!mem_addr) // create a new key { @@ -856,9 +855,9 @@ void nasal_vm::run( &&mcallg, &&mcalll, &&mupval, &&mcallv, &&mcallh, &&ret, &&vmexit }; - bytecode=gen.get_code(); + bytecode=gen.get_code().data(); std::vector code; - for(auto& i:bytecode) + for(auto& i:gen.get_code()) { code.push_back(opr_table[i.op]); imm.push_back(i.num); diff --git a/test/filesystem.nas b/test/filesystem.nas new file mode 100644 index 0000000..e074894 --- /dev/null +++ b/test/filesystem.nas @@ -0,0 +1,12 @@ +import("lib.nas"); + +var fd=io.open("test/filesystem.nas"); +while((var line=io.readln(fd))!=nil) + println(line); +io.close(fd); +println(io.stat("test/filesystem.nas")); + +var dd=unix.opendir("test"); +while((var name=unix.readdir(dd))!=nil) + println(name); +unix.closedir(dd); \ No newline at end of file