程式碼風格
空格及縮排
指令和指令之間至少一個空格。如果一群指令構成一個有意義的片語,則片語和片語之間隔兩個空格。例如以下的 1 counter +! 被視為一個片語,
: up activate begin pause 1 counter +! again ;
指令名稱和它之後的定義之間空三格,如上例,或是將定義寫在下一行,縮排四個空格。如下,
: up ( n -- )
activate
begin
pause 1 counter +!
again
;
較長的巢狀控制結構縮排兩個空格,分號可以放在最後一個指令之後,或另起新的一行放在開頭,如上。
註解
指令說明
很短的指令,如果很容易明瞭它的意思,可以不加指令說明。
較長或較不易理解的指令應加指令說明。指令說明以指令 \ 開始,到同一行結尾。可以放在三個位置。
- 指令之前,例如,
\ 指令說明
: 指令 ( -- ) ... ;
- 和指令名稱同一行且在指令名稱之後,之間空一格,例如,
variable counter \ 計數值
: up \ ( n -- ) 指派工作 `n` 向上計數
activate begin pause 1 counter +! again ;
- 指令內部,用以說明指令實作中較難理解的部份。例如,
: 指令 ( -- )
\ 步驟一
...
\ 步驟二
;
堆疊效果
所有的指令都需要有堆疊效果的註解。
指令的堆疊效果以 ( "input" before -- after ) 表示,"input" 代表指令會從輸入緩衝區取得的資料。 before 是指令會使用的資料堆疊上的資料,after 是指令執行後會放上堆疊的資料。
如果是浮點堆疊,會使用 ( F: before -- after ) 表示。
另外,使用以下字元來代表堆疊上資料的型別或意義:
- addr 或是 a:位址,程式碼空間或是資料空間的位址,或某個變數的位址。
- c:字元
- n:整數
- f:浮點數
- t:真假值
例如:
: ( "name" -- )冒號定義指令之後要跟著被定義指令的名稱。+ ( n1 n2 -- n1+n2 )指令+會將堆疊上的兩個數字相加,並把和放上堆疊。f+ ( F: f1 f2 -- f )將浮點數f1和f2相加,得到f。! ( n a -- )將整數n放進變數位址a。compiling? ( -- t )是否在編譯狀態?
如果指令的執行會依情況產生兩種不同的效果,使用 | 表示有兩種可能情況,例如,
: ?dup ( n -- 0 | n n ) dup if dup then ;
若有必要,可以使用 = 表明堆疊上的資料的意義,或是不用等號,直接使用英文字表示
,例如以下指令讀取某從站 (slave) 某指定的數位輸入頻道 (channel),回傳一真假值,
當真假值為真時,代表輸入是 on。
ec-din@ ( n=channel n=slave -- t=on )或者ec-din@ ( channel slave -- t=on )
後者比較簡潔,是建議的寫法。t=on 不寫成 on 的原因是要表達這是一個布林值,也就是只有 0 和 -1 兩種可能,而 -1 時表示 on。
堆疊效果的註解放的位置有三處:
- 放在以指令
\開始的註解內。例如
\ 簡短的說明 ( n n -- )
\ 更清楚的說明
: 指令 .... ;
- 放在指令定義之後,和指令名稱之間空一個空格,和之後的程式空三個空格。例如,
: 2dup ( n1 n2 -- n1 n2 n1 n2 ) over over ;
- 放在複雜的指令內部說明堆疊的變化,例如,
: game ( n1=seed -- | n2 )
?dup if
xorshift 100 mod abs ( n2 )
else
." 種子不可以為 0" ( )
then ;
或
: .sin-table ( F: start end step -- )
( F: start end step ) 2 fpick 2 fpick 2 fpick
( F: start end step start end step ) .sin-header cr
( F: start end step ) .sin-values
;
命名原則
指令的名稱不區分大小寫。動程科技在本手冊中使用小寫。
以下是動程科技撰寫 Forth 程式時指令的命名原則,也是本手冊指令的命名原則。
| 命名 | 意義 | 書中範例 |
|---|---|---|
| !name | 存入一整筆資料 | |
| name! | 存入一項資料 | handler! |
| @name | 取出一整筆資料 | |
| name@ | 取出一項資料 | |
| #name | 資料總數 | |
| name# | 號碼、代號 | yellow# |
| 'name | 資料位址 | |
| (name) | 實作 name 的內部指令 | (abort) |
| +name | 增加 | +field |
| 致能、啟用 | ||
| -name | 減少、移除 | -work |
| 禁用,使停止 | ||
| .name | 印出資料 | .error .token .row |
| 以某種方式印出 | .r f.r | |
| name. | 印出某種型別的資料 | h. f. |
| ;name | 結束 | |
| ?name | 有條件的執行 | ?dup ?do |
| 檢查 | ?stacks | |
| name? | 狀況,回傳真假值 | compiling? token-empty? |
| /name | 資料的位元組數 | /point /person |
| >name | 轉換成 name | |
| name> | 轉換自 name | |
| name, | 編譯進字典 | 2, f, |
| 0name | 清除,重設 | 0error 0stacks |
| 2name | 兩筆資料 | 2, 2dup |
| name-name | 複合字使用 - 連接 | token-empty? |