interp是核心函数,理解此函数要下极大的功夫。
对有些及难懂的注释了一些。
交流分享是一种学习的好方法。
/* Main interpreter. */
/* If execution terminates normally, return e_InterpreterExit. */
/* If an error occurs, leave the current object in *perror_object */
/* and return a (negative) error code. */
static int interp(i_ctx_t **pi_ctx_p /* context for execution, updated if resched */, const ref * pref /* object to interpret */, ref * perror_object)
{
i_ctx_t *i_ctx_p = *pi_ctx_p;
/* * Note that iref may actually be either a ref * or a ref_packed *. * Certain DEC compilers assume that a ref * is ref-aligned even if it * is cast to a short *, and generate code on this assumption, leading * to "unaligned access" errors. For this reason, we declare * iref_packed, and use a macro to cast it to the more aligned type * where necessary (which is almost everywhere it is used). This may * lead to compiler warnings about "cast increases alignment * requirements", but this is less harmful than expensive traps at run * time. */
/* typedef ushort ref_packed; ref_packed实际上和ref第一数据成员对应的: ushort type_attrs; 而这个type_attrs这个重要的值在iscan.c的scan_token()中设置, 例如:
#define make_bool(pref,bval)/ make_tv(pref, t_boolean, boolval, bval)
#define make_false(pref)/ make_bool(pref, 0)
#define make_true(pref)/ make_bool(pref, 1)
#define make_int(pref,ival)/ make_tv(pref, t_integer, intval, ival)
#define make_int_new(pref,ival)/ make_tv_new(pref, t_integer, intval, ival)
#define make_tv(pref,newtype,valfield,newvalue)/ make_tav(pref,newtype,0,valfield,newvalue)
#define make_ta(pref,newtype,newattrs)/ (r_set_type_attrs(pref, newtype, newattrs) and_fill_sv(pref))
#define r_set_type_attrs(rp,typ,mask)/ ((rp)->tas.type_attrs = ((typ) << r_type_shift) + (mask)) 这些代码在store.h中 */
register const ref_packed *iref_packed = (const ref_packed *)pref;
/* * To make matters worse, some versions of gcc/egcs have a bug that * leads them to assume that if iref_packed is EVER cast to a ref *, * it is ALWAYS ref-aligned. We detect this in stdpre.h and provide * the following workaround: */
#ifdef ALIGNMENT_ALIASING_BUG const ref *iref_temp;
# define IREF (iref_temp = (const ref *)iref_packed, iref_temp)
#else
# define IREF ((const ref *)iref_packed)
#endif
#define SET_IREF(rp) (iref_packed = (const ref_packed *)(rp))
register int icount = 0;
/* # of consecutive tokens at iref */
/* 从函数看来,icount用于数组(过程)的个数 */
register os_ptr iosp = osp; /* private copy of osp */
/* 操作数栈 */ register es_ptr iesp = esp;
/* private copy of esp */
/* 执行栈 */ int code; ref token; /* token read from file or string, */
/* must be declared in this scope */ register const ref *pvalue = 0; /*name的查找结果,比如add,查找对应函数zadd实现*/
uint opindex; /* needed for oparrays */
os_ptr whichp; /* * We have to make the error information into a struct; * otherwise, the Watcom compiler will assign it to registers * strictly on the basis of textual frequency. * We also have to use ref_assign_inline everywhere, and * avoid direct assignments of refs, so that esi and edi * will remain available on Intel processors. */ struct interp_error_s {
int code; int line; const ref *obj; ref full;
} ierror;
/* * Get a pointer to the name table so that we can use the * inline version of name_index_ref. */
const name_table *const int_nt = imemory->gs_lib_ctx->gs_name_table; /*出错处理,这些代码并不复杂*/
#define set_error(ecode)/ { ierror.code = ecode; ierror.line = __LINE__; }
#define return_with_error(ecode, objp)/ { set_error(ecode); ierror.obj = objp; goto rwe; }
#define return_with_error_iref(ecode)/ { set_error(ecode); goto rwei; }
#define return_with_code_iref()/ { ierror.line = __LINE__; goto rweci; }
#define return_with_stackoverflow(objp)/ { o_stack.requested = 1; return_with_error(e_stackoverflow, objp); }
#define return_with_stackoverflow_iref()/ { o_stack.requested = 1; return_with_error_iref(e_stackoverflow); }
/* * If control reaches the special operators (x_add, etc.) as a result of * interpreting an executable name, iref points to the name, not the * operator, so the name rather than the operator becomes the error object, * which is wrong. We detect and handle this case explicitly when an error * occurs, so as not to slow down the non-error case. */
#define return_with_error_tx_op(err_code)/ { if (r_has_type(IREF, t_name)) {/ return_with_error(err_code, pvalue);/ }
else {/ return_with_error_iref(err_code);/ }/ } /* garbage collect,这个功能以后在有时间在研究。 */
int ticks_left = gs_interp_time_slice_ticks; /* * If we exceed the VMThreshold, set ticks_left to -100 * to alert the interpreter that we need to garbage collect. */ set_gc_signal(i_ctx_p, &ticks_left, -100);
esfile_clear_cache(); /* * From here on, if icount > 0, iref and icount correspond * to the top entry on the execution stack: icount is the count * of sequential entries remaining AFTER the current one. */ /* 这种形式能正确执行,因为向"过程"这种形式*/
#define IREF_NEXT(ip)/ ((const ref_packed *)((const ref *)(ip) + 1))
#define IREF_NEXT_EITHER(ip)/ ( r_is_packed(ip) ? (ip) + 1 : IREF_NEXT(ip) ) /* store 意味保存状态之意, short意味packed, 而either两者皆有(packed, ref) */
#define store_state(ep)/ ( icount > 0 ? (ep->value.const_refs = IREF + 1, r_set_size(ep, icount)) : 0 )
#define store_state_short(ep)/ ( icount > 0 ? (ep->value.packed = iref_packed + 1, r_set_size(ep, icount)) : 0 )
#define store_state_either(ep)/ ( icount > 0 ? (ep->value.packed = IREF_NEXT_EITHER(iref_packed), r_set_size(ep, icount)) : 0 )
#define next()/ if ( --icount > 0 ) { iref_packed = IREF_NEXT(iref_packed); goto top; } else goto out #define next_short()/ if ( --icount <= 0 ) { if ( icount < 0 ) goto up; iesp--; }/ ++iref_packed;
goto top
#define next_either()/ if ( --icount <= 0 ) { if ( icount < 0 ) goto up; iesp--; }/ iref_packed = IREF_NEXT_EITHER(iref_packed); goto top
#if !PACKED_SPECIAL_OPS
# undef next_either
# define next_either() next()
# undef store_state_either
# define store_state_either(ep) store_state(ep)
#endif /* We want to recognize executable arrays here, */ /* so we push the argument on the estack and enter */
/* the loop at the bottom. */ if (iesp >= estop) return_with_error(e_execstackoverflow, pref);
++iesp;
ref_assign_inline(iesp, pref);
goto bot;
top: /* * This is the top of the interpreter loop. * iref points to the ref being interpreted. * Note that this might be an element of a packed array, * not a real ref: we carefully arranged the first 16 bits of * a ref and of a packed array element so they could be distinguished * from each other. (See ghost.h and packed.h for more detail.) */ INCR(top);
#ifdef DEBUG /* Do a little validation on the top
(三)ghostscript源码分析之interp函数
最新推荐文章于 2024-03-08 14:32:01 发布
本文深入探讨了Ghostscript的源代码,重点关注了interp函数的实现细节。通过对token、integer、object、arrays和file操作的分析,揭示了 Ghostscript 如何解释和执行 PostScript 语言的关键过程。
摘要由CSDN通过智能技术生成