2026年6月16日 星期二

蛻變編譯

蛻變編譯


曾慶潭 Ching-Tang Tseng
ilikeforth@gmail.com
Hamilton, New Zealand
16 June 2026


本文透過簡單的生物學原理,講解 FORTH 系統中,以蛻變編譯(Meta-compile)生長技術,發展出新系統的基本觀念,很適合作為了解並永久記住操作蛻變編譯時的依據。

日本的心理學家新崎盛紀,在他的著作『直覺力』中,以機能定義『創造』為:『把性質相異的素材,重新排列組合成前所未有的新事物。』,言簡意賅,本身就創造了『創造』。

創作則是創造作品,會有物品產出,它代表著成就,令創作者愉快。好的作品還能用來造福人群,美化世界,這樣的創作就值得鼓勵,而且越多越好。我喜歡創作,也喜歡別人的創作,更喜歡見到專家那麼簡明扼要的描述『創造』。

年輕時,自覺見聞、知識、經驗與觀念都有所欠缺,創作嫌早;年邁後才想要創作,可能就會嫌晚而力不從心;現在恰似正逢其時,該使出渾身解數實現自己的喜好了。已經有許多年的時間,我似乎同時進行了兩項創作,一是文章,另一則是電腦程式系統,兩者皆我所好,總想不要顧此失彼,二者可以兼得,這個網頁貼文的內容因此就由兩者揉合而成。我很愛惜自己的作品,也很希望能與世界互動,並且隨時反省、把握住作品要有正面的效果,讓讀者受益。

回顧 ABC FORTH 數學計算系統,真可算是符合前述『創造』的定義,那裡面實在沒有太多純屬於我個人的作品,在著作書本以便留下設計技術時,我寫過:『我是站在巨人的肩膀上往前看』,表示我取用了大量性質相異的素材,素材早就已經存在,重新排列組合出『ABC FORTH數學計算系統』,它確實是前所未有的新事物,這裡面甚至於擁有許多我自己都還不曾經歷過的使用性能。

創造或創作並不困難,它不是要你從事於『無中生有』的事情,而是要你從事於『有中生好』的工作,重點在構思如何重新組織與安排出別人辦不到的結果。這樣的解說提醒大家,為了人類的福祉,要多行有意義的創造與創作。

『生命』是人人愛惜的,才會有人喜歡養寵物、栽盆景,因為這些東西都有生命特徵,『活潑可愛』通常都是我們對這些喜歡對象的主要描述。根據這個道理,我很可以使用一種很有創意的方式,敘述 FORTH 為什麼能被大家喜愛?因為,我發現 FORTH 相對於其他程式語言,具有別人所沒有的『生命特徵』。

要解釋這樣的觀點,必須引用生物學上對『生命』所下的定義。 FORTH 扯上生物學並不離譜,但不是『電腦』與『人工智慧』上的那種關係,我有我的特殊看法,會有這種創意看法是其來有自。

我從台灣桃園武陵中學高中畢業,武陵中學是一所不差的學校,當年高中一年級時,總共有十個班,一班平均約四十幾個學生,蔡惠美老師教我們生物學,我還記得她把期末考的試題出得非常難拿高分,全用複選題,選完還得寫理由,寫錯了每題都會倒扣。

高中二年級起,全校學生要開始重新分班,根據未來打算選讀大學科系的志向,分出不同的班級,分成自然、文史、農醫、法商四種類別,各自加強學習各別不同的科目,面對大學入學考試,進行不同的選擇。

高一考完期末考後,我才得知,全校只有兩個學生,期末考生物學的分數是及格的,滿分是一百分,六十分及格,我考了七十六分,另外一個後來成為醫生的同學,考了六十一分。蔡老師特別問我是否想唸當年分類為丙組的農醫類組,我恭敬的回答想唸理工科學類別,屬於甲組的自然類組,答案當然令老師失望,不過我確實熱愛所有的自然科學,包括博物學與生物學,至今我仍有能力自己閱讀這方面的書籍。有過這一段歷史,所以我會有 FORTH 與生物學方面的獨特看法。

所有生物學基本教材第一章都討論有關『生命』的現象,你若不熟,可以找一本淺顯的生物學教科書來回憶一下,它很簡單,只是說明,並不難懂,我自己是特別了一點,會牢記它,還會推敲它。一般而言,生物學家都認為生物可以歸納出四種生命特徵,也就是新陳代謝(metabolism)、生長(growing)、感應(sensitivity)與繁殖(re-production)四種生命特徵,我小女兒提醒過我,所有生物都該有另一項『死亡』(mortality)的特別現象,我也覺得合理,應該納入,生物學書本沒這樣寫。

我們可以根據上述的生命特徵來探討 FORTH ,你就可以發現人人喜歡有生命的東西,如果你了解 FORTH 也有生命特徵,它一旦被了解後,自然就會被喜歡,也就不足為奇了。

一般的程式語言系統,還不曾有過被設計成像 FORTH 這樣的結構,也許將來會有,但此前沒有。舉凡市售的程式語言系統,例如:ALGOL、COBOL、BASIC、FORTRAN、PASCAL、ADA、C、LISP、PROLOG、ASSEMBLY ..... 等等我曾接觸過的程式語言,結構都不同於 FORTH ,最大的不同是這些系統整體結構絕對是死的,不管它是以那一種編譯器(Compiler)或執譯器(Interpreter)設計而成的程式語言,它們的編譯器或執譯器是絕對不允許使用者亂動的,誇張一點說,是不容你動它的一絲、一毫、一根汗毛,那怕是僅改一個碼(Code)都不行,所以我很誇張的形容它們都是死的,一點都不為過。它們從大公司出廠的那一天開始,就被製成像標本一樣的死東西,可能很好看,使用者卻絕對不能從它感受到任何一項上述的生命特徵,或要它活過來。請問你以前使用過的任何上述程式語言系統,它的屍體如果仍然存在,它有任何一丁點的改變嗎?沒有,它確實是死在那裡,或者是逝去得無影無蹤了。

回頭來看 FORTH ,它那一點像有生命特徵的樣子?有的,所有的生命特徵它還全都有呢!只差它不會死亡,否則它就令人感到可怕而不敢喜歡了。

生物的新陳代謝,講的是生物攝取食物,獲得養份與能量,過程中有些許物質交換,生物處理源源不斷的輸入,進行活動並排泄廢物。

西藏有一種傳說中的動物被雕刻成飾物,名叫皮丘,傳言牠吃東西,只進不出,愛打麻將的人如果將此飾物帶在口袋裡,象徵一定贏錢,而且只進不出,據說萬一被對手發現,會被痛揙一頓,然後輸贏全都不算。皮丘只是傳說中的動物,不是真的,牠不會新陳代謝,所以不能被介定為生物。

FORTH 就新陳代謝此一特點而論,它是擁有這項特徵, FORTH 一旦在電腦上運轉起來,它的運轉方式就一直模仿著生物的新陳代謝特徵,處理源源不斷的輸入,如果輸入是指令,它會從自己的本體內比對出來,然後就依指令的內容,將此輸入以執行方式消化掉,就好像是取得了外界的能量,進行了一次相當健康的活動,最後愉愉快快的通知使用者一個『ok』,顯示在螢幕上。如果輸入是數字,它就將數字轉換成它自己消化後可以取用的型式,暫時存放在系統內的數字堆疊上,留供後用,這也是另一次系統的活動,有些許的物質交換,我們還可以強調這像是它的系統內部起了變化。如果輸入是一堆垃圾,它也認得,它就拒絕接受,然後不客氣的問你,這是甚麼?自從你會操作 FORTH 系統之後,你不覺得你因 FORTH 會這樣子進行新陳代謝而感到喜歡它嗎?

關於生命特徵的第二個生長現象,對 FORTH 而言更是特別。前已述及,別種程式語言系統的內部是不容更動的, FORTH 不同,它被設計成像生物一樣,隨時可以生長。每當你用冒號定義直接設計 FORTH 指令時, FORTH 的系統就在生長了,除了從冒號 『:』 到半冒號 『;』 之間所定義的程式指令,可以令系統成長外,還有變數『VARIABLE』、常數『CONSTANT』、字彙『VOCABULARY』…等的宣告,以及低階指令從『CODE』到『END-CODE』之間設計的程式指令,也都會令系統成長,而且確確實實與系統紮實的長在一起, FORTH 才能繼續『活潑可愛』的活動下去。另外還有特殊的嵌碼『,』入系統、配置『ALLOT』一段記憶體空間 ..... 等指令,也能令系統成長,由檔案載入程式,長的更快。如果長得不好,還可以使用忘掉『FORGET』指令,將不想要的部份一口氣就排泄掉,某些 FORTH 系統還能使用一個簡單的特殊指令,將現行系統立刻固定下來,Win32Forth系統使用的是指令『FSAVE』。你看, FORTH 怎麼沒有生長特徵?請注意!所有程式都跟系統長在一起, FORTH 只有一個整體式的結構,它會生長,統統長在一起,生物的生長不都也是這種長法嗎?別的程式語言系統,行嗎?

更有甚者, FORTH 的生長特徵是可以修改的,我所創作的『ABC FORTH數學計算系統』,如果不對原始FORTH母系統Win32Forth的核心部份,在生長時進行修改,不可能達到符合要求的性能設計,我只是 FORTH 的老手不是高手,就能辦到此事。我的這一生也搞過其他幾種程式語言系統,但都可以確信,此生是別想在別的系統上動任何念頭了,如果還有來生,那麼,來生再看看吧。

談到生命的第三種特徵──感應現象,是生物得對環境的刺激有所反應,才能稱之為具有感應能力, FORTH 號稱具有立即(Real time)響應能力,指的就是這種能力。操作 FORTH 系統時,你所鍵入(Type in)的每一個字元,都由 FORTH 系統內的執譯器(Interpreter)立刻進行處理,是 FORTH 系統直接對輸入進行反應,是 FORTH 隨時都對刺激它的環境訊息進行感應。要它執行有感應能力的程式時,也可以利用特殊指令『KEY』或『KEY?』直接對鍵盤輸入進行反應。若要設計對電腦周邊的感應程式,當然也比當前任何其它種程式語言系統容易,我們過去幾十年,已經設計過許多這種程式,只有又快又好的感覺。別種程式語言也能用來設計有感應功能的程式,但請注意!是被譯成的程式可以感應,不是別種程式語言系統自身在做感應。

第四種繁殖能力最為特別,一般程式語言系統要想具有繁殖能力,簡直就是天方夜譚、不可思議,賣系統給你的廠商,根本不為系統設計生殖器官,要不然他們就不能繼續賺你的錢了,因為你一定會用首次買到的系統來生出新系統,他們以後怎麼可能再賺到你的錢?微軟的老板就因為這樣而成為有錢的人。作業系統中雖有 COPY 功能,可以讓使用者省下一點還得再買同一系統的錢,但也只能複製程式,絕非繁殖系統。

程式語言系統的生殖器官難道設計不出來嗎?不是的,絕對可以辦到,只是除了 FORTH 以外,別人確實是很難設計出來罷了。因為生殖方法牽扯到生殖的哲理,僅有生殖器官,若沒搞清楚生殖的標準方法,還是生不出新的系統。此前,仍然只有 FORTH 的哲理內包括了生殖哲理,它還沿襲了生物的生殖方式來進行生殖,是唯一具有生殖特徵的程式語言。

生物要能生殖,他的自身首先就得依功能進行高度的分化,然後又要求生命的最基本單元要統一成單純的結構,也就是所謂的單個生物細胞結構都得類似。

想一想你自己的生命,你有高度分化的器官,卻都由細胞組成,細胞雖然不同,其基本結構則都一致,例如:細胞核內有遺傳染色體(Chromosomes)、細胞體內有粒腺體(Mitochondria)、高基氏體(Golgi bodies) ..... 等等,不同器官的不同細胞都必須要有一種類似的結構,如此,生物才能生殖,因為生殖要從單一個胚胎細胞開始。

再想一想 FORTH ,漂亮健全的 FORTH 系統,也有依功能進行高度分化的程式內容,例如:檔案處理、浮點運算、繪圖功能、編輯程式、甚至於等同於生物生殖器的繁殖程式(Meta-compiler)…等等,他們分別被歸類到相關的器官字彙(Vocabulary)內,高度的分化了。但不管各個程式的功能如何,組成它們的最基本單元,也就是基本指令,在 FORTH 中稱之為一個字(Word)者,其結構也都完全統一,只是內容不同。也可視同是最基本單元的常數、變數、字彙 ..... 等,他們的結構也都跟最基本的指令一樣,只有所謂的名稱欄、連結欄、解碼欄、參數欄 ..... 等相同結構。 FORTH 的設計哲理,安排成與生物生存的哲理完全一致, FORTH 就容易擁有生殖特徵。基本細胞結構一致,生物就容易完成生殖;基本指令結構一致, FORTH 就容易也就會生殖。

除此之外, FORTH 的生殖方法,也與生物的生殖方法類似。生物在胚胎生長時,先從單一個胚胎細胞開始,然後進行細胞分裂,在到達某一固定數量前,分裂出來的細胞不做功能分化。我特別請教台北醫學大學的微生物老師商惠芳博士,驗證這種現象,她明確的告訴我,確實如此,生物在繁殖時,細胞分裂到 2 的 5 次方,也就是 32 個以前,是不進行功能性分化的,此後才進行功能性分化。 FORTH 繁殖方法亦然,它也先長出一個不進行功能分化的核心(Kernel)程式,再用這個核心程式去長出各個功能不同的程式,以形成一個健全的新系統。

FORTH 有許多表徴現象,與我們熟悉的生物生命現象如此的類似,絕非偶然,當初發明它的莫查理(Charles H. Moore)先生將其設計成這個樣子,他所想像出來的FORTH 基本哲理,在有意或無意中應該是參考了生命現象而成,這樣形成的可貴哲理,有助於 FORTH 的恆久存在,因為我們熱愛生命,只要你能了解 FORTH ,顯現許多生命特徵的 FORTH ,自然就能為你所愛。

自古以來,我曾接觸過的好幾套 FORTH 系統,它們生殖過程的操作方法也都類似,Win32Forth 系統亦然,新手可以一開始接觸 FORTH 就學生孩子的方法,操作過程也很簡單,耗時並不長,但很可以引起大家的興趣。

在 Win32Forth 系統中,以蛻變編譯器(Meta-compiler)產生新系統的方法:

(1).先由執行中的 Win32Forth 標準系統載入蛻變編譯程式,其程式名稱為 META.F ,由鍵盤鍵入下列指令

FLOAD META.F

系統會自動產生一個核心系統,名稱為『KERNEL應用程式』的可執行檔案。

(2).以 BYE 掉系統的方式,離開現正執行中的 Win32Forth 標準系統,然後去執行前一步驟所新產生出來的 FORTH 可執行檔『KERNEL應用程式』。
此時你已經可以進行一般性的 FORTH 指令操作了,但此核心系統很小,用 WORDS 指令可以看到它所擁有的少數有限指令。

(3).從這個執行中的核心系統載入延伸出整體性能的主控檔案,其程式名稱為 ENTEND.F ,由鍵盤鍵入下列指令

FLOAD EXTEND.F

系統便自行載入所有相關程式,稍等片刻,一個完全像 Win32Forth 的健全新 FORTH 系統,『WIN32FOR應用程式』就會產生出來,另外附帶產生幾個為了應付 XP 作業系統所須要的相關檔案,完成了一次生產。

V6.14版依然使用傳統 FORTH 的蛻變編譯原理來生成系統,也與 V4.2 版的基本原理相同,差別只在更複雜的 V6.14 系統,就有更複雜的 EXTEND.F 內容。

透過生物學的模式,了解 FORTH 蛻變編譯程式的基本原理,是很好的學習方法,學過之後也有助於永久記憶,這是我的經驗。

從上述有別於一般介紹 FORTH 特性的敘述,你可以看出,我以異於常規的方式思考問題,所以也能以異於常規的方式設計系統,『ABC FORTH數學計算系統』就是以這種方式設計出來的。

已經獲得這個系統使用說明的人,用後應該有所體會,這個系統沒能像市售系統那般,提供所有的慣用指令。使用說明的最後一頁告訴大家,設計這個系統的目的並非在重新創作一套程式語言系統,設計它的初衷,只在改善 FORTH 的數學計算應用性能。但是,這個系統絕對可以達到任何數學計算程式要求的程式執行能力,我已舉出大型有用的實例證明了它。

每當我使用這個系統設計程式時,依然難免需要準備好使用說明,隨時參考,才不會用錯指令或函數名稱,這就是使用說明的實際價值。想把所有慣用指令或功能特異的指令都設計出來,我也不是辦不到,但會破壞這個系統的真正價值,我將設計這個系統的眼光看得很遠,試想,五十年後還想讓這個系統容易繼續存在,唯有現在就將其設計成最精簡扼要的程度才有可能。 FORTH 的哲理就是這樣, eFORTH 的精神更是如此, ABC FORTH 也不例外。有 FORTH 先進,建議我將某幾個指令設計成某種格式,將更為理想,我也同意這些構想很好,但我自肘功力絕對不及 Charles H. Moore ,最好暫時別改他的設計,恰如孔子所說的:『爾愛其羊,我愛其禮。』,使用者就請以禮待此系統。

我曾在講演的投影片中列舉了 ABC FORTH 數學計算系統的十大特點:

(1).全面讓不同程度的所有使用者,易於設計數學計算程式。
(2).讓過去幾十年所發展出來的 ALGOL、FORTRAN、BASIC 數學計算程式,易於轉譯改寫進本系統而再度有用。
(3).這個系統易於自行建立,因此可以確保幾十年後這些數學計算程式仍然有用。
(4).改善此前不方便設計數學計算程式的缺點,此後再配合即時性處理數學計算程式的能力,便可以設計出線上立即執行數學計算功能的程式。
(5).讓數學計算程式全面中文化。
(6).讓數學計算程式全面各國語文化。
(7).讓發展出這個系統的技術全面大眾化。
(8).為未來可能出現的新數學體系留下發展典範。
(9).救貧不救懶:對缺乏程式工具與程式技術者有用,對懶得寫程式者不管用。
(10).這是一個永遠免費的公益系統。

在系統公開的初始階段,這十個特點可能要靠我自己身體力行來給予證明,我不怕做這樣的事情,我也樂於從事,因為『ABC FORTH數學計算系統』是我個人的創作,我有恆心與毅力來推廣它的應用。

好的創作是有意義的,在創作中記錄寶貴的經驗就是更有意義的事情,因為對 FORTH 技術的傳承會有幫助。公開好的作品也應該是有目的的,絕對不可以無的放矢,套用一句中華民國到處可見的優良標語:『生命的意義在創造宇宙繼起的生命,生活的目的在增進人類全體的生活。』您是否仔細思考過這個標語的真正意義?這篇文章中談到了生命,『ABC FORTH數學計算系統』是 FORTH 繼起的生命,也談到了目的,這個系統的真正目的就是想增進人類全體的生活。

2026年6月2日 星期二

改變執行秩序的技巧

改變執行秩序的技巧


曾慶潭 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才是 ,指令功能請參考標準指令之相關說明,想要熟悉它們的用法,您得參考許多高手設計的程式後,才能體會出它們的真正意義,我已見過許多,也在一些文章中稱讚那樣的用法。當然,最糟的情況就是『不造不用』、您千萬別當一個『不用』又『不造』的 FORTH 使用者。

本文大膽的開始給予論及的 FORTH 標準指令中文譯名,但譯名全都其來有自,絕不亂譯,傳承 FORTH 技術時,需要中文譯名,譯其名者也應有縱觀天下的眼光,而且要符合時代潮流,我歡迎能有如此素養的同好共同探討。

三個論述的 ANSI 標準指令中文譯名,再度摘要如下:

DEFER 向量
EVALUATE 執行字串
RECURSE 叫用自己

搞通程式設計的先後秩序,是現代 FORTH 較為強調的重點,才會有上述這些指令的加入系統現象,本文回溯古典 FORTH 的歷史,可讓讀者更容易了解新標準指令的性能,講解的方法採取了『四書』首書『大學』第一章,開宗明義的醒世名言:『物有本末,事有終始,知所先後,則近道矣。』