2013-02-10 47 views
3

PostScript裏,如果你有的PostScript標記令牌

[4 5 6] 

你有以下標記:

mark integer integer integer mark 

堆棧是這樣的:

| mark | 
| mark | integer | 
| mark | integer | integer | 
| mark | integer | integer | integer | 
| array | 

現在我的問題: ]標記運算符是一個文字對象還是一個可執行對象?

我正確的是[-mark是一個文字對象(只是數據),並且] -mark是一個可執行對象(因爲當你看到這個時你總是需要創建一個數組)。

PostScript語言參考手冊第3.3.2節給我:

[和]運算符,當被執行時,產生具有烯關閉對象作爲元件字面陣列對象。同樣,< <和>>(LanguageLevel 2)產生一個 文字字典對象。

如果兩個[]運算符都是可執行文件或只有]運算符,那對我來說就不清楚了。

回答

5

摘要。

所有這些特殊標記,[]<<>>,來掃描儀作爲可執行名稱出來。 [<<被定義爲產生標記類型對象(因此它們本身不是運算符,但是它們是在所有運營商都在的systemdict中定義的可執行名稱)。 ]>>被定義爲像任何其他過程或操作符一樣執行的過程或操作符。這些使用counttomark運算符來查找左括號。但是,所有這些令牌都被掃描器專門處理,因爲它們是其分隔符集的一部分,所以它們可以識別它們而不會包含空格。

詳情。

這一切都取決於當你看看它。讓我們來看看解釋者對這些令牌的作用。我將用一個字符串來說明這一點,但它對文件的作用是一樣的。

所以,如果你有一個輸入字符串

([4 5 6]) cvx exec 

cvx使得文本對象可執行。該程序流是也被標記爲可執行文件的文件對象。 exec在執行堆棧上推送一個對象,解釋器在內部解釋器處理循環的下一次迭代中遇到該對象。執行程序流時,可執行文件對象在執行堆棧上處於最頂層。

解釋器使用token調用掃描儀。掃描程序跳過最初的空格,然後讀取所有非空白字符直到下一個分隔符,然後嘗試將該字符串解釋爲數字,並且失敗它成爲可執行文件名稱。括號是分隔符集的一部分,因此被稱爲「自我分隔」。所以掃描器讀取一個括號字符,停止閱讀,因爲它是一個分隔符,發現它不能是一個數字,所以它會產生一個可執行文件名稱。

Top of Exec Stack | Operand Stack 
(4 5 6]) [  | 

接着,解釋器循環執行任何可執行(除非它是陣列)。 執行令牌意味着從字典中加載它,然後執行定義,如果它是可執行文件。 [定義爲-mark-對象,與定義名稱mark相同。這在技術上不是操作員或程序,而只是一個定義。自動加載發生的原因是名稱從設置了可執行標誌的掃描器中出來。

(4 5 6]) | -mark- 

掃描器然後產生4,圖5和6,其是數字,並獲得直接推到操作數棧。 6由]定界,該碼流被推回到流上。

(]) | -mark- 4 5 6 

的解釋並不執行的數量,因爲它們不是可執行,但它也不過,如果它這麼做的。執行數字的動作僅僅是將其推入堆棧。

然後,最後掃描儀遇到右括號]。這就是魔術發生的地方。自分隔,不需要任何空白。掃描儀產生的可執行文件名]和解釋通過加載執行它,它會找出...

{ counttomark array astore exch pop } 

或者,也許實際操作者做這個。但是,是的。 counttomark產生元素的數量。 array創建一個這樣大小的數組。 astore用堆棧中的元素填充數組。並且exch pop一勞永逸地丟棄那個討厭的標記。

對於字典,<<[完全相同。它下降了一個標記。然後,你行了一些鍵值對,並>>是過程,做一些事情來實現的......

{ counttomark dup dict begin 2 idiv { def } repeat pop currentdict end } 

製作一本字典。定義所有的對。彈出標記。產生字典。該版本的程序嘗試通過使其成爲雙倍大小來創建快速字典。將2 idiv移至dup之前製作字典。

所以,爲了得到哲學,counttomark是你正在使用的操作符。它需要一個特殊的對象類型,它不用於其他任何事情,marktype對象-mark-。剩下的只是語法糖,讓您訪問這個堆棧計數功能來創建線性數據結構。

附錄

下面是模型解釋器從currentfile閱讀的過程。

{currentfile token not {exit} if dup type /arraytype ne {exec} if }loop 

exec負責load ING(和進一步執行)任何可執行的名稱。從這裏可以看出,token確實是掃描儀的名稱;並且由解釋器循環直接遇到的程序(數組)未被執行(type /arraytype ne {exec} if)。

在字符串上使用token可以讓你做真的很酷的東西,但是。例如,您可以使用替代名稱動態構建過程主體。這非常像一個lisp宏。

/makeadder { % n . { n add } 
    1 dict begin 
    /n exch def 
    ({//n add}) token %() {n add} true 
    pop exch pop % {n add} 
    end 
} def 

token從字符串讀取整個過程,替換立即評估名稱//n以其當前定義的值。這裏注意到掃描器一次全部讀取一個可執行數組,在返回之前在內部有效執行[ ... ] cvx(在某些解釋器中,像我自己的xpost,這允許您繞過堆棧大小限制來構建數組,因爲數組是建立在單獨的內存中的,但2級垃圾收集使得這在很大程度上不相關)。

還有bind運算符,它通過用運算符對象本身替換運算符名稱來修改過程。這些技巧可以幫助您在快速關鍵的過程中分解名稱查找(如內部循環)。

+0

給了你答案。良好的信息。謝謝! – juFo 2013-02-11 08:21:36

+1

@juFo不,謝謝*你*。好問題。這是一個有趣的小角落。 – 2013-02-11 08:26:56

+0

但是關於[[4 5 6])會導致只是一個字符串[4 5 6]或將實際上導致一個空字符串(因爲它作爲一個數組執行?) 因爲我從來沒有想過它那樣(在一個字符串中) – juFo 2013-02-11 08:32:14

3

[和]都是可執行的令牌。 [產生標記對象]創建一個最後標記的對象數組

+1

左括號似乎有點哲學問題。它在手冊中被列爲命令,因此它是。我不認爲任何人都會調用一個將可執行文件的值推入堆棧的可執行文件,但是您需要進入實現問題來查看左括號是如何不同的。 – agentp 2013-02-10 21:03:53

+0

恰恰喬治。感謝您的評論 – juFo 2013-02-10 21:24:23

+0

給了luser droog的答案,但upvoted你也。 – juFo 2013-02-11 08:22:03