A math parser is required

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by julianbury.

Is there the slightest chance that an Evaluate(math$) funtion
could be provided, enabling PureBasic applications to accept more
sophisticated user input like "101*cos(1.003)+sin(0.973)*96" ?

I notice that other people herein also require one that
can accept binary and hex values - as do I.

Since such a parser already exists for PureBasic's compilation process,
perhaps that could be made available as a function?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If this request is absolutely, resolutely and finally refused,
how can we make use of the Windows Scripting Host's parser?

Is it possible?

Could we make an Evaluate(math$) function to do this?

Aaah, I wish I knew how to do that!

Do any of you guys know how to do that?


Julian ^00^
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Sebi.

Long time ago I created a math parser for PB!

http://www.adventuretipps.de/purebasic/fmlcalc.zip

This file contains the parser DLL and an example.
The example is on german but I think you will also understand how to use it.

The parser use float-values and contains the following features:

- * , - , * , / , ^
- compare text and numbers with =,,>=,
- include your own functions.You can call them with ...(parameters,...)

This version don't work with hex values but maybe I will add a support for it!

In the german forum I had post an example for a simple calculator:
http://www.robsite.de/php/pureboard/viewtopic.php?t=130

Sebi
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by julianbury.

Thank you, Sebi :)
I just downloaded it and now I'm going to sigh off and play with it :wink:


Julian ^00^
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Sebi.

The new version is ready.
You can download it at http://www.adventuretipps.de/purebasic/fmlcalc.zip

In this version you can use Hex, Oct an Bin-Values.
Example: 999h means that it is hex-value,
1543o means that is is an ocal-value and
10101001b that it is an binary value.

I changed the readme.txt file, too.

I hope this will help you.

Sebi
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by julianbury.

Hi Sebi :)

I have just downloaded fmlcalc.zip
A multi-lingual friend has agreed to translate it for me.
So, in a day or two, I may have a proper calculator working (^_^)

Thank you for your kindness


Julian ^00^
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by julianbury.

Hi Sebi,
I have not been able to understand how to make use of fmlcalc.
The translation effort has been unsuccessful.
I have made a Procedure at line 101: Procedure do_the_calculations()
What must I do to bring this to life?

Code: Select all

;=================================
; BIG Calc
; Copyright (C) Julian Bury, 2003
;=================================

#Window =    0
#Times  =    1 ;font ID

;keys
#Up     = 100
#Down   = 101
#Tab    = 108
#Riturn = 113
#Escape = 257

Global maxg ;0 to 48 gadget IDs
Global maxx ;0 to  2 columns
Global maxy ;0 to 15 rows
Global maxl ;0 to 255 calculation lines
Global offs ;0 to 240 offset to displayed section of the data array
Global maxo ;maximum offset to displayed part of the data array

maxg = 48
maxx = 2
maxy = 15
maxl = 255
offs = 0
maxo = maxl-15

Dim valu(maxl+1)
Dim txt$(4,maxl+1)
Dim pos(maxx+1,maxy+1)



; stick some random data in the display gadgets
For t=0 To maxl
  txt$(0,t)="n"+Str(t)
  txt$(1,t)="0.0"
  txt$(2,t)=Str(Random(9))+Mid("+-*/^",1+Random(4),1)+Str(Random(9))
  txt$(3,t)=txt$(2,t)
Next



; Create the window and fill it with string gadgets full of data.
; Establish keyboard control for navigation between gadgets.
If OpenWindow(0,165,0,800,25*17,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"BIG Calc")
  If CreateGadgetList(WindowID())
    FontID.l = LoadFont(#Times, "Times New Roman", 12,#PB_Font_Bold|#PB_Font_HighQuality)
    id=0
    t=0
    For y=0 To maxy
      xpos=1
      ypos=y*25
      StringGadget(id,xpos,ypos,100,24,txt$(0,t+offs))
      pos(0,y)=GadgetID(id)
      id+1

      xpos=101
      ypos=y*25
      StringGadget(id,xpos,ypos,200,24,txt$(1,t+offs))
      pos(1,y)=GadgetID(id)
      id+1

      xpos=302
      ypos=y*25
      StringGadget(id,xpos,ypos,497,24,txt$(2,t+offs))
      pos(2,y)=GadgetID(id)
      id+1
      t+1
    Next
    xpos=1
    ypos=25*16+4
    TextGadget(id,xpos,ypos,797,24,"The selected calculation, formatted for the parser",#PB_Text_Center)
    pos(0,y)=GadgetID(id)
    AddKeyboardShortcut(#Window,#PB_Shortcut_Return,#Riturn)
    AddKeyboardShortcut(#Window,#PB_Shortcut_Up,#Up)
    AddKeyboardShortcut(#Window,#PB_Shortcut_Down,#Down)
    AddKeyboardShortcut(#Window,#PB_Shortcut_Tab,#Tab)
    AddKeyboardShortcut(#Window,#PB_Shortcut_Escape,#Escape)
  EndIf
  For id=0 To maxg
    SetGadgetFont(id,FontID.l)
  Next
  xpos=2
  ypos=0
EndIf



ActivateGadget(2)



;== Procedures ==============

; perform the calculation - everything depends on this ...
; I need a procedure or a function called Parse() to make his work
Procedure do_the_calculations()
  For t=0 To maxl
;    valu(t)=Parse(txt$(2,t))
    txt$(1,t)=Str(valu(t))
  Next
EndProcedure



; update the contents of the display gadgets
Procedure refresh_the_window()
  id=0
  For t=0 To maxy
    SetGadgetText(id,txt$(0,t+offs)) : id+1
    SetGadgetText(id,txt$(1,t+offs)) : id+1 ; #Gadget object not initialised !
    SetGadgetText(id,txt$(2,t+offs)) : id+1
  Next
EndProcedure



;=======================



Repeat ; Main loop

  EventID=WaitWindowEvent()

  ;discover the string with the focus
  If EventID=#PB_Event_Menu
    For x=0 To maxx
      For y=0 To maxy
        If GetFocus_()=pos(x,y)
          xpos=x
          ypos=y
        EndIf
      Next
    Next

    ;I would never have thought to lookup "MenuID" for "keydown detection"!
    em=EventMenuID()
    SetGadgetText(48,Str(em))
    Select em
      Case #Up
        If ypos>0 Or offs>0
          If ypos>0
            ypos-1
          Else
            offs-1
            refresh_the_window()
          EndIf
        EndIf
      Case #Down
        If yposmaxx:xpos=0:EndIf
      Case #Riturn
        do_the_calculations()
        refresh_the_window()
      Case #Escape
        End
    EndSelect
    SetFocus_(pos(xpos,ypos))
  EndIf
Until EventID=#PB_Event_CloseWindow

End
The Parse function is the problem.
I would be greatful for your help.

Thank you in anticipation :)

Julian ^00^
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Sebi.

Sorry. When I inserted the other formats I inserted a litte bug, too.
So you have to download the file again. Then you must copy it to the current directory with the PB-file or in the System-directory.

Before you can use this functions you must insert a "little" Code at the top like in the example.
To calculate use the function "Formel_".

Here your code with the header and the changes.

Code: Select all

;========FMLCALC.DLL - Parser Code========

Global fmlcalc_Loaded
Global fmlcalc_RemFunc
Global fmlcalc_SetFunc
Global fmlcalc_ClearFuncs
Global fmlcalc_GetFuncCallID
Global fmlcalc_GetFuncParamCnt
Global fmlcalc_RemVar
Global fmlcalc_SetVarS
Global fmlcalc_SetVarL
Global fmlcalc_ClearVars
Global fmlcalc_GetVarS
Global fmlcalc_Formel

;This command loads the DLL-file
Procedure.l LoadFmlCalc()
  If fmlcalc_Loaded=0
    If OpenLibrary(0,"fmlcalc.dll")
      fmlcalc_RemFunc=IsFunction(0,"RemFunc")
      fmlcalc_SetFunc=IsFunction(0,"SetFunc")
      fmlcalc_ClearFuncs=IsFunction(0,"ClearFuncs")
      fmlcalc_GetFuncCallID=IsFunction(0,"GetFuncCallID")
      fmlcalc_GetFuncParamCnt=IsFunction(0,"GetFuncParamCnt")
      fmlcalc_RemVar=IsFunction(0,"RemVar")
      fmlcalc_SetVarS=IsFunction(0,"SetVarS")
      fmlcalc_SetVarL=IsFunction(0,"SetVarL")
      fmlcalc_ClearVars=IsFunction(0,"ClearVars")
      fmlcalc_GetVarS=IsFunction(0,"GetVarS")
      fmlcalc_Formel=IsFunction(0,"Formel")
      fmlcalc_Loaded=1
      ProcedureReturn 1
    EndIf
  EndIf
  ProcedureReturn 0
EndProcedure

;This command closes the Dll-file after use
Procedure.l UnloadFmlCalc()
  If fmlcalc_Loaded=1
    If CloseLibrary(0)
      fmlcalc_Loaded=0
      ProcedureReturn 1
    EndIf
  EndIf
  ProcedureReturn 0
EndProcedure

;This command removes a function from the global list
Procedure.l RemFunc_(FncName.s)
  If fmlcalc_Loaded=1
    ProcedureReturn CallFunctionFast(fmlcalc_RemFunc,FncName)
  EndIf
  ProcedureReturn 0
EndProcedure

;With this command you can insert your own functions like
;Sin or Cos...
;ParamCnt is how many Parameters you want for the Procedure.
;Addresse is the address to the Procedure. You can get it with @Procedure()
Procedure.l SetFunc_(FncName.s,ParamCnt.l,Addresse.l)
  If fmlcalc_Loaded=1
    ProcedureReturn CallFunctionFast(fmlcalc_SetFunc,FncName,ParamCnt.l,Addresse.l)
  EndIf
  ProcedureReturn 0
EndProcedure

;Removes all functions from the list
Procedure.l ClearFuncs_()
  If fmlcalc_Loaded=1
    ProcedureReturn CallFunctionFast(fmlcalc_ClearFuncs)
  EndIf
  ProcedureReturn 0
EndProcedure

;With this function you can get the address of a procedure, you've already insert
Procedure.l GetFuncCallID_(FncName.s)
  If fmlcalc_Loaded=1
    ProcedureReturn CallFunctionFast(fmlcalc_GetFuncCallID,FncName)
  EndIf
  ProcedureReturn 0
EndProcedure

;And with this you can get the number of parameters for a procedure
Procedure.l GetFuncParamCnt_(FncName.s)
  If fmlcalc_Loaded=1
    ProcedureReturn CallFunctionFast(fmlcalc_GetFuncParamCnt,FncName)
  EndIf
  ProcedureReturn 0
EndProcedure

;Fmlcalc.dll has a list with values, too. With this command you can delete an value.
Procedure.l RemVar_(VarName.s)
  If fmlcalc_Loaded=1
    ProcedureReturn CallFunctionFast(fmlcalc_RemVar,VarName)
  EndIf
  ProcedureReturn 0
EndProcedure

;Use this function to set a value in the list to a string. This string can contain a value or a text.
Procedure.l SetVarS_(VarName.s,strVal.s)
  If fmlcalc_Loaded=1
    ProcedureReturn CallFunctionFast(fmlcalc_SetVarS,VarName,strVal)
  EndIf
  ProcedureReturn 0
EndProcedure

;This command is the same as SetVarS_(... , Str(lngVal))
Procedure.l SetVarL_(VarName.s,lngVal.l)
  If fmlcalc_Loaded=1
    ProcedureReturn CallFunctionFast(fmlcalc_SetVarL,VarName,lngVal)
  EndIf
  ProcedureReturn 0
EndProcedure

;Remove all items from the value list
Procedure.l ClearVars_()
  If fmlcalc_Loaded=1
    ProcedureReturn CallFunctionFast(fmlcalc_ClearVars)
  EndIf
  ProcedureReturn 0
EndProcedure

;Use this function to read the content of a string.
Procedure.s GetVarS_(VarName.s)
  If fmlcalc_Loaded=1
    ProcedureReturn PeekS(CallFunctionFast(fmlcalc_GetVarS,VarName))
  EndIf
  ProcedureReturn ""
EndProcedure

;Use this function to calculate.
Procedure.s Formel_(Fnc.s)
  If fmlcalc_Loaded=1
    ProcedureReturn PeekS(CallFunctionFast(fmlcalc_Formel,Fnc))
  EndIf
  ProcedureReturn ""
EndProcedure


LoadFmlCalc()  ;Load the parser DLL.


;=================================
; BIG Calc
; Copyright (C) Julian Bury, 2003
;=================================

#Window =    0
#Times  =    1 ;font ID

;keys
#Up     = 100
#Down   = 101
#Tab    = 108
#Riturn = 113
#Escape = 257

Global maxg ;0 to 48 gadget IDs
Global maxx ;0 to  2 columns
Global maxy ;0 to 15 rows
Global maxl ;0 to 255 calculation lines
Global offs ;0 to 240 offset to displayed section of the data array
Global maxo ;maximum offset to displayed part of the data array

maxg = 48
maxx = 2
maxy = 15
maxl = 255
offs = 0
maxo = maxl-15

Dim valu(maxl+1)
Dim txt$(4,maxl+1)
Dim pos(maxx+1,maxy+1)



; stick some random data in the display gadgets
For t=0 To maxl
  txt$(0,t)="n"+Str(t)
  txt$(1,t)="0.0"
  txt$(2,t)=Str(Random(9))+Mid("+-*/^",1+Random(4),1)+Str(Random(9))
  txt$(3,t)=txt$(2,t)
Next



; Create the window and fill it with string gadgets full of data.
; Establish keyboard control for navigation between gadgets.
If OpenWindow(0,165,0,800,25*17,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"BIG Calc")
  If CreateGadgetList(WindowID())
    FontID.l = LoadFont(#Times, "Times New Roman", 12,#PB_Font_Bold|#PB_Font_HighQuality)
    id=0
    t=0
    For y=0 To maxy
      xpos=1
      ypos=y*25
      StringGadget(id,xpos,ypos,100,24,txt$(0,t+offs))
      pos(0,y)=GadgetID(id)
      id+1

      xpos=101
      ypos=y*25
      StringGadget(id,xpos,ypos,200,24,txt$(1,t+offs))
      pos(1,y)=GadgetID(id)
      id+1

      xpos=302
      ypos=y*25
      StringGadget(id,xpos,ypos,497,24,txt$(2,t+offs))
      pos(2,y)=GadgetID(id)
      id+1
      t+1
    Next
    xpos=1
    ypos=25*16+4
    TextGadget(id,xpos,ypos,797,24,"The selected calculation, formatted for the parser",#PB_Text_Center)
    pos(0,y)=GadgetID(id)
    AddKeyboardShortcut(#Window,#PB_Shortcut_Return,#Riturn)
    AddKeyboardShortcut(#Window,#PB_Shortcut_Up,#Up)
    AddKeyboardShortcut(#Window,#PB_Shortcut_Down,#Down)
    AddKeyboardShortcut(#Window,#PB_Shortcut_Tab,#Tab)
    AddKeyboardShortcut(#Window,#PB_Shortcut_Escape,#Escape)
  EndIf
  For id=0 To maxg
    SetGadgetFont(id,FontID.l)
  Next
  xpos=2
  ypos=0
EndIf



ActivateGadget(2)



;== Procedures ==============

; perform the calculation - everything depends on this ...
; I need a procedure or a function called Parse() to make his work
Procedure do_the_calculations()
  For t=0 To maxl
    txt$(1,t)=Formel_(txt$(2,t))
  Next
EndProcedure



; update the contents of the display gadgets
Procedure refresh_the_window()
  id=0
  For t=0 To maxy
    ;Debug txt$(0,t+offs)
    SetGadgetText(id,txt$(0,t+offs)) : id+1
    SetGadgetText(id,txt$(1,t+offs)) : id+1 ; #Gadget object not initialised !
    SetGadgetText(id,txt$(2,t+offs)) : id+1
  Next
EndProcedure



;=======================



Repeat ; Main loop

  EventID=WaitWindowEvent()

  ;discover the string with the focus
  If EventID=#PB_Event_Menu
    For x=0 To maxx
      For y=0 To maxy
        If GetFocus_()=pos(x,y)
          xpos=x
          ypos=y
        EndIf
      Next
    Next

    ;I would never have thought to lookup "MenuID" for "keydown detection"!
    em=EventMenuID()
    SetGadgetText(48,Str(em))
    Select em
      Case #Up
        If ypos>0 Or offs>0
          If ypos>0
            ypos-1
          Else
            offs-1
            refresh_the_window()
          EndIf
        EndIf
      Case #Down
        If yposmaxx:xpos=0:EndIf
      Case #Riturn
        do_the_calculations()
        refresh_the_window()
      Case #Escape
        End
    EndSelect
    SetFocus_(pos(xpos,ypos))
  EndIf
Until EventID=#PB_Event_CloseWindow

End
If you have more questions, just ask me.

PureFan
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by julianbury.

Thanks, Sebi :)

Can't wait to try it!


Julian ^00^
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Sebi.

Have you already downloaded it??? :)

If yes, you must do it again. There was another error. I hope I won't find more of them.

PureFan
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by julianbury.

It works!
wonderful!

Is it possible to get the parser to return real numbers?


Julian ^00^
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Sebi.

What do you mean with "real numbers"???
Numbers like in your question in the beginner topic??

You can do this with:

FloatValue.f = ValF(Formel_("0.5463+0.37464"))

ValF converts the string to the floating-point-value.

The only problem: Float is very inaccurately. But there is no better format. PB doesn't support double or anything else for numbers with a comma.

But if you don't want to calculate prices which should be very exactly you can use float.

PureFan
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by julianbury.

Hi Sebi,
I am using that. It will have to do. Thank you Sebi :)


Julian ^00^
Post Reply