move lvalue check from parse to codegen

This commit is contained in:
ValKmjolnir 2022-11-20 17:06:13 +08:00
parent 9196d7815f
commit 54969681fc
9 changed files with 191 additions and 99 deletions

View File

@ -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`):

View File

@ -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`中找到):

View File

@ -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();

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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};}
}
};

View File

@ -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");
}();