UWSCインタープリター
EVAL関数の恐ろしさに気付いたので、インタープリターを作ってみた。
実行すると、InputBoxが出るから、そこにコマンド入れるだけ。
例えば、
- wid:=GetId(GET_FROMPOINT_WIN)
- CTRLWIN(wid,MIN)
とか入れると、1行目の入力時には、何も起きませんが、
2行目入れたところで、1行目入力時にマウスポインタがあった
アプリケーションが最小化されます!
OPTION EXPLICIT Interpreter.Run() MODULE Interpreter DIM __loop = TRUE PROCEDURE Run() // InputBoxの場所を決定する DIM wid = GETID(GET_LOGPRINT_WIN), __x, __y IFB wid <> -1 THEN __x = STATUS(wid, ST_X) __y = STATUS(wid, ST_Y) + STATUS(wid, ST_HEIGHT) IF __x > G_SCREEN_W - 100 THEN __x = G_SCREEN_W - 100 IF __y > G_SCREEN_H - 100 THEN __y = G_SCREEN_H - 100 ENDIF // メイン処理 DIM cmd = "" WHILE __loop Log("> " + cmd) TRY EVAL(cmd) EXCEPT Log(TRY_ERRMSG) ENDTRY cmd = INPUT("?", "", FALSE, __x, __y) __loop = (cmd <> EMPTY) WEND FEND PROCEDURE Log(msg) PRINT msg FEND ENDMODULE
ちなみに、ちょっと独自のIF関数とかFOR関数とかを組み込もうとしたら、こうなった。
むつい。
ま、実用性はありませんな。
OPTION EXPLICIT Interpreter.Run() MODULE Interpreter DIM __loop = TRUE, __x, __y DIM __evalCmd = EMPTY DIM __subMax = 10 DIM __subCond[0], __subTrue[0], __subFalse[0], __subIndex, __subResult PROCEDURE Interpreter() RESIZE(__subCond, __subMax) RESIZE(__subTrue, __subMax) RESIZE(__subFalse, __subMax) DIM i FOR i = 0 TO __subMax __subCond[i] = EMPTY __subTrue[i] = EMPTY __subFalse[i] = EMPTY NEXT FEND PROCEDURE Run() // InputBoxの場所を決定する DIM wid = GETID(GET_LOGPRINT_WIN) IFB wid <> -1 THEN __x = STATUS(wid, ST_X) __y = STATUS(wid, ST_Y) + STATUS(wid, ST_HEIGHT) IF __x > G_SCREEN_W - 100 THEN __x = G_SCREEN_W - 100 IF __y > G_SCREEN_H - 100 THEN __y = G_SCREEN_H - 100 ENDIF // InputBoxの位置を変更したい場合は以下のスレッドのコメントアウトを外す //THREAD CheckPos() // Eval実行スレッド(実行環境相当) THREAD RunEval() // メイン処理 DIM cmd = "" WHILE __loop Log("> " + cmd) DoEval(GetEvalString(cmd), FALSE) cmd = INPUT("?", "", FALSE, __x, __y) __loop = (cmd <> EMPTY) WEND FEND PROCEDURE Log(msg) PRINT msg FEND FUNCTION SetSub(cond,t=EMPTY,f=EMPTY) DIM i FOR i = 0 TO __subMax IF __subCond[i] = EMPTY THEN BREAK NEXT IFB i = __subMax + 1 THEN RESIZE(__subCond, i) RESIZE(__subTrue, i) RESIZE(__subFalse, i) __subMax = i ENDIF __subCond[i] = cond __subTrue[i] = t __subFalse[i] = f RESULT = i FEND FUNCTION GetEvalString(cmd) RESULT = cmd DIM i // コマンドの特殊変換 SELECT TRUE // ?はログ表示 CASE COPY(cmd, 1, 1) = "?" RESULT = "Log(" + COPY(cmd, 2) + ")" CASE COPY(cmd, 1, 3) = "if(" DoEval("__subIndex:=SetSub" + COPY(cmd,3)) i = __subIndex DoEval("__subResult:=" + GetEvalString(__subCond[i])) __subCond[i] = EMPTY IFB __subResult THEN RESULT = GetEvalString(__subTrue[i]) ELSE RESULT = GetEvalString(__subFalse[i]) ENDIF CASE COPY(cmd, 1, 2) = "b(" DoEval("__subIndex:=SetSub" + COPY(cmd,2)) i = __subIndex RESULT = GetEvalString(__subCond[i]) __subCond[i] = EMPTY IFB __subTrue[i] <> EMPTY THEN DoEval(RESULT) RESULT = GetEvalString(__subTrue[i]) ENDIF IFB __subFalse[i] <> EMPTY THEN DoEval(RESULT) RESULT = GetEvalString(__subFalse[i]) ENDIF CASE COPY(cmd, 1, 4) = "for(" DoEval("__subIndex:=SetSub" + COPY(cmd,4)) i = __subIndex DoEval("__subResult:=" + GetEvalString(__subCond[i])) WHILE __subResult DoEval(GetEvalString(__subFalse[i])) DoEval(GetEvalString(__subTrue[i])) DoEval("__subResult:=" + GetEvalString(__subCond[i])) WEND __subCond[i] = EMPTY RESULT = EMPTY SELEND FEND PROCEDURE DoEval(cmd,wait=TRUE) WHILE __evalCmd<>EMPTY; SLEEP(0.01); WEND __evalCmd = cmd IFB wait THEN WHILE __evalCmd<>EMPTY; SLEEP(0.01); WEND ENDIF FEND PROCEDURE RunEval() WHILE __loop IFB __evalCmd <> EMPTY THEN TRY EVAL(__evalCmd) EXCEPT Log(TRY_ERRMSG) //Log(" -> " + __evalCmd) ENDTRY __evalCmd = EMPTY ELSE SLEEP(0.1) ENDIF WEND FEND // InputBoxのOKボタンをフックすれば、座標監視スレッドはいらんけど、面倒 PROCEDURE CheckPos() DIM wid WHILE __loop SLEEP(1) wid = GETID("UWSC - ", "TFInpBox.UnicodeClass") IFB wid <> -1 THEN __x = STATUS(wid, ST_X) __y = STATUS(wid, ST_Y) ENDIF WEND FEND ENDMODULE