Programming approach advice please...

Everything else that doesn't fall into one of the other PB categories.
naw
Enthusiast
Enthusiast
Posts: 573
Joined: Fri Apr 25, 2003 4:57 pm

Programming approach advice please...

Post by naw »

Hi All,
I'm in the middle of buildin a PB app that uses INI files containing logic and values to calculate Migration Work Effort. I'm trying to avoid hard-coding any of the logic.

I guess I'm effectively trying to build a maths algebra parser.

./Migration.ini:
[Scenario1]
MigrationScenario = MyApplication v3 - v4.6 upgrade
Task1 = 2.5 # Pilot days
Task2 = .5 # Data Conversion days
Task3 = 3 # Application and OS Install days
Task4 = 2.3 # Testing days

./Formula.ini
[ServerMigrationFormula]
Workeffort=(SourceServers.w * Task2) + (TargetServers * (Task3 + Task4 ) + Task1 + (DataToxfer * 1Gbps.w)

So my question is very open - what approach would you take to try do this in PB - any advice would be greatly appreciated?
Should I try to parse each element in the formula?
Would it be best to simply give up and Hard Code the formula?
Is there an equivalent to UNIX'x expr function?
Does anyone know of a PB Lib that makes this stuff easier?
Ta - N
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Post by PolyVector »

Here's a great expression evaluator that may help you... Look about 10 posts down...
viewtopic.php?t=8059&highlight=eval


To use it with variables you might do something like this:

Code: Select all

Expression$=ReplaceString(Expression$,"SourceServers",SourceServers)
Answer$=Eval(Expression$)
Last edited by PolyVector on Mon Sep 13, 2004 1:39 pm, edited 1 time in total.
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

Are .ini files and parsing, etc, required or would embedded scripting be an answer?

BalrogSoft:
viewtopic.php?t=9651&highlight=

FloHimself:
viewtopic.php?t=8056&highlight=lua

Also IIRC there are some VB scripting egs around somewhere.
@}--`--,-- A rose by any other name ..
naw
Enthusiast
Enthusiast
Posts: 573
Joined: Fri Apr 25, 2003 4:57 pm

Post by naw »

@Dare2,
No not scripting - definitely Formula parsing (cant give the users too much control ;-)

@Poly
Hmmm! That looks interesting, I did some searches for eval but there were 100's of *hits* that didnt quite match. I obviously missed that one - but it seems to be perfect, even MEM facility....

Guys thanks very much for your help, unfortunately, I wont be able to post the fruits of my labour because my employer has copyright to my every passing thought :-) - again thanks for your advice
Ta - N
User avatar
GedB
Addict
Addict
Posts: 1313
Joined: Fri May 16, 2003 3:47 pm
Location: England
Contact:

Post by GedB »

Using Lisp style s-expressions is significantly easier than parsing normal expressions.

Instead it would look like this:

(Set Workeffort (+ (* SourceServer Task2) (* TargetServers (+ Task3 Task4)) Task1 (* DataToxfer 1Gbps.w))

This type of evaluation engine is a doddle to write and easily expanded.
naw
Enthusiast
Enthusiast
Posts: 573
Joined: Fri Apr 25, 2003 4:57 pm

Post by naw »

@GedB,

A doddle for you maybe - but I'm a pretty average coder at best...

Also, using s-expressions would discourage my users from adding their own formulae - they need something familiar.

What I'm hoping to do is create 50 - 100 scenarios initially, then for my users to expand this themselves - so it has to be easy to notate.

My requirements are fairly simple, I think
()+-*/ and variables

- not much more than that...
Ta - N
User avatar
GedB
Addict
Addict
Posts: 1313
Joined: Fri May 16, 2003 3:47 pm
Location: England
Contact:

Post by GedB »

Naw,

Trust me, you can get away with some easy easy code. I'll post a sample if I get time.

However, it really isn't something for end users to have to deal with.

Slightly more difficult is using spreadsheet style format:

Workeffort = Sum(Multiply(SourceServer, Task2), Multiply(TargetServers, Sum(Task3, Task4)), Task1, Multiply(DataToxfer, 1Gbps.w))

This makes more sense to end users, especially if they have spreadsheet experience.

The main thing is trying to avoid having to write a recursive descent parser. That is when coding become more difficult.
naw
Enthusiast
Enthusiast
Posts: 573
Joined: Fri Apr 25, 2003 4:57 pm

Post by naw »

@GedB

:-)

The Spreadsheet format looks ok

Workeffort = Sum(Multiply(SourceServer, Task2), Multiply(TargetServers, Sum(Task3, Task4)), Task1, Multiply(DataToxfer, 1Gbps.w))

- I guess this would be easier to pasrse than

Workeffort=(SourceServers.w * Task2) + (TargetServers * (Task3 + Task4 ) + Task1 + (DataToxfer * 1Gbps.w)

I prefer the second example - but either would do what I want

Thanks for the reply, I hope you can find time to post an example, it would be veryt much appreciated and useful learning for me :-)

Ta - N
Ta - N
naw
Enthusiast
Enthusiast
Posts: 573
Joined: Fri Apr 25, 2003 4:57 pm

Post by naw »

Purely by accident, I came accross FMLCalc on http://www.purearea.net/ coded by Sebastian Lackner. Unfortunately, its a DLL - but it seems to do the job I want very nicely - even includes support of Variables which can be notated outside of PB but have their values loaded inside PB...

for instance:

setvarS_("ABC","1234")
Debug(formel_("(([ABC]*2) + 4321) / 2"))

Documentation is in German but I translated through Babelfish (hence the interesting choice of wording in places :-\ )

Thanks All - N

fmlcalc.dll
===========
FmlCalc is DLL for counting complex formulas the running time of a program! With it formulas
can be computed, which does not admit to compiling the program yet at all was and by the user
was entered or from a file read! The DLL contains functions for the following actions:

All basic instructions for counting:

(+ , - , * , / , ^(Power))



Comparisons of text and numbers also:

(= , < , <= , > , >= , <>)



Appendices of texts (&) Using comma numbers and numbers within the negative range (float one uses!)
Counting after more correctly math. order! (point before line...) Extending the DLL by inserting
external functions: Functions can have 0-10 parameters! -Die parameters are always handed over into
stringers! Variables can be used!: They is "[" of; and "]" enclosed!


AGAIN! Now 4 formats are supported! Dec, Hex, is, Oct. In order to define, what for a number it is,
the initial letter must be attached: e.g.. HEX: 4ABh IS: 100101b OCT: 3527o even if it as result a
value in these formats to have want, then they must insert suitable functions (see appendix!)



Functions Parameter Description
========== ========= ============
INSTRUCTIONS FOR EXTERNAL FUNCTIONS

RemFunc FncName.s removes an external function from the list
SetFunc FncName.s specifies an external function or changes the
ParamCnt.l characteristics. Those ADDR-EATS can in PB with
Addresse.l @Prozedur_Name() be determined!
ClearFuncs -n/a- Empties the list with all external functions
GetFuncCallID FncName.s supplies address of the indicated function!
GetFuncParamCnt FncName.s supplies the number of parameters of the indicated
function!

INSTRUCTIONS FOR VARIABLES
==========================

RemVar VarName.s removes a variable from the list
SetVarS VarName.s A variable sets on a text or a number, which is
strVal.s contained in the stringer!
SetVarL VarName.s LngVal.l into a stringer and puts the variable converts
lngVal.l the parameter to the indicated value!
ClearVars -n/a- Empties the list with all variables!
GetVarS VarName.s Supplies ADDR-EAT to the value indicated variable.
Around the value too gotten the instruction PeekS
(can be used...) in PB!

Form of an external function in PB
===========================

Global Result.s ; Definiert a global variable, thereby the result of the function
; also after "ProcedureReturn" remains still preserved!


Procedure.l Externe_Funktion(Parameter1.s, Parameter2.s); Definition the procedure!
;HERE COUNTED AND the RESULT IN Result.s MUST STORED
ProcedureReturn @Result.s ; Return the result!
EndProcedure


Appendix
========
Here still the functions of kind of condition to the expenditure of Hex, are and Oct numbers

;----HEX----
Global Result.s
Procedure.l _Hex( value.s )
Result=Chr(34)+Hex(Val(value))+Chr(34)
ProcedureReturn @Result
EndProcedure

;----BIN----
Global Result.s
Procedure.l _Bin( value.s )
Result=Chr(34)+Bin(Val(value))+Chr(34)
ProcedureReturn @Result
EndProcedure

;----OCT----
Global Result.s
Procedure.l _Oct( value.s )
Result=""
DecValue=Abs(Val(value))
Repeat
Result=Str(DecValue&7)+Result
DecValue>>3
Until DecValue=0
Result=Chr(34)+Result+Chr(34)
ProcedureReturn @Result
EndProcedure

SetFunc_("Hex",1,@_Hex())
SetFunc_("Bin",1,@_Bin())
SetFunc_("Oct",1,@_Oct())

After this code also the instructions are e.g. Hex(9999), Bin(1024) or Oct(999) possible, in order to control the output format.

Author
=====

Programmer: Sebastian Lackner (www.adventuretipps.de)
Fragen, Anregungen und Kritik an purefan@freenet.de
Ta - N
FloHimself
Enthusiast
Enthusiast
Posts: 229
Joined: Wed May 14, 2003 3:38 pm
Location: Lüneburg - Germany

Post by FloHimself »

naw wrote:@Dare2,
No not scripting - definitely Formula parsing (cant give the users too much control ;-)
but it's a very simple task using the lua lib. you can define how much control the user should have. check this simple example:

example.pb:

Code: Select all

Global WorkEffort.f, MigrationScenario$ ;global variables

Procedure lua_getglobal(L, s$)
  lua_pushstring(L, s$)
  lua_gettable(L, #LUA_GLOBALSINDEX)
EndProcedure

Procedure LoadConfig(FileName$)
  L = lua_open()
  lua_baselibopen(L)
  lua_iolibopen(L)
  lua_strlibopen(L)
  lua_mathlibopen(L)

  If (lua_dofile(L, FileName$) <> 0)
    MessageRequester("Error","Cannot run configuration file!")
    End
  Else
    lua_getglobal(L, "MigrationScenario")
    lua_getglobal(L, "WorkEffort")

    If (lua_isnumber(L, -1) = #False) Or (lua_isstring(L, -2) = #False)
      MessageRequester("Error","Invalid configuration file!")
      End
    Else 
      WorkEffort          = lua_tonumber(L, -1)
      MigrationScenario$  = PeekS(lua_tostring(L, -2))
    EndIf
    
    lua_close(L)
  EndIf
EndProcedure

LoadConfig("formula.lua")

MessageRequester(MigrationScenario$, Str(WorkEffort))
End
formula.lua:

Code: Select all

-- formula.lua
-- file contains formula to calculate the var "WorkEffort"
-- 
-- to hide this file from users you can compile it with luac.exe
-- so users can't change any values
--
-- only the vars "WorkEffort" and "MigrationScenario" are read by purebasic
-- any changes in this file may currupt the application and raise
-- a error message

dofile ("migration.lua")

-- program version
MigrationScenario = "MyApplication v3 - v4.6 upgrade"

-- needed values for calculation
SourceServers 	= 5
TargetServers 	= 10
DataToxfer	    = 3
Gbps		       = 2

-- formula
WorkEffort = (SourceServers * Task2) + (TargetServers * (Task3 + Task4)) + Task1 + (DataToxfer * Gbps)
migration.lua

Code: Select all

-- migration.lua
-- file to set custom values
Task1 = 2.5	-- Pilot days 
Task2 = 0.5	-- Data Conversion days 
Task3 = 3	  -- Application and OS Install days 
Task4 = 2.3	-- Testing days 
/EDIT: Typo
naw
Enthusiast
Enthusiast
Posts: 573
Joined: Fri Apr 25, 2003 4:57 pm

Post by naw »

Hi Flo,

Hmm! I dunno now - I started coding this using the FMLcalc DLL - this actually does exactly what I want.

I can load my Constants and Formulae into a User editable (and extendible) INI file.
I can Define variables in PB - such as Number of Servers, Data to Migrate, Application & OS stuff from the Server&Application Audit data that the user enters

Then I can use these simple User Editable formulae & Constants with PB generated Variables to determine an answer.

I can see though that LUA has advantages too...

I'll play around a little.


I'm glad I posted this note, I wanted to be *aware* of things that otherwise I wouldnt have considered & thats happened very nicely - thanks to all
Ta - N
FloHimself
Enthusiast
Enthusiast
Posts: 229
Joined: Wed May 14, 2003 3:38 pm
Location: Lüneburg - Germany

Post by FloHimself »

hi naw,

just wanted to show that it isn't a problem to do this kind of things with lua. sure you can use a ini file for customization, or just create a option window to let the user change values. no problem. just replyed to let everyone know that i'm here, if someone whats to implement scripting features in an application and consider using lua. ;)

if you started with FMLcalc go for it, if it fits your needs!
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Post by PolyVector »

Hey FloHimself!
Just wanted to say that your Lua lib is amazing stuff... Keep it up!
I'm still waiting for better 3d support so I can impliment it in a game :twisted:

Edit:
I was playing with the Lua examples and noticed that average_example.pb crashes when average(l) returns... I changed it to a ProcedureCDLL and it works fine... Does lua use cdecl?
FloHimself
Enthusiast
Enthusiast
Posts: 229
Joined: Wed May 14, 2003 3:38 pm
Location: Lüneburg - Germany

Post by FloHimself »

thanks polyvector!

yes use cdecl functions as cclosure! had to change the calling convention of the lua functions to stdcall, to make it possible to call them from purebasic. therefore i tried to change the cclosure function inside lua to take stdcall functions. changed that back for some reasons, but not the examples. will update the examples when i get some time..

if you don't like to use ProcedureCDLL you can use a macro.. something like:

Code: Select all

!macro ProcedureReturn NRetVals
!{
  !MOV    eax, NRetVals
  !ADD    esp, 16 ;maybe must adjusted..
  !POP    edi
  !POP    esi
  !POP    ebp
  !POP    ecx
  !POP    ebx
  !RET
!}
and call it like:

Code: Select all

  [..]
  lua_pushnumber(l, sum/n)  ; first result average
  lua_pushnumber(l, sum)    ; second result sum
  
  !ProcedureReturn 2
EndProcedure
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Post by PolyVector »

Wow, that's interesting... I didn't know you could create asm macros... I should really learn asm :)
I'll stick to ProcedureCDLL so I don't confuse myself!
Post Reply