id:squeakerさんからいただいたSqueak版Metaの使い方に関するメールです。公開してもかまわないとのことですので私が参考にさせていただいた部分を公開させていただきます。
(前略) match:with:というクラス側にあるメソッドがエントリポイントです。それ から、まずテキストからトークンの列を作り、それからそのトークン列をパー ズする、という形でパーザーを書きたい場合のために、parse:with:というメ ソッドも用意されています。 例えば、MMetaTokenizerのtokenというメソッド定義(の文字列)は (MMetaTokenizer sourceCodeAt: #token) string という式で取得できますが、 MMetaTokenizer match: (MMetaTokenizer sourceCodeAt: #token) string with: #tokenize という式を評価すると、この文字列を正しく分解して配列に収めた結果が得ら れます。一つのトークンだけ取り出す実験であれば、例えば MMetaTokenizer match: 'abc' with: #metaName としてもよいでしょう。#tokenを見ると、#metaNameは#tokenの一種であり、 #tokenizeを見ると、#tokenizeは、#tokenの0個以上の列である、と書かれて います。(どの生成規則も、規則内の最後のものを結果として返します。) match:with:の第一引数は、ReadStreamが作れるコレクションなら何でも良 いので、Stringでなくても良いです。 MSqueakParser2の場合、 MSqueakParser2 match: '3 + (4 * 5)' with: #expr を評価すると、独自の構文木が得られます。 独自のパーザーを書く場合は、例えばまずはMTokenizerのサブクラスを作り (インスタンス変数はいらないので以下のように): MTokenizer subclass: #MTest instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Meta-Examples' そこで生成規則を定義してみます。普通のメソッドを定義するようにブラウザ に書けばよいです。例えば、 test ::= $a | $b と書いてacceptすると、testという生成規則が定義できます。ここですでに実 験ができるので、Workspaceに、 MTest match: 'a' with: #test と書いて評価すれば$aが結果として返り(orを表す'|'はどちらかマッチしたものの 結果を自分の結果として返すので) MTest match: 'b' with: #test であれば、$bが結果として返ります。 MTest match: 'c' with: #test であれば、失敗を表すnilが返ります。すべての生成規則は、失敗を意味する ためにnilを返すという約束になっています。 このようにして徐々にテストして行くやり方で、比較的大きな文法も少しず つ作っていくことができると思います。 -- Yoshiki
いつもお忙しいのに丁寧に教えていただきありがとうございました。
メールの通りにJoyParserというクラスを作り、小さな生成規則を作る→試すということをボトムアップ的にやったら数時間で完成できました。自分的にはかなりラクチン&楽しい作業でした。