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