いままでのあらすじ
プログラミング経験の無い友人と通話していたところ、彼は「文言」(漢文プログラミング言語)でプログラミングを始めてしまいました。これは3割ぐらい私のせいなので、責任を取って私も始めることにしました。
公式サイトを見たところ、
wenyan currently compiles to JavaScript, Python, or Ruby, and will support more languages (e.g. C) in the future.
と書いてあったので、「よし、じゃあRustへのコンパイラを書くか。Rustで。」という気持ちになりました。ということでそれを書いています。GitHubリポジトリはこちら。2020年7月22日現在、愛おしい教科書の「算術第三」まではコンパイルできるようになっています。
内容
今回は、これを実装する上で「仕様を読まずに空気を読む」で組んだ結果だいぶ仕様の理解に苦労し、最終的に教科書(の「變數第二」)に答えの書いてあった仕様である、「獺祭」について解説していきたいと思います。
前提知識
『はじめてのプログラミングを「文言」(漢文プログラミング言語)で 1日目』は読んできていることを前提とします。もしくは原文の明義第一。
「獺祭」?
日本では酒の名前として有名ですね1。なぜそれが仕様の名前なのでしょうか。
実は「獺祭」または「獺祭魚」というのは礼記に出てくる言葉で、自分が捕まえた魚を並べるカワウソの習性を祭り供え物(Mag462さんご指摘ありがとうございます)に喩える用語だそうです。これから解説する仕様は「變數第二」の末尾に説明されているのですが、この「獺祭」の典故を知らないと意味が取れません。私に漢籍の教養がないことを恥じるばかりです。
教科書読解
さて、読んでいきましょう。文脈としては、
加一以三。加六以九。名之曰「甲」。曰「乙」。
と書くことによって変数「甲」に1+3、「乙」に6+9が入る、という説明がされた後で、
凡未名之變數。皆如獺祭然。言
其
者。取至近之魚而棄其餘。言書之
者。盡書之。言名之
者。取若干而名之。曰。然也。善哉此比。問曰。每有未名者。輒祭如是。豈非終累累然焉。今欲盡棄其魚。復當作何書。曰。當書
噫
。噫
者。嘆辭也。所以嘆彼之盡棄也。
という記述があります。先程の典故を踏まえると意味を取ることができて、
- 名前のついていない変数は、カワウソが魚を並べるように並んでいる。
-
其
は、最も近くの魚(=名前のついていない変数)を取って残りを捨てる。 -
書之
は、これ(=並んでいる魚)を全て書く。 -
名之
は、何個かを取ってこれを名付ける。 - 魚を捨てたいときには、
噫
と書け
ということが書いてあります。
先程の例を見ると、
加一以三。加六以九。名之曰「甲」。曰「乙」。
は加一以三。
で魚4
が並べられ、加六以九。
で魚15
が並べられ、名之曰「甲」。曰「乙」。
で魚2匹が消費され変数「甲」と変数「乙」に値が代入される、ということです。
例
せっかくなので、幾つか例を見ていきましょう。
例1
加二以三。加一以三。加三以三。書之。書之。
魚が5
・4
・6
の順に並べられ、最初の書之
がこれらを全て消費し五 四 六
を出力。次の書之
は消費すべき変数がないので空文字列を出力する。
例2
加二以三。加一以八。減其以七。書之。
魚が5
・9
の順に並べられ、次の減其以七
にある其
は川岸から9
を取得して5
を捨てる。よって9
から7
が引かれた2
のみが川岸に置かれるので、書之
により二
が出力される、
例3
加二以三。加一以三。加三以三。名之曰「甲」。曰「乙」。書之
これは、魚が5
・4
・6
の順に並べられ、次の名之曰「甲」。曰「乙」。
によって最も近くの二つである4
と6
がそれぞれ「甲」と「乙」に。川岸にはまだ5
が残っているので、それを書之
が出力する。
例4
加一以三。加六以九。名之曰「甲」。名之曰「乙」。
これは先程見た 加一以三。加六以九。名之曰「甲」。曰「乙」。
に非常に似ているが、なんと挙動が異なる。今回は魚4
と魚15
が並べられたあと、名之曰「甲」。
が最も近くの魚を一つ消費するので、「甲」には15が入り、次の名之曰「乙」
で「乙」に4が入る。
紛らわしい。私はこれで1回バグらせた。
例5
加一以三。加二以三。減其以其。書之。
これは4
と5
が川岸に置かれたあと、減其以其
の最初の其
は5
を取得し、同時に魚を全部捨てる。よって次の其
は何も取得できない2。結果として計算は上手く行かず、不可算數
かなんかが出力される。
例6
吾有一言。曰「「天地。」」。
為是三遍。
書之。
吾有一言。曰「「問天地好在。」」。書之。
云云。
まず文字列「「天地。」」を川岸に置いたあと、ループが始まり、直後に書之
がある。これは川岸に置かれた列「「天地。」」を指し、これを指し続ける。結果、出力されるのは
天地。
問天地好在。
天地。
問天地好在。
天地。
問天地好在。
となる。
余談(というか愚痴)
JavaScriptくんで自由に使える undefined
とかいうものの意味論をRustに移すのがわりとつらいです。ReferenceErrorが実行時にcatchできるのもつらそうです。吾有一言。名之曰三。
を本家実装くんが平気でvar 3 = "";
とかコード生成してくれるのもつらいです。issue・プルリクお待ちしています。