改變執行秩序的技巧
曾慶潭 Ching-Tang Tseng
ilikeforth@gmail.com
Hamilton, New Zealand
2 June 2026
剛開始接觸FORTH程式語言時,大家都對這種程式語言整個的特性感到陌生,因為它的使用習慣與所有其它的程式語言完全不同,系統強調數據傳遞時,全面使用堆疊、大部份指令都採用後算符的格式來設計、程式中竟然可以操控系統的執譯(Interpret)或編譯(Compile)狀態變化……等等,許多特性都只在 FORTH 程式語言中才有,乍看之下是不好用。
但若仔細推敲,卻讓使用者感到其執行結果都是直接了當,方便之至。想看記憶體的內容時,就直接飛取(Fetch, @)來看,或直接傾印(DUMP)來看。想改變數值計算的進制時,就直接將任意的進制值存入系統內名為數基(BASE)的變數。甚至於存或取出大批資料儲存媒體龐大硬碟的內容時,也是實體位置的直接操作。具有電腦對外界直接進行輸出或輸入的指令可用。它的許多長處蓋過了它的許多短處。
事實上,所有 FORTH 的短處,在發明當初,都有它被設計成那樣的理由,這些短處是顧及全面性的問題而建立,不是簡單隨便用一用 FORTH 的人所能體會出來的,一個好手要在設計過大型應用系統之後,才能得到這些感覺。相對的,雖然 FORTH 後來發展出許多新技術,但可以感受得出來,為了解決問題而發展的新技術,通常都只有針對性,而未具有絕對的必要性,歸根結底的研究之後,就能發現幾乎可以不必刻意發展某些新技術,例如:後來才發展出來的局部變數(Local variable)設計技術,即為一例。
某些新發展出來的新技術,就應用層面而言,通常也比較狹隘,難稱能夠顧全大局。例如:我為了改善 FORTH 數學計算的程式設計方法,而在 FORTH 基礎系統上,加建了 ABC FORTH 的新性能,這樣做,純粹只是為了數學計算問題而加建,沒有顧及其它如字串處理類的問題,而且根本不修改原基礎 FORTH 系統的任何功能, FORTH 還是 FORTH 。
新技術與新觀念是需要長時間才能發展累積出來的, FORTH 中令人感到原為短處的性能,都能隨著發展而改善,原為長處的性能,也能因發展而更為提升,這一章就討論這方面的問題。
大家剛開始研究 FORTH 程式語言的性能時,曾經歸納出一份新手學習曲線圖,圖中表示:一開始就講解如何以冒號 (:) 定義開始設計程式,並以半冒號 (;) 結束定義單一個新指令的程式設計,五分鐘內就能學得FORTH程式設計的最基本方式。接下來就有一點困難了,典型第二級比較難以學會的指令是處理文、數字輸入的 WORD 與 NUMBER 指令。然後,第三級學習上更艱難的指令就是創造(CREATE)與實踐(DOES>),兩者組合而成的特異功能性程式。第四級難懂的多工觀念。最後,也屬第四級最難完全透徹了解的觀念,就是 FORTH 能自行產生標的(Target)系統的蛻變編譯。
指令執行的先後秩序
大概所有認得 FORTH 程式語言的人,都知道後算符是怎麼一回事了。尤其是使用者想完成兩個簡單數字的計算時,算元(Operands)就得先擺在前面,將它們先放在堆疊上,然後才能執行後算符式的算子(Operator)指令,所得結果,仍然留在堆疊上。指令執行的先後秩序,跟其它程式語言都不一樣,有點煩人。
但是,這些限制,實際上都並不是絕對一成不變,非這樣不可的規矩, FORTH 程式語言,完全允許使用者對任何不滿意的狀況,自行設計改善程式來改變狀況。例如:如果不滿意於 FORTH 系統硬要使用者按照後算符的規矩使用四則運算,也可以立即設計程式進行改善,程式也很簡短,啟動系統後,幾乎可以立即建立這樣的功能。程式簡單的程度,就如下列:
FORTH DEFINITIONS
VOCABULARY IKQ \ Integer Calculator
VOCABULARY FKQ \ Floating Calculator
ONLY FORTH ALSO IKQ ALSO DEFINITIONS
: NEXTI BL WORD NUMBER DROP ;
: + NEXTI + ;
: - NEXTI - ;
: * NEXTI * ;
: / NEXTI / ;
: = . ;
ONLY FORTH ALSO FKQ ALSO DEFINITIONS
: NEXTF BL WORD COUNT >FLOAT DROP ;
: + NEXTF F+ ;
: - NEXTF F- ;
: * NEXTF F* ;
: / NEXTF F/ ;
: = G. ;
FORTH DEFINITIONS
將上列程式載入系統後,按傳統規矩執行數字的四則運算,就能得到下列直截了當的計算顯示,最後再以宣告 FORTH ,讓系統回到正常字彙之下的方式,將一切恢復成正常的狀態:
IKQ ok
9732 - 123 = 9609 ok
FKQ ok
6.02E23 / 3E0 = 2.006666667E23 ok
FORTH
這樣的四則運算是標準的中算符而不是後算符了,原來的 FORTH 系統卻完好如初,未經破壞。這樣的性能, FORTH 發明當初就已經存在了,因為上述程式中所有用到的指令,在 FORTH 程式語言發明時就已存在。此處藉著這樣的用法,來解釋第二級難度的標準指令 WORD 與 NUMBER 。
首先,必須聲明的是,想要全面實現中算符書寫方式的要求,不能僅只依靠上列的程式來完成。因為,還有許多系統性的問題必須考慮,例如:上述的設計並不顧及先乘除後加減的問題,也不允許任意使用小括弧,也不考慮任何數學函數,也不能用來處理非數字之變數的計算……等等。所以,這樣的性能是具有非常之針對性的,不是一切。
那麼,又是甚麼性能?讓我們能夠迅捷的實現這種針對性的要求。簡而言之,就是透過適合用來改變指令執行秩序的 WORD 指令,予以完成的。
在 FORTH 系統的文、數字輸入處理中,隱性的存在了三個觀念上的緩衝區(Buffers),第一個是終端機輸入緩衝區(Terminal input buffer, TIB),處理直接由鍵盤鍵入的文字,可以直接執行 TIB 指令顯示這個位址。第二個是現行輸入文字緩衝區(Word’s buffer),它就在系統字典長到此處(HERE)的位址處,或稱之為將要建立連結進系統的下一個可用新位址,可以直接執行 HERE 顯示這個位址。第三個是專門用來處理字串,但可隨系統增長而浮動存在的字串暫時儲存緩衝區(Text’s buffer),這個緩衝區的位址,可以直接執行 PAD 指令顯示出來。
古時候的 FORTH 系統,還使用專門用來將輸入字串送進 PAD 緩衝區的指令,它就名叫 -TEXT ,後來的系統不再使用而消失掉了。新作業系統太複雜,而令 FORTH 系統不得不在 TIB 緩衝區,將 FORTH 系統與作業系統進行嚴格的區隔,因此, TIB 緩衝區的一般性操作,也改讓使用者在較高層次的其它高階指令內進行。唯獨這個處於 HERE 緩衝區的 WORD 指令,永遠存在,沒有被除去,只不過某些 FORTH 系統在 WORD 指令執行之後,在堆疊上留或不留下 HERE 的位址,有所差別而已。不被除去的原因也很單純,因為輸入的文、數字,可能立刻就要被編納入系統,所以就理所當然的該留在 HERE 所處的位置。將字串送進記憶體的專門指令中,還有一個專門用來送進任意記憶體位址,而不是這三個緩衝區的 EXPECT 指令,它工作原理簡易,只屬於第一級的初級層次,此處不詳加解釋。
WORD 指令在執行前,必須提供一個當作邊際界標的字元,通常,根據 FORTH 程式語言的習慣,我們都取用空格(Blank, BL)當作界標,隨後, WORD 指令會隨著系統被指定的輸入狀況來處理輸入,輸入有可能只是終端機的螢幕,也可能是來自於一個檔案,或其它能夠被指定的輸入方式。他的處理方式,就是以輸入界標字元為邊界,要求系統處理此單一個輸入字串,處理完則留下 HERE 的位址。系統因此就只處理執行 WORD 指令當時的那一個字。
在上述程式中,面對整數時,系統會把輸入在 HERE 處的字串,經由 NUMBER 指令轉換成數值,放在堆疊上,然後,那個 HERE 位址已經無用了,所以 DROP 掉。面對浮點數時,狀況相類似。如此形成了一個名為 NEXTI 或 NEXTF 可共用的指令,新指令名稱的意思,是準備接受一個後續輸入數字的新指令,這個指令供新的四則運算指令,共同用來設計新的執行內容。例如:加法 (+) 指令,在新的規格中,被定義成先別急著開始直接執行加法,而是透過 NEXTI 或 NEXTF 的要求,先處理一個後續的輸入字串,它必須是一個能被 NUMBER 轉換得成的整數數字,或必須是由 COUNT >FLOAT 兩者組合而成,能將輸入轉換成浮點數的字串,轉換出來的數字均放置到指定堆疊上之後,才執行原本的加法運算。
如此一來,系統碰到加 (+) 指令時,就不會直接加,而是到 + 的後面去處理出一個數字才執行加法了。其它的所有四則運算指令,都被以同一方式,定義成新的執行格式,所以就完成了能夠執行中算符式的四則運算程式設計。
為了使用系統中已經用掉了的同名同功能指令作為名稱,我們藉著字彙的宣告,來區分出彼此的不同。因此,在這樣子使用四則運算時,必須先行宣告使用 IKQ 或 FKQ ,用完了也不可忘了使用宣告 FORTH ,讓整個系統恢復正常。
WORD 指令經常在想要改變單一個指令的執行秩序時,用來設計程式,不單只是處理數字時可以使用,處理文字字串也經常使用。例如:我們想改變檔案處理指令的執行秩序時,不希望檔案的全名必須放在相關操作指令的前面,而希望可以改放在後面,就如同 FLOAD 那樣的使用方式時, WORD 指令就又能派上用場。這類型的使用範例,在 FORTH 程式設計環境中幾乎是屢見不鮮,因此,使用者應該用心了解並活用 WORD 指令的實質功能。我在設計 ABC FORTH 數學計算系統時,當然也用過這些設計。
改變單一個指令的執行秩序,是藉由 WORD 指令的功能來完成;程式的執行秩序,也發展出可以改變先後秩序的技術了。
程式設計的先後秩序
這一次我們不談傳統的由下而上(Bottom-up)程式設計規矩,改談弄亂(Mess up)這種設計規矩的方法。
我在每篇網文中或多或少的都提供給讀者一些 FORTH 的相關技術,希望它們能夠傳承下去,我的目標是想將技術內容寫到最簡單的程度,要人人能看得懂,每篇文章扯到 FORTH 的內容實在不多,觀念又淺顯,所以應該很好學也很容易學,重點是您自己得動手實作設計程式,才會有真正的結果,光看文章是永遠看不出名堂的,這件事我要不斷的提醒大家。
最近在與 FORTH 相關的國際交談網站中瀏覽時,見到有人開始談論許多非英文的環境,出現了各種用 FORTH 創作的新系統。一般的意見我就不提了,其中兩項很突出的言論是:他們看不懂非英文的技術說明,但是覺得系統的性能非常傑出。另外一個突出意見就是: FORTH 的學習曲線非常陡峭(Steep learning curve),他們也同樣感受到 FORTH 的未來發展越來越艱辛。
見到這樣的言論,一則以喜,一則以憂。喜的是:講英文的人終於搞清楚了,他們不再獨霸技術,一生光講英文不學第二國語文就要不如人了,而我們一生辛苦的苦讀中文還得學英文,終於還是得到了許多好處。憂的是:陡峭的 FORTH 學習曲線普及全世界,對講那一種語言而言,統統一樣, FORTH 的確是難學!
不患人之不己知,患不知人也。只講英文的人,看不看得懂我們的技術?實在不重要,但也不可沾沾自喜,設法全面了解他們的所有技術,才是正途。
基本的 FORTH 程式設計原理,是用冒號『:』及半冒號『;』來定義出一個新指令,然後強調:『前面設計好的指令,後面的程式才能拿來用』,亦即『先造後用』,也就是說,程式設計的規矩為由下而上(Bottom-up),最後就完成了整個程式。會 FORTH 的人都知道這幾句話是老調重彈,此處則引用它來產生新話題。古時候最早期的一般 FORTH 系統確實是只能這樣用的,後來就發展出可以不按這個規矩設計程式了。中華民國已經出版過的 FORTH 基本教材,沒談或來不及談這個主題,所以就值得在這裡談。
天下事都是相對的,有大就有小(所以不要老是愛跟別人比較大或小),有高就有低(所以不要老是愛批評別人高或低),設計程式時要由下而上,思考要如何設計時,就得由上而下(Top-down)了。因此, FORTH 發展到後來,就有一些調皮工程師,設法打破這種規矩,想出了一些弄亂規矩的方法,創造實現出了新技巧。技術一直都在演進,新技巧方便、好用就被留下來,反之,就算新技巧能用 FORTH 自身設計出來,也不太有人想用,久了就被世人所淡忘。
其實,本網頁網文已公開的程式中,已經可以找到許多如此設計程式的例子使用了 DEFER 這個指令。想用來設計可以執行出任何一列數學式子的多功能性指令時, DEFER 就具有我們所談論主題的特性。它被擺置在程式的很前面,甚至於可以擺在最前面,使用當時,還不知道它被執行內容的影子到底在那裡?指令的這種性能,幾十年前,我們曾在中山科學研究院的週五夜間 FORTH 研討會上,給了它一個很恰當的中文術語,稱為:『先用後造』,或稱為『未造先用』,本文暫時統一稱之為『先用後造』。有別於『先造後用』的 FORTH 傳統程式設計規矩。
DEFER 指令不是伴隨原始 FORTH 系統而存在的指令,隨便舉一個例子,如早期的 MVP-FORTH 系統就沒有,它也沒被列入 FORTH-83 標準,所以很多早期的 FORTH 基本教材不教這個指令,它現在已經是 ANSI 標準指令之一了。
莫管 DEFER 指令的英翻中意思為何?它最恰當的指令中文譯名應該為:(宣告一個可以儲存起始執行位址用的)『向量』(Execution vector),如此,它便可以順理成章的與常數(CONSTANT)、變數(VARIABLE)、字彙(VOCABULARY)、變常數(VALUE)…等同類指令擺在一起,它們都是想宣告出某種資料結構時,必須使用的指令。
DEFER 的字典意思為『延緩』、『展期』,都不適合拿來當作指令名稱,但經其宣告而成的後續指令,具有這些意義,它表示宣告出一個可變向量名稱,並且可以延緩設計了內容後,才將起始執行位址存入此名稱,簡言之,就是可存執行位址的向量, DEFER 沒有動詞的動作,卻像變數宣告,只有宣告出名詞的意義,因此,就簡稱『向量』最為妥當。
DEFER 很好用,它也不單純的只是擁有『先用後造』性質而已,您若回頭去看看我在前面文章中的使用範例,您就可以體會出,業經 DEFER 宣告過的執行向量指令,可以有千變萬化的執行內容,只要系統的記憶體容納得下,任何在其後面設計出來的指令,管它們是否風馬牛不相及?全都可以當作它的執行內容,所以應該命名為執行『向量』。變動執行向量內容的方法,也簡單到只需使用『’』(遞給)與『IS』(是)兩個指令,便可達到目的,形如下式:
’ [new-name>] IS [deferred-name]
因此,前文的例子,只需一個程式,就可以讓讀者繪出所有合理的函數曲線。它後來才被發明出來,因為好用,就被納入 ANSI FORTH 標準。
我在設計ABC FORTH 數學計算系統時,發展到達最後階段,感覺數目字的輸入格式被系統限制住了,非常不滿意,仔細的研究過整個系統之後,發現修改核心指令 NUMBER 的執行內容,才能根本解決這個問題,而大部份 FORTH 系統都將 NUMBER 的設計內容固定下來,不允許使用者隨意更改,我得依靠執行向量的觀念才能對 NUMBER 指令的執行內容進行修正。解決的辦法就是在系統源程式的 NUMBER 指令前面,宣告出一個執行向量。
大部份國外設計出來的 FORTH 系統,都不管能否在系統中自由使用中文?的問題,想修改這些限制,通常必須修改系統指令名稱欄內的結構,而系統原本的性質還不容許被破壞,解決辦法也是到源程式中找到關鍵指令,將其內容改成執行向量的附屬內容之一,隨後就可以為所欲為的設計出適合中文環境的系統來。但對後來的大型 FORTH 系統而言,此項工程通常有點浩大,使用 FORTH 的能力,未達某種程度的人,不易辦到,進行這種工作也不輕鬆,我自知,我不行。
關於在 FORTH 系統中使用中文的問題,我們有一些經驗,分述如下:
中華民國有不少人曾在 Win32Forth 系統上下過功夫,它可以順利使用中文。
易符公司發行的 F# FORTH 系統則先行考慮了容納中文。
Forth Inc. 發行的 Swift Forth 則無此功能。
OS/2 DPMI FORTH32 系統,在 XP 環境可以執行,但也不能使用中文。
上列後面的這兩個系統,都是當初在開啟其自身所需要的一個顯示視窗時,沒顧及這項要求所致,因牽扯到如何將 FORTH 系統架設在作業系統上的技術,使用者必須從作業系統那方面重新搞起,通常難以修正。
可由 C 編譯而成的 gForth ,通常只藉一個視窗來當作系統的終端機顯示器,所以能顯示中文就能用中文,但指令名稱字長限定為少於 31 個位元組(Bytes),所以中文指令用名不可以太長。
其他的系統我未試用,啟動系統後直接試用,就知結果。
FORTH 是全面透通式的程式語言,透通到能讓使用者在系統內為所欲為,但『後果自行負責』,軍中帶兵的長官下達命令時,常用這一句話。古時候,我們想完成類似 DEFER 指令的功能時,人工操作遞給『’』指令得到 CFA 執行位址,再用 DUMP 指令仔細看可以替換的位置在那裡?配合設計一個變數,進行直接存取更換,也能達到同樣的效果,但操作起來實在太累了,所以 DEFER 是個解決問題的好指令,應該存在。
突破必須先造後用傳統程式設計規矩的指令,不只 DEFER 一個而已,也是後來才出現的 ANSI 標準的另外兩個指令: RECURSE 及 EVALUATE 也是。
EVALUATE 性能與 DEFER 有延伸性關係。比較二者,則 DEFER 形同是只能儲存單一個執行位址的向量, EVALUATE 則形同是可以執行掉被儲存之一長串執行位址的陣列,而且也是在面對必須先用後造的情況時才使用,下列的精簡測試實例,能夠協助您自然了解它的用法,不需要太多文字說明。
: DO-NOT-YET ( - - )
S” DONE1 DONE2 DONE3 ” EVALUATE ;
: DONE1 CR .” ONE DONE . ” ;
: DONE2 CR .” TWO DONE . ” ;
: DONE3 CR .” ALL DONE . ” ;
這個範例程式展示 DO-NOT-YET 指令先用後造了 DONE1、DONE2、DONE3 三個指令,它靠著標準指令 EVALUATE 以及 S”…………” (這是一組就地形成字串的指令)達到目的。因此,此後執行 DO-NOT-YET 指令時就會顯示出這樣的效果。那麼,如果 DEFER 譯成執行的『向量』, EVALUATE 就該譯成『執行字串』了,意思是執行掉前面的一連串字串陣列,它有動詞的動作(執行掉),而不是宣告出名詞。如果沒有 EVALUATE ,就可能需要使用好幾個 DEFER 才能達到目的。只不過這樣安排 EVALUATE 的指令性能,使它無法像 DEFER 一樣也可以隨時更換執行內容而已,將來若有需要,它的格式自然也就會發展成此處所描述而尚未具有的性能。
若再舉一反三推演下去,也可以設計出一個『執行矩陣』來, DEFER 是宣告出一個點, EVALUATE 是執行掉一條線,那個不知名的執行矩陣就是一個面式結構,處理 3D 的執行向量對 FORTH 而言也不是問題,接下來就不描述了。
上述造來造去、用來用去的關係也能用來解釋一個『現造現用』的指令,就是 RECURSE ,先讓我們舉例說明後,再強調它應有的適當中文譯名。
古時候的其他程式語言,例如:FORTRAN,通常稱這種指令性能為自用副程式,性能有一點特別,有些程式語言也不允許使用者如此設計程式。在我們的 FORTH 中,它的意義是『將尚未定義完成的自己納入定義』,常有人舉階乘(Factorial,例如:數學表示式為 5 ! = 5 * 4 * 3 * 2 * 1) 的計算為例,使用自用副程式的方式來完成設計。此處另舉一個反過來往上印出數字的例子,增加您對此性能的認識。程式與實際執行結果,轉錄如下:
\ Nursery rhyme : counting hoptoads
\ 四川民謠:數蛤蟆。
\ 作者:曾慶潭,2010年4月2日於紐西蘭,版權所有。
\ Author: Ching-Tang Tseng, 2Apr2010, All rights reserved.
\ http://forthfortnight.blogspot.com
\ ilikeforth@gmail.com
10 VALUE LIMIT
: READY 2 ;
: GO
CR
DUP . ." toads, "
DUP . ." mouths, "
DUP 2 * . ." eyes, "
DUP 4 * . ." legs. "
." Hoppity hop, hopped into the pond."
1+ DUP LIMIT >
IF DROP EXIT
ELSE RECURSE
THEN ;
: ARE-WE-GOOD? ;
: SING1 ARE-WE-GOOD? READY GO ;
: 預備 1 ;
: 唱
CR
DUP . ." 隻青蛙 "
DUP . ." 張嘴,"
DUP 2 * . ." 個眼睛 "
DUP 4 * . ." 條腿,"
." 噗通!噗通!跳下水。 "
1+ DUP LIMIT >
IF DROP EXIT
ELSE RECURSE
THEN ;
: 準備好了嗎? ;
: 數蛤蟆 準備好了嗎? 預備 唱 ;
: SING2 數蛤蟆 ;
FLOAD RHYME.F
From file: RHYME.F word: GO isn't unique ok
SING1
2 toads, 2 mouths, 4 eyes, 8 legs. Hoppity hop, hopped into the pond.
3 toads, 3 mouths, 6 eyes, 12 legs. Hoppity hop, hopped into the pond.
4 toads, 4 mouths, 8 eyes, 16 legs. Hoppity hop, hopped into the pond.
5 toads, 5 mouths, 10 eyes, 20 legs. Hoppity hop, hopped into the pond.
6 toads, 6 mouths, 12 eyes, 24 legs. Hoppity hop, hopped into the pond.
7 toads, 7 mouths, 14 eyes, 28 legs. Hoppity hop, hopped into the pond.
8 toads, 8 mouths, 16 eyes, 32 legs. Hoppity hop, hopped into the pond.
9 toads, 9 mouths, 18 eyes, 36 legs. Hoppity hop, hopped into the pond.
10 toads, 10 mouths, 20 eyes, 40 legs. Hoppity hop, hopped into the pond. Ok
SING2
1 隻青蛙 1 張嘴,2 個眼睛 4 條腿,噗通!噗通!跳下水。
2 隻青蛙 2 張嘴,4 個眼睛 8 條腿,噗通!噗通!跳下水。
3 隻青蛙 3 張嘴,6 個眼睛 12 條腿,噗通!噗通!跳下水。
4 隻青蛙 4 張嘴,8 個眼睛 16 條腿,噗通!噗通!跳下水。
5 隻青蛙 5 張嘴,10 個眼睛 20 條腿,噗通!噗通!跳下水。
6 隻青蛙 6 張嘴,12 個眼睛 24 條腿,噗通!噗通!跳下水。
7 隻青蛙 7 張嘴,14 個眼睛 28 條腿,噗通!噗通!跳下水。
8 隻青蛙 8 張嘴,16 個眼睛 32 條腿,噗通!噗通!跳下水。
9 隻青蛙 9 張嘴,18 個眼睛 36 條腿,噗通!噗通!跳下水。
10 隻青蛙 10 張嘴,20 個眼睛 40 條腿,噗通!噗通!跳下水。 Ok
請仔細閱讀並實際試用這個程式,它具有多方面的用途。
至少看看中文後再欣賞一下英文,程式裡面的文字,純粹是我個人的創意作品,不認識的單字就請查一下字典,我小女兒協助我在裡面使用了一個無意義的協助發音單字,字典上沒有。
這是一首童謠詩,全中華民國的同胞都熟悉,但您可能不知道童謠文學可以如此與程式科技結合,電腦一路唱下去,可以正確的算出好多條腿。
這樣的童謠還能幫助我們測試系統的回返堆疊容量到底有多少?人們在唱這首童謠時,唱錯的人就得停下來接受處罰,然後換人再唱,不是嗎?您不要以為電腦依此程式一路唱下去,就不會唱錯了,您可以經由更改 LIMIT 的設定值來進行這樣的測試,例如:直接執行 1000 TO LIMIT 。
能使系統算錯了腿數的設定值,就是這個系統回返堆疊的單位容量(Cells capacity),系統立刻執行例外處理。Win32Forth 為 1985 , gForth為 65257 ,出錯時系統都還可以健在,只是不再繼續執行程式。 F# Forth 回返堆疊的容量則很大,我無暇仔細測試,但知道十六進制的 40000 可使系統崩潰,您得重新啟動 F# 後才能再試。
各種 FORTH 系統的回返堆疊容量有這麼大的差異,沒甚麼好奇怪的,它端賴於設計者的系統原始規劃,通常容量也是可調的,只是您得自知調整方法。容量的大小也不代表系統的好壞, F# Forth 啟動後的新鮮狀況,能讓回返堆疊容量這麼大,判斷它係被規劃成開放式的成長空間所致,當程式跑到回返堆疊要用到系統自身的記憶體位置時,系統就崩潰了。 Win32Forth 及 gForth 的回返堆疊空間雖較小,系統卻進行了妥善的處理而不會崩潰。再說, Charles Moore 親自設計的 FORTH CPU i21 ,它的回返堆疊只有 17 個單位,設計人是 FORTH 程式語言的發明人,您能說 i21 不好嗎?
上述程式中使用 RECURSE 的位置有特別意義,它的功能為:就在這個位置填入當時指令(『GO』或『唱』)自身的執行位址,但當時系統尚未完成該指令的編譯,本不允許,例如:您直接將 RECURSE 改成 GO ,就無法通過系統的編譯(但我曾用過可以這樣設計程式的 FORTH 系統,忘了是那一個了), RECURSE 則實現了這樣的要求。了解了它的性能,再配合上述同類指令的譯名, RECURSE 因確實是在做現造現用的工作,它不是宣告性指令,卻像是動詞式的實際動作性指令,執行填入起始執行位址碼於此處的動作,所以應該被譯成『叫用自己』,您說呢?
FORTH 中使用的自用副程式概念,與其他程式語言所用者,在觀念上有點不同。 FORTH 指令間參數的傳遞只靠堆疊,但其他程式語言,次程式傳遞廣泛的資料,凡包裹在小括弧內者均是,彼此不同。除非參數只有少數幾個,否則想要轉譯別種語言的程式成 FORTH 程式時,會感到很不方便。我在使用 ABC FORTH 數學計算系統進行程式轉譯工作時,有此強烈的感覺。
自用副程式的使用要求,係必須在程式中設計了正確的中止執行條件,否則會令系統循環不已。上例中,數字大於 LIMIT 時就會中止,所以執行起來沒有問題,另外,這個可以執行自己的指令,會將自己的 CFA 執行位址不斷的推擠進系統的回返堆疊,如果叫用自己的層次次數太多,就會用光回返堆疊的結構,此一不良情況,您也得自行負責,在 Win32Forth 及 gForth 系統中,將此狀況處理成:用完回返堆疊就算了,執行會自行中止,系統並不會崩潰,所以我們才能利用這種特性來測試回返堆疊的設計容量,您讀了本文,應該自己去試一試。
至於程式設計時偶爾也會用到的性能類似指令,另有:『造了無用』,通常卻『另有妙用』的無執行內容指令NOOP。還有:『造了不給別人用』,『光給自己用一次』的 :NONAME 指令。 NOOP 係非標準指令, :NONAME才是 ,指令功能請參考第2章中的簡要說明,想要熟悉它們的用法,您得參考許多高手設計的程式後,才能體會出它們的真正意義,我已見過許多,也在一些文章中稱讚那樣的用法。當然,最糟的情況就是『不造不用』、您千萬別當一個『不用』又『不造』的 FORTH 使用者。
本文大膽的開始給予論及的 FORTH 標準指令中文譯名,但譯名全都其來有自,絕不亂譯,傳承 FORTH 技術時,需要中文譯名,譯其名者也應有縱觀天下的眼光,而且要符合時代潮流,我歡迎能有如此素養的同好共同探討。
三個論述的 ANSI 標準指令中文譯名,再度摘要如下:
DEFER 向量
EVALUATE 執行字串
RECURSE 叫用自己
搞通程式設計的先後秩序,是現代 FORTH 較為強調的重點,才會有上述這些指令的加入系統現象,本文回溯古典 FORTH 的歷史,可讓讀者更容易了解新標準指令的性能,講解的方法採取了『四書』首書『大學』第一章,開宗明義的醒世名言:『物有本末,事有終始,知所先後,則近道矣。』