UWSCでBrainf*ck

UWSCでBrainf*ckのインタープリターを書いてみた。




Brainf_ck.uws

OPTION EXPLICIT

IFB GET_UWSC_NAME = "Brainf_ck.uws" THEN
	IFB LENGTH(PARAM_STR) THEN
		// ジョジョ言語用 http://d.hatena.ne.jp/toyoshi/20100208/1265587511
		Brainf_ck.Dictionary["スターフィンガ"] = ">"
		Brainf_ck.Dictionary["ロードローラ"] = "<"
		Brainf_ck.Dictionary["オラ"] = "+"
		Brainf_ck.Dictionary["無駄"] = "-"
		Brainf_ck.Dictionary["ハーミットパープル"] = "."
		Brainf_ck.Dictionary["新手のスタンド使いか"] = ","
		Brainf_ck.Dictionary["あ・・・ありのまま今起こったことを話すぜ"] = "["
		Brainf_ck.Dictionary["ザ・ワールド"] = "]"
		Brainf_ck.Dictionary["やれやれだぜ"] = ">"
		Brainf_ck.Dictionary["貧弱"] = "<"

		DIM ret = Brainf_ck.Main(PARAM_STR)
		Brainf_ck.Log(ret)
		INPUT("Result:", ret)
	ELSE
		// とりあえず、Hello, world!
		DIM src[] =	"+++++++++[>++++++++>+++++++++++>+++++<<<-]", _
					">.>++.+++++++..+++.>-.------------.<++++++", _
					"++.--------.+++.------.--------.>+."
		Brainf_ck.Log(Brainf_ck.Main(src))
	ENDIF
ENDIF

MODULE Brainf_ck

	const WHILE = "["
	const LOOP = "]"
	const DATA_MAX = 65536

	HASHTBL _mem
	DIM _index
	HASHTBL _while
	DIM _do
	DIM _regex

	PUBLIC HASHTBL Dictionary

	PROCEDURE Brainf_ck
		_regex = CreateOleObj("VBScript.RegExp")
		_regex.Global = TRUE
		_regex.Pattern = "[^-+<>.,[\]]"
		Clear()
	FEND

	PROCEDURE Clear()
		_mem = HASH_REMOVEALL
		_mem[0] = 0
		_index = 0
		_while = HASH_REMOVEALL
		_do = 0
	FEND

	PROCEDURE Log(msg,n=0)
		DIM t = GETTIME()
		msg = G_TIME_HH2+":"+G_TIME_NN2+":"+G_TIME_SS2+"."+G_TIME_ZZ2+" "+msg
		IF n > 0 THEN msg = msg + " (" + (t - n) + ")"
		PRINT msg
	FEND

	PROCEDURE PrivateMove(d)
		IFB _do = 0 THEN
			DIM index = _index + d
			IFB index < 0 THEN
				Log("Error(decrement) " + index)
				index = 0
			ENDIF
			WHILE index >= LENGTH(_mem)
				_mem[LENGTH(_mem)] = 0
			WEND
			_index = index
		ENDIF
	FEND
	PROCEDURE PrivateAdd(d)
		IFB _do = 0 THEN
			d = d + _mem[_index]
			d = d MOD DATA_MAX
			IF d < 0 THEN d = d + DATA_MAX
			_mem[_index] = d
		ENDIF
	FEND
	FUNCTION PrivatePut()
		IFB _do = 0 THEN
			RESULT = CHR(_mem[_index])
		ELSE
			RESULT = ""
		ENDIF
	FEND
	PROCEDURE PrivateGet()
		IFB _do = 0 THEN
			_mem[_index] = VAL(INPUT("0-" + (DATA_MAX - 1)))
		ENDIF
	FEND
	PROCEDURE PrivateWhile()
		IFB _do = 0 AND _mem[_index] > 0 THEN
			_while[LENGTH(_while)] = ""
		ELSE
			_do = _do + 1
		ENDIF
	FEND
	FUNCTION PrivateLoop(code)
		RESULT = code
		IFB _do = 0 THEN
			DIM i = LENGTH(_while) - 1, part
			part = _while[i]
			IFB _mem[_index] > 0 THEN
				RESULT = part + LOOP + code
				_while[i] = ""
			ELSE
				IF i > 0 THEN _while[i - 1] = _while[i - 1] + WHILE + part + LOOP
				part = _while[i, HASH_REMOVE]
			ENDIF
		ELSE
			_do = _do - 1
			IFB _do < 0 THEN
				Log("Error(While - Loop)")
				_do = 0;
			ENDIF
		ENDIF
	FEND

	FUNCTION PrivateTrans(code)
		DIM i
		FOR i = 0 TO LENGTH(Dictionary) - 1
			code = REPLACE(code, Dictionary[i, HASH_KEY], Dictionary[i, HASH_VAL])
		NEXT
		RESULT = _regex.Replace(code, "")
	FEND

	FUNCTION Run(code)
		DIM ret = "", part = PrivateTrans("" + code)
		WHILE LENGTH(part)
			DIM c = COPY(part, 1, 1)
			part = COPY(part, 2)
			SELECT c
				CASE ">"
					PrivateMove(1)
				CASE "<"
					PrivateMove(-1)
				CASE "+"
					PrivateAdd(1)
				CASE "-"
					PrivateAdd(-1)
				CASE "."
					ret = ret + PrivatePut()
				CASE ","
					PrivateGet()
				CASE WHILE
					PrivateWhile()
					c = 0
				CASE LOOP
					part = PrivateLoop(part)
					c = 0
				DEFAULT
					// nop
					c = 0
			SELEND
			IFB LENGTH(_while) AND c <> 0 THEN
				_while[LENGTH(_while)-1] = _while[LENGTH(_while)-1] + c
			ENDIF
		WEND
		RESULT = ret
	FEND

	FUNCTION Main(args[])
		DIM ret = "", i
		FOR i = 0 TO LENGTH(args) - 1
			IFB FOPEN(args[i], F_EXISTS) THEN
				DIM f = FOPEN(args[i], F_READ OR F_TAB), j
				FOR j = 1 TO FGET(f, F_LINECOUNT)
					ret = ret + Run(FGET(f, j))
				NEXT
				FCLOSE(f)
			ELSE
				ret = ret + Run(args[i])
			ENDIF
		NEXT
		RESULT = ret
	FEND

ENDMODULE