1. 程式人生 > >(二)ghostscript原始碼分析之interp()函式之IREF_NEXT巨集分析

(二)ghostscript原始碼分析之interp()函式之IREF_NEXT巨集分析

interp()函式用了大量的巨集。IREF_NEXT只是其中一個巨集,但是出現的頻率很高。

但是透徹的理解這個巨集將為理解interp()函式提供便利。

它的定義形式如下:

這句看似簡單的程式碼實際上不那麼容易理解,而後面一些列的巨集要麼與此類似,要麼間接的呼叫它。

而ref的定義是下面這個樣子:

要使(const ref*)rp +1 變得有有意義,關鍵在於解析器是怎麼處理的。

我們以"{}"為例,來解釋它。

識別過程,是在scan_token()函式中辦到的,但是具體是怎樣辦到的?

看下面擷取的部分程式碼片段:

現在到了一個很關鍵的函式——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);

這個函式能夠說明為什麼IREF_NEXT能以那樣的形式出現是正確的。

這個函式的原始碼如下:

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 *to;
    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--, to--;
      ref_assign(to, from);
  }
  break;
     case 0:  /* old array */
  while (size--) {
      from--, to--;
      ref_assign_old(parray, to, from, cname);
  }
  break;
     case 1:  /* new array */
  while (size--) {
      from--, to--;
      ref_assign_new(to, from);
  }
  break;
     }
     if (left == 0)
  break;
 }
    } while (ref_stack_enum_next(&rsenum));
    r_set_size(parray, count);
    return 0;
}

由於傳入的age引數是1,所以進入case 1:這個階段。

加粗的黑體字程式碼表明瞭巨集所運用的方式是正確的。

這點可以通過執行除錯來斧正。