今回作成する言語の名前は、「crowbar」とします。
crowbarというのは、四葉のを見つけるといいことがある植物のことではなく (それはclover)、こんな形をした工具のことです。
命名の由来ですが、今回作る言語は、解析木を作成しそれを実行する、 という点において、Perlと似たような位置付けにある言語です。
というわけで、つまりアレです。ニュースなんかでよく聞く、
パールのようなもの
ということでcrowbarと名付けました。あっ、石を投げないでっっ!!
現時点のcrowbar(Ver.0.1)では、変数が使え、 条件分岐、ループ等が記述できますが、 データ型は整数型、実数型、文字列型だけで、 配列もなければ、正規表現による文字列処理の機能も、 オブジェクト指向な機能もありません。
こんなのでPerlのようなものとか言ったら怒られそうですが ――ごもっともです。すみません。ネタを思いついちゃったもので。
私自身、crowbarを「すごく画期的で、使いやすくて、 生産性の高い言語」だとか思っているわけではありませんし、 将来的にそうするつもりもさほどありません。 crowbarはあくまでサンプル言語です ※1。 興味を持たれた方は、 crowbarのソースをベースに「俺言語」を作ってみてはいかがかと (改造も再配布も自由です。ライセンスを参照のこと)。
crowbarの文法は、この記事を読む人が慣れた言語ということで、 ある程度Cを踏襲するようにしました。
私としては、代入演算子はやっぱり:=だよね、とか思わなくもないのですが (こういう問題は、実際にはほとんど「慣れ」 の問題でしかないとも思っていますが)、 crowbarにおいてはそういう「こだわり」は控えたつもりです。 ――それにしちゃ、if文とかの( )がないのはかなりアレですが。 近い将来直すかも。
crowbarで使用可能なデータ型は、以下のとおりです。
現時点では、配列や連想配列やクラスやオブジェクトはありません。
また、論理型もないので、整数型で代用しています。 整数型の0が偽、それ以外の整数は真となります。 if文の条件式など、論理型が必要なところに、 整数型以外の式を書くとエラーになります。
crowbarは、Perl, Rubyなどと同じく、 静的な型付けのない(変数に型がない)言語です。
いやその私自身は、 どちらかというと「 型なし言語逝ってよし!」的な立場に立つものですが、 今回はサンプルということで、 あえて意に沿わない方の言語を作ってみました (^^;
crowbarでは変数宣言は不要であり、最初の代入が宣言を兼ねます(Rubyを真似ました)。 代入されていない変数をいきなり参照するとエラーになります。
変数の字句規則は、Cなどと同様で、 英字で始まり2文字目以降には英数字が使えます。 アンダースコアは英字と同様に使えます。 Perl等とは異なり、先頭に$等を付ける必要はありません。
また、関数内で初めて代入された変数は、ローカル変数になります。 ローカル変数の寿命は、その関数を抜けるまでです。
関数内で、新しいローカル変数を作るつもりで「a = 0」のように書いても、 同名のグローバル変数が存在していると、 単なる「グローバル変数aへの代入」とみなされますから注意してください ※2。
ローカル変数のスコープは「ブロック」ではなく「関数」です。 また、変数は代入が実行された時点で宣言されるので、 以下のような例では、
if a == 10 { b = 10; } print("b.." + b);
aが10の時だけbが宣言され、printで表示可能です。 もしaが10でなければ、未定義変数エラーになります ※3。
crowbarには、Cなどと同じく、if文、while文、for文等があります。
C, C++, Javaといった言語と大きく異なるのは、以下の点です。
具体的には、以下のような体裁になります。
# if文の例 if a == 10 { # a == 10の時に実行される } elsif a == 11 { # a == 11の時に実行される。 } else { # a が10でも11でもない時に実行される。 } # while文の例 while i < 10 { # i が10より小さい間、ここを繰り返す。 } # for文の例 for i = 0; i < 10; i = i + 1 { # ここを10回繰り返す。 }
――正直、中括弧の使用を強制するところまではともかく、 ( )まで無くしてしまったことで、 CやらJavaやらに慣れた人(私を含む) には違和感ありまくりの言語になってしまった気もします。 まあ、ifやwhileなら、条件式を()で囲んでも同じ意味になるからよいですが、 forはそれもできませんし。
中括弧の使用を強制している以上、構文的にこの場所の( )は無駄です。 だったら取ってしまった方がすっきりして良いじゃないか、 と思うわけですが、実際には「慣れ」の要素も大きいようです。 あるプログラミング言語が世間で広く使われるかどうか、 なんてことには、こんなことが結構強く影響しているようにも思います。
また、crowbarでは、以下の文を使うこともできます。意味はCと同じです。
breakやcontinueには、 Javaのようにラベルを付けられるようにしようかとも思ったのですが、 面倒なのでまだやってません。簡単にできるはずですが。
まず、crowbarでは以下の定数式を記述できます。
また、変数も式です。
これらを演算子で結合して式を構築します。 当然ですが括弧も使えます。
crowbarで使える演算子は以下の通りです (優先順位順に並べてあります)。
(単項の)- | 符号の反転 |
* / % | 乗算、除算、剰余 |
+ - | 加算、減算 |
> >= < <= | 大小比較 |
== != | 同値比較 |
&& | 論理AND |
|| | 論理OR |
= | 代入 |
%は、実数に対しても適用可能で、その場合内部的にfmod()が呼び出されます。
また、==, !=, >, >=, <, <= といった類の演算子は、 条件が真であった場合は整数の1を、偽であった場合は0を返します。
Cなどでもそうですが、crowbarにも、負の数を表現する定数はありません。 負の数を使いたい場合には、単項演算子「-」を使います。 Cなどと違い、&&, ||は短絡演算子にはなっていません。 これも単なる手抜きの結果です。
関数定義は、以下のような形式になります。
function hoge(a, b) { c = a + b; print("a+b.." + c + "\n"); return c; }
関数定義は、プログラム中、文の途中でさえなければどこに書いても構いません。
関数にreturn文が存在しない場合、 その関数は特別な定数であるnullを返します。 nullは、今のところ、比較に使えるわけでもなく、何の役にも立ちませんが、 いずれ参照型を導入する際に使おうと思っています。
crowbarには最初から用意されている組み込み関数があります。 一覧は以下の通りです。
print(arg) | argを表示する。argの型は、整数、実数、文字列のいずれでも可。 |
以上!
って、ひとつしかないのに「一覧」もクソもないですな。
crowbarでは、#から行末まではコメントです。 Cに似せるなら/*〜*/かとも思うんですが、やっぱりスクリプト言語ですしねえ。
crowbarインタプリタは、ひとつの実行形式だけで動作しますので、 PATHの通ったところに実行形式を配置してもらえれば、 それだけで実行可能です。
実行は、以下のようにして行ないます(%はプロンプトだと思ってください)。
% crowbar hoge.crb
「hoge.crb」が、crowbarによるプログラムが記述されたファイルです。
今のところ、crowbarには対話的な実行モードはありません。
ここで書くべきことかどうかは疑問ですが、 crowbarはもともとアプリケーション組み込み言語としての用途をそれなりに 考えているつもりなので、Cとの連携方法について書いておきます。
crowbarインタプリタは、Cのプログラムから呼び出すことができます。
以下は、現状のmain.cの記述とほぼ同等なコード片です。 これらの関数を呼び出すためには、CRB.hを#includeする必要があります。
CRB_Interpreter *interpreter; FILE *fp; /* 中略 */ /* crowbarインタプリタを生成 */ interpreter = CRB_create_interpreter(); /* FILE* を引数に渡して解析木にコンパイル */ CRB_compile(interpreter, fp); /* 実行 */ CRB_interpret(interpreter); /* 実行が終わったらインタプリタを破棄 */ CRB_dispose_interpreter(interpreter);
crowbarのソースからmain.cを抜いて、適当にリンクすればよいはずです。
crowbarには現状で組み込み関数がひとつしかありませんが、 crowbarから呼び出せるようなC関数を書くのは比較的容易です。
まず、組み込み関数作成者向けのヘッダファイルCRB_dev.hを#include した上で、以下のような形式の関数を書きます。
CRB_Value hoge_func(CRB_Interpreter *interpreter, int arg_count, CRB_Value *args) { … }
ここで、arg_countが引数の数、argsは引数を格納した可変長配列です。 CRB_Valueの定義については、CRB_dev.hを参照してください。
そして、この関数を、CRB_add_native_function()関数により、 インタプリタに登録します。 具体的な方法については、interface.cを参照してください ※4。