The interp () function uses a large number of macros. Iref_next is only one macro, but it appears frequently.
However, a thorough understanding of this macro will facilitate understanding the interp () function.
It is defined as follows:
# Define iref_next (IP)/<br/> (const ref_packed *) (const ref *) (IP) + 1) <br/>
This seemingly simple code is actually not so easy to understand, and the macros of some columns are either similar or indirectly called.
The definition of ref is as follows:
Struct ref_s {</P> <p> struct tas_s TAS; </P> <p> Union v {/* Name the Union to keep GDB happy */<br/> int intval; <br/> ushort boolval; <br/> float realval; <br/> ulong saveid; <br/> byte * bytes; <br/> const byte * const_bytes; <br/> ref * refs; <br/> const ref * const_refs; <br/> name * pname; <br/> const name * const_pname; <br/> dict * pdict; <br/> const dict * const_pdict; <br/>/* <br/> * packed is the normal variant for referring to packed arrays, <br/> * but we need a writable variant for memory management and for <br/> * storing into packed dictionary key arrays. <br/> */<br/> const ref_packed * packed; <br/> ref_packed * writable_packed; <br/> op_proc_t opproc; <br/> struct stream_s * pfile; <br/> struct gx_device_s * pdevice; <br/> obj_header_t * pstruct; <br/>}value; <br/> };
To make (const ref *) RP + 1 meaningful, the key lies in how the parser handles it.
Let's take "{}" as an example to explain it.
The recognition process is implemented in the scan_token () function, but how is it implemented?
Take a look at some of the code snippets below:
Int <br/> scan_token (I _ctx_t * I _ctx_p, ref * pref, scanner_state * pstate) <br/> {<br/> ..................... <br/> case '{': <br/>/* compare the execution methods of {} and []. */<br/> If (pstack = 0) {/* outermost procedure */<br/> if_not_spush1 () {<br/> scan_putback (); <br/> scan_type = scanning_none; <br/> goto pause_ret; <br/>}< br/>/* pstack for very first {encountered, */<br/>/* for error recovery */<br/> pdepth = Ref_stack_count_inline (& o_stack); <br/>}< br/> make_int (OSP, pstack); <br/> pstack = ref_stack_count_inline (& o_stack ); /* stack depth when starting current */<br/>/* It can be seen from the above: pdepth! = Pstack, so the following processing will change */<br/> if_debug3 ('s ', "[s {] d = % d, S = % d-> % d/N ", <br/> pdepth, (INT) OSP-> value. intval, pstack); <br/> goto snext; <br/> ......................... <br/> case '}': <br/> If (pstack = 0) <br/> sreturn (e_syntaxerror); <br/> OSP --; <br/> {<br/>/* this is the number of object elements in the operator stack */<br/> uint size = ref_stack_count_inline (& o_stack)-pstack; <br/> ref arr;/* in this way, you actually want to put all the objects in the operand stack in arr and point the pointer. */</P> <p> if_debug4 ('s ', "[s}] d = % d, S = % d-> % d, C = % d/N ", <br/> pdepth, pstack, <br/> (pstack = pdepth? 0: <br/> ref_stack_index (& o_stack, size)-> value. intval), <br/> size + pstack); <br/> myref = (pstack = pdepth? Pref: & ARR);/* It has been explained above. Certainly not. */<Br/> If (check_only) {<br/> make_empty_array (myref, 0); <br/> ref_stack_pop (& o_stack, size ); <br/>} else if (ref_array_packing.value.boolval) {<br/> retcode = make_packed_array (myref, & o_stack, size, <br/> idmemory, "Callback (packed )"); <br/> If (retcode <0) {/* Must Be vmerror */<br/> OSP ++; <br/> scan_putback (); <br/> scan_type = scanning_none; <br/> goto pause_ret; <br/>}< br/> r_set_attrs (Myr EF, a_executable ); <br/>} else {/* discusses an easy-to-understand approach */<br/>/* allocate memory space for myref */<br/> retcode = ialloc_ref_array (myref, <br/> a_executable + a_all, size, <br/> "reverse (Proc)"); <br/> If (retcode <0) {/* Must Be vmerror */<br/> OSP ++; <br/> scan_putback (); <br/> scan_type = scanning_none; <br/> goto pause_ret; <br/>} // ref_stack_store this step is very important: copy the size objects in o_stack to myref. <Br/> retcode = ref_stack_store (& o_stack, myref, size, 0, 1, <br/> false, idmemory, "Memory "); <br/> If (retcode <0) {<br/> ifree_ref_array (myref, "Callback (Proc)"); <br/> sreturn (retcode ); <br/>}< br/>/* because all copies are in myref, so we pop all the objects in the process in all operator stacks */<br/> ref_stack_pop (& o_stack, size ); <br/>}< br/> If (pstack = pdepth) {/* This was the top-level procedure. */<br/> spop1 (); <br/> pstack = 0; <br/>}else {<br/> If (OSP <osbot) <br/> ref_stack_pop_block (& o_stack); <br/> pstack = OSP-> value. intval; <br/> * OSP = arr; <br/> goto snext; <br/>}< br/> break; <br/> ............. <br/>}
Now we have a key function-ref_stack_store (const ref_stack_t * pstack, ref * parray, uint count,
Uint Skip, int age, bool check, gs_dual_memory_t * idmemory,
Client_name_t cname );
This function can demonstrate why iref_next can appear in that form.
The source code of this function is as follows:
Int
Ref_stack_store (const ref_stack_t * pstack, ref * parray, uint count,
Uint Skip, int age, bool check, gs_dual_memory_t * idmemory,
Client_name_t cname)
{
Uint left, pass;
Ref *;
Ref_stack_enum_t rsenum;
If (count> ref_stack_count (pstack) | count> r_size (parray ))
Return_error (e_rangecheck );
If (check ){
Int code = ref_stack_store_check (pstack, parray, Count, skip );
If (Code <0)
Return code;
}
To = parray-> value. refs + count;
Left = count, pass = skip;
Ref_stack_enum_begin (& rsenum, pstack );
Do {
Ref * From = rsenum. PTR;
Uint size = rsenum. size;
If (size <= pass)
Pass-= size;
Else {
If (pass! = 0)
Size-= Pass, pass = 0;
From + = size;
If (size> left)
Size = left;
Left-= size;
Switch (AGE ){
Case-1:/* not an array */
While (size --){
From --, --;
Ref_assign (to, from );
}
Break;
Case 0:/* Old array */
While (size --){
From --, --;
Ref_assign_old (parray, to, from, cname );
}
Break;
Case 1:/* New array */
While (size --){
From --, --;
Ref_assign_new (to, from );
}
Break;
}
If (Left = 0)
Break;
}
} While (ref_stack_enum_next (& rsenum ));
R_set_size (parray, count );
Return 0;
}
Because the input age parameter is 1, it enters Case 1: this stage.
The bold italic Code indicates that the macro is used correctly.
This can be done through running debugging.