EVAL

New to FreeBASIC? Post your questions here.
bplus
Posts: 56
Joined: May 01, 2017 15:57

EVAL

Post by bplus »

I would like very much to see FB version / method to do EVAL

Here is how it's done in SmallBASIC (but it is only an Interpreter):

Code: Select all

'quick calculator.bas  SmallBASIC 0.12.2 [B+=MGA] 2016-04-12
'Thanks shian!

repeat
  input "enter string to evaluate ";es
  if es <> "" then ? eval(es)
until es = ""

func eval(s)
  Chain "env " + enclose("EVAL=") + " + Str(" + s + ")"
  eval = env("eval")
end
How might this be done in FB?

Here is how some other BASICs are doing it:
http://retrogamecoding.org/board/index.php?topic=467.0
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: EVAL

Post by MrSwiss »

bplus wrote:I would like very much to see FB version / method to do EVAL
In order to do that, we'd first need to have a description of the EVAL (command: function? / sub? / operator? and,
input/output variable types etc.) ...
With other words: what is EVAL "doing"? (in SmallBASIC)

Just guessing here: have a look at VAL (and it's "derivates") in FB ...
(if it's about: String ==> Number, conversion)
Last edited by MrSwiss on Jun 27, 2017 14:45, edited 1 time in total.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: EVAL

Post by dodicat »

Somebody posted this a few years ago.
I think it is derived from visual basic .
(I added a few extra functions).

Code: Select all

'==============  PARSER START  ==================================
Dim Shared e_input    As String  
Dim Shared e_tok      As String  
Dim Shared e_spelling As String  
Dim Shared e_error    As Integer 


Function SEC(Byval x As Double) As Double
    SEC = 1 / Cos(x)
End Function

Function COSEC(Byval x As Double) As Double
    COSEC = 1 / Sin(x)
End Function

Function COT(Byval x As Double) As Double
    COT = 1 / Tan(x)
End Function

Function ARCSEC(Byval x As Double) As Double 
    ARCSEC = Atn(x / Sqr(x * x - 1)) + Sgn((x) -1) * (2 * Atn(1))
End Function

Function ARCCOSEC(Byval x As Double) As Double
    ARCCOSEC = Atn(x / Sqr(x * x - 1)) + (Sgn(x) - 1) * (2 * Atn(1))
End Function

Function ARCCOT(Byval x As Double) As Double
    ARCCOT = Atn(x) + 2 * Atn(1)
End Function

Function sinh(Byval x As Double) As Double
    sinh = (Exp(x) - Exp(-x)) / 2 
End Function

Function cosh(Byval x As Double) As Double
    cosh = (Exp(x) + Exp(-x)) / 2
End Function

Function tanh(Byval x As Double) As Double
    tanh = (Exp(x) - Exp(-x)) / (Exp(x) + Exp(-x))
End Function

Function sech(Byval x As Double) As Double
    sech = 2 / (Exp(x) + Exp(-x))
End Function

Function cosech(Byval x As Double) As Double
    cosech = 2 / (Exp(x) - Exp(-x))
End Function

Function coth(Byval x As Double) As Double
    coth = (Exp(x) + Exp(-x)) / (Exp(x) - Exp(-x))
End Function

Function arcsinh(Byval x As Double) As Double
    arcsinh = Log(x + Sqr(x * x + 1))
End Function

Function arccosh(Byval x As Double) As Double
    arccosh = Log(x + Sqr(x * x - 1))
End Function

Function arctanh(Byval x As Double) As Double
    arctanh = Log((1 + x) / (1 - x)) / 2 
End Function

Function arcsech(Byval x As Double) As Double
    arcsech = Log((Sqr(-x * x + 1) + 1) / x)
End Function

Function arccosech(Byval x As Double) As Double
    arccosech = Log((Sgn(x) * Sqr(x * x + 1) +1) / x)
End Function

Function arccoth(Byval x As Double) As Double
    arccoth = Log((x + 1) / (x - 1)) / 2
End Function

Function HAVERSINE(Byval x As Double) As Double
    HAVERSINE = (Sin(x/2))^2
End Function

Function e_function(byref fun As String,byval arg As Double) As Double
  Dim n As Double

  Select Case Lcase(fun)
    Case "abs": n = Abs(arg)
    Case "atn": n = Atn(arg)
    Case "cos": n = Cos(arg)
    Case "exp": n = Exp(arg)
    Case "fix": n = Fix(arg)
    Case "int": n = Int(arg)
    Case "log": n = Log(arg)
    Case "rnd": n = Rnd(arg)
    Case "sgn": n = Sgn(arg)
    Case "sin": n = Sin(arg)
    Case "sqr": n = Sqr(arg)
    Case "tan": n = Tan(arg)
    Case "haversine":n=haversine(arg)
    Case "cosec":n=cosec(arg)
    Case "sec":n=sec(arg)
    Case "cot": n=cot(arg)
    Case "asin":n=asin(arg)
    Case "acos":n=acos(arg)
    Case "atn":n=atn(arg)
    Case "arcsec":n=arcsec(arg)
    Case "arccosec":n=arccosec(arg)
    Case "arccot":n=arccot(arg)
    Case "sinh":n=sinh(arg)
    Case "cosh":n=cosh(arg)
    Case "tanh":n=tanh(arg)
    Case "sech":n=sech(arg)
    Case "cosech":n=cosech(arg)
    Case "coth":n=coth(arg)
    Case "arcsinh":n=arcsinh(arg)
    Case "arccoth":n=arccoth(arg)
    Case "arctanh":n=arctanh(arg)
    Case "arcsech":n=arcsech(arg)
    Case "arccosech":n=arccosech(arg)
    Case "arccoth":n=arccoth(arg)
    Case Else
      If Not e_error Then
          locate 1,1
         Print "UNDEFINED FUNCTION " + fun
         e_error = -1
      End If
   End Select
   e_function = n
End Function

Sub e_nxt()
  Dim is_keyword As Integer
  Dim c As String 
  e_tok = ""
  e_spelling = ""
  Do
    c = left(e_input, 1)
    e_input = Mid(e_input, 2)
  Loop While c = " " Or c = Chr(9) Or c = Chr(13) Or c = Chr(10)

  Select Case Lcase(c)

  Case "0" To "9", "."
      e_tok = "num"
      Do
        e_spelling = e_spelling + c
        c = left(e_input, 1)
        e_input = Mid(e_input, 2)
      Loop While (c >= "0" And c <= "9") Or c = "."
      e_input = c + e_input

    Case "a" To "z", "_"
      Dim As Integer is_id
      e_tok = "id"
      Do
        e_spelling = e_spelling + c
        c = Lcase(left(e_input, 1))
        e_input = Mid(e_input, 2)
        is_id = (c >= "a" And c <= "z")
        is_id = is_id Or c = "_" Or (c >= "0" And c <= "9")
      Loop While is_id
      e_input = c + e_input
      is_keyword = -1
      Select Case Lcase(e_spelling)
        Case "and"
        Case "eqv"
        Case "imp"
        Case "mod"
        Case "not"
        Case "or"
        Case "xor"
        Case Else: is_keyword = 0
      End Select
      If is_keyword Then
         e_tok = Lcase(e_spelling)
      End If

    Case "<", ">"
      e_tok = c
      c = left(e_input, 1)
      If c = "=" Or c = ">" Then
         e_tok = e_tok + c
         e_input = Mid(e_input, 2)
      End If

    Case Else
      e_tok = c
  End Select

  If e_spelling = "" Then
    e_spelling = e_tok
  End If
End Sub

Sub e_match (byref token As String)
  If Not e_error And e_tok <> token Then
      locate 1,1
    Print "EXPECTED " + token + ", got '" + e_spelling + "'"
    e_error = -1
  End If
  e_nxt()
End Sub

Function e_prs (byval p As Integer) As Double
   Dim n   As Double  
   Dim fun As String  
   If e_tok = "num" Then
      n = Val(e_spelling)
      e_nxt()
   Elseif e_tok = "-" Then
      e_nxt()
      n = -e_prs(11)   
   Elseif e_tok = "not" Then
      e_nxt()
      n = Not e_prs(6) 
   Elseif e_tok = "(" Then
      e_nxt()
      n = e_prs(1)
      e_match(")")
   Elseif e_tok = "id" Then
      fun = e_spelling
      e_nxt()
      e_match("(")
      n = e_prs(1)
      e_match(")")
      n = e_function(fun, n)
   Else
      If Not e_error Then
         locate 1,1
         Print "syntax error, at '" + e_spelling + "'"
         e_error = -1
      End If
   End If

  Do While Not e_error
    If     p <= 11 And e_tok = "^"   Then 
      e_nxt(): n = n ^ e_prs(12)
    Elseif p <= 10 And e_tok = "*"   Then 
      e_nxt(): n = n *   e_prs(11)
    Elseif p <= 10 And e_tok = "/"   Then 
      e_nxt(): n = n /   e_prs(11)
    Elseif p <= 9  And e_tok = "\"   Then 
      e_nxt(): n = n \   e_prs(10)
    Elseif p <= 8  And e_tok = "mod" Then 
      e_nxt(): n = n Mod e_prs(9)
    Elseif p <= 7  And e_tok = "+"   Then 
      e_nxt(): n = n +   e_prs(8)
    Elseif p <= 7  And e_tok = "-"   Then 
      e_nxt(): n = n -   e_prs(8)
    Elseif p <= 6  And e_tok = "="   Then 
      e_nxt(): n = n =   e_prs(7)
    Elseif p <= 6  And e_tok = "<"   Then 
      e_nxt(): n = n <   e_prs(7)
    Elseif p <= 6  And e_tok = ">"   Then 
      e_nxt(): n = n >   e_prs(7)
    Elseif p <= 6  And e_tok = "<>"  Then 
      e_nxt(): n = n <>  e_prs(7)
    Elseif p <= 6  And e_tok = "<="  Then 
      e_nxt(): n = n <=  e_prs(7)
    Elseif p <= 6  And e_tok = ">="  Then 
      e_nxt(): n = n >=  e_prs(7)
    Elseif p <= 5  And e_tok = "and" Then 
      e_nxt(): n = n And e_prs(6)
    Elseif p <= 4  And e_tok = "or"  Then 
      e_nxt(): n = n Or  e_prs(5)
    Elseif p <= 3  And e_tok = "xor" Then 
      e_nxt(): n = n Xor e_prs(4)
    Elseif p <= 2  And e_tok = "eqv" Then 
      e_nxt(): n = n Eqv e_prs(3)
    Elseif p <= 1  And e_tok = "imp" Then 
      e_nxt(): n = n Imp e_prs(2)
    Else
      Exit Do
    End If
  Loop
  e_prs = n
End Function

Function eval(Byref sp as string ) As double
   dim as double value
   e_error = 0
   e_input = sp
   e_nxt()
   value = e_prs(1)
    if not e_error then return value
   End Function
'======

Function FindAndReplace(byref instring As String,byref ReplaceThis As String,byref WithThis As String) As String 
    var lens1=Len(ReplaceThis),lens2=Len(WithThis)
    If lens1=lens2 Then lens1=0
   dim as string s=instring 
    Dim As Integer position=Instr(s,ReplaceThis)
    While position>0
        If lens1 Then   
            s=Left(s,position-1) & WithThis & Mid(s,position+Lens1)
        Else
            Mid(s,position) = WithThis
        End If
        position=Instr(position+Lens2,s,ReplaceThis)
    Wend
    Function=s
End Function
'=================== END OF PARSER =======================

'===============================================================================


dim as string e
dim as double f

  
    
   e = " 13^(1/3)*(cos(20 )*asin(.5)^3*21*log(123)/2.5)*atn(123)*A_1* B_1+Arccot(2)"
  'A_1  and B_1 are variables in the string
   e= FindAndReplace(e,"A_1","10")
   e= FindAndReplace(e,"B_1","10.345")
    f = Eval(e)
   

print
print "Input     = " ; e
print
print "Answer    = " ; f
print "FB Answer = " ; (13^(1/3)) * (cos( 20 )*asin(.5)^3 * 21 * log(123) / 2.5 ) * atn(123) * 10 * 10.345+arccot(2)
print
sleep
 
If you want to use variables in the string, call them something which won't clash with function/operator names.
bplus
Posts: 56
Joined: May 01, 2017 15:57

Re: EVAL

Post by bplus »

MrSwiss wrote:
bplus wrote:I would like very much to see FB version / method to do EVAL
In order to do that, we'd first need to have a description of the EVAL (command: function? / sub? / operator? and,
input/output variable types etc.) ...
With other words: what is EVAL "doing"? (in SmallBASIC)
The EVAL function takes an expression in string form eg (1 + 2 / 3) ^ (21 % 5)" or len("This is some string") or mid("This is some string", 6, 4) or 100 >= 10 (return Boolean 0|1) and return the value of that string as if run as a line in a BASIC program. You would have to substitute in the value of variables, a literal string or number, before calling EVAL.

Like variable = expression, EVAL returns what the variable would be set at inside BASIC values tables, if the expression contained just literals.

Oops, now that I have described it, I can see that there would be all sorts of variable type declarations that would make this extremely difficult for FB.
Yikes!

Well I certainly know very little about what can be done in FB, maybe there is still hope?

It's that darn contest, I made a nice simple little interpreter and I want to make a stand alone with it. It revolves around finding the equivalent method I used with SmallBASIC to handle expression evaluations.
bplus
Posts: 56
Joined: May 01, 2017 15:57

Re: EVAL

Post by bplus »

Dodicat, thanks I think you are onto it. I like seeing Boolean operators included. I have worked math evaluator with nested parenthesis using recursion but I left out Booleans (and strings of course!). I will study.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: EVAL

Post by MrSwiss »

bplus wrote:I can see that there would be all sorts of variable type declarations that would make this extremely difficult for FB.
I think that, since math. can easily be done in FB, such an evaluator, makes not a lot of sense.
Apart from the fact, that this would really be a speed brake (compared to straigt math.).
This might be an issue, in an interpreter, however ...
bplus
Posts: 56
Joined: May 01, 2017 15:57

Re: EVAL

Post by bplus »

MrSwiss wrote:
bplus wrote:I can see that there would be all sorts of variable type declarations that would make this extremely difficult for FB.
I think that, since math. can easily be done in FB, such an evaluator, makes not a lot of sense.
Apart from the fact, that this would really be a speed brake (compared to straigt math.).
This might be an issue, in an interpreter, however ...
Hi MrSwiss,

It started with those practice calculators to learn to program in new BASIC dialect. You get fancier and fancier adding functions, Radian, degrees conversions... THEN you get the brilliant idea to try a graphing calculator! That's when you realize you need a formula evaluator so you can do things over a range of x values...

It's true after some point, you say to yourself, this is just easier to graph with straight BASIC, just plug in whatever formula you need to graph...

I was fine with that too until from a totally different direction I built this little interpreter (it does not use any punctuation other than spaces) and think it would be neat to make a stand alone exe of it.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: EVAL

Post by MrSwiss »

Hi bplus,

whilst doing your evaluator, you might be interested in my easy #include, for FBgfx:
GFX_MATH.bi which is using "single line macros" for the most common stuff, like:
degrees to radians; radians to degrees etc. (faster than Functions, "inlined" code).
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: EVAL

Post by BasicCoder2 »

Not sure if it is relevant to your question but I once had to try and work out a simple expression evaluator.
http://www.freebasic.net/forum/viewtopi ... hilit=eval
It was only for simple arithmetic although I don't see why transcendental functions couldn't be added.
.
bplus
Posts: 56
Joined: May 01, 2017 15:57

Re: EVAL

Post by bplus »

BasicCoder2 wrote:Not sure if it is relevant to your question but I once had to try and work out a simple expression evaluator.
http://www.freebasic.net/forum/viewtopi ... hilit=eval
It was only for simple arithmetic although I don't see why transcendental functions couldn't be added.
.
Spot on! I will also study your method of parsing as well. Thanks

Hi MrSwiss,

I have to confess that I see allot a talk at this site about macro's and don't quite know what is being talked about.

I don't think a macro is a one line function definition like:
def mySinPlus(x) = sin(x) + cos(x)

or a subroutine attached to a special key press which I have also heard the term macro applied... so I need helpful description.

Also for radian and degree conversions, I generally setup constants eg D2R = pi/180 and just multiply degrees by constant when need radian conversion. I would be surprised to learn there is faster method.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: EVAL

Post by MrSwiss »

Hi bplus,

Macros (in the sense of a programming language, not the keyboard stuff), are code pieces that are
coded once (similar to procedures) but, unlike procedures the code is "expanded" (rewritten) at the
position in code, the macro is called. Below: your "ex. code" as a valid "single line macro" in FB:
bplus wrote:

Code: Select all

#Define mySinPlus(x)  ( sin(x) + cos(x) )
about:
D2R = pi/180 (looks like: val*D2R in code) ... with the macro, using the same constant the code is:

Code: Select all

RAD(val)  ' RAD = macro name
which is far less cryptic than above (and does the very same thing).
The benefit here, is the better readability of code (less documentation needed, as a result).

Did you have a look, at my provided (linked) example #include? (should have answered above really)
St_W
Posts: 1626
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: EVAL

Post by St_W »

FreeBasic does not come with an EVAL function because it is a compiled language, not an interpreted one. This means that all the source code parsing is done at compile time and machine code is generated. So there's no parsing functionality available at runtime. This is what you would need: an expression parser+evaluator. dodicat already posted an example implementation of such a parser. I think we already had also some different ones here on the forums in the past years. Depending on the features you want to provide the implementation may get quite complicated.

Regarding macros: they are evaluated at compile time, even before the source code is parsed, so they are quite a different thing than expression evaluation at runtime and won't really help for that. Nevertheless, you should know about them ;-)
You can't make any FB function (or even worse: macro) available in an expression evaluator at runtime in any other way than implementing a parser + interpreter for the respective functions. So you will have to do a lot of things that the FreeBasic compiler also does, like macro expansion and parsing.
bplus
Posts: 56
Joined: May 01, 2017 15:57

Re: EVAL

Post by bplus »

Good! thanks, I am starting to feel like I am back at school being piled with several books to read! Apparently I'm becoming a student of EVAL, I have worked a few versions at JB myself and was hoping for short way around.

But as St_W points out, that I am slowly come to realize the difference between Compiled and Interpreted... with my little Interpreter in SmallBASIC (SB), still need to have SB around to do the EVAL, might as well just write the code in SB?

Yes MrSwiss, I looked at your link but did not see. The matter of what a macro is had to be settled first, then your example makes much more sense, I can see what you mean better. My eyes aren't use to reading FB automatically yet, there are many new concepts to digest.

I imagine FB itself has something like an EVAL function built into it. Is it built from FB or some other language?
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: EVAL

Post by MrSwiss »

bplus wrote:I imagine FB itself has something like an EVAL function built into it. Is it built from FB or some other language?
This would depend on the location (there are 3 mayor components, to FB):
  • the compiler itself (FB)
    the crt library (C-Runtime-Lib)
    the gfx library (Graphics-Lib, in C)
A lot of those evaluations, however, are simple assertions, e.g. variable-Type checks etc.
Again: a compiler and a interpreter are, two different pairs, of shoes ...
Post Reply