Forth 教學(Forth Tutorial)


by Phil Burk

中譯版本: 0.01.00
中譯者: Cnoize Chuang

To pForth Home Page

內容列表(Table of Contents)

這份教學文件的目的是提供一系列的經驗讓讀者認識 Forth 系統的主要概念. 這只是一個起點. 讀者可以不必依序閱讀. 從好奇心啟發的自由研究可能是學習任 何語言的最好方法. Forth 特別適合用於這種型式的學習方法.

The intent of this tutorial is to provide a series of experiments that will introduce you to the major concepts of Forth. It is only a starting point. Feel free to deviate from the sequences I provide. A free form investigation that is based on your curiosity is probably the best way to learn any language. Forth is especially well adapted to this type of learning.

這份教學文件是為了符合 ANS Forth 標準的 pforth 實作而寫的. 作者嘗試將這 份文件所使用的詞限制在 ANS 標準的部分, 但是有些 pforth 特有的詞可能已經 包含在其中了.

This tutorial is written for the PForth implementation of the ANS Forth standard. I have tried to restrict this tutorial to words that are part of the ANS standard but some PForth specific words may have crept in.

在這份教學文件中, 作者將用大寫英文字母來書寫讀者所需輸入的程式, 並且加以 縮排. 讀者可以用大寫英文字母或小寫來輸入. 在每一行的結束, 按 RETURN 或是 ENTER 鍵; 這將會讓 Forth 解譯讀者所輸入的程式.

In the tutorials, I will print the things you need to type in upper case, and indent them. You can enter them in upper or lower case. At the end of each line, press the RETURN (or ENTER) key; this causes Forth to interpret what you've entered.

Forth 的語法(Forth Syntax)

跟任何電腦語言相比, Forth 的語法是最簡單的. 這種語法簡敘如下: "Forth 程式碼是一群用空白分隔的字母. " 它甚至比英文還簡單! 每一個 詞(word) 相當於 C 語言中的函式或副程序. 它們是依照在程式碼中出現 的次序而執行的. 下列的敘述就可能出現在一個 Forth 的程式碼中:

Forth has one of the simplest syntaxes of any computer language. The syntax can be stated as follows, "Forth code is a bunch of words with spaces between them." This is even simpler than English! Each word is equivalent to a function or subroutine in a language like 'C'. They are executed in the order they appear in the code. The following statement, for example, could appear in a Forth program:

注意在 WAKE.UP 中有一個小數點. 這一個小數點在 Forth 編譯器中並沒有特別的意義. 作者只是簡單地用一個點來連接兩個英文單成讓它變成一個詞. Forth 的詞名可以是任 何字母、數字、或是標點符號的組合. 我們將會遇見下列這種名字型式的詞:

Notice that WAKE.UP has a dot between the WAKE and UP. The dot has no particular meaning to the Forth compiler. I simply used a dot to connect the two words together to make one word. Forth word names can have any combination of letters, numbers, or punctuation. We will encounter words with names like:

它們都叫做 詞(words). 這個單字 "$%%-GL7OP" 也是合法的 Forth 詞, 雖然它的名字並不好. 程式設計員可以用合乎情理的方法來命名.

They are all called words. The word $%%-GL7OP is a legal Forth name, although not a very good one. It is up to the programmer to name words in a sensible manner.

現在是執行你的 Forth 並開始實驗的時間. 請查閱你的 Forth 手冊來取得如何 執行它的指示.

Now it is time to run your Forth and begin experimenting. Please consult the manual for your Forth for instructions on how to run it.

堆疊的操作(Stack Manipulation)

Forth 語言是奠基於 堆疊 的內容. 想像一個堆疊中放置了包含數值的區塊. 你可以從這一個堆疊的最上方增加或移除數字. 你也可以重新排列這些數值的順序. Forth 使用了數個堆疊. 資料堆疊是一個用來在 Forth 詞中傳遞資料的堆疊, 所以我們將會把我們的注意力集中在那裡. 返回堆疊是另一個主要用來作為 系統內部使用的堆疊. 在這份教學文件中, 當我們提到 "堆疊" 這個專有名詞時, 我們是指資料堆疊.

The Forth language is based on the concept of a stack. Imagine a stack of blocks with numbers on them. You can add or remove numbers from the top of the stack. You can also rearrange the order of the numbers. Forth uses several stacks. The DataStack is the one used for passing data between Forth words so we will concentrate our attention there. The Return Stack is another Forth stack that is primarily for internal system use. In this tutorial, when we refer to the "stack," we will be referring to the Data Stack.

堆疊一開始是空的. 要將一些數字放在堆疊上, 輸入:

The stack is initially empty. To put some numbers on the stack, enter:

讓我們現在利用 Forth 的詞 '.' 來印出在堆疊上的數字. 這個詞 '.' 是發音 成 "dot". 這是一個不容易寫在使用手冊上的詞, 因為它只是一個小數點.

Let's now print the number on top of the stack using the Forth word ' . ', which is pronounced " dot ". This is a hard word to write about in a manual because it is a single period.

輸入:

Enter:

你應該可以看見最後你輸入的數字: 9182, 被印出來了. Forth 有一個非常方便 的詞來顯示什麼東西在堆疊上. 它是 .S, 唸作 "dot S". 這個名字是由顯示 用的 '.' 和堆疊的 'S' 來組成的. (如果 TRACE-STACK 變數被設成 True 的話, PForth 將會自動在每一行的最後印出堆疊中的內容.) 如果你輸入:

You should see the last number you entered, 9182 , printed. Forth has a very handy word for showing you what's on the stack. It is .S , which is pronounced "dot S". The name was constructed from "dot" for print, and "S" for stack. (PForth will automatically print the stack after every line if the TRACE-STACK variable is set to TRUE.) If you enter:

你可以看見你的數字在一個列表中. 在最右邊的數字是在堆疊的最上方.

you will see your numbers in a list. The number at the far right is the one on top of the stack.

你可以注意到 9182 並不在堆疊上. '.' 詞將會在顯示堆疊上的數值時順便將它 移除. 相對地, '.S' 將不會修改堆疊的狀態.

You will notice that the 9182 is not on the stack. The word ' . ' removes the number on top of the stack before printing it. In contrast, ' .S ' leaves the stack untouched.

我們用 堆疊示意圖 的方式來標明這些詞在堆疊上運作的效果. 一個 堆疊示意圖包含在括號中. 在 Forth, 括號是代表註解. 在下面的例子中, 你不需要 輸入註解中的內容. 當然在你作程式設計時, 我們將會鼓勵使用註解和堆疊示意圖 來使得程式碼使容易理解. 在這份手冊中, 我們通常以粗體字來標明堆疊示意圖, 就像是下面的例子. 不要輸入這個程式. 一個用於 '.' 的堆疊示意圖就是如下所示:

We have a way of documenting the effect of words on the stack with a stack diagram. A stack diagram is contained in parentheses. In Forth, the parentheses indicate a comment. In the examples that follow, you do not need to type in the comments. When you are programming, of course, we encourage the use of comments and stack diagrams to make your code more readable. In this manual, we often indicate stack diagrams in bold text like the one that follows. Do not type these in. The stack diagram for a word like ' . ' would be:

. ( N -- , print number on top of stack )
在 "--" 左邊的符號是表示在被這一詞處理的堆疊內容. 在這一個例子中, N 可以 代表任何的整數數字. 在 "--" 右邊直到 "," 中的內容, 是代表這個詞處理後, 堆疊上所留下的內容. 在這一個例子中是不存在的, 因為 'dot' 吃掉了傳進去的 N 值. (要注意這些堆疊的描敘是不必要的, 但是它們將會對於學習其他人的程式 有很大的幫助).

The symbols to the left of -- describe the parameters that a word expects to process. In this example, N stands for any integer number. To the right of --, up to the comma, is a description of the stack parameters when the word is finished, in this case there are none because 'dot' "eats" the N that was passed in. (Note that the stack descriptions are not necessary, but they are a great help when learning other peoples programs.)

在逗點後的文字是這一個詞的英文描述. 你將會注意到在 "--" 之後, N 就不見 了. 你也許會擔心事實上目前還有其他的數值在堆疊上, 是 23 和 7. 但是堆疊示意圖 只描敘這一個詞所影響的部分堆疊值. 在主詞彙表後有一個特別的小節來更仔細的描敘 堆疊示意圖.

The text following the comma is an English description of the word. You will note that after the -- , N is gone. You may be concerned about the fact that there were other numbers on the stack, namely 23 and 7 . The stack diagram, however, only describes the portion of the stack that is affected by the word. For a more detailed description of the stack diagrams, there is a special section on them in this manual right before the main glossary section.

在例子中, 你可能要清除堆疊. 你可以輸入 0SP, 發音為 "zero S P", 然後堆疊就會被清除了.

Between examples, you will probably want to clear the stack. If you enter 0SP, pronounced "zero S P", then the stack will be cleared.

由於堆疊是 Forth 的中心, 能夠簡單地改變堆疊是很重要的. 讓我們來看看 操作堆疊的更多詞.

Since the stack is central to Forth, it is important to be able to alter the stack easily. Let's look at some more words that manipulate the stack.

輸入:

Enter:

你將會注意到有兩份 777 在堆疊上. 這一個詞 DUP 複製了在堆疊最上方 的物件. 如果你需要使用堆疊上的值但仍需要保留一份複本時, 這將會很有用. DUP 的堆疊示意圖是:

You will notice that there are two copies of 777 on the stack. The word DUP duplicates the top item on the stack. This is useful when you want to use the number on top of the stack and still have a copy. The stack diagram for DUP would be:

DUP ( n -- n n , 複製堆疊最上方的數值 )

DUP ( n -- n n , DUPlicate top of stack )
另一個有用的詞, 是 SWAP. 輸入:

Another useful word, is SWAP. Enter:

DUP 的堆疊示意圖是:

The stack diagram for SWAP would be:

SWAP ( a b -- b a , 將堆疊最上面的兩個數值交換位置 )

SWAP ( a b -- b a , swap top two items on stack )
現在輸入:

Now enter:

這一個詞 OVER 將會複製一份堆疊上第二筆元素的內容. 它的堆疊示意圖將是:

The word OVER causes a copy of the second item on the stack to leapfrog over the first. It's stack diagram would be:

OVER ( a b -- a b a , 複製一份堆疊上第二個元素 )

OVER ( a b -- a b a , copy second item on stack )

這邊有另一個常用的 Forth 詞:

Here is another commonly used Forth word:

DROP ( a -- , 將堆疊最上面的元素移除 )

DROP ( a -- , remove item from the stack )

你可以猜猜看我們輸入下列程式後會看到什麼:

Can you guess what we will see if we enter:

另外一個操作堆疊的有用的詞是 ROT, 輸入:

Another handy word for manipulating the stack is ROT. Enter:

因此 ROT 的堆疊示意圖是:

The stack diagram for ROT is, therefore:

ROT ( a b c -- b c a , 將堆疊中的第三個元素移到最上面 ) 

ROT ( a b c -- b c a , ROTate third item to top ) 

你現在已經學會更多的堆疊操作詞了. 你將會在幾乎每一個 Forth 程式中看到 它們. 我應該警告你如果你使用太多的堆疊操作詞在你的程式中, 則你應該重新 檢查你的程式碼, 也許應該重新組織它們. 你將可以發現你可以使用 local 或 是 global 變數 來避免過多的堆疊操作. 這些稍後將會討論到.

You have now learned the more important stack manipulation words. You will see these in almost every Forth program. I should caution you that if you see too many stack manipulation words being used in your code then you may want to reexamine and perhaps reorganize your code. You will often find that you can avoid excessive stack manipulations by using local or global VARIABLES which will be discussed later.

如果你要取得在堆疊上任意位置的元素, 使用 PICK. 試著輸入:

If you want to grab any arbitrary item on the stack, use PICK . Try entering:

PICK 會複製一份堆疊上的第 N 個元素. 而這個數字 N 是從 0 開始的, 因此:

PICK makes a copy of the Nth item on the stack. The numbering starts with zero, therefore:

0 PICK 與 DUP 相等
1 PICK 與 OVER 相等
PICK ( ... v3 v2 v1 v0 N -- ... v3 v2 v1 v0 vN )

PICK ( ... v3 v2 v1 v0 N -- ... v3 v2 v1 v0 vN ) 

(警告. Forth-79 和 FIG Forth 標準跟 ANS 和 Forth '83 標準不同, 它們是從 1 開始而不是 0.)

(Warning. The Forth-79 and FIG Forth standards differ from the ANS and Forth '83 standard in that their PICK numbering starts with one, not zero.)

我將其他有用的堆疊操作詞的堆疊示意圖包含如下. 將一些數字放進堆疊, 並且 呼叫它們來得到一些它們如何作用的感覺. 再次提醒, 在括號中的文字只是一些註解, 並且不需要將它們輸入.

I have included the stack diagrams for some other useful stack manipulation words. Try experimenting with them by putting numbers on the stack and calling them to get a feel for what they do. Again, the text in parentheses is just a comment and need not be entered.

DROP ( n -- , 移除堆疊最上方的元素 )

?DUP ( n -- n n | 0 , 如果非零則複製一份, '|' 意思是'或' )

-ROT ( a b c -- c a b , 將最上面的元素旋轉到第三個元素 )

2SWAP ( a b c d -- c d a b , 兩個一組的交換位置 )

2OVER ( a b c d -- a b c d a b , 兩個一組的跳取 )

2DUP ( a b -- a b a b , 兩個一組的複製 )

2DROP ( a b -- , 移除兩個元素 )

NIP ( a b -- b , 移除第二個元素 )

TUCK ( a b -- b a b , 將最上面的元素複製成第三個元素 )

---------------------------------------------------------

DROP ( n -- , remove top of stack ) 

?DUP ( n -- n n | 0 , duplicate only if non-zero, '|' means OR ) 

-ROT ( a b c -- c a b , rotate top to third position ) 

2SWAP ( a b c d -- c d a b , swap pairs ) 

2OVER ( a b c d -- a b c d a b , leapfrog pair ) 

2DUP ( a b -- a b a b , duplicate pair ) 

2DROP ( a b -- , remove pair ) 

NIP ( a b -- b , remove second item from stack ) 

TUCK ( a b -- b a b , copy top item to third position ) 

問題(Problems):

在每個問題開始時輸入:

Start each problem by entering:

然後用你已經學過的堆疊操作詞來讓最後堆疊上的數值跟問題中列出的相同:

Then use the stack manipulation words you have learned to end up with the following numbers on the stack:

問題的答案 可以在這份教學文件的結尾找到.
Answers to the problems can be found at the end of this tutorial.

算術(Arithmetic)

巨大的享受可以簡單地從在堆疊中移動數字中產生. 然後最後你將會想要對它們 做一些有用的事情. 這一節將會描述如何在 Forth 中進行算術的操作.

Great joy can be derived from simply moving numbers around on a stack. Eventually, however, you'll want to do something useful with them. This section describes how to perform arithmetic operations in Forth.

Forth 的算術運算工作是在目前堆疊的最上方運作的. 如果你要將堆疊最上方 的兩個數字加在一起, 使用這一個 Forth 詞 +, 發音成 "plus". 輸入:

The Forth arithmetic operators work on the numbers currently on top of the stack. If you want to add the top two numbers together, use the Forth word + , pronounced "plus". Enter:

這種風格的算術表示法是叫做 後置表示法 或是 RPN. 如果你有 HP 的計算機, 你將會很熟悉. 在接下來的範例中, 我將會在註解中放置等價的 代數式子.

This style of expressing arithmetic operations is called Reverse Polish Notation, or RPN. It will already be familiar to those of you with HP calculators. In the following examples, I have put the algebraic equivalent representation in a comment.

其他的算數運算元是 - * /, 輸入:

Some other arithmetic operators are - * / . Enter:

有些運算的組合是非常常用的, 而為了加快速度, 它們已經被直接使用組合語言 重寫了. 例如, 2* 是 2 * 的縮寫. 你應該在需要增加你的程式的速度時 使用它們. 它們包括:

Some combinations of operations are very common and have been coded in assembly language for speed. For example, 2* is short for 2 * . You should use these whenever possible to increase the speed of your program. These include:

試著輸入:

Try entering:

有一件你應該要注意的事情是當你使用 / 來對於整數作運算時, 餘數將會消失. 輸入:

One thing that you should be aware of is that when you are doing division with integers using / , the remainder is lost. Enter:

這對於所有的語言在所有的電腦都是真的. 稍後我們將會探討 /MODMOD, 它們將會給我們除法之後的餘數.

This is true in all languages on all computers. Later we will examine /MOD and MOD which do give the remainder.

定義一個新詞(Defining a New Word)

現在是用 Forth 寫一個小程式的時間了. 你可以用已經學過的詞定義一個新詞. 讓我們定義一個計算兩個數平均值的新詞, 並且加以測試.

It's now time to write a small program in Forth. You can do this by defining a new word that is a combination of words we have already learned. Let's define and test a new word that takes the average of two numbers.

我們將會使用兩個新的詞 : ("colon"), 和 ; ("semicolon"). 這兩個詞開始和結束一個典型的 Forth 定義. 輸入:

We will make use of two new words, : ( "colon"), and ; ( "semicolon") . These words start and end a typical Forth definition. Enter:

恭喜. 你剛寫好了一個 Forth 程式. 讓我們看看剛才發生什麼了. 冒號告訴 Forth 增加一個新詞到詞的列表中. 這個列表叫做 Forth 詞典. 新詞的名字就是跟隨在 冒號後面的名字. 任何跟隨在這個名字後的 Forth 詞都將會被編譯進這個新詞. 這將會持續到遇到分號為止, 而它將會結束這一個定義.

Congratulations. You have just written a Forth program. Let's look more closely at what just happened. The colon told Forth to add a new word to its list of words. This list is called the Forth dictionary. The name of the new word will be whatever name follows the colon. Any Forth words entered after the name will be compiled into the new word. This continues until the semicolon is reached which finishes the definition.

讓我們輸入這一個詞來測試:

Let's test this word by entering:

一旦這一個詞被定義了之後, 它可以用來被定義更多詞. 讓我們來寫一個詞來測試 我們的詞. 輸入:

Once a word has been defined, it can be used to define more words. Let's write a word that tests our word.. Enter:

試著合併你已經學過的詞到你所選擇的新的 Forth 定義中. 如果你保證不受影響, 你可以利用輸入下列的詞來得到所有可用來設計程式的詞的列表:

Try combining some of the words you have learned into new Forth definitions of your choice. If you promise not to be overwhelmed, you can get a list of the words that are available for programming by entering:

別擔心, 這些詞中只有一小部分將會直接在你的程式中使用.

Don't worry, only a small fraction of these will be used directly in your programs.

更多的算術(More Arithmetic)

當你需要一個除法計算的餘數時. /MOD 會像傳回商一樣地傳回餘數. MOD 將會只傳 回餘數. 輸入:

When you need to know the remainder of a divide operation. /MOD will return the remainder as well as the quotient. the word MOD will only return the remainder. Enter:

另外兩個有用的詞是 MIN and MAX. 它們分別接受兩個輸入值, 並且回傳其中的最小值或是最大值. 試著輸入:

Two other handy words are MIN and MAX . They accept two numbers and return the MINimum or MAXimum value respectively. Try entering the following:

另外一些有用的詞是:

Some other useful words are:

ABS ( n -- abs(n) , n 的絕對值 )

NEGATE ( n -- -n , 取負值, 比 -1 * 快 )

LSHIFT ( n c -- n<<c, n 向左 shift c 位數 )

RSHIFT ( n c -- n>>c, n 邏輯右 shift c 位數 )

ARSHIFT ( n c -- n>>c, n 算術右 shift c 位數 ) -------------------------------------------------------------------

ABS ( n -- abs(n) , absolute value of n ) 

NEGATE ( n -- -n , negate value, faster then -1 * ) 

LSHIFT ( n c -- n<<c , left shift of n ) 

RSHIFT ( n c -- n>>c , logical right shift of n ) 

ARSHIFT ( n c -- n>>c ) , arithmetic right shift of n ) 

ARSHIFT 或 LSHIFT 可以用來快速進行 2 次方數值的乘法. 右 shift 一位數可以 用來做除以 2 之用. 這通常會比做一個正常的乘法或除法快. 試著輸入:

ARSHIFT or LSHIFT can be used if you have to multiply quickly by a power of 2 . A right shift is like doing a divide by 2. This is often faster than doing a regular multiply or divide. Try entering:

算術溢位(Arithmetic Overflow)

如果你在計算時有超過堆疊的 32-bit 精確度的問題, 你可以使用 "*/". 這將會在內部運算時產生一個 64-bit 長度的數值. 試試看下列的三種方法來做 相同的數值運算. 只有使用 "*/" 的那一種方法會得出正確的答案, 5197799.

If you are having problems with your calculation overflowing the 32-bit precision of the stack, then you can use */ . This produces an intermediate result that is 64 bits long. Try the following three methods of doing the same calculation. Only the one using */ will yield the correct answer, 5197799.

轉換代數式至 Forth (Convert Algebraic Expressions to Forth)

我們要如何用 Forth 表達複雜的代數式呢? 例如: 20 + (3 * 4)

How do we express complex algebraic expressions in Forth? For example: 20 + (3 * 4)

要轉換這一個式子, 你必須把運算的順序照著實際執行的順序排列. 因此, 在 Forth 中, 看起來將會是:

To convert this to Forth you must order the operations in the order of evaluation. In Forth, therefore, this would look like:

執行順序在 Forth 中是從左至右的, 所以並不會有模稜兩可的情形. 比較下列的 代數式和它們的 Forth 等價式: (不要輸入這些)

Evaluation proceeds from left to right in Forth so there is no ambiguity. Compare the following algebraic expressions and their Forth equivalents: (Do not enter these!)

如果有任何的式子困擾你, 試著一次只輸入一個詞, 並且每次都用 .S 來檢查堆疊.

If any of these expressions puzzle you, try entering them one word at a time, while viewing the stack with .S .

問題(Problems):

將下列的代數式轉換成等價的 Forth 式子. (不要輸入它們, 因為它們並不是 Forth 程式碼.)

Convert the following algebraic expressions to their equivalent Forth expressions. (Do not enter these because they are not Forth code!)

用你已經學過的詞來寫這些新詞:

Use the words you have learned to write these new words:

問題的答案可以在這份教學文件的結尾找到.
Answers to the problems can be found at the end of this tutorial.

字元輸入和輸出(Character Input and Output)

在堆疊頂端的數字可以代表任何事物. 最上層的數字可以是多少藍鯨還存活在地球上, 或是你有多少公斤的體重. 它也可以是一個 ASCII 字元. 試著輸入:

The numbers on top of the stack can represent anything. The top number might be how many blue whales are left on Earth or your weight in kilograms. It can also be an ASCII character. Try entering the following:

你將看見 "Hi" 在 OK 之前顯示出來. 72 在 ASCII 中是代表 'H' 字元, 而 105 是 'i' 字元. EMIT 會取出堆疊中的數字, 並且以字元的型式輸出. 如果你要找到任何 字元的 ASCII 值, 你可以使用 "ASCII" 這個詞. 輸入:

You should see the word "Hi" appear before the OK. The 72 is an ASCII 'H' and 105 is an 'i'. EMIT takes the number on the stack and outputs it as a character. If you want to find the ASCII value for any character, you can use the word ASCII . Enter:

這本手冊背後有一個 ASCII 圖表來列出完整的字元集. (譯註: 電子版的沒有, 但是可用下列小程式列出: 256 32 do i emit bl emit i 16 mod 0 = if cr then loop )

There is an ASCII chart in the back of this manual for a complete character list.

注意, CHAR 這個詞有點不平常, 因為它並不是從堆疊輸入的, 而是將跟隨的字元 當作輸入的符號. 在堆疊示意圖中, 我們將輸入放入尖括弧中來代表這種情形 <input>. 下面是 CHAR 的堆疊示意圖.

Notice that the word CHAR is a bit unusual because its input comes not from the stack, but from the following text. In a stack diagram, we represent that by putting the input in angle brackets, <input>. Here is the stack diagram for CHAR.

CHAR ( <char> -- char , 將字元的 ASCII 值放進堆疊中 ) 

CHAR ( <char> -- char , get ASCII value of a character ) 

使用 EMIT 來顯示字串是非常冗長乏味的. 幸運地我們有一種更好的方法. 輸入:

Using EMIT to output character strings would be very tedious. Luckily there is a better way. Enter:

." 詞, 發音為 "dot quote", 將會把到引號為止的所有跟隨符號顯示到螢幕上. 你需要確定在第一個引號後留一個空白. 當你需要顯示一個換行符號時, 你可以用 CR 這個詞來顯示. 輸入:

The word ." , pronounced "dot quote", will take everything up to the next quotation mark and print it to the screen. Make sure you leave a space after the first quotation mark. When you want to have text begin on a new line, you can issue a carriage return using the word CR . Enter:

你可以用 SPACE 來顯示一個空白字元. 一串空白字元可以用 SPACES 來輸出. 輸入:

You can emit a blank space with SPACE . A number of spaces can be output with SPACES . Enter:

對於字元的輸入, Forth 可以用 KEY 這個詞, 它是輸出用詞 EMIT 的相反. KEY 將會等待使用者按一個鍵, 並且把這個鍵的值留在堆疊上. 試試下列程式:

For character input, Forth uses the word KEY which corresponds to the word EMIT for output. KEY waits for the user to press a key then leaves its value on the stack. Try the following.

[注意: 在某些電腦上, 輸入會有緩衝區, 所以你必須在輸入字元後按 ENTER 鍵. ]

[Note: On some computers, the input if buffered so you will need to hit the ENTER key after typing your character.]

EMIT ( char -- , 輸出一個字元 ) 

KEY ( -- char , 輸入一個字元 ) 

SPACE ( -- , 輸出一個空白 ) 

SPACES ( n -- , 輸出 n 個空白 ) 

CHAR ( <char> -- char , 將跟隨的字元轉成 ASCII 值 ) 

CR ( -- , 顯示換行符號 ) 

." ( -- , 輸出在 " 分界前的文字 )  ------------------------------------------------------------

EMIT ( char -- , output character ) 

KEY ( -- char , input character ) 

SPACE ( -- , output a space ) 

SPACES ( n -- , output n spaces ) 

CHAR ( <char> -- char , convert to ASCII ) 

CR ( -- , start new line , carriage return ) 

." ( -- , output " delimited text ) 



從檔案中編譯(Compiling from Files)

PForth 可以讀取普通的文字檔, 所以你可以用你想要用的編輯器來寫你的程式.

PForth can read read from ordinary text files so you can use any editor that you wish to write your programs.

範例程式(Sample Program)

將下列程式碼輸入到你的檔案.

Enter into your file, the following code.

現在把這個檔案儲存到磁碟上.

Now save the file to disk.

\ 字元後跟隨的文字將會被當成註解. 它在 BASIC 中是 REM 敘述, 在 C 中是 /* --- */. 在括號中的文字也會被當成註解.

The text following the \ character is treated as a comment. This would be a REM statement in BASIC or a /*---*/ in 'C'. The text in parentheses is also a comment.

使用 INCLUDE(Using INCLUDE)

"INCLUDE" 在 Forth 中的意思是從一個檔案中編譯.

"INCLUDE" in Forth means to compile from a file.

你可以用 INCLUDE 指令來編譯這一個檔案. 如果你將你的檔案存成 SAMPLE.FTH, 然後你就可以用下列的指令來編譯它:

You can compile this file using the INCLUDE command. If you saved your file as WORK:SAMPLE, then compile it by entering:

Forth 將會編譯你的檔案, 並且告訴你有多少位元組已經被加進詞典中了. 要測試 你寫的詞, 輸入:

Forth will compile your file and tell you how many bytes it has added to the dictionary. To test your word, enter:

你的兩個詞, SQUARE 和 TEST.SQUARE 現在已經在 Forth 詞典中了. 我們現在可以 做一件在一個程式設計語言中非常不平常的事情. 我們可以 "反編譯" 這些程式碼, 只須告訴 Forth FORGET 它. 輸入:

Your two words, SQUARE and TEST.SQUARE are now in the Forth dictionary. We can now do something that is very unusual in a programming language. We can "uncompile" the code by telling Forth to FORGET it. Enter:

這將會從詞典中移除 SQUARE 和任何緊隨著它的任何事物, 例如: TEST.SQUARE. 如果你現在試著執行 TEST.SQUARE, 它將不會被找到.

This removes SQUARE and everything that follows it, ie. TEST.SQUARE, from the dictionary. If you now try to execute TEST.SQUARE it won't be found.

現在讓我對我們的檔案做一些修改, 再重新載入它. 回到編輯器, 並且做出下列的 改變: (1) 改變 TEST.SQUARE 成使用 15 而不是 7, (2) 在 SQUARE 的定義之前加入 下列這一行:

Now let's make some changes to our file and reload it. Go back into the editor and make the following changes: (1) Change TEST.SQUARE to use 15 instead of 7 then (2) Add this line right before the definition of SQUARE:

現在儲存你的修改, 並且回到 Forth 視窗.

Now Save your changes and go back to the Forth window.

你也許會好奇以 ANEW 開始的這一行的作用是什麼? ANEW 總是用在一個 檔案的開頭. 它在字典中的程式碼之前定義了一個特別的記號. 這個記號通常有 一個字首是 "TASK-", 並且跟隨著這個檔案的名字. 當你重新 INCLUDE 這一個檔案 時, ANEW 將會自動地 FORGET 從上面 ANEW 敘述開始的所有程式碼. 這允許你一次 又一次地重新 INCLUDE 一個檔案, 而不需手動地 FORGET 這個檔案的第一個詞. 如果沒有 FORGET 這些程式碼, 詞典最終將會被填滿.

You're probably wondering what the line starting with ANEW was for. ANEW is always used at the beginning of a file. It defines a special marker word in the dictionary before the code. The word typically has "TASK-" as a prefix followed by the name of the file. When you ReInclude a file, ANEW will automatically FORGET the old code starting after the ANEW statement. This allows you to Include a file over and over again without having to manually FORGET the first word. If the code was not forgotten, the dictionary would eventually fill up.

如果你有一個大計劃需要一堆檔案, 你可以用一個檔案來自動載入所有你需要 的檔案. 有時你需要載入有可能已載人的程式碼. INCLUDE? 詞將會只載入 不在詞典中的程式碼. 在接下來的例子中, 我假定檔案是在磁碟機 WORK: 並且叫做 SAMPLE. 如果不是, 請用實際的名字取代. 輸入:

If you have a big project that needs lots of files, you can have a file that will load all the files you need. Sometimes you need some code to be loaded that may already be loaded. The word INCLUDE? will only load code if it isn't already in the dictionary. In this next example, I assume the file is on the volume WORK: and called SAMPLE. If not, please substitute the actual name. Enter:

只有第一個 INCLUDE? 將會導致這一個檔案被載入.

Only the first INCLUDE? will result in the file being loaded.

變數(Variables)

Forth 不像其他的編譯式語言一樣, 著重於使用變數. 這是因為數值通常都保存在 堆疊上. 當然有些狀況下, 仍然有使用變數的需要. 要創造一個變數, 以下列的方式 來使用 VARIABLE 詞:

Forth does not rely as heavily on the use of variables as other compiled languages. This is because values normally reside on the stack. There are situations, of course, where variables are required. To create a variable, use the word VARIABLE as follows:

這會創造一個命令為 MY-VAR 的詞. 在記憶體中的一塊空間將會保留為儲存 32-bit 的數值之用. VARIABLE 被當成 "創造詞", 因為它將會在詞典中創造新的詞. 現在 輸入:

This created a variable named MY-VAR . A space in memory is now reserved to hold its 32-bit value. The word VARIABLE is what's known as a "defining word" since it creates new words in the dictionary. Now enter:

你看到的這個數字是保留給 MY-VAR 記憶體中的位置. 要將資料存進記憶體中, 你可 以使用 ! 詞, 發音是 "store". 它看起來是驚嘆號, 但是對於一個 Forth 程式設計師來說, 它是將 32-bit 的資料寫進記憶體中的方法. 要讀取包含在這 記憶體位置中的數值時, 使用 Forth 詞 @, 發音為 "fetch". 試著輸入 下列程式:

The number you see is the address, or location, of the memory that was reserved for MY-VAR. To store data into memory you use the word ! , pronounced "store". It looks like an exclamation point, but to a Forth programmer it is the way to write 32-bit data to memory. To read the value contained in memory at a given address, use the Forth word @ , pronounced "fetch". Try entering the following:

這將會設定變數 MY-VAR 的值為 513, 然後讀回這個數值並且印出它. 這個堆疊示意圖 如下所述:

This sets the variable MY-VAR to 513 , then reads the value back and prints it. The stack diagrams for these words follows:

@ ( address -- value , 將值從記憶體位置中取出 )

! ( value address -- , 將值存進記憶體位置 )

VARIABLE ( <name> -- , 宣告一個 4 位元組的記憶體空間 )

@ ( address -- value , FETCH value FROM address in memory ) 

! ( value address -- , STORE value TO address in memory )

VARIABLE ( <name> -- , define a 4 byte memory storage location)

一個用來檢查變數數值的方便的詞是 ? , 發音為 "question". 試著輸入:

A handy word for checking the value of a variable is ? , pronounced "question". Try entering:

如果 ? 沒有被定義, 我們可以定義它為:

If ? wasn't defined, we could define it as:

想像你正在寫一個遊戲, 並且你要追蹤最高的分數. 你可以將最高分保存在一個 變數之中. 當你回報一個分數時, 你可以再檢查一次最高分數. 試著以上一節所述 的方式輸入下列程式碼:

Imagine you are writing a game and you want to keep track of the highest score. You could keep the highest score in a variable. When you reported a new score, you could check it aginst the highest score. Try entering this code in a file as described in the previous section:

將這個檔案存到磁碟中, 並且用 INCLUDE 詞來編譯這個程式碼. 以下列的方式 測試你的詞:

Save the file to disk, then compile this code using the INCLUDE word. Test your word as follows:

Forth 詞 @ 和 ! 以 32-bit 的單位來運作. 有些 Forth 是 "16-bit" Forth. 它們 以 16-bit 的單位來存取. Forth 有些詞是用來在 8-bit 和 16-bit 的單位下運作的. C@ 和 C! 是以字元為單位來運作的, 它們通常是 8-bit 的單位. 'C' 代表字元, 因為 ASCII 字元是 8-bit 的數值. 使用 W@ 和 W! 來處理 16-bit 單位的資料.

The Forth words @ and ! work on 32-bit quantities. Some Forths are "16-bit" Forths. They fetch and store 16-bit quantities. Forth has some words that will work on 8 and 16-bit values. C@ and C! work characters which are usually for 8-bit bytes. The 'C' stands for "Character" since ASCII characters are 8-bit numbers. Use W@ and W! for 16-bit "Words."

另外的有用詞是 +! , 發音成 "plus store". 它將一個數值加進一個 記憶體中的 32-bit 數值. 試試:

Another useful word is +! , pronounced "plus store." It adds a value to a 32-bit value in memory. Try:

Forth 也提供一些跟 VARIABLE 很像的詞. 在詞彙表中找出 VALUE 和 ARRAY. 也看看 區域變數(local variables)" 這一節, 它是只存在 Forth 詞執行時的變數.

Forth also provides some other words that are similar to VARIABLE. Look in the glossary for VALUE and ARRAY. Also look at the section on "local variables" which are variables which only exist on the stack while a Forth word is executing.

警告有關於提取和存入資料至記憶體的一段話: 你目前學會的 Forth 指令是危險的. 一個電腦的運作是奠基於在記憶體的正確位置 有正確的數值. 你現在知道了如何在記憶體的任何地方寫入新數值. 由於一個位置 也只是一個數值, 你可以, 但不應該輸入以下的程式:

A word of warning about fetching and storing to memory: You have now learned enough about Forth to be dangerous. The operation of a computer is based on having the right numbers in the right place in memory. You now know how to write new numbers to any place in memory. Since an address is just a number, you could, but shouldn't, enter:

253000 將會被當成一個位置, 而你將會把這位置的值設成 73. 我不知道在這之後 會發生什麼, 也許什麼事都沒有. 這就像用來福槍射穿你公寓建築的牆. 你不知道 你將會射到誰或什麼東西. 由於你與其他的程式和作業系統分享程式碼, 你將很容易 導致電腦表現得很奇怪, 甚至 crash. 然而不要讓這件事困擾你太久. 電腦 crash 並 不像是汽車 crash 一樣, 不會傷害電腦. 你只須要重開機. 最嚴重的事有可能發生 在你正在寫入資料到磁碟時, 電腦 crash 了, 你可能損失一個檔案. 這就是為什麼 我們製作備分的原因. 這相同的潛在的問題存在於任何強力的語言, 並不是只有 Forth. 然而這有可能較不會出現於 BASIC 中, 因為 BASIC 為你保護了一大堆事情, 包括 寫一個強力程式的危險.

The 253000 would be treated as an address and you would set that memory location to 73. I have no idea what will happen after that, maybe nothing. This would be like firing a rifle through the walls of your apartment building. You don't know who or what you are going to hit. Since you share memory with other programs including the operating system, you could easily cause the computer to behave strangely, even crash. Don't let this bother you too much, however. Crashing a computer, unlike crashing a car, does not hurt the computer. You just have to reboot. The worst that could happen is that if you crash while the computer is writing to a disk, you could lose a file. That's why we make backups. This same potential problem exists in any powerful language, not just Forth. This might be less likely in BASIC, however, because BASIC protects you from a lot of things, including the danger of writing powerful programs.

另一種遇到問題的方式是一種叫做 "奇數位置記憶體存取". 68000 處理器將詞 和長詞排列為 16 和 32 bit 的數字, 在偶數的位置. 如果你在奇數的位置上做 @!W@W! 的動作, 68000 處理器將會因此 而產生一個例外情況, 並且試著去結束.

Another way to get into trouble is to do what's called an "odd address memory access." The 68000 processor arranges words and longwords, 16 and 32 bit numbers, on even addresses. If you do a @ or ! , or W@ or W! , to an odd address, the 68000 processor will take exception to this and try to abort.

Forth 利用 trap 這種例外並且回到 OK 提示符號的方式來提供一些保護. 如果 你真的需要存取在奇數位置上的資料, 檢查在詞典中的 ODD@ODD! 指令. C@C! 在奇數及偶數位置上都工作得很好.

Forth gives you some protection from this by trapping this exception and returning you to the OK prompt. If you really need to access data on an odd address, check out the words ODD@ and ODD! in the glossary. C@ and C! work fine on both odd and even addresses.

常數(Constants)

如果你有一個數字常常出現在程式中, 我們建議你將它定義為 "常數". 輸入:

If you have a number that is appearing often in your program, we recommend that you define it as a "constant." Enter:

我們剛定義了一個詞叫做 MAX_CHARS, 使用它時, 它將會傳回它被定義時的堆疊上的值. 它不能被改變, 除非你編輯程式並且重新編譯它. 使用 CONSTANT 可以增加 你的程式的可讀性並且減少錯誤. 想像如果你常在你的程式引用到 128 這個數字, 例如 8 次. 然後你決定將這個數字改變成 256. 如果你廣域地改變所有的 128 成 256, 你也許會修改到不打算改變的部分. 如果你手動修改, 你可能會遺漏部分, 特別是在 你的程式由超過一個檔案組成的情況. 使用 CONSTANT 將會讓這種修改更容易. 而使用的程式碼會跟直接使用數字一樣快並且佔用一樣少的空間. 我建議對於所有 的數字都將它定義成常數.

We just defined a word called MAX_CHARS that returns the value on the stack when it was defined. It cannot be changed unless you edit the program and recompile. Using CONSTANT can improve the readability of your programs and reduce some bugs. Imagine if you refer to the number 128 very often in your program, say 8 times. Then you decide to change this number to 256. If you globally change 128 to 256 you might change something you didn't intend to. If you change it by hand you might miss one, especially if your program occupies more than one file. Using CONSTANT will make it easy to change. The code that results is equally as fast and small as putting the numbers in directly. I recommend defining a constant for almost any number.

邏輯運算子(Logical Operators)

下兩節跟抉擇有關. 第一節有關於回答下列問題: "這個數值過大嗎?" 或是 "這個猜想跟答案一樣嗎?". 像這類問題的答案不是 TRUE 就是 FALSE. Forth 用 0 來代表 FALSE, -1 來代表 TRUE. TRUE 和 FALSE 是大寫的, 因為它們已經定義成 Forth 常數了. 輸入:

These next two sections are concerned with decision making. This first section deals with answering questions like "Is this value too large?" or "Does the guess match the answer?". The answers to questions like these are either TRUE or FALSE. Forth uses a 0 to represent FALSE and a -1 to represent TRUE. TRUE and FALSE have been capitalized because they have been defined as Forth constants. Try entering:

你將會注意到第一行顯示 0, 就是 FALSE. 而第二行是 -1, 就是 TRUE. 等號在 Forth 中是被當成一個問題, 而不是敘述. 它會問是否堆疊上的兩個數值是相等的. 它將 不會將它們兩者設成相等. 你可以問其他的問題. 輸入:

You will notice that the first line printed a 0, or FALSE, and the second line a -1, or TRUE. The equal sign in Forth is used as a question, not a statement. It asks whether the top two items on the stack are equal. It does not set them equal. There are other questions that you can ask. Enter:

在加洲, 可以喝酒的年齡是 21. 你現在可以寫一個簡單的詞來幫助酒保. 輸入:

In California, the drinking age for alcohol is 21. You could write a simple word now to help bartenders. Enter:

在堆疊示意圖中的 flag 一詞是代表一個邏輯值.

The word FLAG in the stack diagram above refers to a logical value.

Forth 提供了特別的詞來使一個數值與 0 相比. 它們是 0=, 0>0< . 使用 0> 會比分開地呼叫 0 和 > 更快. 輸入:

Forth provides special words for comparing a number to 0. They are 0= 0> and 0< . Using 0> is faster than calling 0 and > separately. Enter:

在更複雜的判斷時, 你可以用 布林 運算元 OR, AND, 和 NOT. OR 在堆疊上的兩個數值其中之一是 TRUE 時傳回 TRUE.

For more complex decisions, you can use the Boolean operators OR , AND , and NOT . OR returns a TRUE if either one or both of the top two stack items are true.

AND 只有在兩者都是 TRUE 時才傳回 TRUE.

AND only returns a TRUE if both of them are true.

NOT 會顛倒堆疊上旗標的數值. 輸入:

NOT reverses the value of the flag on the stack. Enter:

邏輯運算可以合併.

Logical operators can be combined.

這裡是這類詞的堆疊示意圖. 觀看詞典來得到更完整的列表.

Here are stack diagrams for some of these words. See the glossary for a more complete list.

< ( a b -- flag , 如果 A 小於 B, 則真 )

> ( a b -- flag , 如果 A 大於 B, 則真 )

= ( a b -- flag , 如果 A 等於 B, 則真 )

0= ( a -- flag , 如果 A 等於 0, 則真 )

OR ( a b -- a||b , 對於 A 和 B 中的位元進行 OR 運算 )

AND ( a b -- a&b , 對於 A 和 B 中的位元進行 AND 運算 )

NOT ( flag -- opposite-flag , 若真則假, 若假則真 ) ---------------------------------------------------------

< ( a b -- flag , flag is true if A is less than B )

> ( a b -- flag , flag is true if A is greater than B )

= ( a b -- flag , flag is true if A is equal to B )

0= ( a -- flag , true if a equals zero )

OR ( a b -- a||b , perform logical OR of bits in A and B )

AND ( a b -- a&b , perform logical AND of bits in A and B )

NOT ( flag -- opposite-flag , true if false, false if true )

問題(Problems):

1) 寫一個詞叫做 LOWERCASE? , 它將會檢查是否在堆疊上的數值是一個 ASCII 小寫字元, 如果是, 則回傳 TRUE. 一個小寫的 'a' 是 97. 一個 ASCII 'z' 是 122. 用 " A ` a q z { " 等字元來測試.

1) Write a word called LOWERCASE? that returns TRUE if the number on top of the stack is an ASCII lowercase character. An ASCII 'a' is 97 . An ASCII 'z' is 122 . Test using the characters " A ` a q z { ".

問題的答案 可以在這份教學文件的結尾找到.
Answers to the problems can be found at the end of this tutorial.

流程控制指令(Conditionals) - IF ELSE THEN CASE

你現在可以用你在上一節學過的 TRUE 和 FALSE 旗標了. "流程控制" 詞將會從堆疊 接受這些旗標, 並且依照這些值, 也許會分支到其他的地方. 輸入下列的程式碼.

You will now use the TRUE and FALSE flags you learned to generate in the last section. The "flow of control" words accept flags from the stack, and then possibly "branch" depending on the value. Enter the following code.

你可以看見當一個 TRUE 在堆疊上時, 第一部分被執行. 如果一個 FALSE 在堆疊上時, 第一個部分被跳過, 而第二部分被執行. 如果輸入下列程式碼, 你可以發現一件有趣的事情.

You can see that when a TRUE was on the stack, the first part got executed. If a FALSE was on the stack, then the first part was skipped, and the second part was executed. One thing you will find interesting is that if you enter:

在堆疊上的值將會被當成 TRUE. 流程控制詞將會把非零的值當成 TRUE.

the value on the stack will be treated as true. The flow of control words consider any value that does not equal zero to be TRUE.

IF...THEN 架構中, ELSE 是選用的. 試試下列程式碼:

The ELSE word is optional in the IF...THEN construct. Try the following:

許多 Forth 也支援很像 C 語言中 switch() 的 CASE 敘述. 輸入:

Many Forths also support a CASE statement similar to switch() in 'C'. Enter:

閱讀詞典中的 CASE 來取得更多資訊.

See CASE in the glossary for more information.

問題(Problems):

寫一個詞叫做 DEDUCT 來從你的銀行存款帳戶中扣除一個數值. 假定這個存款是以美元 為單元. 印出這個存款. 如果存款變成負值時印出一個警告.

1) Write a word called DEDUCT that subtracts a value from a variable containing your checking account balance. Assume the balance is in dollars. Print the balance. Print a warning if the balance is negative.

問題的答案 可以在這份教學文件的結尾找到.
Answers to the problems can be found at the end of this tutorial.

迴圈(Loops)

另一組有用的詞是 BEGIN...UNTIL . 它們是用來不斷地重覆執行, 直到 指定的狀況是真時才結束. 試試:

Another useful pair of words is BEGIN...UNTIL . These are used to loop until a given condition is true. Try this:

這個詞將會從 N 計數到 0.

This word will count down from N to zero.

如果你知道你將執行一個迴圈多少次, 你可以用 DO...LOOP 的架構, 輸入:

If you know how many times you want a loop to execute, you can use the DO...LOOP construct. Enter:

這將會印出 "ba" 並且跟隨著四次的 "na". 結束的值是比開始的值先放在堆疊上的. 小心不要放反了這兩個值. Forth 將會開始它的長路, 會花不少時間. 這個順序的 理由是更容易利用堆疊傳遞迴圈的計數值. 研究一下作字元圖形的下列詞, 輸入:

This will print "ba" followed by four occurrences of "na". The ending value is placed on the stack before the beginning value. Be careful that you don't pass the values in reverse. Forth will go "the long way around" which could take awhile. The reason for this order is to make it easier to pass the loop count into a word on the stack. Consider the following word for doing character graphics. Enter:

如果你要取得迴圈計數值, 你可以使用這個詞 'I'. 這裡有一個簡單的詞可以顯示 數字和它們相關的 ASCII 字元.

If you want to access the loop counter you can use the word I . Here is a simple word that dumps numbers and their associated ASCII characters.

如果你要在迴圈結束之前離開一個 DO LOOP 迴圈, 你可以使用詞 LEAVE. 輸入:

If you want to leave a DO LOOP before it finishes, you can use the word LEAVE. Enter:

請查閱手冊來學習如何使用下列的詞: +LOOPRETURN. FIXME

Please consult the manual to learn about the following words +LOOP and RETURN . FIXME

另一種有用的迴圈架構是 BEGIN WHILE REPEAT 迴圈. 這允許你在實際 在每次做任何事情之前, 先做迴圈的測試. 如果堆疊上的旗標值是 TRUE 的話, WHILE 詞將會繼續讓迴圈執行. 輸入:

Another useful looping construct is the BEGIN WHILE REPEAT loop. This allows you to make a test each time through the loop before you actually do something. The word WHILE will continue looping if the flag on the stack is True. Enter:

問題(Problems):

1) 用 DO LOOP 來改寫 SUM.OF.N

2) 用 BEGIN UNTIL 來改寫 SUM.OF.N

3) 加分題, 不要用任何迴圈或是條件式的方式來改寫 SUM.OF.N

1) Rewrite SUM.OF.N using a DO LOOP.

2) Rewrite SUM.OF.N using BEGIN UNTIL.

3) For bonus points, write SUM.OF.N without using any looping or conditional construct!

問題的答案 可以在這份教學文件的結尾找到.

Answers to the problems can be found at the end of this tutorial.

文字輸入和輸出(Text Input and Output)

你稍早時學過了如何做單一字元的輸入和輸出. 這一節集中在使用字串中的字元. 你可以在你的程式中用 S" 來內嵌一個文字字串. 注意你必須在 S" 後接一個空白. 文字的字串是由一個 " 來結束. 輸入:

You learned earlier how to do single character I/O. This section concentrates on using strings of characters. You can embed a text string in your program using S". Note that you must follow the S" by one space. The text string is terminated by an ending " .Enter:

注意 TEST 將會留兩個數字在堆疊上. 第一個數字是第一個字元的位置. 第二個數字 是這個字串中字元的數量. 你可以用下列的方式來印出這個字串中的字元.

Note that TEST leaves two numbers on the stack. The first number is the address of the first character. The second number is the number of characters in the string. You can print the characters of the string as follows.

CHAR+ 將位置增加至指向下一個字元. 你可以用 TYPE 指令印出整個字串.

CHAR+ advances the address to the next character. You can print the entire string using TYPE.

如果我們只需用一個位置來描述字串, 而不需一起傳遞字串的長度的話, 將會很方便. C 語言的這種做法是在字串的結尾放置一個零來表示它結束. Forth 的解決方法不同. 一個 Forth 的文字字串是在第一個位元組有字串長度的計數, 而緊隨著就是字串中 字元的內容. 這種格式的字串可以 Forth 的詞 C" 來製造出來, 發音成 "c quote". 輸入:

It would be nice if we could simply use a single address to describe a string and not have to pass the number of characters around. 'C' does this by putting a zero at the end of the string to show when it ends. Forth has a different solution. A text string in Forth consists of a character count in the first byte, followed immediately by the characters themselves. This type of character string can be created using the Forth word C" , pronounced 'c quote'. Enter:

印出來的數字應該是字串開始的位置. 它應該有一個位元組包含字元的長度. 現在輸入:

The number that was printed was the address of the start of the string. It should be a byte that contains the number of characters. Now enter:

你應該看到系統印出 14. 記住 C@ 會從堆疊上的位置取得一個字元/位元組. 你可以利用 COUNT 指令把一個有計數長度的 Forth 字串轉換成一個位置.

You should see a 14 printed. Remember that C@ fetches one character/byte at the address on the stack. You can convert a counted Forth string to an address and count using COUNT.

使用 COUNT 將會得到字串的長度和它的開始位置. COUNT 只適用於長度小於 256 的字元集合, 因為 255 是可以存入計數位元組的最大長度. 然而 TYPE 可以適用 於更大長度的字串, 因為它使用的長度是放置在堆疊上的. 它們的堆疊示意圖如下所示:

The word COUNT extracts the number of characters and their starting address. COUNT will only work with strings of less than 256 characters, since 255 is the largest number that can be stored in the count byte. TYPE will, however, work with longer strings since the length is on the stack. Their stack diagrams follow:

CHAR+ ( address -- address' , 將位置增加一個字元的大小 )

COUNT ( $addr -- addr #bytes , 分解字串資訊 ) 

TYPE ( addr #bytes -- , 輸出在位置中的若干字元 )

CHAR+ ( address -- address' , add the size of one character )

COUNT ( $addr -- addr #bytes , extract string information ) 

TYPE ( addr #bytes -- , output characters at addr )

$addr 是計數位元組的位置. 錢字符號是用來標明跟字串相關的詞.

The $addr is the address of a count byte. The dollar sign is often used to mark words that relate to strings.

你可以輕易地使用 ACCEPT 詞來輸入一個字串. (你也許要把上面的例子 放進一個檔案中, 因為它們非常方便.) ACCEPT 從鍵盤中輸入字元, 並且將 它放進指定的位置. ACCEPT 輸入時是接收到最大接收量或是收到換行符號為止. ACCEPT 會傳回輸入了多少字元. 你可以寫一個詞來輸入文字. 輸入:

You can easily input a string using the word ACCEPT. (You may want to put these upcoming examples in a file since they are very handy.) The word ACCEPT receives characters from the keyboard and places them at any specified address. ACCEPT takes input characters until a maximum is reached or an end of line character is entered. ACCEPT returns the number of characters entered. You can write a word for entering text. Enter:

輸入一個字串, 它將會被顯示出來. 你可以用這個程式來寫格式化的信.

Enter a string which should then be echoed. You could use this in a program that writes form letters.

ACCEPT ( addr maxbytes -- numbytes , 輸入文字, 儲存至位置)
ACCEPT ( addr maxbytes -- numbytes , input text, save at address ) 

你可以用剛寫的詞 INPUT$ 來寫一個從鍵盤中讀取數字的程式.

You can use your word INPUT$ to write a word that will read a number from the keyboard. Enter:

這個詞將會傳回一個單精度的數字和一個 TRUE, 否則它只是傳回 FALSE. 如果輸入的字串包含一個正確的數值, NUMBER? 將會傳回一個雙精確度的數值. 雙精確度是一個 64-bit 的數值, 所以我們用 DROP 來丟棄高位元的 32 bits, 因而 得到一個單精確度的 32-bit 數字.

This word will return a single-precision number and a TRUE, or it will just return FALSE. The word NUMBER? returns a double precision number if the input string contains a valid number. Double precision numbers are 64-bit so we DROP the top 32 bits to get a single-precision 32 bit number.

改變數值基底(Changing Numeric Base)

我們的數字系統是十進位, 或稱為 "base 10". 這是指一個像是 527 的數字等於 (5*100 + 2*10 + 7*1). 使用 10 為計算的基底完全是一個任意的選擇. 無疑地, 這跟大多數人有 10 跟手指(及腳趾) 有關. 巴比倫人用 60 當數字的基底, 這是我們選擇一小時有六十分鐘的原因. 電腦硬體使用基底 2, 或是叫做 "binary". 一個電腦數字像是 1101 是等於 (1*8 + 1*4 + 0*2 + 1*1), 如果你把這些數值 加起來, 你會得到 8+4+1=13. 在二進位中的 10 是等於 (1*2 + 0*1), 十位進中的 2. 就像是在任何基底 N 中 10 是 N.

Our numbering system is decimal, or "base 10." This means that a number like 527 is equal to (5*100 + 2*10 + 7*1). The use of 10 for the numeric base is a completely arbitrary decision. It no doubt has something to do with the fact that most people have 10 fingers (including thumbs). The Babylonians used base 60, which is where we got saddled with the concept of 60 minutes in an hour. Computer hardware uses base 2, or "binary". A computer number like 1101 is equal to (1*8 + 1*4 + 0*2 + 1*1). If you add these up, you get 8+4+1=13 . A 10 in binary is (1*2 + 0*1), or 2. Likewise 10 in any base N is N .

因為 Forth 可以在任何基底下工作, 所以使得探索不同的數字基底非常容易. 試試下列的指令.

Forth makes it very easy to explore different numeric bases because it can work in any base. Try entering the following:

另一個有用的數值基底是 hexadecimal, 是基底 16. 對於超過基底 10 的 系統有一個問題就是我們平常的數字系統只有數字 0 到 9. 對於 16 進位的數字, 我們使用字母 A 到 F 來表示 10 到 15. 因此 16 進位 3E7 代表 (3*256 + 14*16 + 7*1). 試著輸入:

Another useful numeric base is hexadecimal. which is base 16. One problem with bases over 10 is that our normal numbering system only has digits 0 to 9. For hex numbers we use the letters A to F for the digits 10 to 15. Thus the hex number 3E7 is equal to (3*256 + 14*16 + 7*1). Try entering:

一個叫做 BASE 的變數是用來追蹤目前數值基底用的. HEX, DECIMAL, 和 BINARY 都是以改變這個變數的方式來工作的. 你可以將這個變數改變 成任何你所想要的數值. 試試:

A variable called BASE is used to keep track of the current numeric base. The words HEX , DECIMAL , and BINARY work by changing this variable. You can change the base to anything you want. Try:

你現在是在基底 7. 當你取出並印出 BASE 的數值時會顯示 10, 因為十進位的 7 在 7 進位中是 10.

You are now in base 7 . When you fetched and printed the value of BASE, it said 10 because 7, in base 7, is 10.

PForth 定義了一個詞叫做 .HEX, 它將會把一個數字以 16 進元的單位印出, 無論目前的基底是什麼.

PForth defines a word called .HEX that prints a number as hexadecimal regardless of the current base.

你可以為任何基底定義一個像是 .HEX 的詞. 它所需要的是一種暫時將 BASE 改變成 所需的數值, 印出數字, 然後再存回的方法. 試試下列詞:

You could define a word like .HEX for any base. What is needed is a way to temporarily set the base while a number is printed, then restore it when we are through. Try the following word:

問題的答案(Answers to Problems)

如果你的答案能用, 但是不完全跟這邊列出來的相同, 別擔心. 在 Forth 中, 有許多種方法可以做相同的事情.

If your answer doesn't exactly match these but it works, don't fret. In Forth, there are usually many ways to the same thing.

堆疊的操作(Stack Manipulations)

算術(Arithmetic)

邏輯運算子(Logical Operators)

流程控制指令(Conditionals)

迴圈(Loops)

回到 pForth 首頁
Back to pForth Home Page