Hatena::ブログ(Diary)

senzogawaのNな日々 このページをアンテナに追加 RSSフィード

2004 | 11 | 12 |
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 12 |
2011 | 01 | 03 | 04 | 05 | 06 |
2012 | 01 | 08 | 09 |
2013 | 02 |

2010-04-17

Luaで定義節命令を呼ぶ場合にdefineresetも使えるようにする

| Luaで定義節命令を呼ぶ場合にdefineresetも使えるようにする - senzogawaのNな日々 を含むブックマーク Luaで定義節命令を呼ぶ場合にdefineresetも使えるようにする - senzogawaのNな日々 のブックマークコメント

 Luaでnumaliasの話題があったが、単に定義節限定命令を呼ぶ記述だと、現行のバージョン*1ではdefinereset時には呼ばれないため、定義されているはずのエイリアスやエフェクトが無かったりして落ちる。

 一応、definereset時も有効化できる方法を書いておく。


 簡単に要点のみを書くと、system.luaにて、以下のような記述とすればよい。

NSExec('luasub game')
function NSCOM_game()
  -- ここから定義節命令を呼び出す処理を書く。
  NSExec('numalias HOGE,0') -- 例
  -- ここまで。
  NSExec('_game')
end
NSCOM_game()

 これで起動時はsystem.lua読み込みにてNSCOM_gameを呼び出し、以降はluasubにてgame命令がフックされて定義節命令を呼んでくれる。

 luasubは一旦登録するとdefineresetでも消えないことを利用した方法だ。


 この方法を応用して狂った処理を仕込むと、NScripter側へ定義節命令を提供できる。

 00.txtと99.txtをプログラマーのものにしてもらうなら使う機会はある・・・かも。

 以下がそのライブラリ*2

http://senzogawa.s90.xrea.com/dl/sample/nscrjack.zip

*1:Ver.2.95にて確認

*2:上述のコードを含め、もちろん未保証。利用は自己責任で。

2010-02-02

notifの落とし穴

| notifの落とし穴 - senzogawaのNな日々 を含むブックマーク notifの落とし穴 - senzogawaのNな日々 のブックマークコメント

 ONScripterの開発日誌を見ての話なので、ちょっと気が引けるが、notifの解釈について気になったので突っ込みついでに。


 NScripterにおけるnotifは、後続の条件式について、論理演算子で区切った式ごとに真偽を反転させる命令なので、「notif 真 & 偽 文」は、ついつい「if not(真 & 偽) 文」のように解釈してくれると期待してしまうが、実際には「if 偽 & 真 文」と同義であり、「notif 真 & 偽 文」の場合、条件式は真とならず、文は実行されない。


 つまり、論理演算子よりも「not」の評価優先度が高く、しかも個別の式に適用される。

 で、「|」は後に追加された演算子だが、上記の「&」が「|」でも同様の評価優先度と考え、「notif 真 | 偽 文」の文は実行されるべきと思う。


 実際にONScripterでの該当箇所のソースを見ると、andの場合は各式を反転しているのに対し、orの場合は論理演算後の結果を反転している。

 余計なお世話だろうが、ソースとしては以下のようになるはず。


// ScriptParser::ifCommand()より抜粋
    	f = if_flag ? f : !f;
        condition_flag |= f;
        // (中略)
        if (condition_status == 2 && !condition_flag || 
            condition_status != 2 && !f) 
            return RET_SKIP_LINE;

 ただ、実はNScripterも動作が怪しく、「notif 真 | 偽 文」は実行されるのに、「notif 偽 | 真 文」は実行されない。

 また、「notif 偽 | 真 | 偽 文」が実行されるのに、「notif 偽 | 偽 | 真 文」でも実行されないため、おそらく最後の式の結果に依存しているのではないかと思われる。末尾に検証スクリプトを書いておく。

 とはいえ、notifは結構古いので、今後サポートされるのかどうかは不明だ。


 以上の通りだが、notifには最初えらく戸惑った覚えがある。

 はっきり言ってややこしいので、論理演算を使う場合はnotifを使わないことをお勧めする。せっかく論理和演算子の追加により、ド・モルガンの法則を使ってすっきり反転して書けるようになったんだし。


 以下は検証コード。

*define
game
*start
mov %0,1
mov %1,1
mov %9,0
; 0,0
if %0==0 & %1==0 puttext "if 0 & 0 偽"
notif %0==0 & %1==0 puttext "notif 0 & 0 真":inc %9
if %0!=0 & %1!=0 puttext "if !0 & !0 真":inc %9
notif %0!=0 & %1!=0 puttext "notif !0 & !0 偽"
; 1,0
if %0==1 & %1==0 puttext "if 1 & 0 偽"
notif %0==1 & %1==0 puttext "notif 1 & 0 偽"
if %0!=1 & %1!=0 puttext "if !1 & !0 偽"
notif %0!=1 & %1!=0 puttext "notif !1 & !0 偽"
; 0,1
if %0==0 & %1==1 puttext "if 0 & 1 偽"
notif %0==0 & %1==1 puttext "notif 0 & 1 偽"
if %0!=0 & %1!=1 puttext "if !0 & !1 偽"
notif %0!=0 & %1!=1 puttext "notif !0 & !1 偽"
; 1,1
if %0==1 & %1==1 puttext "if 1 & 1 真":inc %9
notif %0==1 & %1==1 puttext "notif 1 & 1 偽"
if %0!=1 & %1!=1 puttext "if !1 & !1 偽"
notif %0!=1 & %1!=1 puttext "notif !1 & !1 真":inc %9
itoa $9,%9
mesbox $9+"/4","真の数"
\
mov %9,0
; 0,0
if %0==0 | %1==0 puttext "if 0 | 0 偽"
notif %0==0 | %1==0 puttext "notif 0 | 0 真":inc %9
if %0!=0 | %1!=0 puttext "if !0 | !0 真":inc %9
notif %0!=0 | %1!=0 puttext "notif !0 | !0 偽"
; 1,0
if %0==1 | %1==0 puttext "if 1 | 0 真":inc %9
notif %0==1 | %1==0 puttext "notif 1 | 0 真":inc %9
if %0!=1 | %1!=0 puttext "if !1 | !0 真":inc %9
notif %0!=1 | %1!=0 puttext "notif !1 | !0 真":inc %9
; 0,1
if %0==0 | %1==1 puttext "if 0 | 1 真":inc %9
notif %0==0 | %1==1 puttext "notif 0 | 1 真":inc %9
if %0!=0 | %1!=1 puttext "if !0 | !1 真":inc %9
notif %0!=0 | %1!=1 puttext "notif !0 | !1 真":inc %9
; 1,1
if %0==1 | %1==1 puttext "if 1 | 1 真":inc %9
notif %0==1 | %1==1 puttext "notif 1 | 1 偽"
if %0!=1 | %1!=1 puttext "if !1 | !1 偽"
notif %0!=1 | %1!=1 puttext "notif !1 | !1 真":inc %9
itoa $9,%9
mesbox $9+"/12","真の数"
\
end

2009-10-22

luasub、luacallの自動化

| luasub、luacallの自動化 - senzogawaのNな日々 を含むブックマーク luasub、luacallの自動化 - senzogawaのNな日々 のブックマークコメント

 第二弾として、ちょっと便利なプチメタプログラミングを。

 luasub、luacallを書くのは面倒なので、以下のおまじないをsystem.luaの末尾*1に記述すると、漏れなく呼び出せる。

for k,v in pairs(_G) do
  if k:match('^NSCALL_') then
    NSExec('luacall ' .. k:sub(8))
  elseif k:match('^NSCOM_') then
    NSExec('luasub ' .. k:sub(7))
  end
end

 要するにグローバルで定義しているNSCALL_とNSCOM_で始まるキー名は未定義の命令とみなしてガシガシ定義してしまえという、ちょいと乱暴なやり口。


 実用としては、起動が遅くなったり、重複定義してしまったりで微妙なところだけど、ちょっとしたものを書くのは楽。

 より厳密にするなら値の型チェックや定義名の書式チェックを追加するといい。

*1:module関数を書いた場合はその直前行。