haXeで作るプログラミング言語(11)

改行で後置括弧演算子を結合しないようにする。

if(a){
  b;
}
{
  c;
}

上の例のようにif文の、後ろに括弧があった場合、ローカルブロックになるのがC言語です。

通常の手法であればif文の後ろにローカルブロックがあるだけとできます。
しかし、今の式ベースの言語のパーサでは{c;}が{}演算子として結合してしまいます。
この状況を改善するためには括弧演算子は改行が間に入ると結合しないという文法にすることにするとうまくいきます。
同じ行で結合させたくない場合は間にセミコロンを入れれば結合させないようにするのです。
セミコロンや改行は必要なときに入れます。
cyanではセミコロンは改行と同じ意味としています。
ただ、C言語系統の言語で改行とセミコロンが同じ意味というのは行き過ぎだと思います。
なぜなら、深く考えることなく複数行に渡って1つの文や式を書けるのがCの特徴であるからです。
Cの流れの中の1つのJavaScriptActionScriptでも、改行がセミコロン的な役割のような感じになっています。
また、短く書くことができるのもC言語の特徴であるように思います。
短く、分かりやすく、複数行に渡って書けて、オフサイドルールはなしで、すべての括弧は演算子として扱えて、
括弧で終わることが多い式となると、改行があった場合のみ例外的に結合しないとするのが妥当であると思うのです。


では、実装していきます。
まず、lexに改行があったかどうかをチェックするような改良をします。

	var ln:bool;
	
	function lex():String {
		var r : EReg = ~/^[\t ]([\r\n]*)[\t \r\n]*([0-9]+|[;\[\]{}()]|[+*\-\/=<>]+|[a-zA-Z_][a-zA-Z0-9]*)/;
		token2 = token;
		if(r.match(src)){
			if(r.matched(1).length > 0) {
				ln = true;
			} else {
				ln = false;
			}

変更箇所だけ見るとこんなかんじです。
lnというメンバ変数を用意して、正規表現の最初の部分の空白を取り除く箇所で、改行のみの行が引っかかるようにします。
そして、改行のみ連続であった場合は、lnをtrueとし、そうでなければlnをfalseにします。
これで改行のチェックはできました。

あとは、括弧演算子結合する箇所でこのフラグが立っていた場合は結合しなくすれば完成です。

			if(opMs.exists(token) && (tagp = opMs.get(token)) >= p) {

このifに!lnであることを追加して以下のようにします。

			if(!ln && opMs.exists(token) && (tagp = opMs.get(token)) >= p) {

あとはCalc11.hxmlを以下のように書き換えて、コンパイル

-main Calc11
-neko Calc11.n
>||

たとえば
>|haxe|
b=2\n ( b)

こんな式を実行してみましょう。

neko Calc11
op(op(sym(b),R=,num(2)),M(),sym(b))

のようにパースされていましたが、

op(op(sym(b),R=,num(2)),@,op(nil,P(),sym(b)))

に変わりました。やった!
ということで、今回は改行を挟むと括弧演算子が連結しなくしました。
しかし、もっといいアイディアがあるかもしれません。
もし、C言語風の式言語でこうするともっといいよというアイディアありましたら教えてください。


PS.いやぁ、やってることは簡単なのだけど一度止まると書き始めるのが大変でした。
動摩擦力係数と静摩擦力係数のような、そんなものが脳の中にも存在するのかもしれませんね。
なんでもかんでも考えてたら何も集中できないから、始めるまでは思考が始まろうとしても
すぐとめるような仕組みがあったほうがいいんでしょうけど。。。