2008年11月29日 星期六

FORTH-83標準指令


FORTH-83 標準指令

譯者:曾慶潭

堆疊註解之方式: ( 執行前 –- 執行後 )
堆疊代號縮寫說明:
n 任意16位元整數或16位元有號數。
+n 正的16位元有號數。
u 16位元無號數。
+i 正的堆疊指標,堆疊頂數值( +i本身不算 )之指標為0。
f 旗號,0 表假,-1 ( 十六進制FFFF )表真。
d 任意32位元整數或32位元有號數。
c 任意8位元數值( 高效8位元不使用 )或指ASCII符號。
addr 記憶體位址。
x 任意FORTH順序碼。
string 含兩個參數:一為字串位址,另一為字串長度,其中字串長度在堆疊頂端,且最大為255。
cfa FORTH指令之解碼欄位址。
pfa FORTH指令之參數欄位址。
『 』 位於此符號中的中文,均為譯者賦予的較適當中文名稱。

****************************************

請注意!這些中文譯名,只適合在溝通FORTH技術時使用,不適合在設計FORTH程式時使用,讀者請勿曲解本文譯者的好意。
30幾年前,我們就已進行過以中文設計FORTH程式的發展,結果是全面失敗。後來,也有許多人進行過同樣的發展,甚至於寫進出版的書中,顯示出來的程式設計結果,只能以一句話形容:『慘不忍睹』。主要的原因,就是FORTH程式的語法與中文語法根本不符,不適合強行發展。
由BASIC程式語言抽取出來的30幾個數學計算專用指令及其語法,則較無與中文使用習慣不符的問題。因此,本文譯者也僅只在ABC FORTH數學計算系統中,強調可以使用中文設計程式。
最近,我們又在網路資訊中,見到海峽兩岸,均有執迷不悟的FORTH熟手,網貼慘不忍睹的FORTH中文程式。本文譯者謹根據經驗,給予大家善意的建議,不要這樣使用FORTH,這樣做,會同時破壞了中華文化與FORTH精神。變通的可行做法,則是以整句中文來定義出新的FORTH指令,延伸性發展與應用時,便沒有語法不符的問題。
提醒大家,一般FORTH系統均將指令字長限制為最多31個英文字元,使用中文語句當指令名稱時,便不得超過15個字。Win32Forth系統的指令名稱長度允許使用量,高達256個字元,能用來設計128個中文字的句型式指令,因此,比較適合融入中文。
人人都有使用FORTH的自由,但請勿曲解自由而亂來!


我在國際論壇中見過有人常以『FORTH 83 標準是16位元』來攻擊這份標準不適用於新時代。這是濫引說明的胡扯言論,我不以為然,我的個人看法認為,只需將文件中的16位元視同為目前流行系統所強調的一個記憶體單元(cell)便可。實踐是檢驗真理的唯一標準,2012年7月我在64位元系統中完成過ABC FORTH系統的增建,2017年的今天,我照樣只用這份標準,照樣完成64位元系統中增建ABC FORTH系統的設計,更甚的是,我連獨立的全高階軟體浮點運算包括所有基本函數,也都只用這份FORTH 83標準完成設計,其中數字輸入處理所需用到的關鍵指令,FORTH 83標準絕對優於其後的所有任何標準,特別值得強調。

我對目前眾說紛紜的所謂標準有個看法,制定者都別有心機,意有所圖,不夠格稱得上是為群眾服務。因此,我通常只將後來的所有標準視同為參考手冊,我不認為那是標準。

另外,讀者請勿期待本網頁刊載ANS FORTH指令集的中譯。
因為,莊哲維小老弟,早就為中華民國同胞譯過了全套文件,而且早就放在網上,任憑大家自由下載使用,但他應該仍然擁有全部譯文的版權。想要另作它用者,請用fastman7@gmail.com信箱與莊兄聯繫。
我以老手的資格,給予該套譯文完全正面的肯定,任何人也不應對莊哲維的誠意抱持任何的疑問,否則,我就網上發難,給予不客氣的批評。現今,能在FORTH界貢獻心力者實在不多,我們不要重複浪費可貴的有限人力,願意貢獻者,就請分頭貢獻。

讀者也請不用懷疑這一份FORTH-83標準指令譯文的版權問題。
中華民國FORTH語言協會,於民國七十六年四月(April 1987)出版的『FORTH期刊』第10期中,就刊載過這篇譯文,標示譯者為許承先先生,他是我服務於核能研究所核子反應器廠副廠長職務期間的部屬,當時,為了鼓勵他學FORTH,特將我的個人筆記,交給他整理出全篇譯文,刊入期刊,我是那份期刊的主編,也終生保留了FORTH-83標準指令卡,以及所有的個人FORTH筆記,當然有權使用我自己的譯文,沒有剽竊問題,這已經是幾十年的工作了,不是一蹴可幾的譯文。
長期推廣FORTH已夠辛苦,最近卻得為一些網上有意挑釁的言論,重新檢討使用材料的版權問題,大費周章的重寫聲明,實在令我感到厭煩,有心挑釁者,若來煩我,等同於担誤了整個社會,別自討沒趣了。

****************************************


1. 堆疊操作指令

DUP ( n - - n , n ) 複製堆疊頂端之值。
DROP ( n - - ) 丟棄堆疊頂端之值。
SWAP ( n1 , n2 - - n2 , n1 ) 互換堆疊頂上兩值。
OVER ( n1 , n2 - - n1 , n2 , n3 ) n3為n1之複製。
ROT ( n1 , n2 , n3 - - n2 , n3 , n1 ) 將n1旋轉置放至堆疊頂端。
PICK ( . . . +i - - . . . n ) 複製n(i)至堆疊頂端。
ROLL ( . . . +i - - . . . ) 將n(i)旋轉置放至堆疊頂端。
?DUP ( n - - 0 | n , n ) 若n不為0則複製n。
DEPTH ( - - +n ) 取得在使用DEPTH前放入堆疊數值之個數。『堆疊深度』
>R ( n1 - - ) 將n1推入回返堆疊。
R@ ( - - n1 ) 從回返堆疊複製n1。
R> ( - - n1 ) 從回返堆疊取回n1。

2. 記憶體操作指令

@ ( addr - - n ) 取出位址中之內容( 16位元 )。『飛取』
C@ ( addr - - c ) 取出位址中之內容( 8位元,而高效8位元內容為0 )。
! ( n , addr - - ) 將n存入位址中。『存妥』
C! ( c , addr - - ) 將c存入位址中。
+! ( n , addr - - ) 將n加存入位址中。
CMOVE ( addr1 , addr2 , u - - ) 『字元式搬運』
從addr1處搬移u個8位元數據至addr2處,低效位址先搬。
CMOVE> (addr1 , addr2, u - - )
從addr1處搬移u個8位元數據至addr2處,高效位址先搬。
FILL ( addr , u , c - - ) 『填入』
從addr處開始,將u個位元組( 每組8個位元 )填入c。

3. 算術運算操作指令

+ ( n1 , n2 - - sum ) n1加上n2。
- ( n1 , n2 - - diff ) n1減去n2。
* ( n1 , n2 - - product ) n1乘以n2。
/ ( n1 , n2 - - quotient ) n1除以n2 ( 餘數捨去 )。
MOD ( n1 , n2 - - remainder ) n1除以n2所得之餘數。
/MOD ( n1 , n2 - - rem , quot ) /與MOD二指令合併執行。
1+ ( n1 - - n2 ) n2=n1+1
1- ( n1 - - n2 ) n2=n1-1
2+ ( n1 - - n2 ) n2=n1+2
2- ( n1 - - n2 ) n2=n1-2
2/ ( n1 - - n2 ) n2=n1/2 ( 有號數 )。
ABS ( n1 - - u1 ) u1為n1之絕對值。
NEGATE ( n1 - - n2 ) n2=0-n1 ( 2的補數 )。
MAX ( n1 , n2 - - maximum ) 留下n1與n2中之較大者。
MIN ( n1 , n2 - - minimum ) 留下n1與n2中之較小者。
UM* ( u1 , u2 - - ud-product ) u1 * u2 ( 無號數 )。
UM/MOD ( u1, u2 - - u-rem , u-quo ) 與/MOD相似,但為無號數。
D+ ( dn1 , dn2 - - dn-sum ) dn1加上dn2。
DNEGATE ( dn1 - - dn2 ) dn2=0-dn1 ( 2的補數 )。
*/ ( n1 , n2 , n3 - - quot )
n1乘以n2後除以n3,其中之積為32位元之過渡數值。(『32位元』應改述為『雙整數』較妥)

4. 邏輯運算操作指令

AND ( n1 , n2 - - n1-and-n2 ) 『而且』 每一位元分別進行邏輯『且』( AND )之運算。
OR ( n1 , n2 - - n1-or-n2 )『或者』 每一位元分別進行邏輯『或』( OR )之運算。
XOR ( n1 , n2 - - n1-xor-n2) 『一是一非』
每一位元分別進行邏輯『一是一非則為真』( XOR )之運算。
NOT ( n1 - - not-n1 )『不對』邏輯上之1的補數。

5. 比較運算操作指令

< ( n1 , n2 - - f ) 若n1<n2則留下旗號真。
> ( n1 , n2 - - f ) 若n1>n2則留下旗號真。
= ( n1 , n2 - - f ) 若n1=n2則留下旗號真。
0< ( n - - f ) 若n為負數則留下旗號真。
0> ( n - - f ) 若n為正數則留下旗號真。
0= ( n - - f ) 若n=0則留下旗號真。
u< ( u1 , u2 - - f ) 若u1 < u2則留下旗號真( 無號數 )。
d< ( d1 , d2 - - f ) 若d1 < d2則留下旗號真。

6. 流程控制操作指令

QUIT ( - - )『潰停』
清除回返堆疊,設定系統為執譯狀態,然後接受且執譯新的輸入。
ABORT ( - - )『放棄執行』
清除數據堆疊並執行QUIT。

※ 下列指令限用於編譯狀態且立即被執行( f被其下個指令耗用 ):

BEGIN x1 f UNTIL
重複執行指令串 x1直到 f為真。
BEGIN x1 f WHILE x2 REPEAT
重複執行指令串 x1直到 f為假,當 f 為真時仍執行 x2。
f IF x1 THEN
若 f為真則執行 x1。
f IF x1 ELSE x2 THEN
若 f為真則執行 x1否則執行 x2。

※ DO設定n2為起始指標值,n1為其上限指標值,並從堆疊上移除此二數。

n1 n2 DO x1 LOOP
重複x1然後將指標增加1,當指標等於其上限值時停止此迴路。
n1 n2 DO x1 n +LOOP
重複x1然後將指標增加n,當指標之值越過其上限值減1與上限值之間時停止此迴路。
DO x1 LEAVE x2 LOOP
立即脫離迴路,不執行x2。『離開迴路』

其他流程控制用指令( 限用於編譯狀態 ) :

EXIT ( - - )立即脫離定義指令,但勿用於迴路DO … LOOP/+LOOP中。『跳出』
I ( - - n ) n為DO … LOOP/+LOOP之最內層指標。
J ( - - n ) n為DO … LOOP/+LOOP之次外層指標。

7. 輸入與輸出操作指令

KEY ( - - c ) 從輸入裝置上讀取一個 ASCII值。
EXPECT ( addr , +n - - )
讀取+n個字元或直到遇到回位鍵為止,並將其轉置於addr開始之緩衝區。
SPAN ( - - addr )
取得最近執行之EXPECT讀取的確實字元數目所放置之位址。
EMIT ( c - - ) 顯示一個ASCII字元。
TYPE ( string - - ) 顯示一個字串或數個字元。
CR ( - - ) 執行換列動作。
SPACE ( - - ) 顯示空白。
SPACES ( n - - ) 顯示n個空白。
. ( n - - ) 顯示n,若n為負數則前置負號。( 『.』可唸作『拓印』)
U. ( u - - ) 顯示u。

8. 轉換操作指令

BASE ( - - addr ) 為數基存放之位址,用於基底轉換。『基底』
DECIMAL ( - - ) 設定BASE存放10( 以十進制為基底 )。
PAD ( - - addr ) 臨時緩衝區之位址( 至少有84個字元長 )。『暫存區位址』
WORD ( c - - addr )
從輸入字串中讀入包封字串之地址,此輸入字串以c為標界字元,或直到最後一個字元為止( 忽略前置標界字元 )。
COUNT ( addr - - string )
使用於非包封字串,長度置於addr,字元開始位址為addr+1。
-TRAILING ( string1 - - string2 )
將string1之尾部空白字棄除以縮短長度。
CONVERT ( +d1 , addr1 - - +d2 , addr2 )
轉換addr1+1開始的字串成相對應的堆疊數字,將此數值累加在雙整數d1上,轉換終止於第一個非數字的字母( 就是addr2 )。

以下為數字輸出轉換操作指令,
可轉換一個雙精度數值成為置於PAD之數字字串:

<# ( d1 - - d1 ) 設定轉換開始。『開始削剖』數字
# ( d1 - - d2 ) 轉換d1之一位數。『削剖一位』數字
#S ( d1 – 0 , 0 ) 轉換其後之所有位數。『削剖出剩下的』數字
HOLD ( d1 , c - - d1 ) 加入ASCII符號c到字串中去。
SIGN ( d1 - - d1 , n ) 若n<0則加入ASCII符號『-』到字串前。
#> ( d1 - - string ) 終止轉換,留下字串。『削剖結束』

9. 詞典操作指令

’ name ( - - cfa ) 『遞給』
在現行搜尋順序中找出name指令而將其cfa留下。
FIND ( addr - - cfa , f )『搜尋』
在現行搜尋順序中找出位於addr之包封指令,找到了則留下cfa與代表真之旗號值,否則仍留下addr與代表假之旗號值0。
EXECUTE ( cfa - - )按所給之cfa執行指令。『執行』
>BODY ( cfa - - pfa ) 按所給之cfa換算成pfa。
HERE ( - - addr ) 字典區下一個可用位置之位址。系統字典區記憶體只用到『此處』
ALLOT ( n - - ) 保留字典區後續n個位元組空間。『控留』記憶體
, ( n - - ) 將n編譯入字典。『嵌碼』( 嵌音『看』)
FORTH ( - - ) 主要字彙,執行後成為第一個被搜尋之字彙。
DEFINITIONS ( - - )『收納新定義指令』
將現在編譯字彙設定成與搜尋順序中第一個字彙相同。
FORGET name ( - - )『忘掉』
將name與所有其後所加之指令從現行編譯字彙中刪除。

10. 編譯操作指令

STATE ( - - addr )『狀態』
表示編譯狀態之變數所在的位址,( 若為編譯狀態以非0表示 )。
[ ( - - ) 設定系統為執譯狀態( 立即型態 )。『不編納了』
] ( - - ) 設定系統為編譯狀態。『恢復編納』
IMMEDIATE ( - - ) 使最近定義之指令成為立即型態。『立即化』
: name x1 ; ( - - ) 『:』唸作『開始定義』,『;』唸作『定義結束』
於字典區建立指令name之進入名稱並編譯順序碼x1,遇到半冒號時停止編譯,此指令之執行動作為執行x1。
CREATE name ( - - ) 此後name指令執行時 ( - - addr )
於字典區建立指令name之進入名稱,當執行此指令時將其下一個可用字典空間之位址留下,但被定址處無資料儲存。『創造』資料結構
DOES> x1 ( - - ) 此後涉及指令執行時 ( - - pfa )
將最近完整定義之指令重新定義其執行動作,當被改變之定義指令執行時,其pfa被置於堆疊且控制轉移給順序碼x1( 立即型態 )。『實踐』後續指令
CONSTANT name ( n - - ) 此後name執行時 ( - - n )
建立具有數值n之常數名稱。
VARIABLE name ( - - ) 此後name執行時 ( - - addr )
建立變數名稱,變數使用時留下變數之位址於堆疊上。
VOCABULARY name ( - - ) 此後name執行時 ( - - )
建立字彙名稱,字彙使用時可用來改變第一個搜尋順序為此字彙。
( ccc ) ( - - ) ccc可被視為註解。
FORTH-83 ( - - ) 顯示為83標準系統之訊息。

下列為限用於編譯狀態並立即執行之指令:

.” ccc ” ( - - ) 編譯字串ccc,當執行時顯示此字串。『拓印字串』
ABORT” ccc ” ( f - - )『放棄執行』
編譯字串ccc,當執行時若旗號f為真則顯示字串並放棄執行後續指令。
LITERAL ( n - - ) 此後涉及指令執行時 ( - - n )『列妥』
編譯n,當稍後執行時留下n在堆疊上。
['] name ( - - cfa )
將名為name指令之cfa視同數值編譯之。
[COMPILE] name ( - - )
編譯名為name指令之cfa,但此指令必須為立即指令。
COMPILE name ( - - )
用於一個編譯指令的定義中,當該定義稍後被執行時,此名為name之指令會重新編譯入字典中,以取代被執行。

11. 周邊裝置操作指令

BLOCK ( u - - addr )『區塊』
從現行大容量儲存裝置( 如磁碟上之某檔案 )讀取第u個區塊至緩衝區,並送回緩衝區之位址。
BUFFER ( u - - addr )
設定第u個區塊為可用緩衝區,並送回其位址但其內容尚未標示定獻。
UPDATE ( - - )
標定最近使用之區塊以便最後重寫入大容量儲存裝置。
SAVE-BUFFERS ( - - )
將所有標定過的區塊重寫入大容量儲存裝置。
FLUSH ( - - )『閃存』
執行SAVE-BUFFERS指令,並開放所有緩衝區( 關閉所有開啟之檔案 )。
TIB ( - - addr ) 現行輸入( 鍵盤 )字串之位址。
#TIB ( - - addr ) 現行TIB中所含字元之數目所放置的位址。『#』代表此位址之內容為存放數量的意思。
BLK ( - - addr ) 現行輸入區塊( 0表輸入來自鍵盤 )之位址。
>IN ( - - addr ) 輸入字串目前之偏移值所放置的位址。『>』代表此變數的內容為指到某位址的意思。

將被系統執譯的下一個來源文字的地址由BLK與>IN之內容決定:
BLK @ = 0 表示 addr = ( TIB @ ) + ( >IN @ )
BLK @ = u 表示 addr = ( u BLOCK ) + ( >IN @ )

LOAD ( u - - )『載入』
先保留BLK與>IN,再設定BLK為u而>IN為0以重新指定輸入,輸入完畢後,重新叫回BLK與>IN。