Code archives/Miscellaneous/BriskVM invoker as function pointers

This code has been declared by its author to be Public Domain code.

Download source code

BriskVM invoker as function pointers by GW2015
This program will read an already generated invoker file and convert it to one that uses function pointers, giving a large speed boost.
It does not overwrite the original invoker file.ead in an existing invoker file and will spit out a copy that internally uses function pointer.
Rem
	BVM invoker converter by AWoodard 2014 (admin at kerneltrick.com)
EndRem

SuperStrict 
Framework brl.retro 

Local aa$[] = AppArgs[..]	'// for debugging

Global outStream:TStream 

If AppArgs.Length <> 2 Then 
	Print "Usage: BVM_Converter <invoker.bmx>"	
	End
EndIf

outstream =  WriteFile(StripExt(AppArgs[1]) + "_" + ".bmx" )

reprocess(AppArgs[1])
'------------------------------------------------------------------------------------------------------------
Function _Print(s$)
	WriteString(outStream,s+"~n")	
End Function
'------------------------------------------------------------------------------------------------------------
Function reprocess( file$)
	Local invokertext$	'raw text
	Local aLines$[]		'invoker text split by line
	Local startline%	'start of invoke function 
	Local endline%		'end of select/case 
	Local startSelect%	'line of 'Select ret%"
	Global firstLine$ = "Function BVM_Invoke%(withTimeOut% = False)"
	Local maxIndex% = 0
	Local Locals$[]
	Local cases:TList = CreateList()
		
	If Not FileType(file)=1 Then RuntimeError("Not a valid invoker file! " + file)
	invokertext = LoadText(file)
	aLines = invokertext.split("~n")
	
	startline = find_string(aLines, firstline)
	If Not startline Then RuntimeError("Cant Find function def!")
	
	endline = find_string(aLines, "End Function", startline+1 )
	If Not endline Then RuntimeError("Cant Find end block!")
	
	startselect = find_string(aLines, "Select ret%")
	
	maxIndex = FindMaxIndex(aLines, startline, endline)	'// find the largest case value

	Locals = GatherLocals(Locals, aLines, startline, endline)	'wtf!? 'Locals' array is not passes by ref?!
	

	'// write pre
	For Local i% = 0 Until startline	'// write out the file before our mods
		_Print(aLines[i])
	Next
	
	_Print "Function Err2%()"
	_Print "	BVM_SetLastError(BVM_ERR_ERROR%, ~qFatal error : unknown command of id ~q + BVM_IntToStr(tBVMf.ret))" '+ ", the invoker seems To be out of sync with the 'Test' command set")"
	_Print "	BVM_ReportDebugError(BVM_GetLastErrorMsg())"
	_Print "	Return 0"
	_Print "End function~n"


	_Print "Function BVM_FP_run%(index%)"
	_Print "	Local tmpfunc%() = tBVMf.FP[index]"
	_Print "	return tmpfunc()"
	_Print "End Function~n"

		
	_Print "Type tBVMf"
		_Print "~tGlobal hasInit%=0"
		_Print "~tGlobal withTimeOut%"
		_Print "~tGlobal FP:byte ptr["+(maxindex+1)+"]"
	'// Get locals from func
		For Local s$ = EachIn locals 
			_Print "~tGlobal " + s
		Next
		
	''Print "~t'GLOBALS"
	
	
	Local block$[]
	For Local i% = 0 Until MaxIndex 
'		Print i
		block = GetBLockContents(aLInes, i, startline, endline ) 
		If block.length Then 
			WriteFuncBlock(i,block)
			cases.AddLast(String(i))
		End If
	Next
	
	'// set all the pointers to the ERR function at start
	_Print "	Function Init()"
		_Print "~t~tFor Local i% = 0 Until "+maxindex
		_Print "~t~t~tFP[i]=Err2"
		_Print "~t~tNext"
		
		'// now just replace the ones we use
		For Local s$ = EachIn cases
			_Print "~t~tFP["+Int(s)+"] = tBVMf._bvmf_" + Int(s)
		Next
	_Print "	hasInit=1"
	_Print "	End Function~n"
	

	
	_Print "End Type"
	
	_Print firstline
	_Print "local ret%"
	_print "tBVMf.withTimeOut%=withTimeOut"
	_print " if not tBVMf.hasInit then tBVMf.init()" 
	_Print " Repeat" 
	_Print "	If withTimeOut% Then"
	_Print "		ret% = BVM_RunWithTimeOut()"
	_Print "	Else"
	_Print "		ret% = BVM_Run()"
	_Print "	End If"
	_Print "	tBVMf.ret = ret"
	_Print "	Select ret"
	_Print "		Case 0"
	_print "			BVM_FlushDebugLog(); Return 1"
	_Print "		Case 1"
	_Print "			If withTimeOut% Then"
	_Print "				Return -1"
	_Print "			Else"
	_Print "				BVM_ReportDebugError(BVM_GetLastErrorMsg())"
	_Print "				Return 0"
	_Print "			End If"
	_Print "		Case -1"
	_Print "			BVM_ReportDebugError(BVM_GetLastErrorMsg())"
	_Print "			Return 0"
	_Print "		Default"
	_Print "	'		If Int(tBVMf.FP[ret]) <> 0 Then"
	_Print "				BVM_FP_run(ret)"
	_Print "	'		Else"
	_Print "	'			BVM_SetLastError(BVM_ERR_ERROR%, ~qFatal error : unknown command of id ~q + BVM_IntToStr(ret%))" '+ ", the invoker seems To be out of sync with the 'Test' command set")"
	_Print "	'			BVM_ReportDebugError(BVM_GetLastErrorMsg())"
	_Print "	'			Return 0"
	_Print "	'		endif"
	_Print "	End Select	"
	
	'_print "	if ret = 0 then" 
	'_print "		BVM_FlushDebugLog(); Return 1"
	'_print "	EndIf"	
	
	'_Print "	if ret = -1 then"

	'_Print "	EndIf"
	
	_Print " Forever"
	_Print "End Function~n"
	
	For Local I% = endline +1 Until aLines.Length
		_Print aLines[i]
	Next
	
End Function
'------------------------------------------------------------------------------------------------------------
Function GatherLocals$[](Locals$[], aLInes$[], _start%, _end%)
	For Local i% = _start To _end
		If Left(Trim(aLines[i]),5) = "Local" Then
			Locals :+ [ aLines[i].Split("Local ")[1] ]
		EndIf
	Next
	Return locals
End Function
'------------------------------------------------------------------------------------------------------------
Function Find_string%(aLines$[], needle$, start%=0)
	For Local i% = start Until aLines.Length
		If Lower(Trim(alines[i])) = Lower(Trim(needle)) Then
			Return i
		EndIf
	Next
	Return False
End Function
'------------------------------------------------------------------------------------------------------------
Function WriteFuncBlock$(num%, contents$[])
	_Print "	Function _bvmf_" + num + "%()"
	For Local s$ = EachIn contents
		_Print s.Replace("~t~t","~t")
	Next
	_Print "	End Function~n"
End Function
'------------------------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------------------------
Function FindMaxIndex%( aLines$[], _start%, _end%)
	'// Find the largest case value //
	Local res%=-9999
	Local num%
	Local aTmp$[]
	
	Assert(_end < aLines.length)
		For Local i% = _start Until _end
			If alines[i].Contains("Case 0") Then Continue
			If Left(Trim(aLines[i]),4) = "Case" Then 
				aTmp =  Trim(aLines[i]).Split(" ")
				num = Int(aTmp[1])
				If Not num Then
					RuntimeError("wrong number at line " + i)
				End If	
				If num > res Then res = num
			EndIf
		Next
		
		Return res
End Function
'------------------------------------------------------------------------------------------------------------
Function GetBLockContents$[](aLInes$[], num%, _start%, _end%)
	'// get the contents of the case block and return as a string array or empty //
	Local state% = False
	Local block$[]
	
	For Local i% = _start Until _end	
		If Lower(Trim(aLines[i])) = "case " + num Then
			'If state Then Return block		
			state = True
			Continue
		EndIf 
		If state Then
			If Left(Lower(Trim(aLines[i])),4) = "case" Then Return block 
			block :+ [aLInes[i]]
		EndIf
'		Print i
	Next
	Return block
End Function

'------------------------------------------------------------------------------------------------------------

Comments

None.

Code Archives Forum