CompileIt! はC言語を使っている方にも便利なツールです。なんたって HyperTalk でプログラムを組めます。C言語の煩わしさから開放された壮快感は、HyperTalk をネイティブな言語とする人ならきっと分かって貰えると思います。
○ HyperCard 内で全てが完結する
CompileIt! は良くも悪くも「 HyperCard スタック」です。HyperCard 以外のアプリを立ち上げる必要がなく、ターゲットスタックを開いたままで、ソースの編集、コンパイル、インストール、テスト、そしてソース修正の一連の作業が、HyperCard の上で行えます。
○ XCMD に特化している
いわゆる main 関数はなく、普通の HyperTalk のハンドラを書くのと同じようにソースを書くことが出来ます。引数や返値も普通のハンドラと全く同じに書けます。受け取った引数は自動的に必要な型に変換され、HyperCard に値を返す時は CompileIt! が自動的にC文字列を作ります。
○ 変数宣言がない
HyperTalk ですから変数宣言はありません。変数の型は CompileIt! が最適なものを推測して割り当てます。これは諸刃の剣ですが、私にとっては実に快適な環境です。CompileIt! が変数にどのような型を割り当てたのかは、コンパイル後に確認することが出来ます。
○ ToolBox
CompileIt! では、.h ファイル、.o ファイルに相当するものを、スタックである CompileIt! 自身がカードやリソースとして持っています。 void型の関数はコマンドとして、関数型のコールは関数として、普通の HyperTalk のように書くことが出来ます。新しい関数はカードを追加するという形でインストールされます。
○ コールバック
CompileIt! ではコールバックを意識することがほとんどありません。例えば StrToLong を使わずとも、文字列変数をそのまま足し算に用いることが出来ます。変数や定数を式の中で使うとき、あるいは ToolBoxルーチンに渡す時、CompileIt! が自動的にコンバート作業をしてくれます。ただしそのままでは効率が悪いので、多少の最適化をほどこしてやる必要がある場合があります。
○ Pascal構文によるアクセス
参照、逆参照、配列など、HyperTalk に無い構文については、Pascal構文が取り入れられています。もともと変数の型そのものが無いために、配列アクセスでは要素の型を指定して読み書きします。
逆参照オペレータ ... ptr@ handle@@
参照オペレータ ... @var @filter
構造体メンバー ... structRec.member structPtr@.member
配列 ... ptr@.varType[ n ]
------------------- THINK C 版 ------------------- // -------------------------------- // UxGetInputLevel 1.0(TC) // 1998.8.30 // for THINK C 7.1J Osaka10 tab4 // -------------------------------- #include "HyperXCmd.h" #include Sound.h #include SoundInput.h typedef struct { short status; short volume; } LevelMeterRec; void setMyGlobal( XCmdPtr paramPtr, long theValue ); long getMyGlobal( XCmdPtr paramPtr ); /* ---------- main ---------- */ pascal void main( XCmdPtr paramPtr ) { Str255 theStr; OSErr err; char levelMeterOn = 1; long inRefNum; LevelMeterRec levelMeter; ZeroToPas( paramPtr, *paramPtr->params[0], theStr ); if ( theStr[1] == '?' ){ paramPtr->returnValue = PasToZero( paramPtr, "\pUxGetInputLevel() -- get volume / UxGetInputLevel(-1) -- close" ); return; } if ( theStr[1] == '!' ){ paramPtr->returnValue = PasToZero( paramPtr, "\pUxGetInputLevel(TC) XFCN v1.0 1998 UDI" ); return; } if ( StrToNum( paramPtr, theStr ) == -1 ){ inRefNum = getMyGlobal( paramPtr ); if ( inRefNum != 0 ){ err = SPBCloseDevice( inRefNum ); } setMyGlobal( paramPtr, 0 ); } else { inRefNum = getMyGlobal( paramPtr ); if ( inRefNum == 0 ){ err = SPBOpenDevice( "\p", siWritePermission, &inRefNum ); if ( err ){ paramPtr->returnValue = PasToZero( paramPtr, "\pError : Can't Open Sound device" ); return; } err = SPBSetDeviceInfo( inRefNum, siLevelMeterOnOff, &levelMeterOn ); setMyGlobal( paramPtr, inRefNum ); } err = SPBGetDeviceInfo( inRefNum, siLevelMeterOnOff, ( Ptr)&levelMeter ); NumToStr( paramPtr, levelMeter.volume, theStr ); paramPtr->returnValue = PasToZero( paramPtr, theStr ); } } void setMyGlobal( XCmdPtr paramPtr, long theValue ){ Str255 theStr; NumToStr( paramPtr, theValue, theStr ); SetGlobal( paramPtr, "\pgUxGetInputVol", PasToZero( paramPtr, theStr ) ); } long getMyGlobal( XCmdPtr paramPtr ){ Str255 theStr; Handle valueHand; valueHand = GetGlobal( paramPtr, "\pgUxGetInputVol" ); ZeroToPas( paramPtr, *valueHand, theStr ); DisposHandle( valueHand ); return( StrToNum( paramPtr, theStr ) ); } ------------------- CompileIt! 版 ------------------- -- CompileIt! script -- UxGetInputLevel 1.0(Cit) -- 1998.9.05 -- for CompileIt! 2.6 global uData: L -- shared variable function UxGetInputLevel x global gUxGetInputVol -- HyperCard's global if x is "?" then return "UxGetInputLevel() -- get volume / UxGetInputLevel(-1) -- close" end if if x is "!" then return "UxGetInputLevel(Cit) XFCN v1.0cit 1998 UDI" end if if x = -1 then put gUxGetInputVol into myInRefNum if myInRefNum <> 0 then get SPBCloseDevice( myInRefNum ) end if put 0 into gUxGetInputVol return empty end if put gUxGetInputVol into myInRefNum if myInRefNum = 0 then get SPBOpenDevice( "", siWritePermission, myInRefNum ) if it <> 0 then return "Error : Can't Open Sound device" get SPBSetDeviceInfo( myInRefNum, siLevelMeterOnOff, 1 ) put myInRefNum into gUxGetInputVol end if get SPBGetDeviceInfo( myInRefNum, siLevelMeterOnOff, @uData ) put uData.integerType[2] into theResult return theResult end UxGetInputLevel