日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Forth

發布時間:2023/12/18 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Forth 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C 語言使你迷茫?Forth 可能是一個答案

程序語言 2010-05-25 22:27:28 閱讀153 評論0 ??字號: ? 訂閱

轉自:http://www.embeddedsoft.cn/news-detail.aspx?Id=100

原標題 Lost at C? Forth May Be the Answer?

原作者 Tom Napier 和 Eric Krieg

原文引自 www.Forth.org

曾經有個時期,人們不害怕從 IBM 購買計算機,和那時一樣,現在人們當然也不害怕用C語言來編寫嵌入式系統程序。如果還要再選擇一個的話,那通常是匯編語言,盡管時尚正在轉向Java 。只有很少的程序員使用Forth ,這種語言組合了匯編語言的速度、靈活性和緊縮性,又具有C語言的結構化和易讀性。這些為數不多的程序員還發現了 Forth 能夠提高編程的生產率。

在這篇文章中,我們希望(再一次)介紹 Forth 。你將會驚異于不需要復雜的工具就可以如此之快和交互式地編寫和測試嵌入式程序。

編寫程序的第一步是設計程序行為的細節。有些人畫流程圖,有些人用程序設計性語言(PDL),通過與英語類似的方式描述操作的序列和測試條件。完成 這些之后,設計就被分成模塊,每一塊都被轉成可執行的代碼,全部的事情就是編譯、連接、測試,這個迭代的過程可能會持續幾個月。

如果PDL能夠直接執行,就不需要把它翻譯成另一種語言,那你該省去多少時間呀!如果你能交互式地測試每個程序模塊,確認它能正確地工作,那不就更 方便了嗎?再假設有一種語言,它可以執行得和其它的語言一樣快、只要1K字節的運行開銷、符合 ANSI標準、可以擴展以滿足你應用程序的特殊需要,經過一到兩個星期的熟悉,你每天可以編寫出三倍于你同伴的代碼,那么你對這種語言感興趣嗎?如果是, 請聽如何用Forth來做到這些。

Forth 是什么?

從某種意義上說, Forth 不是一種語言,我們更應該把它看成一種為手頭的任務編寫應用語言的程序設計方法。你編寫的大部分程序都是你工作的需要而不是編譯器的需要。 Forth 支持你需要的任何操作和語法。

Forth 理解一定范圍的原語字,它們處理全部正常的算術、邏輯和程序流操作,然而它也有一個確定的辦法向語言加入新字。你可以確定哪些字能更好地描述你的應用,然 后你用現有的字定義這些字。一但你定義了一個新字,這個字就變成了語言的一部分,可以用來定義其它的字。最高級別的字就是程序本身。

在 Forth 中,每個事物是一個字或者是一個數,它們彼此被空格分開。 Forth沒有詞法分析,語法也很少。沒有操作符,沒有函數,沒有過程,沒有子程序,甚至沒有程序,只有字和數。

每個字告訴計算機去執行一個清晰的精巧定義的操作。定義一個字之后,你就可以把它作為一個獨立的元素來測試。在你開始測試的時候你不需要完成全部程序,你可以在鍵盤上輸入任何一個字,執行它,看結果是不是你所需要的。

Forth 也是它自己程序的符號調試器,所以測試一個 Forth 程序比測試其它語言的程序更快。你用增量化的方式編寫 Forth 定義、測試定義。一但確認一個字能夠工作,就可以把它加入到你的程序中;一但你定義了最高級別的字,就可以結束編程工作而不需要進一步的調試。

盡管 Forth 程序通常是自頂向下設計的,但是你需要自底向上編寫,它要求你在使用一個字之前先定義它。但是實際上, Forth 程序通常是從兩端向中間編寫的。開始的時候,你知道所需要的程序頂級行為,你也知道與硬件交互的字必須做的事情,于是就有中間的工作需要完成。

你也可以先給某個功能一個名字,在定義之前使用它(如果你需要測試編譯,你就給它一個空的名字)。一個程序的頂級字可以是一個無限循環,它用字 GET.FRONT.PANEL.INPUT 開始,后面是字 CHECK.USER.INPUT.LIMITS ,所以我們可以用 Forth 做 PDL 。當然,你在這里假設 CHECK.USER.INPUT.LIMITS 是存在的,最后你還得定義這個字的精確行為。

把程序分成可管理的自我描述的小塊是每個優良程序的行為。所不同的是,在 Forth 中,最后的結果是一個可執行的程序,而不是另一個漫長過程的開始。

Forth 是編譯器嗎?

Forth 是編譯的,但是它的用戶界面是解釋的。 Forth 維護一個它所知道的所有字的字典。每個定義由定義這個字的那些字的地址列表組成(為使代碼更短,在32位或者更長地址的機器上可以使用16位的標記而不是 實際的地址)。編譯的過程就是把新的字和它們的定義加入到字典。

由于Forth把源程序中的每個字翻譯成對應的地址, Forth 的編譯器就很像是一個匯編器。圖1是 Forth 編譯器完整的流程圖,如果把C語言編譯器流程圖同樣地畫出來,那會是一張 4' x 6' 的招貼海報。

?

圖 1 Forth 編譯器的完整的流程圖

對于源程序中的每個字,這個循環都要執行一次

把Forth程序想像成全部是由子程序組成的,可能會對我們理解Forth系統有所幫助。由于每個字調用子程序,所以不需要 CALL 指令,它只是一個地址。在運行時,一個機器碼片段讀出下一個指令的地址,把當前程序計數器保存在返回棧上,執行這個調用。這個小小的開銷對于每個字都要執 行一次,導致了 Forth 程序比優化的匯編程序要慢。

Forth 是如何工作的?

執行一個無休止的子程序調用序列并不是一件很有效率的事情。幸運的是,大約有60個字是用機器碼字義的。每個定義最終都是由這些“原語字”組合而成的,它們執行某些真正的工作。

原語定義了一個虛擬的Forth機器,要把 Forth 移植到一個新的系統上,只有這些原語字需要重寫。某些Forth運行在 DOS 和 Windows上,而在嵌入式應用中,這些由機器碼定義的原語字就是操作系統。

Forth 在堆棧上傳遞參數。在一個字執行之前,所需要的參數必須在堆棧上。而在執行之后,如果有任何的結果,也留在堆棧上。

這與大多數現代計算機語言的行為精確地一致,但是現代計算機語言的堆棧通常是隱藏起來的。在 Forth 中,程序員知道堆棧上的內容,并能夠直接處理它們。例如,Forth 原語字 SWAP 交換堆棧上的兩個元素。大多數語言保存未決的操作,當你寫下 C = A + B ,編譯器把“ = ”和“ + ”操作放到未決的表中直到讀到表達式的結尾。然后它重寫這個表達式為“取 A ,取 B ,加,存入 C ”。

Forth 消去了中間過程,在 Forth 中,你把同樣的操作寫成是 A @ B @ + C ! 。這里的 @ 和 ! 是 Forth “讀取”和“存儲”操作的縮寫, + 非常奇怪地表示加法。

幸運的是,只有不多的 Forth 字用這種密碼表示。大多數的 Forth 接受多達 31 個字符,大多數的標準字描述了它們的功能。好的 Forth 程序是自解釋的,所以應該盡量使你定義的字成為自描述的。調試這個字的方法是打入它的輸入參數,后隨這個字。它立即執行,就好像 Forth 是一個解釋器,允許你測試堆棧上的結果。

一個堆棧元素典型地有 32 位(有些Forth系統為16 位)并且是無類型的,它可以表示一個有或者無符號的整數、一個地址、一個單精度的浮點數或者是一個布爾標志。你需要對此保持跟蹤。

Forth 的哲學是許可而不是禁止。如果你有一個好的原因把布爾值加到地址上,Forth不會阻止你。對于這些事情,Forth中沒有任何東西能夠阻止你把一個錯誤的項目放到堆棧上。 Forth 非常快速而高效,但是你自己也得睜大眼睛。

創建一個新的字義

Forth 中最重要的字可能是冒號,它把編譯器從運行模式切換到編譯模式并創建一個新的字典項。在冒號之后的第一個字是將要定義的字的名字,定義接著名字之后。邏輯上,定義被一個分號結束,這將編譯一個返回指令并把編譯器切換到運行模式。

于是,一個完整的 Forth 定義看起來像下面這樣:

: MAGNITUDE (X Y—vector magnitude) DUP * SWAP DUP * + SQRT ;

括號中的表達式是堆棧說明,它提醒程序員這個字的輸入輸出參數是什么。 DUP(復制)操作產生棧頂元素的另一個拷貝, * 是單精度乘法,SQRT得到一個數的平方根。

作為 Forth 靈活性方面的一個例子,假設你需要 C 語言的 ++ 操作符, Forth 與之最近的等效是 + ! ,它把一個指定的數加到一個變量中。如果你定義:

: ++ 1 SWAP +! ;

則 ALPHA ++ 加 1 到變量 ALPHA 中, Forth 與 C 語言的唯一區別是 Forth 不允許 ALPHA++ ,但是C語言允許,因為 Forth 并不分析表達式,它會把 ALPHA++ 作為一個定義字。

程序結構

Forth 是高度結構化的,如果你確實需要,當然也有辦法編譯一個GOTO,但你通常使用 IF ELSE THEN BEGIN UNTIL WHILE REPEAT DO 和 LOOP 來控制程序的流程。這些字把條件跳轉指令編譯到定義中。

Forth 的IF檢查棧頂標志,這個標志是許多 Forth 比較操作字中的一個留下的。比如我們希望比較堆棧上的兩個數,如果相等就執行選擇1,如果不等就執行選擇2, Forth 的語法是這樣的:

= IF 選擇 -1 ELSE 選擇 -2 THEN.

(我在自己的程序中使用 ENDIF代替THEN ,因為我覺得 THEN 對于 Basic 來說不合理。Forth 允許這樣的個人化選擇,盡管你的老板或者伙伴不允許)

常數 變量 和串

源文件中的一個數作為立即數編譯。一個命名的常數在編譯時存儲一個值并在運行時把這個值放到堆棧上。命名一個變量則編譯一個存儲空間。引用一個變量則把它的地址放到堆棧上以準備讀寫。一個 Forth 串是一個變量區,它的第一個字節是串的長度。

由于變量指示了它的地址,所以能夠在使用這個變量之前處理這個地址。例如,如果你使用的 Forth 系統沒有 ARRAY 數組結構,你可以定義一個, Forth 能夠指定定義字的新類型。另外,你可以"偽造"數組。 BETA 7 + C@ 讀取數組中的第八個字節,這個數組開始于 BETA 變量的地址。

Forth 源程序的一個不足是我們不清楚一個字表示的是變量還是函數。有些人使用這樣的傳統:用連字符表示變量名而用小數點表示函數名。由于好的 Forth 代碼與英語非常相似,在視覺上不需要分析一個整行就可以區別代碼和說明,許多用戶就用大寫字母表示代碼而用小寫字母表示注釋。

Forth 硬件

Forth 幾乎在每個現存的或者曾經存在過的微處理器上都有實現,但是有些芯片更適合 Forth 系統運行。很明顯,那些與圖 2 的 Forth 虛擬機更接近的芯片能更好地運行 Forth 。 Forth 需要兩個堆棧,那些支持一個以上堆棧的芯片將運行得更快。由于 Forth 只需要不多的寄存器,所以硅片上如果有寄存器也只能浪費。

?

圖 2 Forth 虛擬機結構

Forth 虛擬機具有 HARVARD 體系結構,實現時通常用一個分離的寄存器保存棧頂元素

最小的 Forth 系統執行 16 位或者 32 位長的算術運算,所以 Forth 在 8 位芯片上運行較慢。歷史上, Motorola微處理器比Intel 處理器更適合運行 Forth 。 MC6809 和 MC68X0 是理想的 Forth 8 位芯片。

由于 Forth 虛擬機相對簡單,它可以在一個門陣列中實現。最早的努力是 Charles Moore , Forth 的發明人,指導 Harris公司于 1989 年推出了 RTX2000 。這個 10MIPS 的單芯片 Forth 引擎使用哈佛體系結構,并把參數棧和返回棧放到芯片上。不幸的是,這款芯片在商業上沒有成功,現在只用于一些專用的市場,比如人造衛星。

使用 Forth

現在有各種級別的商業和公共的 Forth 版本。對于一個 8 位或者 16 位處理器的嵌入式應用,最方便方法的是在 PC 機上編寫 Forth 程序,然后再把最終的代碼傳送到目標系統上,由于開發系統能夠使用全部的 DOS 或者 Windows 能力,在最終的產品中只需要包含一個小的運行時間包和程序自身,字典只是在編譯和調試程序時才需要,在最終的產品里可以被去除。

由于 Forth 程序趨向于編譯大約每行10個字節,一個 2000 行的程序加上 4K 字節的運行時間文件可以很容易地放到 32K 字節的 PROM 中。如果目標系統運行串行口并能在 RAM 中執行,那我更喜歡在目標系統上編譯和設計。盡管這意味著需要為字典和編譯器找到存儲器空間,但是它大大有助于硬件測試。我的許多硬件問題都是這樣解決 的:編寫短的 Forth 程序來觸發 I/O 位,再用一個示法器觀察可疑的區域。

一個商業化的 Forth 系統有一個初始字典,它包含有 Forth 原語和需要實現 Forth 編譯器的字。許多 Forth 系統有內建的編輯器,但是你可以使用任何方便的編譯器。你也可能得到在操作系統上如 Windows 上開發 Forth 程序的庫。對于一個使用單板PC的嵌入式應用, DOS 庫就很有用了。

你也可以得到一個 Forth 擴展庫,在程序需要它們的時候裝入這些庫。例如,簡單的Forth只處理整數,而浮點是可選的。編寫自己的庫也很簡單,我曾經用從 Delta Research 公司得到的 JForth 編寫分析濾波器的程序。 JForth 支持 Windows 、下拉菜單、輸入固件和控制參數滑塊。然而,它不能處理復數,我在 20 分鐘里就編寫好了自己的浮點復數程序庫。

在一個編寫一系列相關控制儀器的團隊中,應該有一個成員被指定編寫硬件接口函數庫,處理諸如用一致方式訪問前臺控制和顯示等等工作。由于 Forth 允許程序員開發特殊的解決問題的方法,在一個大的項目中,你必須有好的文檔和團隊成員之間的緊密協調。使用 Forth 的公司應該為它們的程序員維護一個 Forth 內部擴展標準用于它們的產品和技術。

用 Forth 可以做什么?

簡單地回答是:任何事情。其它的計算機語言限制你只能執行編譯器的編寫者認為你需要的操作。由于 Forth 是天然可擴展的,你可以做你需要的一切事情。如果所有的方案都不行,你還可以直接進入機器代碼并創建你需要的任何數據結構。

JForth 甚至實現了C的結構,后者通常用于與主機的操作系統進行交互。我曾經需要一個結構,它寫入30個命名的一維數組,作為一個單個的命名的兩維數組。大家都說這用C實現起來很方便,但我從來就沒有見到有人試著做過。

Forth 標準

自從 Charles Moore 1970 年發明 Forth 之后,出現了許多 Forth 標準和方言。Forth鼓勵創新,所以總是有定制和改進它的傾向,就是在大家表面上接受了標準時也一樣。我從1979 年開始從事古老的 FIG-Forth 編程,它已經非常古老甚至都無法改變。從那時開始,又有了 Forth-79 和 Forth-80 ,現在是一個 ANSI 的 Forth 標準( X3.215/1994 )。

如何比較 Forth 和 C ?

Forth 和C 都使得程序員能夠在更高的級別上思維,并從較慢的匯編語言開發過程中解脫出來。 Forth 合理的文檔順序可以免去 C 語言中的原型說明。

全部的C 語言標準程序流控制( do if else while switch )在 Forth 中都存在,而且連名字都常常一致,所有重要的邏輯和算術操作也存在,條件比較、數組和聯合都在 Forth 中支持, COSNTANT 替代了 #define , Forth 的直接堆棧處理省去了大多數的 C 語言 auto 變量。 Forth 字典的使用和 FORTGET 定義的能力比C語言的弱作用域操作能力更強大。你甚至可以比 C++ 更少痛苦地支持自己的數據類型。

Forth 假設你知道自己正在做的事情。它可以阻止你犯打字和結構不完整的錯誤,但是編譯的錯誤代碼手冊通常只有一頁,而不是整整一章。有人曾經說過:Forth 不能夠標識語法錯誤,因為它不知道你準備使用什么語法。

在C語言中,你受到的保護更多。但即使如此,你還是必須做一些事情,如強制類型轉換之類,來請求編譯器幫助你做一些檢查。

Forth 比 C 語言有這樣一些優點:

?? 開發環境更加簡單。你不需要安裝整個 Forth 開發包,因為 Forth 就是它自己的開發系統,在一個嵌入式應用中,也是它自己的操作環境。它提供了一個 OS 、源碼編譯器和你需要的全部調試程序,這些都放在一個360K字節的軟盤上,結果是,你使用單一的工具集和單一的用戶界面。你可以把這些與其它工具比較: 一個編譯器、OS、一個調試器,可能還有一個目標調試程序,它們都來自不同的開發商,并且不是為彼此協同工作而設計的;

?? 當你購買 Forth 時,你通常可以得到全部開發環境的源代碼。相反,你可以試著讓 Borland 或者 Microsoft 給你想要的、向后兼容的 C 語言進行更強的類型檢測、模糊控制邏輯或者不同的浮點實現;

?? 常常能夠在目標系統上開發 Forth 程序。在我的 C 程序合同中,我使用 Sun 工作站運行 MAKE 來編譯和連接執行代碼。然后在一個目標機器上,我在目標系統上電之前下載代碼并測試它。如果我想做一個調整,它將花費一個小時來完成全部的過程。使用 Forth ,我可以通過目標機的串行口來打入一個新字,把參數放到堆棧上,然后調用它來檢查這個字是否工作。我可以簡單地結合新字以截獲對老字的調用;

?? 使用編譯器的擴展能力可以使你進行任何時尚的編碼而不需要切換語言。 Forth 從一開始就已經是面向對象的、“沙箱支持”和平臺獨立的。加入數據結構或者操作符重載幾乎窒息了 C++ ,但在 Forth 中卻沒有任何問題;

?? 你可以比C語言更容易地進入匯編語言,所有的數據結構都可以從匯編語言中訪問;

?? 目標測試更容易。你可以使用與代碼中一樣的命令來交互式地檢查和處理數據,在C語言中做同樣的事情需要更多的知識,它需要許多的鍵盤輸入來控制調試器。你 不需要一個目標操作系統, Forth 就是一個很好的 OS 。許多 Forth 支持多用戶和多任務。因為每個任務有一個獨立的參數棧和返回棧,所以任務的切換能夠瞬時而高效。

?? Forth 在編譯時分配存儲器資源,它的執行時間是確定的。它不需要花費不確定的時間來整理存儲器碎片。在一個實時OS 中,我選擇不使用動態的存儲器分配,但是如果你需要一些像 alloc() 和 free() 一類的操作,那也不是大問題,一頁的代碼足以實現這些功能。由于是基于堆棧的, Forth 可以用很少的開銷進行中斷服務,因為它不需要保存上下文。

不好的一面是, Forth 可能有些慢。在一個大的程序中,它可能比最新的 C 語言產生的代碼占用更多的空間。然而,盡管用 Forth 編寫的 "Hello world" 程序可以達到 2K 字節,但是它不需要裝載更大的運行時間庫。 Forth 鼓勵程序員使用定點表示法,這可以極大地提高運行速度,但是在編碼時需要更多地進行分析。

Forth 的最大缺點如同"第 22 條軍規"。知道 Forth 的人不多,而人們又通常不愿意學習某些東西,除非其它的人都希望使用它。這就是蓋茨先生的生活方式。

如果你能夠說服你的老板讓你使用 Forth ,它將成為你的秘密武器。工業經驗顯示 Forth 程序員可以達到C程序員 10 倍以上的生產率。

我們這里給出一個 Forth 和C語言差異的例子。這是一個嵌入式程序,使用板上的 PIC 驅動晶振。我們用 Forth 編寫了一個程序以顯示 PIC 程序員如何工作。下面的列表1是這個程序外層循環的 PDL 描述。列表 2 提供了可執行的 Forth 程序。這花了我 10 分鐘時間(在一個實際的 Forth 程序中,這些代碼將要被因子化成幾個定義),而列表 3 是同樣程序的 C 語言版本。

列表 1 一個抖動產生器的頂層程序 PDL 描述

Main Program:

HouseKeep (set ports, clear flags, set defaults)

Read upload bit (has user saved previous settings?)

If low

CopyPROM (load defaults from EEPROM)

Endif

ReadConfiguration (get former settings from EEPROM)

SetConfiguration (set board registers)

Beginloop: (Start of endless loop)

Read self-test bit

Read self-test number

If bit=0 and number <>0 (self test operation)

Case: (test number)

On 1 do test 1

On 2 do test 2

On 3 do test 3

On 4 do test 4

Endcase;

Else (normal operation)

Read interface flag (Check for faults or user input)

If set

Read status word (Identify faults or user input)

If fault flag, do soft reset, endif

If jitter flag <> jitter state, toggle state, endif

If calibration request, Calibrate, endif

If Bit 0, SetAmplitude, Endif

If Bit 1, SetBitRate, SetAmplitude, Endif

If Bit 2, SetBitRate, SetAmplitude, Endif

If Bit 3, SetFrequency, Endif

If parameters have changed

Update EEPROM

Endif

Clear interface flag

Endif

Endif

Endloop;

進一步學習

要學習更多 Forth 知識,最好的辦法是加入非贏利的 Forth Interest Group (FIG) 組織。它們出版一本名為《Forth DIMENSIONS》的雜志,也銷售圖書和公共域版本的 Forth 系統軟件。

經典但是有些過時的書是 Leo Brodie 的《 Starting Forth 》(中譯本: 《Forth 語言入門》)。如果找不到它,可以從FIG購買。 Brodie 的《 Forth 思維方式》沒有告訴你如何使用 Forth ,但對 Forth 和其它語言的結構和哲學思想進行了很好的考察。另一個好的入門書是 C. Kevin McCabe 的《 Forth 基礎》第一卷。

為了用 Forth 實現一個嵌入式系統,你可以先得到一個公共域版本,你也可以根據你的處理器購買一個現成的版本。 Forth Inc. 提供基于 DOS 的版本,可用于80196、80186、68HC16 和 TMS320C31 ,它們也有用于68HC11和8051的 Windows 版本。

一些小的 Forth 開發商在《 Forth DIMENSIONS》 上作廣告。

為什么不使用 Forth

人們常說 C 語言程序員很容易找到而 Forth 程序員卻很難找。這是事實。很少的“程序員”知道 Forth ,但是,我們發現硬件工程師卻常常熟悉它。有經驗的工程師通常比職業程序員能寫出更好的嵌入式代碼,因為后者不熟悉硬件。

你需要知道你公司的目標是什么。如果你真的需要產品,那么你就需要 Forth 。這就是路。

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

Tom Napier 曾是火箭科學家,健康學家和工程管理,最近九年時間從事宇宙飛船的通信設備開發,現在是顧問和作家。

你可以通過電子郵件與 Eric 聯系 http://www.voicenet.com/~eric/Forth.htm

?

英文轉自:http://web.archive.org/web/19990423140254/http://www.circuitcellar.com/DesignForum/features/9805022/TNtext.htm

Just as at one time, no one got fired for buying from IBM, now no one gets fired for programming embedded applications in C. If an alternative is considered, it’s usually assembly, although fashion is now swinging towards Java. Very few programmers use Forth, a language that combines the speed, versatility, and compactness of assembly language with the structure and the legibility of C. These few have found Forth to increase programming productivity.

In this article, we’d like to (re)introduce you to Forth. You’ll be surprised how quickly and interactively you can write and test embedded programs without using complex tools.

The first step in writing any program is to work out in detail what it has to do. Some people draw flowcharts, while others use a Program Design Language (PDL) that describes the sequence of operations and test conditions in an English-like manner. Once this is done, the design is broken up into modules, and each is converted into executable code. The whole thing is compiled, linked, and tested, an iterative process that can take months.

However, if the PDL could be executed and you didn’t need to translate it into another language, think how much time you could save. Wouldn’t it be more convenient if you could test each program module interactively to verify its operation? Suppose too that there’s a language that executes as quickly as any other language, has a run-time overhead of a thousand bytes, conforms to an ANSI standard, and can be extended to cope with any special requirements your application has. What if, after a week or two of familiarization, you could turn out at least three times as much finished code in a day as your fellow programmers? Would you be interested? If so, listen up to hear how you can do all this with Forth.

What is Forth?

In a sense, Forth is not a language but rather a programming methodology for writing an application language for the task in hand. You write the bulk of your program in terms of the job’s requirements, not the compiler’s edicts. Forth supports whatever operations and syntax you need.

Forth understands a range of primitive words that handle all the normal arithmetical, logical, and program flow operations. However, it also has a defined way of adding words to the language. You can decide what words best describe your application. You then define these words in terms of existing words. Once you’ve defined a word, it becomes part of the language and can be used to define other words. The highest level word is the program itself.

In Forth everything is either a word or a number. Both are separated by spaces. There is no parsing in Forth and very little syntax. There are no operators, no functions, no procedures, no subroutines, not even programs—just words and numbers.

Every word tells the computer to execute a clearly defined finished operation. After you define a word, you can test it as a stand-alone element. You don’t need to complete the program before you start testing. You can type any word at the keyboard, have it execute, and see if the result is what you expected.

Forth is its own symbolic debugger, so testing a Forth program is much faster than testing a program in another language. You write Forth incrementally, defining and testing words in turn. Once you’re sure a word works, you can incorporate it into your program. Once you’ve defined the highest level word, you have a finished program that should need no further debugging.

Although a Forth program is normally designed from the top level down, you write it from the bottom level up—it expects you to define words before you use them. In practice, however, Forth programs are often written from both ends towards the middle. At the outset, you know what top-level program behavior you need, and you know what the low-level hardware-interactive words have to do. It’s the stuff in the middle that needs working out.

You can assign names to functions and use these names before you define them. (Give them null definitions if you want to test compile.) The top-level word of a program might be an endless loop which starts with the word GET.FRONT.PANEL.INPUT followed by CHECK.USER.INPUT.LIMITS, thereby using Forth as its own PDL. Of course, having assumed the existence of CHECK.USER.INPUT.LIMITS, you eventually have to define exactly what this word should accomplish.

Breaking down a program into manageable and self-descriptive chunks is exactly what all good programmers do. The difference: in Forth, the end result is an executable program, not just the first step of a long process.

Is Forth a Compiler?

Forth is compiled, but its user interface behaves like an interpreter. It maintains a dictionary of all the words it knows. Each definition consists of a list of the addresses of the words that form the definition. (For code brevity, Forth on machines with 32-bit or longer addresses may use 16-bit tokens rather than addresses.) Compilation adds the new words and their definitions to the dictionary.

Because Forth compiles each word in the source one-for-one to an execution address, a Forth compiler resembles an assembler. Figure 1 shows the complete flowchart of a Forth compiler. Similar charts for C are 4’ x 6’ wall posters.

?

Figure 1—

Here’s the complete flowchart of a Forth compiler. The loop is executed once for each word in the source.

It may be helpful to think of a Forth program as consisting entirely of subroutines. Since every word calls a subroutine, there is no need for a CALL instruction, only an address. At run time, a machine code fragment fetches the next instruction address, saves the current program counter on the return stack, and executes the call. This tiny overhead is executed once for each word, making Forth marginally slower than an optimized assembly-language program.

How Forth Works

Executing an endless series of subroutine calls is not a very productive enterprise. Luckily, some 60 Forth words are defined in machine language. Every definition eventually calls a combination of these "primitives" and does some real work.

The primitives define a virtual Forth machine. To port Forth to a new system, only the primitives are rewritten. While some Forths run under DOS or Windows, in an embedded application the machine-code definitions of the primitives are the operating system.

Forth passes parameters onto a stack. Before a word is executed, the necessary parameters must be present on the stack. After execution, the results, if any, are left on the stack.

This is precisely what happens in most modern computer languages, but the stack is usually hidden. In Forth, the programmer is aware of what is on the stack and can manipulate it directly. For example, the primitive Forth word SWAP exchanges the top two elements of the stack. Most languages save pending operations. When you write C = A + B, the compiler puts the "equals" and "plus" operations on its pending list until it gets to the end of the expression. Then, it rewrites it as "Fetch A, Fetch B, Add, Store C."

Forth cuts out the middle step. In Forth, you write the same operation as A @ B @ + C !. The @ and ! are Forth’s shorthand for the "fetch" and "store" operations. The + , oddly enough, represents addition.

Luckily, only a handful of Forth words are this cryptic. Most Forths accept names up to 31 characters long, and most standard words describe their function. Good Forth is self-commenting, so make your words as self-descriptive as possible. At run time, any numbers you type are placed on top of the parameter stack. You debug a word by typing its input parameters, then the word. It executes immediately as if Forth were an interpreter, allowing you to check the results on the stack.

A stack element typically has 32 bits (some Forths use 16) and is untyped. It might represent a signed or unsigned integer, an address, a single-precision floating-point number, or a Boolean flag. You need to keep track.

Forth’s philosophy is to permit, not to impede. If you have a good reason to add a Boolean to an address, Forth won’t stop you. For that matter, there’s nothing in Forth that prevents you from putting the wrong number of items on the stack. Forth is fast and efficient, but you have to keep your eyes open.

Creating a New Definition

Perhaps the most important word in Forth is the colon, which switches the compiler from run mode to compile mode and creates a new dictionary definition. The first word in the source after a colon is the name of the word to be defined. The definition follows the name. Logically enough, the definition is terminated by a semi-colon. This compiles a return instruction and switches the compiler back to run mode.

Thus, a complete Forth definition might look like this:

: MAGNITUDE (X Y—vector magnitude) DUP * SWAP DUP * + SQRT ;

The expression in parentheses is the stack picture. It reminds the programmer what the word’s input and output parameters are. DUP (duplicate) generates a second copy of the top element on the stack, * is a single-precision multiplication, and SQRT takes the square root of a number.

As an example of Forth’s flexibility, suppose you had a hankering for C’s ++ operation. Forth’s nearest equivalent is +! which adds a specified number to a variable. If you define : ++ 1 SWAP +! ; then ALPHA ++ adds one to the variable ALPHA. What Forth does not allow, but C does, is writing this as ALPHA++. Since Forth does not parse expressions, it would read ALPHA++ as an undefined word.

Program Structure

Forth is highly structured. There is a way to compile a GOTO if you really want to, but normally you use the words IF, ELSE, THEN, BEGIN, UNTIL, WHILE, REPEAT, DO, and LOOP to control the flow of the program. These words compile conditional jumps into a definition.

Forth’s IF checks the top of the stack for a flag left by one of Forth’s many comparison words. To execute option 1 if the top two numbers on the stack are equal and option 2 if they are not, Forth’s syntax is:

= IF do-option-1 ELSE do-option-2 THEN.

(I use ENDIF in my programs because I feel that THEN is an illogical throw-back to BASIC. Forth condones such personal idiosyncrasies, even if your bosses and co-workers may not.)

Constants, Variables, and Strings

A number in the source is compiled as a literal. A named constant stores a value at compile time and puts that value on the stack when it is invoked. Naming a variable compiles a storage space. Using a variable puts that address on the stack, ready for a fetch or store operation. A Forth string is just a variable whose first byte specifies its length.

Since a variable supplies its address, it can be manipulated before being used. For example, if you were using a Forth that had no ARRAY structure, you could define one. Forth can specify new types of defining words. Alternatively, you could fake it. BETA 7 + C@ fetches the eighth byte in the array that starts at the address of the variable BETA.

One deficiency of Forth source is that it may be unclear whether a word represents a variable or a function. Some follow the convention of hyphenating variable names but splitting function names with periods. Since good Forth code can be quite English-like, it is handy to distinguish code from comments visually without needing to parse a line. Thus, many commonly use upper case for code and lower case for comments.

Hardware for Forth

Forth has been implemented on just about every microprocessor which has ever existed but some chips are more suitable than others. Obviously, the closer the chip architecture comes to the Forth virtual machine outlined in Figure 2, the better Forth runs. Forth needs two stacks so it runs faster on a chip that supports more than one. Since Forth needs few registers, a chip with many is just a lot of wasted silicon.

?

Figure 2—

The Forth virtual machine has a Harvard architecture. Hardware implementations frequently keep
the top stack element in a separate register.

Minimal Forths do arithmetic on 16- or 32-bit integers, so Forth runs slowly on eight-bit chips. Historically, Motorola microprocessors have been more suited to Forth than Intel ones. The MC6809 and the MC680X0 series were ideal 8-bit chips for Forth.

Since the Forth virtual machine is relatively simple, it can be implemented on a gate array. A pioneering effort by Charles Moore, the inventor of Forth, led Harris to introduce their RTX 2000 in 1989. This 10-MIPS single-chip Forth engine used a Harvard architecture with its parameter and return stacks on the chip. Unfortunately, it was not a commercial success and is now used only in niche markets such as processors on satellites.

Using Forth

Commercial and public-domain versions of Forth exist at all levels. For an embedded application on an 8- or 16-bit processor, it may be most convenient to write Forth programs on a PC and then transfer the finished code to the target system. While the development system may use the full facilities of DOS or Windows, there is no need for the finished product to contain more than a small run-time package and the program itself. Even the dictionary is only needed when compiling and debugging the program. It can be omitted from the final code.

Because Forth programs tend to compile to about 10 bytes per line, a 2000-line program plus a 4-KB run-time file easily fits in a 32-KB PROM. If the target system supports a serial port and executes from RAM, I prefer to compile and debug on the target. Even though this means finding memory space for the dictionary and the compiler, it helps immensely in testing the hardware. I’ve resolved many hardware bugs by programming a short Forth loop to wiggle a bit so I could follow a signal through the suspect area with an oscilloscope.

A commercial Forth comes with an initial dictionary that contains the Forth primitives and the words needed to implement the compiler. Many Forths have a built-in source editor, but you can use any editor you find convenient. You will probably be supplied with libraries of the operating system calls needed to develop Forth programs under OSs like Windows. For an embedded application using a single-card PC, a DOS function library is useful.

You can also get a library of Forth extensions, which you can load if your program requires them. For example, simple Forths process only integers, so floating-point arithmetic is optional. It’s easy to write your own libraries. I’ve been using JForth from Delta Research to write programs which analyze filters. JForth supports windows, pull-down menus, input gadgets, and slider control of parameters. However, it can’t handle complex numbers. I wrote my own floating-point complex arithmetic library in 20 minutes.

In a team writing programs to control a series of related instruments, one member should be assigned to write a library of hardware-interface functions to do things like access the front-panel controls and displays in a consistent manner. Because Forth lets programmers develop idiosyncratic ways of solving problems, you must have good documentation and close coordination between team members on a large project. Companies using Forth should maintain in-house standards for Forth extensions that relate to their products and teach these to all their programmers.

What Can You Do With Forth?

The simple answer: anything. Other computer languages limit you to the set of operations the compiler authors thought you’d need. Because Forth is naturally extensible, you can do what you need. If all else fails, you can easily drop into machine code and create any data structure you need.

JForth even implements C structs, which it uses to interact with the host operating system. I once needed a structure which was written to 30 named, one-dimensional arrays. It was read as a single, named, two-dimensional array. I’m told this is feasible in C, but I’ve never met anyone who wanted to try it.

Forth Standards

Since its invention by Charles Moore about 1970, many Forth standards and dialects have emerged. Forth encourages innovation so there has always been a tendency for Forth vendors to customize and improve it, even when ostensibly adhering to a standard. I do most of my professional Forth programming in 1979 vintage FIG-Forth on the grounds that it is already so obsolete that it won’t change. Since then, there was Forth-79 and Forth-83 and now there’s an ANSI standard for Forth (X3.215/1994).

How does Forth Compare with C?

Both Forth and C let you think at a higher level and spare you the slower development process of assembler. Forth’s logical compilation order eliminates the need for C prototypes within a file.

All the standard program controls of C (do, if, else, while, switch, etc.) are in Forth, often with the same names. All the important logical and mathematical operators are there, too. Conditional compilation, arrays, and unions are all supported with a Forth flair. Constants replace #defines, and Forth’s direct stack manipulation eliminates most need for auto variables. Forth’s use of vocabularies and its ability to FORGET definitions are more powerful than C’s weak scope operators. You can support your own data types with even less pain than in C++.

Forth assumes you know what you are doing. It protects you from typographical errors and incomplete structures, but the manual has only one page of compiler error codes, not a whole chapter. As someone once said, Forth can’t flag syntax errors since it doesn’t know what syntax you decided to use.

In C, you’re more protected. But then, you also have to do things like type casting to circumvent a patronizing compiler constantly checking up on you.

Forth has these advantages over C:

  • The development environment is much simpler. You don’t need to install a whole development suite since Forth is its own development system and, in an embedded application, its own operating system. It offers an OS, source editor, and all the debug utilities you need, and they fit on one 360-KB floppy.
    As a result, you’re working with a single tool set and a single user interface. Compare this with having a compiler, OS, debugger, and maybe a target monitor program, all coming from different vendors and not designed to work together.
  • When you buy Forth, you often get the source code for the whole development environment. Try telling Borland or Microsoft that you want to make a backward compatible variant of C to do stronger type checking, fuzzy logic, or different floating-point implementation.
  • It’s often possible to develop a Forth program on the target system itself. In my present C contract, I use a Sun workstation to run Make and to compile and link a target executable. Then, on a target machine, I download the code before powering it up and testing it. If I want to make an adjustment, it takes an hour to go through the whole loop again.
    With Forth, I could type a new word right into the serial port of the target, push parameters onto the stack, then call it to see if it worked. I could easily "splice" the new word to intercept any calls to the old word.
  • The extensibility of the compiler lets you follow any coding fad that comes along without switching languages. Forth has been object oriented, "sandbox supporting," and platform independent from the get go. Added data structures or operator overloading that would choke C++ would not be a problem in Forth.
  • You can drop into assembly much easier than in C, and all data structures are accessible from assembler.
  • Target testing is far easier. You can interactively examine and manipulate data using the same commands you used in the code. To do the same thing in C requires advanced knowledge. It takes lots of key pressing to dominate a debugger.
  • You don’t need a target OS. Forth is at its best when it is the OS. Some Forths support multiple users and multitasking. Since each task has an independent parameter stack and return stack, task switching is essentially instantaneous.
  • Forth allocates memory resources at compilation, which makes operation times determinate. It doesn’t spend an unknown time defragmenting memory.
    In a real-time OS, I prefer not to dynamically allocate memory, but if you want something akin to alloc() and free(), that’s up to you. A page of code would cover it. Forth can service interrupts with little latency since, being stack based, it doesn’t need to save the context.
  • On the negative side, Forth can be a little slower. In a large program, it may use slightly more code than newer C compilers. However, although a "hello world" program in Forth might run to 2 KB, it has no huge run-time libraries to load. Forth encourages programmers to use fixed-point notation, which can greatly speed execution, but requires more analysis during coding.

    The biggest drawback of Forth is the Catch 22 that attends any nonconformist idea. Not many people know Forth, and people won’t usually learn something unless everyone else is already using it. That’s how Mr. Gates makes a living.

    If you can persuade your boss to let you use Forth, it can be your secret weapon. Industry experience has shown that a Forth programmer is up to ten times more productive than a C programmer.

    We’d like to show you some of the differences between Forth and C. For an embedded program using an onboard PIC to drive a jittering oscillator, we wrote an emulation program in Forth to show the PIC programmer how things should work. Listing 1, below, shows the PDL description of the outer loop of this program. Listing 2 offers the executable Forth. It took me about ten minutes. (In a real Forth program, this much code would be factored into several definitions.) Listing 3 presents the C version of the same program.

    ?

    Listing 1— Here’s the top level of a program for a jitter generator in PDL ? Main Program:
    HouseKeep (set ports, clear flags, set defaults)
    Read upload bit (has user saved previous settings?)
    If low
    CopyPROM (load defaults from EEPROM)
    Endif
    ReadConfiguration (get former settings from EEPROM)
    SetConfiguration (set board registers)
    Beginloop: (Start of endless loop)
    Read self-test bit
    Read self-test number
    If bit=0 and number <>0 (self test operation)
    Case: (test number)
    On 1 do test 1
    On 2 do test 2
    On 3 do test 3
    On 4 do test 4
    Endcase;
    Else (normal operation)
    Read interface flag (Check for faults or user input)
    If set
    Read status word (Identify faults or user input)
    If fault flag, do soft reset, endif
    If jitter flag <> jitter state, toggle state, endif
    If calibration request, Calibrate, endif
    If Bit 0, SetAmplitude, Endif
    If Bit 1, SetBitRate, SetAmplitude, Endif
    If Bit 2, SetBitRate, SetAmplitude, Endif
    If Bit 3, SetFrequency, Endif
    If parameters have changed
    Update EEPROM
    Endif
    Clear interface flag
    Endif
    Endif
    Endloop;

    Going Further

    The best way to learn more about Forth is to join the nonprofit Forth Interest Group (FIG). They publish a journal, Forth Dimensions , and sell books and public domain versions of Forth.

    The classical, but now dated, book on Forth is Leo Brodie’s Starting Forth . If you can’t find it elsewhere, you can buy it from FIG. Brodie’s Thinking Forth won’t teach you how to use Forth from scratch but is a fine examination of the philosophy and structure of Forth and other languages. Another good beginner’s book is volume 1 of C. Kevin McCabe’s Forth Fundamentals .

    To implement an embedded system in Forth, you can adapt a public-domain version. Alternatively, you can buy a ready-made system designed around your target processor. Forth Inc. advertises versions of their DOS-based chipForth for the 80196, 80186, 68HC16, and 320C31. They also have Forths running under Windows for the 68HC11 and 8051 processors.

    A number of smaller Forth vendors advertise in Forth Dimensions .

    Why Not Use Forth?

    We’ve often been told that it’s easy to find C programmers and that hardly anyone uses Forth. This is true. Few "programmers" know Forth, but we’ve found that hardware engineers are often familiar with it. Engineers with programming experience generally write better embedded code than career programmers who are unfamiliar with hardware.

    You need to ask what your company’s aim is. If you really want to get product out the door, then check Forth out. It’s the way to go.

    Tom Napier has worked as a rocket scientist, health physicist, and engineering manager. He spent the last nine years developing space-craft communications equipment but is now a consultant and writer.

    You may reach Eric via http://web.archive.org/web/20000128093128/http://www.voicenet.com/~eric/forth.htm .

    References and Sources

    Forth Dimensions (journal), books on Forth, public-domain versions of Forth
    Forth Interest Group (FIG)
    100 Dolores St., Ste. 183
    Carmel, CA 93923
    http://web.archive.org/web/20000128093128/http://www.forth.org/

    Forth, Inc.
    111 N. Sepulveda Blvd., Ste. 300
    Manhattan Beach, CA 90266
    http://web.archive.org/web/20000128093128/http://www.forth.com/

    總結

    以上是生活随笔為你收集整理的Forth的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。