Commits

camlspotter  committed 2025213

section level

  • Participants
  • Parent commits 6cd8a75

Comments (0)

Files changed (1)

 CamlP4 も悲観的入門
 ===============================
 
+=======================
 肝に命じること
 =======================
 
 CamlP4 はオーパーツもしくはロストテクノロジー。全部を理解しようとしてソース本体を読み始めると魂を取られ帰ってこれなくなる。真髄は理解できないものとして、便利に使う、使えなさそうならさっさと諦める、という姿勢が重要。
 
+============================================
 OCaml の文法拡張フレームワークとしてのP4
 ============================================
 
 
 というわけで OCaml の文法を拡張する道具としての P4 についてしか述べない。
 
+=======================================
 どう動作するのか
 =======================================
 
 
 ことになる
 
+=================================================
 Original Syntax, Revised Syntax なんと複雑な!
 =================================================
 
 では Revised syntax を習得するべきか。否。Revised syntax は無視してよろしい。というか無視しろ。この文法は P4 でしか役に立たないので覚えるのは時間の無駄である。Original syntax では Quote が書けなくなるじゃないですか…という人には、Quote を使わなくても P4 は書ける、と答えよう。Revised syntax でうんうん唸るなら書けない、書きにくい Quote が現れたらそこはベタに AST コンストラクタを書く(生書き)。もちろん Quote が書けてそちらの方が簡便な場合は Quote を使おう。それが近道だ。
 
 camlp4, camlp4o, camlp4of, camlp4oof, camlp4orf, camlp4r,  camlp4rf … ナメてんのか!
------------------------------------------------------------------------------------
+======================================================================================
 
 Quote の外と中の言語を上記の Syntax のどちらで書くか、そして reflective であるかどうか(言語拡張が Quote 内部にも適用されるべきか)の違いにより、 P4 には 2x2x2 = 8 種類のバリアントが想定される、そのため P4 には沢山のコマンドがある。君が使うべきはまず一つ、
 
 
 解説: P4 は OCaml コンパイラのプリプロセッサとして動作させることが多い。P4 と ocamlc の間でのソースのやり取りはわざわざ人間に読める OCaml コードを出力する意義は無いのでバイナリで行われる。 出力先がターミナル以外の場合、プリンタを明示しないと P4 がバイナリを吐くのはそのためである。
 
+=============================================
 もう複雑ではなくなったね!
 =============================================
 
 次に進もう。
 
 
+===============================================
 できないことを知ろう
 ===============================================
 
 * Lexer を変更してオレオレリテラル書きたい! => 諦めろ。  えっでも書けるようなドキュメントが => 諦めろ。pa_xxx.cmo を積み重ねる方式の P4 での文法拡張では常にバニラLexerが使用される
 * 型チェックした後の情報から… => 諦めろ。P4 は型付け前、パース段階で AST をいじるフレームワークなので、型付け情報は扱えない。でも… => じゃあ P4 内部で自分で型推論器実装してみればなんとかなるはずなので勝手にやってくれ
 
+=============================
 文法拡張のテンプレート
 =============================
 
 * [重要] 上のテンプレを camlp4temp.ml に保存し ocamlc でコンパイルせよ。コマンドは ocamlc -pp camlp4of -I `ocamlc -where`/camlp4 -c camlp4temp.ml
 * [重要] 上記コンパイルコマンドを一々打ち込まなくても良いよう、自分の使用しているビルドツールのルールを作成せよ。
 
+===================================
 Quotation と Anti-quotation
 ===================================
 
 さて、テンプレに触れたから早速文法拡張に移りたいところだが…その前に Quotation system を見なければならない。少し落ち着け。Quote system とは OCaml 内部で OCaml の syntax tree (AST) を OCaml ソースの形で記述できるようにするための言語内 DSL だと思って良い。AST を簡単にいじるために必須なツールだ。
 
 Quote
---------------------------
+==============
 
 P4 では Quasi-quotation (Quote) が使える。Quote を使えば、言語 AST の内部表現を書く(生書きとでも呼ぼう)代わりに、より人間様に判りやすい言語ソースをそのまま書くことができる。
 
 * let _ = <<[]>> というファイルを作り、 camlp4of で出力して、出力を確認せよ。結果は役に立つのでメモしておくこと。使える expander のリストが手に入った!
 
 Quote が展開される AST の定義
--------------------------------
+=================================
 
 さて、Quote が AST 内部表現に展開される例を見たが、そこで出てくる Ast.ExId やら Ast.IdUid はどこで定義されているか。どのようなコンストラクタがあるか。もっとも簡単な資料は OCaml ソースコードディレクトリ($OCAML と略記)の $OCAML/camlp4/Camlp4/Camlp4Ast.partial.ml である。これは Revised syntax で記述されており、なおかつこのファイル自体が P4 が作成される際にコンパイルされるわけではないのだが、もっとも判りやすい。ここに定義された型名は Quote <:XXX< ... >> のコンテクスト名 XXX として使用できる。
 
 * [重要] これらを camlp4of で展開してどのような AST ツリーになるか確認せよ
 
 _loc とは「例の場所」
--------------------------
+==========================
 
 Quote 展開例でしばしば見られる自由変数 _loc は式の場所を指す。この自由変数はもっと外のパターンで Quote を使っている限り、自動的に束縛されることになっているので Quote を使っている限りは気にすることはない。ただし、 Quote を使わず生書きする場合は少し注意する必要がある。
 
 
 
 テンプレ内部での Quote
------------------------------
+============================
 
 Quote の展開例で見たように、 quote 展開では Camlp4Ast.partial.ml に記述されたコンストラクタが Ast. を付けて使用される。(例えば Ast.PaId) これを P4 文法拡張で使用する際には、テンプレの「文法拡張部」で Ast という名前のモジュールにアクセスできるようになっていなければならない。
 
 * 自由変数 _loc をλ抽象で適当になんとかして再度コンパイルを試みよ
 
 Anti-quotation
---------------------
+====================
 
 Anti-quotation(Anti-quote) は Quotation の中に外部の値を導入するための Quote の中の Quote。
 書式は $ 式 $ と書く。例えば <:expr< $x$ + 1 >> と書けば、x に束縛された expr 型を持つ
 使うのは避けよとは言わないが、注意しておくべし。
 
 Quotation system まとめ
--------------------------
+============================
 
 * Quote が使いづらいと思ったら Camlp4Ast のコンストラクタを生書きすればよい。
 * Quote や Anti-quote の展開がわからなかったら例題を作って camlp4of で実際にどうなるか確かめる
 
 
+=================================
 文法拡張
 =================================
 
 やっと肝心の文法拡張について述べることができる。
 
 P4 パーサーの性質
-----------------------
+=====================
 
-CamlP4 のパーサーは、LALR(1) スタイルによるバニラOCamlの文法定義( $OCAML/parsing/lexer.mll と $OCAML/parsing/parser.mly )とは別に実装された、 LL(?(シラネ)) スタイルのパーサーである。わしはパーサー技術のことはよく知らんから適当なことを今から言うが、CamlP4 が LL という性質の違うパーサ技術を採用しているのは lex/yacc ではダイナミックな変更が難しいからだと思われる。LL は Parsec でみなさんおなじみの通りそのままコードを書けばよろしい。各文法要素をパースする LL の部品に名前をつけておいて、その名前で部品にアクセス、それを消したり、上書きしたり、新しい部品を追加したり…普通の(どちらかというと継承っぽい)プログラミングすたいるが使える。
+CamlP4 のパーサーは、LALR(1) スタイルによるバニラOCamlの文法定義( $OCAML/parsing/lexer.mll と $OCAML/parsing/parser.mly )とは別に実装された、 LL(?(シラネ)) スタイルのパーサーである。わしはパーサー技術のことはよく知らんから適当なことを今から言うが、CamlP4 が LL という性質の違うパーサ技術を採用しているのは lex/yacc ではダイナミックな変更が難しいからだと思われる。LL は Parsec でみなさんおなじみの通りそのままコードを書けばよろしい。各文法要素をパースする LL の部品に名前をつけておいて、その名前で部品にアクセス、それを消したり、上書きしたり、新しい部品を追加したり…普通の(どちらかというと継承っぽい)プログラミングスタイルが使える。
 
 P4 では LL のパーサーを書くためのストリームパターンマッチのための DSL が用意されている。(この特殊文法も P4 で書かれているとかまあ再帰っぽいのでワクワクするかもしれないが時間の無駄なのでさっさと先に進もう)
 
 拡張を伴わない文法ルールの基礎
--------------------------------------------
+=================================
 
 LL ではあるがルール記述は yacc の様なちょっと BNF っぽい書き方ができる DSL が用意されている:
 
 わかりますよね?わからない?えっ、パーサーの基礎も知らずに P4 とか無理ですよ?言わなかったけど。
  
 改造の基本
-----------
+==============
 
 テンプレ、もしくは誰かが書いた pa_XXX.ml からはじめる。スクラッチするのはめんどくさい。
 
 
 
 元の文法はどこに定義されていますか
---------------------------------------
+=======================================
 
 わかりました。では、私が変更することになる大本の OCaml 文法はどこで調べたら良いですか?
 もっともな疑問であるが…正直これが大変であり、P4 の近寄り難さを演出している
 camlp4rf を使ってやれば Revised syntax で書かれているコードをバニラで読むことは出来るのだが… Quote が全て展開されているのでかなりきつい。まあここは Revised syntax を理解してなくても空気で読むしか無い…
 
 Camlp4OCamlParser.ml を眺めよ!!
---------------------------------------------------
+====================================
 
 とこき下ろしたが、実のところ Camlp4OCamlParser.ml は最も複雑な P4 文法拡張なので、ルールの削除や追加の例はこのファイルを眺めるのが最適である。読むなよ!眺めるだけだ!