luaの構文はいけてないので C言語ぽくしよう。
luaは C言語に組み込まれて使われることが多いのに、構文がなぜか pascalライクでいけていないので、
Cライクな構文で書けるように修正してみました。
もちろん、既存の構文でも書くことができます。
両対応です。
コード。ライセンスはご自由に。
https://github.com/rti7743/rtilabs/tree/master/files/asobiba/lua
-- c-like lua function add(x,y) { return x + y } //階乗 function factorial_while(n) { //whileで階乗してみる sum = 1 i = 1 while(i <= n){ sum = sum * i i = i + 1 } return sum } //階乗 function factorial_for(n) { //forで階乗してみる //すまないが、 lua のforを 完全にc-likeにしきれていないんだ sum = 1 for (i = 1 , n , 1 ) { //or for (i = 1 , n ) { sum = sum * i; } return sum } //山川 function yamaorkawa(str) { table = {} //もちろん大丈夫 if (str == "yama") { return "kawa" } else if (str == "kawa") { return "yama" } else { return "nazo"; } } //山川 function yamaorkawa_luastyle(str) if str == "yama" then return "kawa" elseif str == "kawa" then return "yama" else return "nazo"; end end //山川 function yamaorkawa_sjis(str) { if (str == "山") { return "川" } else if (str == "川") { return "山" } return "イミフwww" } //ダメ文字列で出力 print( l_cecho("癒ソニーの表") );
luaの構文はストップワードが上手く設計されており、 C言語風な表記をすると多少コストが掛かります。
これは、lua が {} をテーブルの初期化として利用しているためで、それとのバディングをさけながら構文を解析していかないといけないためです。
ただし、実際に動くようにしてみると、効果は絶大で、C言語になれた人には超読みやすい luaコードができます。
主に、 llex.c と lparser.c の修正になります。
構文パースの部分に大胆に手を入れているので修正範囲は結構広大です。
修正箇所には、c-like とかコメント入れているので、暇な人は見てね。
static void ifstat (LexState *ls, int line) { /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ FuncState *fs = ls->fs; int escapelist = NO_JUMP; /* exit list for finished parts */ int isbraket = 0; test_then_block(ls, &escapelist,&isbraket); /* IF cond THEN block */ if (isbraket) { /* if (){ } else if () { } else { } c-like style */ while(1) { check_match(ls, '}', TK_IF, line); if (!testnext(ls, TK_ELSE)) { break; } if ( ls->t.token == TK_IF ) { /* c-like else if { } */ test_then_block(ls, &escapelist,&isbraket); /* ELSEIF cond THEN block */ if (!isbraket) { error_expected(ls, '{'); } continue; } else { checknext(ls,'{'); block(ls); /* `else' part */ } } } else { while (ls->t.token == TK_ELSEIF) test_then_block(ls, &escapelist,&isbraket); /* ELSEIF cond THEN block */ if (testnext(ls, TK_ELSE)) block(ls); /* `else' part */ check_match(ls, TK_END, TK_IF, line); } luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ }
おまけ機能 SJIS対応
これだけはつまらないので、おまけ機能を2つ入れました。
1つは、SJIS対応です。
フラグを立てることにより、 lau からSJISが制御でもプログラムが書けるようにしました。
UTF-8などを使いたい時は、OFFにすればそのまま行けます。
ちなみに、ディフォルトでオフです。
lua_setmultibyte に 1を渡すだけで SJIS 対応になります。
簡単でしょ?
// Luaを開く lua_State* L = luaL_newstate(); //マルチバイト(SJISとか)が使えるように修正するフラグを作ってみた。 lua_setmultibyte(L,1);
おまけ機能 this引き回しの簡略化
luaでは、 C++コードでの this の引き回しが面倒です。
一度、 userdataテーブルにいれて引き回すといっためんどいことをしなければなりません。
// Luaを開く lua_State* L = luaL_newstate(); //thisのセット lua_pushlightuserdata(L ,(void*) this); lua_setfield(L,"_this"); //thisを使いたいシーンが来たら、 lua_getfield(L,LUA_REGISTRYINDEX,"_this"); myclass* p = (myclass*)lua_touserdata(L,-1); lua_pop(L,1); //p に this が入っているよ!! p->myFunc();
確かに userdata を使うやり方は this 以外にもデータを格納できて汎用性はあるのですが、
ふつーの C++ コードだと this さえあれば、あとはこちら側のコードで実装できますし、 オーバーヘッドのある userdata に値を入れる必要性がどれだけあるのか疑問です。
と、いうことで、 this 専用の領域を作って、関数を追加してみました。
// Luaを開く lua_State* L = luaL_newstate(); //ついでに this 引き回しに使えるフラグを追加してみた。 lua_setusertag(L,(void*)this); //thisを追加したシーンが来たら myclass* p = (myclass*)lua_getusertag(L); //p に this が入っているよ!! p->myFunc();
とても簡単ですね。
C++的には型を void* にしないといけないのがあれですが、template<>とかいっても、 lua は *.c なので諦めましょう。
まー、いいじゃない。
tagという命名にしましたが、これは C++Builder にあやかった名前です。
C#にもあったよね。中の人が同じという噂だけども。