(三)ghostscript源码分析之interp函数

本文深入探讨了Ghostscript的源代码,重点关注了interp函数的实现细节。通过对token、integer、object、arrays和file操作的分析,揭示了 Ghostscript 如何解释和执行 PostScript 语言的关键过程。
摘要由CSDN通过智能技术生成
​
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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yshuise

权术横行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值