kmizuの日記

プログラミングや形式言語に関係のあることを書いたり書かなかったり。

Fortressのお話(あるいは、2007年1月のとあるWeb日記)

昨日、内輪でチャットしているときに、ふと、学部生~修士時代の自分のWeb日記(tDiary)を見てみたくなって、色々発掘してたら、面白いものが出てきてので、張り付けていこうと思います(ほとんどが駄文なので、なんか考古学的に(?)意味があるやつだけ載せる予定です)。で、今日載せるのはFortressの話。当時の日記の文面の原文をそのまま貼っただけなのであれですが、ポシャっちゃったFortressがどういう試みをしていたかという観点で興味深いかなと思います。なお、今の自分に比べて考察とか未熟なところがありますがご容赦を。あと、ツッコミは歓迎ですが、いかんせん当時の自分の考えなので、細かい理由は忘れてる可能性があります。

Fortressは、普通のプログラミング言語ですから、当然配列を使えるわけです。配列型の変数の宣言構文は次のような感じで、これはまあ全然すごくないというか普通です。ちなみに、ZZ32は32bit整数型です。Fotressの言語仕様をちゃんと読んだわけじゃないので、間違ってる可能性もありますが、とりあえず整数型であることは間違いないようです。

arr :ZZ32[3, 3] (* 3*3の2次元配列を宣言 *)

さて、配列をあらかじめ決まった要素で初期化するのにいちいち順番に代入していくのは面倒ですから、Fortressでも他言語のように配列のリテラル表記を使うことができます。

arr :ZZ32[3, 3] = [ 9 8 7
                    6 5 4
                    3 2 1 ]

改行によって配列の行の終わりを示せるというのは、まあ良いでしょう。面白いのは、配列の要素のセパレータとして空白を使うことができるところです。え、面白く無い?いやいや、前回のFortressに関するエントリに書いたのですが、Fotressではx yのように空白で区切って式を並べて書くことで、乗算を書くことができるのです。Fortressの配列リテラルの中では、通常の計算式を書くことができますから、単純に考えて文法を設計したら、

arr :ZZ32[3, 3] = [ (9 8 7)
                    (6 5 4)
                    (3 2 1) ]

のように解釈されてしまうと思うわけです。で、こんな文法になっているということは、「配列リテラルの中に出現する式」だけを特別扱いしているに違い無いと思い、Rats!で書かれたFortressの文法を読んでいたら、案の定そうなっていました。Literal.ratsファイルから該当すると思われる箇所を引用すると、

Expr Literal =
     openparen w closeparen
     { yyValue = new VoidLiteral(createSpan(yyStart,yyCount)); }
   / yyValue:NumericLiteral
   / yyValue:CharLiteral
   / yyValue:StringLiteral
   / opencurly w a1:Entry a2s:(w comma w Entry)* w closecurly
     { List<com.sun.fortress.interpreter.useful.Pair<Expr,Expr>> elements =
           new ArrayList<com.sun.fortress.interpreter.useful.Pair<Expr,Expr>>();
       elements.add(new com.sun.fortress.interpreter.useful.Pair<Expr,Expr>(a1.getKey(), a1.getValue()));
       for (Entry e : (List<Entry>)a2s.list()) {
           elements.add(new com.sun.fortress.interpreter.useful.Pair<Expr,Expr>(e.getKey(), e.getValue()));
       }
       yyValue = new MapExpr(createSpan(yyStart,yyCount), elements);
     }
   / opensquare w yyValue:RectElements w closesquare ;


/* RectElements ::= NoSpaceExpr MultiDimCons* */
MultiDim RectElements =
     a1:NoSpaceExpr a2s:MultiDimCons*
     { if (a2s == null || a2s.isEmpty())
           yyValue = new MultiDimElement(a1.getSpan(), a1);
       else
           yyValue = FortressUtil.multiDimCons(a1, a2s.list());
     };


/* MultiDimCons ::= RectSeparator NoSpaceExpr */
com.sun.fortress.interpreter.useful.Pair<Integer,Expr> MultiDimCons =
     a1:RectSeparator a2:NoSpaceExpr
     { yyValue = new com.sun.fortress.interpreter.useful.Pair<Integer,Expr>(a1,a2); };

赤字で強調したところがポイントで、おそらく配列リテラル中では「NoSpaceExpr」だけが出現できるということなんでしょう。で、この「NoSpaceExpr」が一体何なのかということですが、これは定義が複雑なのでとりあえず置いておきますが、ただ単に「スペースを含まない式」では無いようです。というのは、スペースで区切った式でも()で囲むことで配列リテラル中に書けるからです。