change mcall to call->mcall&allow differen lvalue in assignment
This commit is contained in:
parent
ae0dae5956
commit
ab99d2d1ed
86
README.md
86
README.md
|
@ -243,6 +243,92 @@ f(1024,2048);
|
||||||
0x00000011: nop 0x00000000
|
0x00000011: nop 0x00000000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
2021/6/21 update: Now gc will not collect nullptr.And the function of assignment is complete,now these kinds of assignment is allowed:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var f=func()
|
||||||
|
{
|
||||||
|
var _=[{_:0},{_:1}];
|
||||||
|
return func(x)
|
||||||
|
{
|
||||||
|
return _[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var m=f();
|
||||||
|
m(0)._=m(1)._=10;
|
||||||
|
|
||||||
|
[0,1,2][1:2][0]=0;
|
||||||
|
```
|
||||||
|
|
||||||
|
In the old version,parser will check this left-value and tells that these kinds of left-value are not allowed(bad lvalue).
|
||||||
|
|
||||||
|
But now it can work.And you could see its use by reading the code above.To make sure this assignment works correctly,codegen will generate byte code by nasal_codegen::call_gen() instead of nasal_codegen::mcall_gen(),and the last child of the ast will be generated by nasal_codegen::mcall_gen().So the bytecode is totally different now:
|
||||||
|
|
||||||
|
```asm
|
||||||
|
.number 10
|
||||||
|
.number 2
|
||||||
|
.symbol _
|
||||||
|
.symbol x
|
||||||
|
0x00000000: intg 0x00000002
|
||||||
|
0x00000001: newf 0x00000005
|
||||||
|
0x00000002: intl 0x00000002
|
||||||
|
0x00000003: offset 0x00000001
|
||||||
|
0x00000004: jmp 0x00000017
|
||||||
|
0x00000005: newh 0x00000000
|
||||||
|
0x00000006: pzero 0x00000000
|
||||||
|
0x00000007: happ 0x00000000 (_)
|
||||||
|
0x00000008: newh 0x00000000
|
||||||
|
0x00000009: pone 0x00000000
|
||||||
|
0x0000000a: happ 0x00000000 (_)
|
||||||
|
0x0000000b: newv 0x00000002
|
||||||
|
0x0000000c: loadl 0x00000001
|
||||||
|
0x0000000d: newf 0x00000012
|
||||||
|
0x0000000e: intl 0x00000003
|
||||||
|
0x0000000f: offset 0x00000002
|
||||||
|
0x00000010: para 0x00000001 (x)
|
||||||
|
0x00000011: jmp 0x00000016
|
||||||
|
0x00000012: calll 0x00000001
|
||||||
|
0x00000013: calll 0x00000002
|
||||||
|
0x00000014: callv 0x00000000
|
||||||
|
0x00000015: ret 0x00000000
|
||||||
|
0x00000016: ret 0x00000000
|
||||||
|
0x00000017: loadg 0x00000000
|
||||||
|
0x00000018: callg 0x00000000
|
||||||
|
0x00000019: callfv 0x00000000
|
||||||
|
0x0000001a: loadg 0x00000001
|
||||||
|
0x0000001b: pnum 0x00000000 (10.000000)
|
||||||
|
0x0000001c: callg 0x00000001
|
||||||
|
0x0000001d: pone 0x00000000
|
||||||
|
0x0000001e: callfv 0x00000001
|
||||||
|
0x0000001f: mcallh 0x00000000 (_)
|
||||||
|
0x00000020: meq 0x00000000
|
||||||
|
0x00000021: callg 0x00000001
|
||||||
|
0x00000022: pzero 0x00000000
|
||||||
|
0x00000023: callfv 0x00000001
|
||||||
|
0x00000024: mcallh 0x00000000 (_)
|
||||||
|
0x00000025: meq 0x00000000
|
||||||
|
0x00000026: pop 0x00000000
|
||||||
|
0x00000027: pzero 0x00000000
|
||||||
|
0x00000028: pzero 0x00000000
|
||||||
|
0x00000029: pone 0x00000000
|
||||||
|
0x0000002a: pnum 0x00000001 (2.000000)
|
||||||
|
0x0000002b: newv 0x00000003
|
||||||
|
0x0000002c: slcbeg 0x00000000
|
||||||
|
0x0000002d: pone 0x00000000
|
||||||
|
0x0000002e: pnum 0x00000001 (2.000000)
|
||||||
|
0x0000002f: slc2 0x00000000
|
||||||
|
0x00000030: slcend 0x00000000
|
||||||
|
0x00000031: pzero 0x00000000
|
||||||
|
0x00000032: mcallv 0x00000000
|
||||||
|
0x00000033: meq 0x00000000
|
||||||
|
0x00000034: pop 0x00000000
|
||||||
|
0x00000035: nop 0x00000000
|
||||||
|
```
|
||||||
|
|
||||||
|
As you could see from the bytecode above,mcall/mcallv/mcallh operands' using frequency will reduce,call/callv/callh/callfv/callfh at the opposite.
|
||||||
|
|
||||||
|
And because of the new structure of mcall, addr_stack, a stack used to store the memory address, is deleted from nasal_vm, and now nasal_vm use nasal_val** mem_addr to store the memory address. This will not cause fatal errors because the memory address is used __immediately__ after getting it.
|
||||||
|
|
||||||
## Test data
|
## Test data
|
||||||
|
|
||||||
### version 6.5(i5-8250U windows10 2021/6/19)
|
### version 6.5(i5-8250U windows10 2021/6/19)
|
||||||
|
|
|
@ -56,7 +56,7 @@ enum op_code
|
||||||
op_callfv, // call function(vector as parameters)
|
op_callfv, // call function(vector as parameters)
|
||||||
op_callfh, // call function(hash as parameters)
|
op_callfh, // call function(hash as parameters)
|
||||||
op_callb, // call builtin-function
|
op_callb, // call builtin-function
|
||||||
op_slcbegin, // begin of slice like: vec[1,2,3:6,0,-1]
|
op_slcbegin,// begin of slice like: vec[1,2,3:6,0,-1]
|
||||||
op_slcend, // end of slice
|
op_slcend, // end of slice
|
||||||
op_slc, // slice like vec[1]
|
op_slc, // slice like vec[1]
|
||||||
op_slc2, // slice like vec[nil:10]
|
op_slc2, // slice like vec[nil:10]
|
||||||
|
@ -499,16 +499,27 @@ void nasal_codegen::call_func(nasal_ast& ast)
|
||||||
|
|
||||||
void nasal_codegen::mcall(nasal_ast& ast)
|
void nasal_codegen::mcall(nasal_ast& ast)
|
||||||
{
|
{
|
||||||
mcall_id(ast.get_type()==ast_id?ast:ast.get_children()[0]);
|
if(ast.get_type()==ast_id)
|
||||||
int child_size=ast.get_children().size();
|
{
|
||||||
for(int i=1;i<child_size;++i)
|
mcall_id(ast);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
calc_gen(ast.get_children()[0]);
|
||||||
|
for(int i=1;i<ast.get_children().size()-1;++i)
|
||||||
{
|
{
|
||||||
nasal_ast& tmp=ast.get_children()[i];
|
nasal_ast& tmp=ast.get_children()[i];
|
||||||
|
switch(tmp.get_type())
|
||||||
|
{
|
||||||
|
case ast_callh:call_hash(tmp);break;
|
||||||
|
case ast_callv:call_vec(tmp); break;
|
||||||
|
case ast_callf:call_func(tmp);break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nasal_ast& tmp=ast.get_children().back();
|
||||||
if(tmp.get_type()==ast_callh)
|
if(tmp.get_type()==ast_callh)
|
||||||
mcall_hash(tmp);
|
mcall_hash(tmp);
|
||||||
else if(tmp.get_type()==ast_callv)
|
else if(tmp.get_type()==ast_callv)
|
||||||
mcall_vec(tmp);
|
mcall_vec(tmp);
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -264,18 +264,14 @@ void nasal_parse::check_memory_reachable(nasal_ast& node)
|
||||||
{
|
{
|
||||||
if(node.get_type()==ast_call)
|
if(node.get_type()==ast_call)
|
||||||
{
|
{
|
||||||
if(node.get_children()[0].get_type()!=ast_id)
|
nasal_ast& tmp=node.get_children().back();
|
||||||
die(node.get_line(),"cannot get memory of temp data");
|
|
||||||
for(auto& tmp:node.get_children())
|
|
||||||
{
|
|
||||||
if(tmp.get_type()==ast_callf)
|
if(tmp.get_type()==ast_callf)
|
||||||
die(tmp.get_line(),"cannot get memory of func-returned value");
|
die(tmp.get_line(),"bad left-value");
|
||||||
if(tmp.get_type()==ast_callv && (tmp.get_children().size()>1 || tmp.get_children()[0].get_type()==ast_subvec))
|
if(tmp.get_type()==ast_callv && (tmp.get_children().size()>1 || tmp.get_children()[0].get_type()==ast_subvec))
|
||||||
die(tmp.get_line(),"cannot get memory of temp sliced vector");
|
die(tmp.get_line(),"bad left-value");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(node.get_type()!=ast_id)
|
else if(node.get_type()!=ast_id)
|
||||||
die(node.get_line(),"cannot get memory of temp data");
|
die(node.get_line(),"bad left-value");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nasal_ast nasal_parse::null_node_gen()
|
nasal_ast nasal_parse::null_node_gen()
|
||||||
|
@ -428,9 +424,9 @@ nasal_ast nasal_parse::args_gen()
|
||||||
else if(tmp.get_type()==ast_dynamic_id)
|
else if(tmp.get_type()==ast_dynamic_id)
|
||||||
checked_dynamic_ids=true;
|
checked_dynamic_ids=true;
|
||||||
if(checked_default_val && tmp.get_type()!=ast_default_arg)
|
if(checked_default_val && tmp.get_type()!=ast_default_arg)
|
||||||
die(tmp.get_line(),"must use default parameters after using it once: "+args_format);
|
die(tmp.get_line(),"must use default paras after using it once: "+args_format);
|
||||||
if(checked_dynamic_ids && &tmp!=&node.get_children().back())
|
if(checked_dynamic_ids && &tmp!=&node.get_children().back())
|
||||||
die(tmp.get_line(),"dynamic parameter must be the end: "+args_format);
|
die(tmp.get_line(),"dynamic para must be the end: "+args_format);
|
||||||
}
|
}
|
||||||
std::unordered_map<std::string,bool> argname_table;
|
std::unordered_map<std::string,bool> argname_table;
|
||||||
for(auto& tmp:node.get_children())
|
for(auto& tmp:node.get_children())
|
||||||
|
@ -439,8 +435,8 @@ nasal_ast nasal_parse::args_gen()
|
||||||
switch(tmp.get_type())
|
switch(tmp.get_type())
|
||||||
{
|
{
|
||||||
case ast_dynamic_id:
|
case ast_dynamic_id:
|
||||||
case ast_id:new_name=tmp.get_str();break;
|
case ast_id: new_name=tmp.get_str();break;
|
||||||
case ast_default_arg:tmp.get_children()[0].get_str();break;
|
case ast_default_arg:new_name=tmp.get_children()[0].get_str();break;
|
||||||
}
|
}
|
||||||
if(argname_table.count(new_name))
|
if(argname_table.count(new_name))
|
||||||
die(tmp.get_line(),"parameter's name repeats: "+new_name);
|
die(tmp.get_line(),"parameter's name repeats: "+new_name);
|
||||||
|
|
59
nasal_vm.h
59
nasal_vm.h
|
@ -5,15 +5,15 @@ class nasal_vm
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/* reference from nasal_gc */
|
/* reference from nasal_gc */
|
||||||
nasal_val**& stack_top; // stack top
|
nasal_val**& stack_top;// stack top
|
||||||
/* values of nasal_vm */
|
/* values of nasal_vm */
|
||||||
int pc; // program counter
|
int pc; // program counter
|
||||||
bool loop_mark; // when mark is false,break the main loop
|
bool loop_mark;// when mark is false,break the main loop
|
||||||
std::stack<int> ret; // ptr stack stores address for function to return
|
std::stack<int> ret; // ptr stack stores address for function to return
|
||||||
std::stack<int> counter; // iterator stack for forindex/foreach
|
std::stack<int> counter; // iterator stack for forindex/foreach
|
||||||
std::vector<std::string> str_table; // symbols used in process
|
std::vector<std::string> str_table;// symbols used in process
|
||||||
std::vector<opcode> exec_code; // byte codes store here
|
std::vector<opcode> exec_code;// byte codes store here
|
||||||
std::stack<nasal_val**> addr_stack;// used for mem_call
|
nasal_val** mem_addr; // used for mem_call
|
||||||
nasal_gc gc; // garbage collector
|
nasal_gc gc; // garbage collector
|
||||||
|
|
||||||
void die(std::string);
|
void die(std::string);
|
||||||
|
@ -308,48 +308,42 @@ void nasal_vm::opr_lnk()
|
||||||
}
|
}
|
||||||
void nasal_vm::opr_addeq()
|
void nasal_vm::opr_addeq()
|
||||||
{
|
{
|
||||||
nasal_val** mem_addr=addr_stack.top();addr_stack.pop();
|
|
||||||
nasal_val* new_val=gc.gc_alloc(vm_num);
|
nasal_val* new_val=gc.gc_alloc(vm_num);
|
||||||
new_val->ptr.num=mem_addr[0]->to_number()+stack_top[0]->to_number();
|
new_val->ptr.num=mem_addr[0]->to_number()+stack_top[-1]->to_number();
|
||||||
stack_top[0]=mem_addr[0]=new_val;
|
(--stack_top)[0]=mem_addr[0]=new_val;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void nasal_vm::opr_subeq()
|
void nasal_vm::opr_subeq()
|
||||||
{
|
{
|
||||||
nasal_val** mem_addr=addr_stack.top();addr_stack.pop();
|
|
||||||
nasal_val* new_val=gc.gc_alloc(vm_num);
|
nasal_val* new_val=gc.gc_alloc(vm_num);
|
||||||
new_val->ptr.num=mem_addr[0]->to_number()-stack_top[0]->to_number();
|
new_val->ptr.num=mem_addr[0]->to_number()-stack_top[-1]->to_number();
|
||||||
stack_top[0]=mem_addr[0]=new_val;
|
(--stack_top)[0]=mem_addr[0]=new_val;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void nasal_vm::opr_muleq()
|
void nasal_vm::opr_muleq()
|
||||||
{
|
{
|
||||||
nasal_val** mem_addr=addr_stack.top();addr_stack.pop();
|
|
||||||
nasal_val* new_val=gc.gc_alloc(vm_num);
|
nasal_val* new_val=gc.gc_alloc(vm_num);
|
||||||
new_val->ptr.num=mem_addr[0]->to_number()*stack_top[0]->to_number();
|
new_val->ptr.num=mem_addr[0]->to_number()*stack_top[-1]->to_number();
|
||||||
stack_top[0]=mem_addr[0]=new_val;
|
(--stack_top)[0]=mem_addr[0]=new_val;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void nasal_vm::opr_diveq()
|
void nasal_vm::opr_diveq()
|
||||||
{
|
{
|
||||||
nasal_val** mem_addr=addr_stack.top();addr_stack.pop();
|
|
||||||
nasal_val* new_val=gc.gc_alloc(vm_num);
|
nasal_val* new_val=gc.gc_alloc(vm_num);
|
||||||
new_val->ptr.num=mem_addr[0]->to_number()/stack_top[0]->to_number();
|
new_val->ptr.num=mem_addr[0]->to_number()/stack_top[-1]->to_number();
|
||||||
stack_top[0]=mem_addr[0]=new_val;
|
(--stack_top)[0]=mem_addr[0]=new_val;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void nasal_vm::opr_lnkeq()
|
void nasal_vm::opr_lnkeq()
|
||||||
{
|
{
|
||||||
nasal_val** mem_addr=addr_stack.top();addr_stack.pop();
|
|
||||||
nasal_val* new_val=gc.gc_alloc(vm_str);
|
nasal_val* new_val=gc.gc_alloc(vm_str);
|
||||||
*new_val->ptr.str=mem_addr[0]->to_string()+stack_top[0]->to_string();
|
*new_val->ptr.str=mem_addr[0]->to_string()+stack_top[-1]->to_string();
|
||||||
stack_top[0]=mem_addr[0]=new_val;
|
(--stack_top)[0]=mem_addr[0]=new_val;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void nasal_vm::opr_meq()
|
void nasal_vm::opr_meq()
|
||||||
{
|
{
|
||||||
addr_stack.top()[0]=stack_top[0];
|
mem_addr[0]=(--stack_top)[0];
|
||||||
addr_stack.pop();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void nasal_vm::opr_eq()
|
void nasal_vm::opr_eq()
|
||||||
|
@ -738,18 +732,20 @@ void nasal_vm::opr_slc2()
|
||||||
}
|
}
|
||||||
void nasal_vm::opr_mcallg()
|
void nasal_vm::opr_mcallg()
|
||||||
{
|
{
|
||||||
addr_stack.push(&gc.global[exec_code[pc].num]);
|
mem_addr=&gc.global[exec_code[pc].num];
|
||||||
|
(++stack_top)[0]=mem_addr[0];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void nasal_vm::opr_mcalll()
|
void nasal_vm::opr_mcalll()
|
||||||
{
|
{
|
||||||
addr_stack.push(&gc.local.back()[exec_code[pc].num]);
|
mem_addr=&gc.local.back()[exec_code[pc].num];
|
||||||
|
(++stack_top)[0]=mem_addr[0];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void nasal_vm::opr_mcallv()
|
void nasal_vm::opr_mcallv()
|
||||||
{
|
{
|
||||||
nasal_val* val=*stack_top--;
|
nasal_val* val=stack_top[0];
|
||||||
nasal_val* vec_addr=*addr_stack.top();
|
nasal_val* vec_addr=(--stack_top)[0];
|
||||||
int type=vec_addr->type;
|
int type=vec_addr->type;
|
||||||
if(type==vm_vec)
|
if(type==vm_vec)
|
||||||
{
|
{
|
||||||
|
@ -760,10 +756,9 @@ void nasal_vm::opr_mcallv()
|
||||||
case vm_str:num=(int)str2num(val->ptr.str->c_str());break;
|
case vm_str:num=(int)str2num(val->ptr.str->c_str());break;
|
||||||
default:die("mcallv: error value type");break;
|
default:die("mcallv: error value type");break;
|
||||||
}
|
}
|
||||||
nasal_val** mem_addr=vec_addr->ptr.vec->get_mem(num);
|
mem_addr=vec_addr->ptr.vec->get_mem(num);
|
||||||
if(!mem_addr)
|
if(!mem_addr)
|
||||||
die("mcallv: index out of range:"+num2str(num));
|
die("mcallv: index out of range:"+num2str(num));
|
||||||
addr_stack.top()=mem_addr;
|
|
||||||
}
|
}
|
||||||
else if(type==vm_hash)
|
else if(type==vm_hash)
|
||||||
{
|
{
|
||||||
|
@ -774,13 +769,12 @@ void nasal_vm::opr_mcallv()
|
||||||
}
|
}
|
||||||
nasal_hash& ref=*vec_addr->ptr.hash;
|
nasal_hash& ref=*vec_addr->ptr.hash;
|
||||||
std::string& str=*val->ptr.str;
|
std::string& str=*val->ptr.str;
|
||||||
nasal_val** mem_addr=ref.get_mem(str);
|
mem_addr=ref.get_mem(str);
|
||||||
if(!mem_addr)
|
if(!mem_addr)
|
||||||
{
|
{
|
||||||
ref.elems[str]=gc.nil_addr;
|
ref.elems[str]=gc.nil_addr;
|
||||||
mem_addr=ref.get_mem(str);
|
mem_addr=ref.get_mem(str);
|
||||||
}
|
}
|
||||||
addr_stack.top()=mem_addr;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
die("mcallv: cannot get memory space in other types");
|
die("mcallv: cannot get memory space in other types");
|
||||||
|
@ -788,7 +782,7 @@ void nasal_vm::opr_mcallv()
|
||||||
}
|
}
|
||||||
void nasal_vm::opr_mcallh()
|
void nasal_vm::opr_mcallh()
|
||||||
{
|
{
|
||||||
nasal_val* hash_addr=*addr_stack.top();
|
nasal_val* hash_addr=stack_top[0];
|
||||||
if(hash_addr->type!=vm_hash)
|
if(hash_addr->type!=vm_hash)
|
||||||
{
|
{
|
||||||
die("mcallh: must call a hash");
|
die("mcallh: must call a hash");
|
||||||
|
@ -796,13 +790,12 @@ void nasal_vm::opr_mcallh()
|
||||||
}
|
}
|
||||||
nasal_hash& ref=*hash_addr->ptr.hash;
|
nasal_hash& ref=*hash_addr->ptr.hash;
|
||||||
std::string& str=str_table[exec_code[pc].num];
|
std::string& str=str_table[exec_code[pc].num];
|
||||||
nasal_val** mem_addr=ref.get_mem(str);
|
mem_addr=ref.get_mem(str);
|
||||||
if(!mem_addr) // create a new key
|
if(!mem_addr) // create a new key
|
||||||
{
|
{
|
||||||
ref.elems[str]=gc.nil_addr;
|
ref.elems[str]=gc.nil_addr;
|
||||||
mem_addr=ref.get_mem(str);
|
mem_addr=ref.get_mem(str);
|
||||||
}
|
}
|
||||||
addr_stack.top()=mem_addr;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void nasal_vm::opr_ret()
|
void nasal_vm::opr_ret()
|
||||||
|
|
Loading…
Reference in New Issue