⚡ move lvalue check from parse to codegen
This commit is contained in:
parent
9196d7815f
commit
54969681fc
15
README.md
15
README.md
|
@ -593,16 +593,19 @@ Luckily, we have developed some useful native-functions to help you add modules
|
|||
After 2021/12/3, there are some new functions added to `lib.nas`:
|
||||
|
||||
```javascript
|
||||
var dylib=
|
||||
{
|
||||
dlopen: func(libname){return __dlopen;},
|
||||
dlsym: func(lib,sym){return __dlsym; },
|
||||
var dylib={
|
||||
dlopen: func(libname){
|
||||
...
|
||||
},
|
||||
dlclose: func(lib){return __dlclose; },
|
||||
dlcall: func(funcptr,args...){return __dlcall;}
|
||||
dlcall: func(ptr,args...){return __dlcallv},
|
||||
limitcall: func(arg_size=0){
|
||||
...
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Aha, as you could see, these functions are used to load dynamic libraries into the nasal runtime and execute.
|
||||
As you could see, these functions are used to load dynamic libraries into the nasal runtime and execute.
|
||||
Let's see how they work.
|
||||
|
||||
First, write a cpp file that you want to generate the dynamic lib, take the `fib.cpp` as the example(example codes are in `./module`):
|
||||
|
|
|
@ -569,16 +569,19 @@ import("./dirname/dirname/filename.nas");
|
|||
在2021/12/3更新后,我们给`lib.nas`添加了下面的这一批函数:
|
||||
|
||||
```javascript
|
||||
var dylib=
|
||||
{
|
||||
dlopen: func(libname){return __dlopen;},
|
||||
dlsym: func(lib,sym){return __dlsym; },
|
||||
var dylib={
|
||||
dlopen: func(libname){
|
||||
...
|
||||
},
|
||||
dlclose: func(lib){return __dlclose; },
|
||||
dlcall: func(funcptr,args...){return __dlcall;}
|
||||
dlcall: func(ptr,args...){return __dlcallv},
|
||||
limitcall: func(arg_size=0){
|
||||
...
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
看名字就大概能猜出来,这些函数就是用来加载动态库的,这样nasal解释器可以根据用户需求灵活加载动态库来执行。让我们看看这些函数该如何使用。
|
||||
这些函数是用来加载动态库的,这样nasal解释器可以根据用户需求灵活加载动态库来执行。让我们看看这些函数该如何使用。
|
||||
|
||||
首先,用C++写个项目,并且编译成动态库。我们就拿`fib.cpp`作为例子来说明(样例代码可以在`./module`中找到):
|
||||
|
||||
|
|
2
main.cpp
2
main.cpp
|
@ -99,7 +99,7 @@ void execute(const string& file,const std::vector<string>& argv,const u32 cmd)
|
|||
if(cmd&VM_OPT)
|
||||
optimize(parse.tree());
|
||||
if(cmd&VM_AST)
|
||||
parse.print();
|
||||
parse.tree().dump();
|
||||
|
||||
// code generator gets parser's ast and linker's import file list to generate code
|
||||
gen.compile(parse,ld).chkerr();
|
||||
|
|
91
nasal_ast.h
91
nasal_ast.h
|
@ -3,8 +3,7 @@
|
|||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
enum ast_node:u32
|
||||
{
|
||||
enum ast_node:u32{
|
||||
ast_null=0, // null node
|
||||
ast_root, // mark the root node of ast
|
||||
ast_block, // expression block
|
||||
|
@ -22,7 +21,7 @@ enum ast_node:u32
|
|||
ast_callv, // id[index]
|
||||
ast_callf, // id()
|
||||
ast_subvec, // id[index:index]
|
||||
ast_args, // mark a sub-tree of function parameters
|
||||
ast_params, // mark a sub-tree of function parameters
|
||||
ast_default, // default parameter
|
||||
ast_dynamic, // dynamic parameter
|
||||
ast_and, // and keyword
|
||||
|
@ -65,23 +64,65 @@ enum ast_node:u32
|
|||
ast_ret // return keyword, only used in function block
|
||||
};
|
||||
|
||||
const char* ast_name[]=
|
||||
{
|
||||
"null", "root", "block", "file",
|
||||
"nil", "num", "str", "id",
|
||||
"func", "hash", "vec", "pair",
|
||||
"call", "callh", "callv", "callf",
|
||||
"subvec", "args", "default", "dynamic",
|
||||
"and", "or", "=", "+=",
|
||||
"-=", "*=", "/=", "~=",
|
||||
"==", "!=", "<", "<=",
|
||||
">", ">=", "+", "-",
|
||||
"*", "/", "~", "neg",
|
||||
"!", "trino", "for", "forindex",
|
||||
"foreach", "while", "iter", "cond",
|
||||
"if", "elsif", "else", "ltuple",
|
||||
"tuple", "def", "massign", "continue",
|
||||
"break", "return"
|
||||
const char* ast_name[]={
|
||||
"NullNode",
|
||||
"AbstractSyntaxTreeRoot",
|
||||
"CodeBlock",
|
||||
"FileIndex",
|
||||
"LiteralNil",
|
||||
"LiteralNumber",
|
||||
"LiteralString",
|
||||
"Identifier",
|
||||
"Function",
|
||||
"HashMap",
|
||||
"Vector",
|
||||
"HashMapPair",
|
||||
"IdentifierCallExpression",
|
||||
"HashMapCallExpression",
|
||||
"VectorCallExpression",
|
||||
"FunctionCallExpression",
|
||||
"SubVector",
|
||||
"ParameterList",
|
||||
"DefaultParameter",
|
||||
"DynamicParameter",
|
||||
"AndExpression",
|
||||
"OrExpression",
|
||||
"EqualExpression",
|
||||
"AddEqualExpression",
|
||||
"SubEqualExpression",
|
||||
"MultEqualExpression",
|
||||
"DivEqualExpression",
|
||||
"LinkEqualExpression",
|
||||
"CompareEqualExpression",
|
||||
"NotEqualExpression",
|
||||
"LessExpression",
|
||||
"LessOrEqualExpression",
|
||||
"GreatExpression",
|
||||
"GreatOrEqualExpression",
|
||||
"AddExpression",
|
||||
"SubExpression",
|
||||
"MultExpression",
|
||||
"DivExpression",
|
||||
"LinkExpression",
|
||||
"NegativeExpression",
|
||||
"NotExpression",
|
||||
"TrinocularExpression",
|
||||
"ForLoop",
|
||||
"ForindexLoop",
|
||||
"ForeachLoop",
|
||||
"WhileLoop",
|
||||
"Iterator",
|
||||
"ConditionExpression",
|
||||
"IfExpression",
|
||||
"ElsifExpression",
|
||||
"ElseExpression",
|
||||
"LeftTuple",
|
||||
"Tuple",
|
||||
"Definition",
|
||||
"MultipleAssignment",
|
||||
"ContinueExpression",
|
||||
"BreakExpression",
|
||||
"ReturnExpression"
|
||||
};
|
||||
|
||||
class ast
|
||||
|
@ -98,8 +139,8 @@ public:
|
|||
nd_line(l),nd_col(c),nd_type(t),nd_num(0){}
|
||||
ast(const ast&);
|
||||
ast(ast&&);
|
||||
void print_tree();
|
||||
void print(u32,bool,std::vector<string>&);
|
||||
void dump() const;
|
||||
void print(u32,bool,std::vector<string>&) const;
|
||||
void clear();
|
||||
|
||||
ast& operator=(const ast&);
|
||||
|
@ -174,13 +215,13 @@ void ast::clear()
|
|||
nd_child.clear();
|
||||
}
|
||||
|
||||
void ast::print_tree()
|
||||
void ast::dump() const
|
||||
{
|
||||
std::vector<string> tmp;
|
||||
print(0,false,tmp);
|
||||
}
|
||||
|
||||
void ast::print(u32 depth,bool last,std::vector<string>& indent)
|
||||
void ast::print(u32 depth,bool last,std::vector<string>& indent) const
|
||||
{
|
||||
for(auto& i:indent)
|
||||
std::cout<<i;
|
||||
|
@ -191,7 +232,7 @@ void ast::print(u32 depth,bool last,std::vector<string>& indent)
|
|||
std::cout<<":"<<rawstr(nd_str);
|
||||
else if(nd_type==ast_num || nd_type==ast_file)
|
||||
std::cout<<":"<<nd_num;
|
||||
std::cout<<"\n";
|
||||
std::cout<<" -> "<<nd_line<<":"<<nd_col<<"\n";
|
||||
if(last && depth)
|
||||
indent.back()=" ";
|
||||
else if(!last && depth)
|
||||
|
|
|
@ -220,6 +220,8 @@ private:
|
|||
// func end stack, reserved for code print
|
||||
std::stack<u32> fbstk;
|
||||
std::stack<u32> festk;
|
||||
|
||||
bool check_memory_reachable(const ast&);
|
||||
|
||||
void die(const string&,const u32,const u32,const u32);
|
||||
void regist_num(const f64);
|
||||
|
@ -272,6 +274,25 @@ public:
|
|||
const std::vector<opcode>& codes() const {return code;}
|
||||
};
|
||||
|
||||
bool codegen::check_memory_reachable(const ast& node)
|
||||
{
|
||||
if(node.type()==ast_call){
|
||||
const ast& tmp=node.child().back();
|
||||
if(tmp.type()==ast_callf){
|
||||
die("bad left-value",tmp.line(),tmp.col(),1);
|
||||
return false;
|
||||
}
|
||||
if(tmp.type()==ast_callv && (tmp.size()==0 || tmp.size()>1 || tmp[0].type()==ast_subvec)){
|
||||
die("bad left-value",tmp.line(),tmp.col(),1);
|
||||
return false;
|
||||
}
|
||||
}else if(node.type()!=ast_id){
|
||||
die("bad left-value",node.line(),node.col(),1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void codegen::die(const string& info,const u32 line,const u32 col,const u32 len=1)
|
||||
{
|
||||
err.load(file[fileindex]);
|
||||
|
@ -592,6 +613,9 @@ void codegen::call_func(const ast& node)
|
|||
*/
|
||||
void codegen::mcall(const ast& node)
|
||||
{
|
||||
if(!check_memory_reachable(node)){
|
||||
return;
|
||||
}
|
||||
if(node.type()==ast_id)
|
||||
{
|
||||
mcall_id(node);
|
||||
|
|
|
@ -99,9 +99,9 @@ public:
|
|||
res.push_back(line);
|
||||
}
|
||||
}
|
||||
const string& operator[](usize n){return res[n];}
|
||||
const string& name(){return file;}
|
||||
usize size(){return res.size();}
|
||||
const string& operator[](usize n) const {return res[n];}
|
||||
const string& name() const {return file;}
|
||||
usize size() const {return res.size();}
|
||||
};
|
||||
|
||||
class error:public flstream
|
||||
|
|
|
@ -107,7 +107,6 @@ private:
|
|||
bool check_func_end(const ast&);
|
||||
bool check_special_call();
|
||||
bool need_semi_check(const ast&);
|
||||
void check_memory_reachable(const ast&);
|
||||
ast null();
|
||||
ast nil();
|
||||
ast num();
|
||||
|
@ -117,7 +116,7 @@ private:
|
|||
ast hash();
|
||||
ast pair();
|
||||
ast func();
|
||||
ast args();
|
||||
ast params();
|
||||
ast lcurve_expr();
|
||||
ast expr();
|
||||
ast exprs();
|
||||
|
@ -138,7 +137,7 @@ private:
|
|||
ast incurve_def();
|
||||
ast outcurve_def();
|
||||
ast multi_id();
|
||||
ast multi_scalar(bool);
|
||||
ast multi_scalar();
|
||||
ast multi_assgin();
|
||||
ast loop();
|
||||
ast while_loop();
|
||||
|
@ -154,7 +153,6 @@ public:
|
|||
ptr(0),in_func(0),in_loop(0),
|
||||
toks(nullptr),root(0,0,ast_root),
|
||||
err(e){}
|
||||
void print(){root.print_tree();}
|
||||
const error& compile(const lexer&);
|
||||
ast& tree(){return root;}
|
||||
const ast& tree() const {return root;}
|
||||
|
@ -183,7 +181,6 @@ void parse::die(u32 line,u32 col,u32 len,string info,bool prev=false)
|
|||
col-=2;
|
||||
len+=2;
|
||||
}
|
||||
|
||||
// used to report lack of ',' ';'
|
||||
if(prev && ptr){
|
||||
line=toks[ptr-1].line;
|
||||
|
@ -191,7 +188,6 @@ void parse::die(u32 line,u32 col,u32 len,string info,bool prev=false)
|
|||
len=toks[ptr-1].str.length();
|
||||
len+=toks[ptr-1].type==tok_str?2:0;
|
||||
}
|
||||
|
||||
err.err("parse",line,col,lookahead(tok_eof)?1:len,info);
|
||||
}
|
||||
void parse::match(u32 type,const char* info)
|
||||
|
@ -305,20 +301,6 @@ bool parse::need_semi_check(const ast& node)
|
|||
}
|
||||
return !check_func_end(node);
|
||||
}
|
||||
void parse::check_memory_reachable(const ast& node)
|
||||
{
|
||||
if(node.type()==ast_call){
|
||||
const ast& tmp=node.child().back();
|
||||
if(tmp.type()==ast_callf){
|
||||
die(tmp.line(),tmp.col(),1,"bad left-value");
|
||||
}
|
||||
if(tmp.type()==ast_callv && (tmp.size()==0 || tmp.size()>1 || tmp[0].type()==ast_subvec)){
|
||||
die(tmp.line(),tmp.col(),1,"bad left-value");
|
||||
}
|
||||
}else if(node.type()!=ast_id){
|
||||
die(node.line(),node.col(),1,"bad left-value");
|
||||
}
|
||||
}
|
||||
ast parse::null()
|
||||
{
|
||||
return {toks[ptr].line,toks[ptr].col,ast_null};
|
||||
|
@ -411,7 +393,7 @@ ast parse::func()
|
|||
ast node(toks[ptr].line,toks[ptr].col,ast_func);
|
||||
match(tok_func);
|
||||
if(lookahead(tok_lcurve)){
|
||||
node.add(args());
|
||||
node.add(params());
|
||||
}else{
|
||||
node.add(null());
|
||||
}
|
||||
|
@ -419,9 +401,9 @@ ast parse::func()
|
|||
--in_func;
|
||||
return node;
|
||||
}
|
||||
ast parse::args()
|
||||
ast parse::params()
|
||||
{
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_args);
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_params);
|
||||
match(tok_lcurve);
|
||||
while(!lookahead(tok_rcurve)){
|
||||
ast tmp=id();
|
||||
|
@ -534,7 +516,6 @@ ast parse::calc()
|
|||
tmp.add(calc());
|
||||
node=std::move(tmp);
|
||||
}else if(tok_eq<=toks[ptr].type && toks[ptr].type<=tok_lnkeq){
|
||||
check_memory_reachable(node);
|
||||
// tok_eq~tok_lnkeq is 37 to 42,ast_equal~ast_lnkeq is 21~26
|
||||
ast tmp(toks[ptr].line,toks[ptr].col,toks[ptr].type-tok_eq+ast_equal);
|
||||
tmp.add(std::move(node));
|
||||
|
@ -764,7 +745,7 @@ ast parse::definition()
|
|||
}
|
||||
match(tok_eq);
|
||||
if(lookahead(tok_lcurve)){
|
||||
node.add(check_tuple()?multi_scalar(false):calc());
|
||||
node.add(check_tuple()?multi_scalar():calc());
|
||||
}else{
|
||||
node.add(calc());
|
||||
}
|
||||
|
@ -804,7 +785,7 @@ ast parse::multi_id()
|
|||
}
|
||||
return node;
|
||||
}
|
||||
ast parse::multi_scalar(bool check_call_memory)
|
||||
ast parse::multi_scalar()
|
||||
{
|
||||
// if check_call_memory is true,we will check if value called here can reach a memory space
|
||||
const u32 panic_set[]={
|
||||
|
@ -817,9 +798,6 @@ ast parse::multi_scalar(bool check_call_memory)
|
|||
match(tok_lcurve);
|
||||
while(!lookahead(tok_rcurve)){
|
||||
node.add(calc());
|
||||
if(check_call_memory){
|
||||
check_memory_reachable(node.child().back());
|
||||
}
|
||||
if(lookahead(tok_comma)){
|
||||
match(tok_comma);
|
||||
}else if(lookahead(tok_eof)){
|
||||
|
@ -834,14 +812,14 @@ ast parse::multi_scalar(bool check_call_memory)
|
|||
ast parse::multi_assgin()
|
||||
{
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_multi_assign);
|
||||
node.add(multi_scalar(true));
|
||||
node.add(multi_scalar());
|
||||
match(tok_eq);
|
||||
if(lookahead(tok_eof)){
|
||||
die(thisline,thiscol,thislen,"expected value list");
|
||||
return node;
|
||||
}
|
||||
if(lookahead(tok_lcurve)){
|
||||
node.add(check_tuple()?multi_scalar(false):calc());
|
||||
node.add(check_tuple()?multi_scalar():calc());
|
||||
}else{
|
||||
node.add(calc());
|
||||
}
|
||||
|
@ -948,7 +926,6 @@ ast parse::iter_gen()
|
|||
while(is_call(toks[ptr].type)){
|
||||
node.add(call_scalar());
|
||||
}
|
||||
check_memory_reachable(node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
|
16
stl/lib.nas
16
stl/lib.nas
|
@ -456,14 +456,14 @@ var dylib={
|
|||
# get dlcall function with limited parameter list
|
||||
limitcall: func(arg_size=0){
|
||||
if(arg_size==0){return func(ptr){return __dlcall};}
|
||||
else if(arg_size==1){return func(ptr,_0){return __dlcall};}
|
||||
else if(arg_size==2){return func(ptr,_0,_1){return __dlcall};}
|
||||
else if(arg_size==3){return func(ptr,_0,_1,_2){return __dlcall};}
|
||||
else if(arg_size==4){return func(ptr,_0,_1,_2,_3){return __dlcall};}
|
||||
else if(arg_size==5){return func(ptr,_0,_1,_2,_3,_4){return __dlcall};}
|
||||
else if(arg_size==6){return func(ptr,_0,_1,_2,_3,_4,_5){return __dlcall};}
|
||||
else if(arg_size==7){return func(ptr,_0,_1,_2,_3,_4,_5,_6){return __dlcall};}
|
||||
else if(arg_size==8){return func(ptr,_0,_1,_2,_3,_4,_5,_6,_7){return __dlcall};}
|
||||
elsif(arg_size==1){return func(ptr,_0){return __dlcall};}
|
||||
elsif(arg_size==2){return func(ptr,_0,_1){return __dlcall};}
|
||||
elsif(arg_size==3){return func(ptr,_0,_1,_2){return __dlcall};}
|
||||
elsif(arg_size==4){return func(ptr,_0,_1,_2,_3){return __dlcall};}
|
||||
elsif(arg_size==5){return func(ptr,_0,_1,_2,_3,_4){return __dlcall};}
|
||||
elsif(arg_size==6){return func(ptr,_0,_1,_2,_3,_4,_5){return __dlcall};}
|
||||
elsif(arg_size==7){return func(ptr,_0,_1,_2,_3,_4,_5,_6){return __dlcall};}
|
||||
elsif(arg_size==8){return func(ptr,_0,_1,_2,_3,_4,_5,_6,_7){return __dlcall};}
|
||||
else{return func(ptr,args...){return __dlcallv};}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -32,22 +32,66 @@ var z2 = {
|
|||
listt2: y2,
|
||||
};
|
||||
|
||||
println(w);#//1
|
||||
println(x);#//hello
|
||||
println(y);#//[1,hello]
|
||||
println(z);#//{...}
|
||||
println(z1);#//{...}
|
||||
println(y2);#//[...]
|
||||
println(y[0]);#//1
|
||||
println(y1[2][1]);#//hello
|
||||
println(z.numb);#//1
|
||||
println(z.listt[2][1]);#//hello
|
||||
println(z1.hashh.listt[2][1]);#//hello
|
||||
println(w); #//1
|
||||
println(x); #//hello
|
||||
println(y); #//[1,hello]
|
||||
println(z); #//{...}
|
||||
println(z1); #//{...}
|
||||
println(y2); #//[...]
|
||||
println(y[0]); #//1
|
||||
println(y1[2][1]); #//hello
|
||||
println(z.numb); #//1
|
||||
println(z.listt[2][1]); #//hello
|
||||
println(z1.hashh.listt[2][1]); #//hello
|
||||
println(y2[3].hashh.listt[2][1]);#//hello
|
||||
println(f);#//func(..){..}
|
||||
f();#//f is called
|
||||
println(z.funcc);#//func(..){..}
|
||||
z.funcc();#//f is called
|
||||
println(z.funcccall);#//func(..){..}
|
||||
z2.listt2[3].hashh.funcc();#//f is called
|
||||
println(y1[f2()][w]);#//hello
|
||||
println(f); #//func(..){..}
|
||||
f(); #//f is called
|
||||
println(z.funcc); #//func(..){..}
|
||||
z.funcc(); #//f is called
|
||||
println(z.funcccall); #//func(..){..}
|
||||
z2.listt2[3].hashh.funcc(); #//f is called
|
||||
println(y1[f2()][w]); #//hello
|
||||
|
||||
|
||||
# ValKmjolnir
|
||||
func(){
|
||||
var tm=maketimestamp();
|
||||
var duration=0;
|
||||
var f1=func(){}
|
||||
var f2=func(){var a=1;return a+1;}
|
||||
var f3=func(){var (a,b)=(1,1);return a+b+1;}
|
||||
tm.stamp();
|
||||
for(var i=0;i<1e7;i+=1);
|
||||
duration=tm.elapsedMSec()/1e3;
|
||||
println("total ",duration," sec, ",str(int(1e7/duration/1e6))," M calc/sec");
|
||||
tm.stamp();
|
||||
for(var i=0;i<1e7;i+=1)f1();
|
||||
duration=tm.elapsedMSec()/1e3;
|
||||
println("total ",duration," sec, ",str(int(1e7/duration/1e6))," M calc/sec");
|
||||
tm.stamp();
|
||||
for(var i=0;i<1e7;i+=1)func{}();
|
||||
duration=tm.elapsedMSec()/1e3;
|
||||
println("total ",duration," sec, ",str(int(1e7/duration/1e6))," M calc/sec");
|
||||
tm.stamp();
|
||||
for(var i=0;i<1e7;i+=1)f2();
|
||||
duration=tm.elapsedMSec()/1e3;
|
||||
println("total ",duration," sec, ",str(int(1e7/duration/1e6))," M calc/sec");
|
||||
for(var i=0;i<1e7;i+=1)
|
||||
func{
|
||||
var a=1;
|
||||
return a+1;
|
||||
}();
|
||||
duration=tm.elapsedMSec()/1e3;
|
||||
println("total ",duration," sec, ",str(int(1e7/duration/1e6))," M calc/sec");
|
||||
tm.stamp();
|
||||
for(var i=0;i<1e7;i+=1)f3();
|
||||
duration=tm.elapsedMSec()/1e3;
|
||||
println("total ",duration," sec, ",str(int(1e7/duration/1e6))," M calc/sec");
|
||||
for(var i=0;i<1e7;i+=1)
|
||||
func{
|
||||
var (a,b)=(1,1);
|
||||
return a+b+1;
|
||||
}();
|
||||
duration=tm.elapsedMSec()/1e3;
|
||||
println("total ",duration," sec, ",str(int(1e7/duration/1e6))," M calc/sec");
|
||||
}();
|
Loading…
Reference in New Issue