Stack in Common Lisp

スタックマシンにはスタックが必要。リストで代用しても別にいいが、メモリーの物理的な構造とほとんど同じである配列で試して勉強してみる。
個人的には有限な固定長の「配列」にはとてもとても心理的抵抗がある。単に自分は何かの恐怖症なのかもしれないが。「スタックの適当なサイズ」をとりあえずとはいえ定数として決める、という怖さ。でも、無限のメモリー、ディスク、は、例えそう見えたとしても誰かが用意してくれた安全な枠組みでしかない。あくまで現実に存在するのは有限サイズだ。適切な数値を判断し、決断しなくてはならない。


スタックの大きさをとりあえず適当に選び、
(defvar *max-stack* 200)


スタックを Common Lisp の配列として make-array で作成し、スタックポインタ sp を vm のスロットに加え、スタックの操作を書いた。

(defvar *max-stack* 200)

(defclass vm () ;; stack machine
  ((codes :accessor codes :initform nil)
   (stack :accessor stack :initform (make-array *max-stack* :initial-element nil))
   (pc :accessor pc :initform 0)
   (sp :accessor sp :initform 0)
   (fp :accessor fp :initform 0)
   ))

(defmethod vm-push ((vm vm) n)
  (with-slots (stack sp) vm
    (setf (aref stack sp) n)
    (incf sp)))

(defmethod vm-pop ((vm vm))
  (with-slots (stack sp) vm
    (decf sp)
    (aref stack sp)))

(defmethod vm-top ((vm vm))
  (with-slots (stack sp) vm
    (aref stack (1- sp))))

わざわざ vm をオブジェクトとして表しているためとはいえ、なんて冗長なんだろう。
その点では、C はとても簡潔だ。講義資料 http://www.hpcs.is.tsukuba.ac.jp/~msato/lecture-note/comp2007/ の st_machine.c より抜粋。

#define MAX_STACK 200
int Stack[MAX_STACK];
#define Push(x)	 Stack[Sp--] = (x)
#define Pop	 Stack[++Sp]
#define Top 	 Stack[Sp+1]

配列処理となったら C 言語はとても簡潔で豊かな表記法を持っている。