More Related Content
PDF
マイクロサービスバックエンドAPIのためのRESTとgRPC PDF
PDF
PDF
PDF
PDF
PPTX
PDF
What's hot
PDF
PDF
PDF
PPTX
PDF
PPTX
PDF
PPT
PDF
ODP
PPTX
PPTX
PDF
PPTX
【修正版】Django + SQLAlchemy: シンプルWay PDF
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ PDF
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について PDF
PDF
PDF
PPTX
pg_bigmで全文検索するときに気を付けたい5つのポイント(第23回PostgreSQLアンカンファレンス@オンライン 発表資料) Similar to 謎の言語Forthが謎なので実装した
PDF
Electronで作るおれおれマークダウンエディタ2 PDF
PDF
FP習熟度レベルとFSharpxのIteratee PDF
PDF
[Basic 11] 文脈自由文法 / 構文解析 / 言語解析プログラミング PPT
PDF
PFIセミナー 2013/02/28 「プログラミング言語の今」 PPTX
Node.jsでつくるNode.js ミニインタープリター&コンパイラー PDF
PDF
V6 Interpreter (Nagoya Geek Bar 2011-05-02) PDF
コンパイルターゲット言語としてのWebAssembly、そしてLINEでの実践 PDF
PDF
PPT
Impractical Introduction of Boost Spirit Qi [PPT] KEY
Functional Pearl + Brainfuck PPTX
PDF
PDF
Cookpad Summer Intern 2015 - Programming Paradigm PPT
PDF
More from t-sin
PDF
PDF
SECDマシン 実装と動きとその他もろもろについて PDF
Common Lisp製のテキストエディタLemにフレーム多重化機能をつくった PDF
PDF
Sounds Like Common Lisp - ゼロからはじめるサウンドプログラミング PDF
PythonでLispを実装した (evalつき) PDF
バッテリー強奪! PythonをCommon Lispから使う PDF
PDF
One - Common Lispでもワンライナーしたい PDF
Inquisitor -Common Lispに文字コード判定を- 謎の言語Forthが謎なので実装した
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
謎の⾔語、Forth 2/5
典型的なForth の実装には、LISPにおけるRead–eval–print
loop(英語版)(REPL)に対応する、⼊⼒されたワードを即
座に実⾏する対話型のインタプリタモードと(これは、正規
のオペレーティングシステムがないシステム向けのシェルに
も適している)、後の実⾏のために⼀連のワードをコンパイ
ルするモードのふたつのモードがある。後者にはコロン(:)
というワードにより遷移しセミコロン(;)というワードで脱
する。
─ 『Forth』, Wikipediaより
- 12.
- 13.
謎の⾔語、Forth 4/5
なぞすぎるプロダクト群…
1991 -http://www.1-9-9-1.com/
Forthで書かれたHTTPサーバー
なぜかコードがすごくちいさい
forsh - https://bitbucket.org/cowile/forsh
Forthで書かれたシェル
もちろん後置記法
fmacs - https://github.com/larsbrinkhoff/fmacs
Forthで書かれたEmacs
どういうこと??
- 14.
- 15.
- 16.
- 17.
- 18.
プログラム例1
1 + 2* 10 を計算
// スタック: []
1
// スタック: [1]
2
// スタック: [2 1]
10
// スタック: [10 2 1]
*
// スタック: [20 1]
+
// スタック: [21]
- 19.
- 20.
- 21.
プログラム例3 2/7
前提: ufの持つ命令(⼀部)
スタック操作ワード
swap(2要素交換), dup (複製), rot (先頭要素と3番⽬を
交換), drop (削除), over (2番⽬の要素を先頭に複製)
I/Oワード
. (スタックトップを出⼒), .s (スタックをデバッグ出⼒)
数値演算・⽐較ワード
+ , - , * , / , = , <
論理演算ワード
and , or , not
- 22.
- 23.
プログラム例3 4/7
<= 使⽤例
(<=20 21) → t を計算
21 20
// スタック: [20 21]
<=
// 上の定義の⼀語め (over)にジャンプ
// 引数を複製する
over
// スタック: [21 20 21]
over
// スタック: [20 21 20 21]
// Forthは偽が0、真が0以外
<
// スタック: [-1 20 21]
(つづく)
- 24.
プログラム例3 5/7
<= 使⽤例(つづき)
//スタック: [-1 20 21]
rot
// スタック: [21 20 -1]
swap
// スタック: [20 21 -1]
=
// スタック: [0 -1]
or
// スタック: [-1]
// ワードの終わりが来たので<=呼び出し位置にジャンプ
;
- 25.
- 26.
- 27.
- 28.
実装: パーサ
スペース以外の⽂字で区切って切り出し、リストに溜める
ついでに数値はCLの数値に変換しておく
(defun parse(stream)
(let (code buf atomp numberp)
(flet ((read-atom (ch)
...))
(loop
:for ch := (read-char stream nil :eof)
:until (eq ch :eof)
:do (case ch
(#space (terminate-atom))
(#newline (terminate-atom))
(t (read-atom ch)))
:finally (progn
(terminate-atom)
(return (nreverse code)))))))
split-sequence を使えばほぼ⼀撃ですねこれ(今きづいた
- 29.
実装: ワードまわり
ワードの構造体と実⾏状態の構造体をつくる
(defstruct wordname fn start system-p)
(defstruct vm code ip dict stack
rstack ifdepth skip-to debug-p)
ディクショナリは word のリスト
find とか push で探索や追加を⾏う
通常はスタック2本(データ・呼び出し)でよいが、
インタプリタとするにはifのネストを読み⾶ばすために3本⽬
が要る
- 30.
- 31.
実装: 解釈器2/2
if で実⾏しない部分(if がネストし得る)を読み⾶ばす
if ⽂スキップ
if だったら→ネスト数を1加算
then だったら→ネスト数を1減算
もしスキップ開始時のネスト数と今のネスト数が同じな
ら
→スキップ処理終了
それ以外→読み⾶ばす
- 32.
実装: ワード定義1/2
ufでは :によるワードの定義も解釈時に⾏う
基本的には、
1. : がきたら、
2. 名前を読み取り、
3. プログラム開始位置を覚え、
4. ; まで読み⾶ばし、
5. 名前と開始位置から word 構造体をディクショナリに push
という流れ
: ... ; のネストは不可
これはForth 2012の仕様でも同様
「コンパイルモード時にコンパイルモードに⼊る」の排除か
- 33.
実装: ワード定義2/2
だいたいこんなコードです(ハミ出る)
(defun define-word(vm)
(let ((name (get-atom vm)))
(when (null name)
(error "invalid word definition : it doesn't have a name.
(let ((start-pos (vm-ip vm)))
(loop
:for atom := (get-atom vm)
:until (eq atom 'uf/dict::|;|)
:do (when (null atom)
(error "invalid word definition '~a': it doesn't
(let ((word (make-word :name name :system-p nil :start
(let ((w (find name (vm-dict vm) :key #'word-name)))
(if (and (not (null w)) (word-system-p w))
(error "cannot overwrite the predefined word: ~s"
(push word (vm-dict vm))))))))
- 34.
実装: 初期ワード定義
. (出⼒)とか+ とかを実装していく
ここはひたすら気合いです
;; I/O
(defword (|.|)
(format t "~a" (pop (vm-stack vm))))
(defword (|cr|)
(terpri))
(defword (|emit|)
(format t "~a" (code-char (pop (vm-stack vm)))))
(defword (|.s|)
(format t "~s" (vm-stack vm)))
;; stack maneuvers
(defword (|swap|)
(let ((o1 (pop (vm-stack vm)))
(o2 (pop (vm-stack vm))))
(push o1 (vm-stack vm))
(push o2 (vm-stack vm))))
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.