面向堆疊程式設計，或基於堆疊程式設計，是依賴於堆疊機器模型來操縱資料和傳遞引數的程式設計範型。一些程式語言適合這種描述，著名的有 Forth、、 PostScript、BibTeX 樣式設計語言和很多組合語言。 概述 面向堆疊語言運算於一個或多個堆疊之上，每個都充任不同用途。因此，用其他程式語言構造的程式，在面向堆疊系統中使用可能需要修改 Luerweg T 2015 Stack based programming paradigms Concepts of Programming LanguagesCoPL15 33。進一步的說，一些面向堆疊語言運算，採用字尾表示法也稱為逆波蘭表示法，就是說，命令的任何實際引數（argument）或形式引數（parameter），都在這個命令之前陳述。例如，字尾表示法寫為，而非 ，這是字首表示法也稱為波蘭表示法，或者，這是中綴表示法。 基於堆疊演算法 PostScript 是字尾式基於堆疊語言的例子。在這種語言中表達式的一個例子是。計算這個表示式，涉及到理解堆疊導向是如何工作的。 堆疊導向可以用如下傳送帶類比來體現。在傳送帶（輸入）末端，按順序擺放了標記著 2、3 和 mul 的盤子。在傳送帶末端的盤子（2）可以拾取，但其他盤子不能被訪問，直到在末端的盤子被移除。這些盤子只能儲存在一個堆疊中，並且只能在這個堆疊頂上被增加或移除，而不能在中間或底部。可以提供空白盤子（和一個標記者）並且盤子可以永久丟棄。 拾取盤子 2 並把它放置在堆疊上，接著拾取盤子 3 並把它放置在堆疊上，然後拾取 mul 盤子。這是一個要進行的指令。接著從堆疊取走頂部的兩個盤子，將其標籤（2 和 3）相乘，並在一個新盤子上寫下結果（6）。丟棄兩個舊盤子（2 和 3）和盤子 mul，並將新盤子放置在堆疊上。當傳送帶上不再具有更多的盤子，計算的結果（6）就展示在這個堆疊頂上。 這是一個非常簡單的計算。如果是更復雜的計算比如，那麼需要些什麼？如果它最初寫為字尾形式，就是說，計算可以按完全形同的方式進行，並完成出正確結果。計算步驟展示在下面的表格中。每列展示一個輸入元素（在傳送帶末端的盤子），和處理這個輸入之後堆疊的內容： 輸入 堆疊 在處理完所有輸入之後，這個堆疊包含 56，它是答案。 從而可以得出如下結論：基於堆疊的程式語言只有一種處理資料方式，即透過從堆疊頂部選取一塊資料，術語叫做 彈出，和將資料放回堆疊，術語叫 壓入。可以按常規或用其他種類程式語言書寫的任何表示式，可以寫成字尾（或字首）形式，從而服從面向堆疊語言去做出解釋。 堆疊操縱 因為堆疊是在面向堆疊語言中操縱資料的關鍵方式，這種語言通常提供某種堆疊操縱運算元。經常提供的有：dup，重複堆疊頂部元素；exch（或 swap），交換堆疊頂部元素（第一個成為第二個而第二個成為第一個）；roll，迴圈的置換在堆疊中或堆疊一部份上的元素；pop（或 drop）丟棄棧頂元素，還有隱含的 push 等等。這些是在研習過程中的關鍵。 堆疊作用的示意 為了輔助理解語句的作用，使用簡短註釋來展示在這個語句前後的堆疊頂部。如果有多個專案，堆疊的頂部在最右端。這個表示法常用於 Forth 語言，在它那裡的註釋包圍在圓括號內。 之前 之後 例如，描述如下基本 Forth 堆疊運算元： dup a a a drop a swap a b b a over a b a b a rot a b c b c a 還有如下這樣描述 fib 函式： fib n n 它等價於霍爾邏輯的先決條件和後置條件。二者註釋也可以稱為斷言，儘管在基於堆疊語言中無此必要。 PostScript 堆疊 PostScript 和其他一些堆疊語言有用於其他用途的其他獨立堆疊。 變數和字典 已經分析了不同表示式的求值。變數的實現對於任何程式語言都是重要的，但是對於面向堆疊語言，它有著特殊關切，因為這是與資料互動的唯一方式。 在面向堆疊語言比如 PostScript 中實現變數的方式，通常涉及到一個獨立的特殊化了堆疊，它持有鍵 值對的 字典。要建立一個變數，首先必須建立一個鍵（變數名字），具有與之關聯的一個值。在 PostScript 中，一個名字資料物件字首著一個 ，所以 x 是名字資料物件，可以被關聯上舉例的數 42。define（定義）命令是 def，程式碼如下： x 42 def 在堆疊頂部的字典中，將名字 x 關聯於數 42。在 x 和 x 之間存在不同，前者是表示一個名字的資料物件，而 x 表示 x 所定義的東西。 過程 在基於堆疊語言中，過程自身被當作資料物件。在 PostScript 中，過程被指示在 和 之間。例如，在 PostScript 語法中有： dup mul 表示一個匿名過程，它重複在堆疊頂部的東西並接著相乘二者得出結果，這是個求平方的過程。 因為過程被當作一個簡單的資料物件，可以定義過程的名字。在檢索到它們的時候，直接執行它們。字典在儲存各種定義的同時，提供了控制作用域的一種方式。 因為資料物件被儲存在最頂部字典，自然出現了一種未預料的能力：在從一個字典查詢一個定義的時候，檢查最頂部字典，接下一直往下。如果在一個不同的字典中已經定義了同名的一個過程，呼叫區域性的那個過程。 典型過程的剖析 過程經常接受實際引數。它們被過程以非常特殊的方式處理，不同於其他程式語言。下面檢視 PostScript 下的一個斐波那契數列程式： fib dup dup 1 eq exch 0 eq or not dup 1 sub fib exch 2 sub fib add if def 在堆疊上使用了遞迴定義。斐波那契數函式接受一個實際引數。首先，它被測試是否為 1 或 0。 假定計算 fib 4，下面分解這個程式的每個關鍵步驟和反映堆疊： 堆疊：4 dup 堆疊：4 4 dup 堆疊：4 4 4 1 eq 堆疊：4 4 false exch 堆疊：4 false 4 0 eq 堆疊：4 false false or 堆疊：4 false not 堆疊：4 true 因為這個表示式求值為真，求值最內層過程： 堆疊：4 dup 堆疊：4 4 1 sub 堆疊：4 3 fib （這裡是遞迴呼叫） 堆疊：4 F 3 exch 堆疊：F 3 4 2 sub 堆疊：F 3 2 fib （這裡是遞迴呼叫） 堆疊：F 3 F 2 add 堆疊：F 3F 2 這是預期的結果。 這個過程不使用命名變數，單純使用堆疊。命名變數可以使用 a exch def 構造來建立。例如 n exch def n n mul，是有命名變數 n 的一個求平方的過程。假定 sq n exch def n n mul def，並呼叫 3 sq，以如下方式分析過程 sq： 堆疊：3 n exch 堆疊：n 3 def 堆疊：空（它已經被定義） n 堆疊：3 n 堆疊：3 3 mul 堆疊：9 這是預期結果。 控制和流程 因為存在匿名過程，流程控制可以自然出現。ifthenelse 語句需要三段資料：條件，如果條件為真要做的過程，和如果條件為假要做的過程。例如在 PostScript 中： 2 3 gt 2 is greater than three 2 is not greater than three ifelse 所進行的幾乎等價於 C 程式碼： if 2 3 printf 2 is greater than threen else printf 2 is not greater than threen 迴圈和其他構造也是類似的。 基於堆疊程式語言 dc Canonware Onyx Factor Forth Joy PostScript 參見 逆波蘭表示法 串接程式語言 引用 Category 程式設計典範