How to run a string?

General FreeBASIC programming questions.
dkl
Site Admin
Posts: 3235
Joined: Jul 28, 2005 14:45
Location: Germany

Re: How to run a string?

Post by dkl »

They're here now:
http://sourceforge.net/projects/fbc/fil ... Libraries/

(I didn't update them for the 1.00.0 release, because it's way too much work)

By the way, you can probably also find the precompiled Lua library on the Lua homepage:
http://lua-users.org/wiki/LuaBinaries
http://luabinaries.sourceforge.net/download.html
e.g., for FB-win32, you'd probably have to download the "Windows x86 (MingW 4 Compatible)" package.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: How to run a string?

Post by dodicat »

Thanks dkl.
I got both, the dll from lua site, the static from dkl's freebasic link.
However, running the code gives:

Code: Select all

-11            0
-10            0
-9             0
-8             0
-7             0
-6             0
-5             0
-4             0
-3             0
-2             0
-1             0
 0             0
 1             0
 2             0
 3             0
 4             0
 5             0
 6             0
 7             0
 8             0
 9             0
 10            0
 11            0
Programm-Ende
 
Using disphelper, and adjusting Rock's code, VIZ:

Code: Select all

'==== SETUP disphelper ==================

#define UNICODE
#include Once "disphelper/disphelper.bi"
Dim shared as IDISPATCH PTR VB_FB
dhInitialize(TRUE)
dhToggleExceptions(True)
dhCreateObject "MSScriptControl.ScriptControl",NULL,@VB_FB
dhPutValue VB_FB,".Language %s","VBScript"

Sub _END() destructor 
    SAFE_RELEASE(VB_FB)
    dhUninitialize True
End Sub

Function FindAndReplace(S as string,F as string,R as string)as string
    Dim Ret as zstring ptr
    dhGetValue "%s",@Ret,VB_FB,".Eval %s","Replace("""+S+""","""+F+""","""+R+""")"
    Return *Ret
End Function

Function eval(s As String) As Double
    Dim value As Zstring Ptr
    dhGetValue "%s",@value,VB_FB,".Eval %s",s
    Return Val(*value)
End Function

Function LoadFile(ByRef filename As String) As String
    Dim h As Integer
    Dim txt As String
    h = FreeFile
    If Open( filename For Binary Access Read As #h ) <> 0 Then Return "File not found"
    If LOF(h) > 0 Then
        txt = String(LOF(h), 0)
        If Get( #h, ,txt ) <> 0 Then txt = ""
    End If
    Close #h
    Return txt
End Function


dim as string s=Loadfile("formula.lua")
 s=FindAndReplace(s,"y=","")
For x As Integer=-11 To 11
    Print x,
    var s2=FindAndReplace(s,"x",str(x))
    print eval(s2)
Next

PRINT "Programm-Ende"
sleep

 
I get

Code: Select all

-11            112
-10            92
-9             74
-8             58
-7             44
-6             32
-5             22
-4             14
-3             8
-2             4
-1             2
 0             2
 1             4
 2             8
 3             14
 4             22
 5             32
 6             44
 7             58
 8             74
 9             92
 10            112
 11            134
Programm-Ende
 
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: How to run a string?

Post by dodicat »

This seems to work:

Code: Select all


'y=x^2+x+2 is the include file



dim as double y
For x As Integer=-11 To 11
#include once "formula.lua"
print x,
print y
next x
PRINT "Programm-Ende"
sleep
 
And from RockTheSchock (using a string instead of a file):

Code: Select all


#INCLUDE ONCE "Lua/lua.bi"
#INCLUDE ONCE "Lua/lauxlib.bi"
'#INCLUDE ONCE "Lua/lualib.bi"

function Evaluate(byval Expression as string,StringVariable as string,DoubleVariable as double,byref lua as lua_state ptr) as double
    lua_pushnumber(Lua, DoubleVariable)      
    lua_setglobal(Lua, StringVariable) 
    luaL_dostring(Lua,Expression)
    lua_getglobal(Lua,left(Expression,1))
    Evaluate= lua_tonumber(Lua, 0)
    lua_pop(Lua, 1)  
end function

DIM Lua AS lua_State PTR  =   luaL_newstate             ' Schnittstelle zu Lua

'luaL_requiref (lua,LUA_MATHLIBNAME,@luaopen_math,1)                'sandboxing only math allowed

dim as string s="y=x^2+x+2"

For x As double=-11 To 11 step .5
    Print x,Evaluate(s,"x",x,lua)
Next

PRINT "Programm-Ende"
lua_close Lua                             ' Lua-State freigeben
Sleep 
RockTheSchock
Posts: 252
Joined: Mar 12, 2006 16:25

Re: How to run a string?

Post by RockTheSchock »

The basic lua implementation is 5x faster then the disphelper implementation. With a precompiled function the lua code gets even 10x faster.(50x faster then disphelper)

EDIT: made some corrections with stack and lua_pop

Code: Select all

#Include Once "Lua/lua.bi"
#Include Once "Lua/lauxlib.bi"
#Include Once "Lua/lualib.bi"

Function Evaluate(ResultVariable As String,ByVal Expression As String,StringVariable As String,DoubleVariable As Double,ByRef lua As lua_state Ptr) As Double
	lua_pushnumber(Lua, DoubleVariable)
	lua_setglobal(Lua, StringVariable)
	luaL_dostring(Lua,ResultVariable+"="+Expression)
	lua_getglobal(Lua,ResultVariable)
	Evaluate = lua_tonumber(Lua, -1)
	lua_pop(Lua, 1)
End Function

Function Evaluate2(fname As String,ByVal Expression As String,StringVariable As String,DoubleVariable As Double,ByRef lua As lua_state Ptr) As Double
	Static func As String
	If Len(func)=0 Then                        'setup and compile function		
		func = "function " + fname +"("+StringVariable+")" +Chr(13)+Chr(10) _
		+ "   return " + Expression +Chr(13)+Chr(10) _
		+ "end"
		Print
		Print "Setting up Function:"
		Print func
		If luaL_dostring(Lua,func) Then
			 PRINT "Error: " & *lua_tostring(Lua, -1),__LINE__		
			 sleep	 			 
		EndIf
	EndIf
	
	
	lua_getglobal(Lua, fname)
	lua_pushnumber(Lua, DoubleVariable)
	IF lua_pcall(Lua, 1, 1, 0) Then
		Print "Error: " & *lua_tostring(Lua, -1),__LINE__
		sleep
	EndIf
	Evaluate2 = lua_tonumber(Lua, -1)
	lua_pop(Lua, 1)
End Function


Dim Lua As lua_State Ptr  =   luaL_newstate             ' Schnittstelle zu Lua

Dim As String e="x^2+x+2"
Dim t As Double

Print "Evaluate"
t=Timer
For x As Double=-11000 To 11000 Step 0.1
	Evaluate("y",e,"x",x,lua)
Next
t=Timer-t
Print Using "Elapsed time: #.## seconds"; t

Print
Print "Evaluate2"
t=Timer
For x As Double=-11000 To 11000 Step 0.1	
	Evaluate2("f",e,"x",x,lua)	
Next
t=Timer-t
Print Using "Elapsed time: #.## seconds"; t
Print "Programm-Ende"
Print lua_gettop(lua)
lua_close Lua                             ' Lua-State freigeben
Sleep
If you wanna know about the stack read this :
http://stackoverflow.com/questions/1844 ... r-18451429
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: How to run a string?

Post by dodicat »

Thank you RockTheSchock, interesting stuff.
I might have a practise with the lua library, seems fast.

Surprisingly, just using #include is very fast:

Code: Select all


'y=x^2+x+2 is the include file



dim as double y
dim as double t=timer
For x As double=-11000 To 11000 Step 0.1
#include once "formula.lua"
if x=-6964.399999985319 then print y
next x
PRINT "Programm-Ende",y
print "Time taken ";timer-t
sleep
 
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How to run a string?

Post by fxm »

dodicat wrote:Surprisingly, just using #include is very fast
Of course:
#include is a preprocessor statement to include contents of another source file.
This is realized during compilation phase.
Therefore execution time is not impacted.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: How to run a string?

Post by dodicat »

So, formula.lua is only loaded once, and depending where in your code you place #include "formula.lua", it is put there, inline.

This makes the code very fast, at least 10 times faster than a function call.

I do remember dkl discussing inline functions a while back.
TJF
Posts: 3809
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Re: How to run a string?

Post by TJF »

@dodicat

#INCLUDE code segments get imported to the source code before compiling (pre-process). This isn't related to inline-functions, which are macros (#DEFINEs) that return a value.

You can compile with option -pp to see what happens in your code.
RockTheSchock
Posts: 252
Joined: Mar 12, 2006 16:25

Re: How to run a string?

Post by RockTheSchock »

The thing about embedding lua is, you dont need to compile your freebasic code anymore. So if you want dynamicly created/inputed/loaded formulas you need to compile/interpret them. If you bundle the freebasic compiler with your application your application will be huge. You will eventually also have a problem with the license. If your application depends on freebasic to run properly you have to use gpl licence for your program, too.

If you use lua just a copyright notice in the program or its documentation is enough. If you need a formula eval function to draw simple graphs or to make some sort of table calculation sheet i would use lua. The size of your programm will be just 200kb bigger with lua embedded. In lua you could also make create a sandbox enviroment, so the worst thing that can happen is that the lua formula eats CPU or RAM resources, but it wont corrupt your harddisk or files:
http://stackoverflow.com/questions/1224 ... er-6982080

i made it even 2.5X faster using a for loop within lua which calls the formula function. The results are passed by calling a CDECL function from lua which then stores the values to a shared array.

Code: Select all

#Include Once "Lua/lua.bi"
#Include Once "Lua/lauxlib.bi"
#Include Once "Lua/lualib.bi"

Declare Sub EvaluateForAndCall(fname As String,ByVal Expression As String,StringVariable As String,DoubleVariable As Double,ByRef lua As lua_state Ptr,startx As Double,stopx As Double, stepx As Double)
Declare Function Evaluate2(fname As String,ByVal Expression As String,StringVariable As String,DoubleVariable As Double,ByRef lua As lua_state Ptr) As Double
Declare Function Evaluate(ResultVariable As String,ByVal Expression As String,StringVariable As String,DoubleVariable As Double,ByRef lua As lua_state Ptr) As Double

Dim As Double startx=-11000,stopx=110000,stepx=0.1
'Dim As Double startx=-11,stopx=11,stepx=0.5
Type PointType 
	x As Double
	y As Double
End Type
ReDim Shared result((stopx-startx)/stepx)  As PointType

Dim Lua As lua_State Ptr  =   luaL_newstate             ' Schnittstelle zu Lua
luaL_openlibs(Lua)

Dim As String e="x^2+x+2"
Dim t As Double


Print "----------------------"
Print "EvaluateForAndCall"
Print "----------------------"
t=Timer
EvaluateForAndCall("f",e,"x",0,lua,startx,stopx,stepx)

Dim calculatesomething As Double	
For i as integer = LBound(result) To UBound(result)
	calculatesomething=result(i).x+result(i).y
Next
t=Timer-t
Print Using "Elapsed time: #.## seconds"; t
Print
Print



Print "----------------------"
Print "Evaluate"
Print "----------------------"
t=Timer
For x As Double=startx To stopx Step stepx
	'Print Evaluate("y",e,"x",x,lua)
	Evaluate("y",e,"x",x,lua)
Next
t=Timer-t
Print Using "Elapsed time: #.## seconds"; t
Print
Print

Print "----------------------"
Print "Evaluate2"
Print "----------------------"
t=Timer
For x As Double=startx To stopx Step stepx
	'Print Evaluate2("f",e,"x",x,lua)
	Evaluate2("f",e,"x",x,lua)	
Next
t=Timer-t
Print Using "Elapsed time: #.## seconds"; t
Print
Print


Print "Programm-Ende"
lua_close Lua                             ' Lua-State freigeben
Sleep


FUNCTION dosomething CDECL (BYVAL L AS lua_State PTR) AS Long
	Static counter As Integer
	result(counter).x=lua_tonumber(L, 1)
	result(counter).y=lua_tonumber(L, 2)
	counter+=1
   Return 0
END Function

Sub EvaluateForAndCall(fname As String,ByVal Expression As String,StringVariable As String,DoubleVariable As Double,ByRef lua As lua_state Ptr,startx As Double,stopx As Double, stepx As Double)		
	Dim func As String 
	func = "function " + fname +"("+StringVariable+")" +Chr(13)+Chr(10) _
	+ "   return "+StringVariable+","+ Expression +Chr(13)+Chr(10) _
	+ "end" +Chr(13)+Chr(10) _	
	+ "for " + StringVariable + "=" + Str(startx) + "," + Str(stopx)+ "," + Str(stepx) +" do" +Chr(13)+Chr(10) _
	+ "   myfunc("+fname +"("+StringVariable+"))" +Chr(13)+Chr(10) _
	+ "end"
			
	Print func
	lua_pushcfunction(lua, @dosomething)
	lua_setglobal(lua, "myfunc")
	If luaL_dostring(Lua,func) Then
		 PRINT "Error: " & *lua_tostring(Lua, -1),__LINE__		
		 sleep	 			 
	EndIf
End Sub

Function Evaluate2(fname As String,ByVal Expression As String,StringVariable As String,DoubleVariable As Double,ByRef lua As lua_state Ptr) As Double
	Static func As String
	If Len(func)=0 Then                        'setup and compile function		
		func = "function " + fname +"("+StringVariable+")" +Chr(13)+Chr(10) _
		+ "   return " + Expression +Chr(13)+Chr(10) _
		+ "end"
		
		Print func
		If luaL_dostring(Lua,func) Then
			 PRINT "Error: " & *lua_tostring(Lua, -1),__LINE__		
			 sleep	 			 
		EndIf
	EndIf
	
	lua_getglobal(Lua, fname)
	lua_pushnumber(Lua, DoubleVariable)
	IF lua_pcall(Lua, 1, 1, 0) Then
		Print "Error: " & *lua_tostring(Lua, -1),__LINE__
		sleep
	EndIf
	Evaluate2 = lua_tonumber(Lua, -1)
	lua_pop(Lua, 1)
End Function

Function Evaluate(ResultVariable As String,ByVal Expression As String,StringVariable As String,DoubleVariable As Double,ByRef lua As lua_state Ptr) As Double
	lua_pushnumber(Lua, DoubleVariable)
	lua_setglobal(Lua, StringVariable)
	luaL_dostring(Lua,ResultVariable+"="+Expression)
	lua_getglobal(Lua,ResultVariable)
	Evaluate = lua_tonumber(Lua, -1)
	lua_pop(Lua, 1)
End Function
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: How to run a string?

Post by dodicat »

RockTheSchock

To use the evaluate function, Could you not omit the function name, and just use say "f".
Also, a change in expression could cause a different function to compile, and if the expression does not change then use the previous function.

I see that there are loads of built in Lua functions, many more than vbscript.

Code: Select all

#Include Once "Lua/lua.bi"
#Include Once "Lua/lauxlib.bi"
#Include Once "Lua/lualib.bi"

Function Eval(ByVal Expression As String,StringVariable As String,DoubleVariable As Double,ByRef lua As lua_state Ptr) As Double
    static as string funclast,func
                          'setup and compile function   
    if funclast<>expression then
        func = "function " + "f" +"("+StringVariable+")" +Chr(13)+Chr(10) _
        + "   return " + Expression +Chr(13)+Chr(10) _
        + "end"
        
        Print  func:print
        If luaL_dostring(Lua,func) Then
             PRINT "Error: " & *lua_tostring(Lua, -1),__LINE__      
             sleep               
        EndIf
    EndIf
    funclast=expression
    lua_getglobal(Lua, "f")
    lua_pushnumber(Lua, DoubleVariable)
    IF lua_pcall(Lua, 1, 1, 0) Then
        Print "Error: " & *lua_tostring(Lua, -1),__LINE__
        sleep
    EndIf
    Eval = lua_tonumber(Lua, -1)
    lua_pop(Lua, 1)
End Function


Dim Lua As lua_State Ptr  = luaL_newstate :luaL_openlibs(Lua)


dim as string g="math.sin(x)"

print eval(g,"x",.5,lua)
g="x+7"
print eval(g,"x",.6,lua)
g+="+x^2"
print eval(g,"x",2,lua)

g="math.cos(x)^2 + math.sin(x)^2 +x"
for x as double=0 to 5
    print  eval(g,"x",x,lua)
    next x
sleep
 
Thank you TJF

Sorry Bob Paw, for straying off topic a bit.
RockTheSchock
Posts: 252
Joined: Mar 12, 2006 16:25

Re: How to run a string?

Post by RockTheSchock »

Well the code evolved. So i just copied it. But the idea behind it was to keep track of several formula functions. Eventually one could save / load / edit them or even call another custom function from within another.

You can define for one function also a seperate environment where you include only all the math.xxx functions as local. So you dont need to type math.sin() but only sin(). Look at the sandbox link i gave.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: How to run a string?

Post by dodicat »

Thanks RockTheSchock.

I'll investigate the lua script library.

But it is very fast.
Here's an old plotter (previously disphelper)) converted to lua.

I have created lua (the lua_State Ptr) inside the function to save passing an extra parameter.

There are several test strings, just press a key to get each one.

Code: Select all

#Include Once "Lua/lua.bi"
#Include Once "Lua/lauxlib.bi"
#Include Once "Lua/lualib.bi"

Function Eval(ByVal Expression As String,StringVariable As String,DoubleVariable As Double) As Double
    static as string funclast,func
    static Lua As lua_State Ptr 
    if funclast<>expression then
        lua=luaL_newstate
        luaL_openlibs(Lua)
        func = "function " + "f" +"("+StringVariable+")" +Chr(13)+Chr(10) _
        + "   return " + Expression +Chr(13)+Chr(10) _
        + "end"
        
        Print  func:print
        If luaL_dostring(Lua,func) Then
             PRINT "Error: " & *lua_tostring(Lua, -1),__LINE__      
             sleep 
        EndIf
    EndIf
    funclast=expression
    lua_getglobal(Lua, "f")
    lua_pushnumber(Lua, DoubleVariable)
    IF lua_pcall(Lua, 1, 1, 0) Then
        Print "Error: " & *lua_tostring(Lua, -1),__LINE__
        sleep
    EndIf
    Eval = lua_tonumber(Lua, -1)
    lua_pop(Lua, 1)
End Function
'================================================================

#define map(a,b,x,c,d) ((d)-(c))*((x)-(a))/((b)-(a))+(c)
dim as integer w,h
screeninfo w,h
screenres w,h
Width ,h\16 'make the font slightly larger
dim as string fn
dim as single lx,hx,ly,hy
dim as integer xval,yval
dim as integer count
do
    count=0
    read fn
    if fn="end" then exit do
    read lx
    read hx
    read ly
    read hy
   cls
 '================== the vewing box =============  
line(.1*w,.1*h)-(.9*w,.9*h),,bf
draw string(.1*w,.5*h),str(lx),5
draw string(.9*w-20,.5*h),str(hx),5
draw string(.5*w,.1*h),str(hy),5
draw string(.5*w,.9*h-20),str(ly),5
draw string(.45*w,.1*h+20),fn,0
'===============================================
'plotter
for x as single=lx to hx step (hx-lx)/1000
    count+=1
     var value=eval(fn,"x",x)
     
     xval=map(lx,hx,x,.1*w,.9*w)
     yval=map(hy,ly,value,.1*h,.9*h)'cartesian
     
     if count=1 then
     pset(xval,yval),0
 else
     line -(xval,yval),0
  end if   
    next x
sleep
loop until inkey=chr(27)
locate 2,2
print "Done"
 sleep
 const pi=4*atn(1)
 'data function(in x),lowerX,upperX,lowerY,upperY (cartesian co-ordinates)
 data "math.sin(x)",-10,10,-1.5,1.5
 data "math.cos(x)",0,2*pi,-2,2
 data "x^2",-5,5,0,25
 data "math.sin(x)/x",-20,20,-1,2
 data "3*math.sin(3*x)+2*math.cos(2*x)+math.sin(x)",-5,5,-10,10
 data "(((((-2*x+5)*x)+7)*x-3)*x+9)+3",-5,5,-100,100
 data "2*math.random()-2*math.random()",0,8,-2,2
 data "1/math.exp(x^2)",-3,3,-1.5,1.5
 data "1/(1+x^2)",-3,3,-1.5,1.5
 data "end"

  
BobPaw
Posts: 41
Joined: Dec 13, 2014 2:03
Location: Texas, USA

Re: How to run a string?

Post by BobPaw »

Last edited by BobPaw on Feb 25, 2015 1:10, edited 1 time in total.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: How to run a string?

Post by D.J.Peters »

No one knows Squirrel V3.0 for FreeBASIC (32/64-bit Windows and Linux)
http://www.freebasic.net/forum/viewtopi ... 14&t=17573

Joshy
ike
Posts: 387
Joined: Jan 17, 2011 18:59

Re: How to run a string?

Post by ike »

Code: Select all

#INCLUDE ONCE "Lua/lua.bi"
#INCLUDE ONCE "Lua/lauxlib.bi"
#INCLUDE ONCE "Lua/lualib.bi"

DIM Lua AS lua_State PTR
Lua = luaL_newstate

dim as double x = 1.01, y = 1.02, z
lua_pushnumber(Lua, 0)                 ' Push number on the stack
lua_setglobal(Lua, "z")                ' take off the stack and assign "z"

lua_pushnumber(Lua, x)                 ' Push number on the stack
lua_setglobal(Lua, "x")                ' take off the stack and assign "x"

lua_pushnumber(Lua, y)                 ' Push number on the stack
lua_setglobal(Lua, "y")                ' take off the stack and assign "y"

IF luaL_dofile(Lua, "fn.lua") THEN
  PRINT "Error: " & *lua_tostring(Lua, -1)
END IF

lua_getglobal(Lua, "z")                ' Set value of "z" on the stack
z = lua_tonumber(Lua, 1)             ' output value
? z
lua_close Lua
SLEEP



fn.lua file is just one line:

z = 2 * x + y

or more


if x>1 then x = 100 end

z = 2 * x + y
Post Reply