(2) ghostscript source code analysis: f_next Macro Analysis of interp () function

Source: Internet
Author: User

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.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.