Author Topic: Expression evaluator  (Read 19468 times)

0 Members and 1 Guest are viewing this topic.

Aurel

  • Guest
Expression evaluator
« on: June 19, 2012, 08:04:08 AM »
Hi Charles...
I want try convert one expression evaluator from EB to Oxygen and i
find one problem in inverse function of INSTR called InstrP.
This function require one optional parameter.
Do we have in oxygen opt or optional statment ?
here is this function:
Code: [Select]
FUNCTION InstrP(source As STRING, search As STRING,start as INT) As INT
'this sub searches for the LAST string search in the string source,
'reverse of the function instr(). The sub returns 0 if the search could not be found.
'Also this function neglects content between brackets () in source
   INT n, bopen,bclose
   STRING sign
   start=255
   n=start
   IF n > LEN(source) THEN n = LEN(source) - LEN(search)+1
   bopen=0   'number of bracket open
   bclose=0  'number of bracket close
   DO
      sign = MID(source, n, LEN(search))
      IF sign=search AND bopen=bclose THEN RETURN n   'exit the sub, return n
      IF LEFT(sign,1)=chr(28) THEN bopen++
      IF LEFT(sign,1)=chr(29) THEN bclose++
      n=n-1
   IF n <= 0 THEN EXIT DO
   END DO
   RETURN 0   'if the string search is not found, then return 0
END FUNCTION

Or maybe i made mistake in DO loop ?
Any suggestion ?

Aurel

  • Guest
Re: Expression evaluator
« Reply #1 on: June 19, 2012, 11:42:45 AM »
Hmm
I don't understand why i can't replicate original code ::)
Original code have DO/UNTIL <expr> loop
So have replace do/until with Oxygen code ?

Aurel

  • Guest
Re: Expression evaluator
« Reply #2 on: June 19, 2012, 12:12:10 PM »
Oh my,i'm still not sure what i do wrong or now right ::)
But looks that now work.
So you can now test program.
By the way original author is Jos de Jong aka Joske, Kent know him
from CodingMonkeys forum.I also use this code as base for expr evaluator in ABasic
of course with variables,linked list etc.
Ok full code...
Code: [Select]
/*
Simple Expression Evaluator
Supports expressions with operators + - * / ^ E and parentheses ( )
Original by: JOS de JONG -> Joske
*/
indexbase 0
#lookahead ' for procedures
INT TRUE = 1
INT FALSE = 0
STRING out,msg

'test
'---------------------------------
String in$
'in$ = "(2+3)-1"
'in$ = "2+(3-2)"
'in$ = "(2+3)*3"
in$ = "12/(3-1)"
out = Eval_line(in$)
print out



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

FUNCTION Eval_line(expression As STRING) As STRING
'this sub evaluates the expression and returns a string that
'can contain the answer or an (error) message.
'the expression can have values, operators + - * / ^ E and parentheses ( )
   FLOAT ans
   
   msg=""
   ans = Eval(expression)    'evaluate the expression
'print "ANS: "+ str(ans)
   IF msg<>"" THEN RETURN msg         :'return (error) message if not empty
   RETURN "Ans = " + str(ans)      :'return the answer
END FUNCTION

'_______________________________________________________________
FUNCTION Eval(expression As STRING) As FLOAT
'evaluate expression
'The expression can contain operators, values, parentheses, spaces
'Input:  a string containing an expression
'Output: a FLOAT, containing the answer of the expression.
   STRING expr, op
   INT n, i
   FLOAT value1, value2, res
   expr = Trim(expression)      :'copy the expression to another to keep the original string intact
           
   'check if expr is equal to a value. If so, return the value of expr
   IF IsOK_value(Trim(expr))=TRUE THEN RETURN val(Trim(expr))

   'check for the operator with the lowest precedence (outside parenthesis), and evalulate it
   'order from low to high:   + - * / ^ E
   FOR i=1 TO 6
      op = MID("+-*/^E", i, 1)

      n = InstrP(expr, op,len op)
      'print "N: " + str(n)
      WHILE n > 0
         IF IsOK_operator(expr,op,n) = TRUE
            'this is indeed an operator. evaluate it
            'IF n=1: ert("Error: Missing value before operator " + op): RETURN : END IF
            'IF n=LEN(expr): ert("Error: Missing value after operator " + op):RETURN : END IF
            'IF op="E" THEN
               'IF MID(expr,n+1,1)="+" THEN Replace(expr,n+1,1," ")   :'replace "2e+3" with "2e 3"  (remove unary plus)
           ' END IF
            value1 = Eval(LEFT(expr,n-1))
            value2 = Eval(Right(expr,LEN(expr)-n))
           
            IF op ="+" THEN res = value1 + value2
            IF op ="-" THEN res = value1 - value2
            IF op ="*" THEN res = value1 * value2
            IF op ="/"
               'IF value2=0: ert("Error: Divide by zero") :RETURN 0 :END IF
               res = value1 / value2
            END IF
            IF op ="^" THEN res = value1 ^ value2
            'IF op ="E" THEN res = value1 * 10^value2
               
            'print "RES: "+ str(res)
            RETURN res
         END IF
           
         IF n>0 THEN n = InstrP(UCASE(expr), op, n-1)      :'search for previous operator
      WEND
   NEXT i

   IF LEFT(expr,1)="(" AND RIGHT(expr,1)=")" THEN
      'remove parentheses at start and end, for example "(2+3)" -> "2+3"
      RETURN Eval(MID(expr,2,LEN(expr)-2))
   END IF

   'if still not evalved, then return an error
   'ert("Error: Syntax error in part '" + expr + "'")
   RETURN 0
END FUNCTION
                 
'_______________________________________________________________
FUNCTION IsOK_operator(expr As STRING, op As string, n As int) As string
'this sub checks of the operator at postion n in expr is a legal operator
'for example the "+" in "2.3E+3" is no operator, and the "-" in "-2.5" is no operator but a unary minus
STRING sign2

   IF op="+"
      IF UCASE(MID(expr,n-1,1))="E"
         IF n>2
            IF INSTR("1234567890.", MID(expr,n-2,1))>0 THEN RETURN FALSE
         END IF
      END IF
   ENDIF
   
   IF op="-"
      IF n=1
         'this is an unary minus
         RETURN FALSE
      ELSE
         'check for an unary minus (for example 2*-3  or  2.5E-6)
         sign2 = LEFT(expr,n-1)
         sign2 = RTRIM(sign2)
         sign2 = Right(sign2,1)
         IF INSTR("+-/*^", sign2)>0 THEN RETURN FALSE
         'IF UCASE(MID(expr,n-1,1))="E"
            'IF n>2
               'IF INSTR("1234567890.", MID(expr,n-2,1))>0 THEN RETURN FALSE
           ' END IF
         'END IF
      END IF
   END IF
   
   RETURN TRUE
END FUNCTION
                 
'_______________________________________________________________
FUNCTION IsOK_value(expr As STRING) As string
'this sub checks if expr is a legal value. if so, returns true. if not, returns false
   INT i
   STRING sign
   
   FOR i=1 TO LEN(expr)
      sign = UCASE(MID(expr,i,1))
      IF INSTR("1234567890.-", sign)=0 THEN RETURN FALSE         'check for legal signs in the string
      'IF sign="." THEN IF INSTR(expr,".",i+1)>0 THEN RETURN FALSE   'check if there is max. 1 point in the string
      IF sign="-" THEN
IF i<>1 THEN RETURN FALSE
END IF  'check for correct use of minus: only at position 1
   NEXT i
   
   RETURN TRUE
END FUNCTION
               
'__________________________________________________________________

                       
'__________________________________________________________________
FUNCTION Trim(mystr As STRING) As STRING
'remove spaces and tabs at start and end of the string
   RETURN LTRIM(RTRIM(mystr))
END FUNCTION

'__________________________________________________________________

'__________________________________________________________________
FUNCTION InstrP(source As STRING, search As STRING,start as INT) As INT
'this sub searches for the LAST string search in the string source,
'reverse of the function instr(). The sub returns 0 if the search could not be found.
'Also this function neglects content between brackets () in source
   INT n, bopen,bclose
   STRING sign
   start=255
   n=start
   IF n > LEN(source) THEN n = LEN(source) - LEN(search)+1
   bopen=0   'number of bracket open
   bclose=0  'number of bracket close
  do
   
      sign = MID(source, n, LEN(search))
      IF (sign=search) AND (bopen=bclose) THEN Return n  'exit the sub, return n
      IF LEFT(sign,1)="(" THEN bopen=bopen+1
      IF LEFT(sign,1)=")" THEN bclose=bclose+1
      n=n-1
   if n<=0 then exit do
   end do
   
 
   RETURN 0  'if the string search is not found, then return 0

END FUNCTION
'_________________________________________________________________________
FUNCTION Right(getStr As String,rLen As Int) As String
String retStr
retStr = MID(getStr,-rLen)
Return retStr
END FUNCTION
'_________________________________________________________________________
FUNCTION Replace(t as string,w as string,r as string) As String 
   '======================================= 
   ' 
   sys    a,b,lw,lr 
   string s=t 
   ' 
   lw=Len w 
   lr=Len r 
   a=1 
   '   
   DO 
     a=INSTR a,s,w 
    IF a=0 THEN EXIT DO 
     s=LEFT(s,a-1)+r+MID(s,a+lw) 
     a=a+lr 
   END DO 
   RETURN s 
END FUNCTION 

Aurel

  • Guest
Re: Expression evaluator
« Reply #3 on: November 26, 2013, 04:09:36 PM »
Hi Charles...
Do you have maybe somewhere better ...
i mean faster expression evaluator example ?
« Last Edit: January 06, 2014, 11:51:10 AM by Aurel »

Charles Pegge

  • Guest
Re: Expression evaluator
« Reply #4 on: November 26, 2013, 10:35:30 PM »
Hi Aurel,

One possibility is to use Oxygen's dynamic compiling facility.

Take a look at examples/DynamicCompile/..

Eval.o2bas
Code: [Select]
function eval (string s) as double
'=================================
  '
  sys    a,c
  string t,er
  '
  t="function f() as double {return "+s+"} : c=@f "
  '
  a=compile t
  er=error
  '
  if er then
    print "runtime error: "  er : exit function
  end if
  '
  c=call a
  declare f()as double at c
  function=f()
  '
  freememory a
  '
  end function

  '=====
  'TESTS
  '=====
 
  print eval "3*3*3"
  print eval "sqr(64)"
  print eval "pi()"

Dynamic compiling requires Oxygen.dll so it won't work in independent mode (RTL32/RTL64).

Aurel

  • Guest
Re: Expression evaluator
« Reply #5 on: November 27, 2013, 01:26:12 AM »
Hi Charles..
Yes i know that compile function and i know that need oxygen.dll
I ask because i found in my evaluator (by joske)
that on this way it eat lot of memory..
is this because he use lot of strings.

Peter

  • Guest
Re: Expression evaluator
« Reply #6 on: November 27, 2013, 07:30:17 AM »
My lunch today.  Bought it by Lidl. Cost 0.99 Cent

.

JRS

  • Guest
Re: Expression evaluator
« Reply #7 on: November 27, 2013, 09:21:06 AM »
Our southern friends are getting ready for Thanksgiving with this famous dish.  :D




Peter

  • Guest
Re: Expression evaluator
« Reply #8 on: November 27, 2013, 09:54:01 AM »
Yes,  all natural, not synthetic.

JRS

  • Guest
Re: Expression evaluator
« Reply #9 on: November 27, 2013, 09:59:49 AM »
Yes, and Bubba approved.

Aurel

  • Guest
Re: Expression evaluator
« Reply #10 on: November 27, 2013, 12:41:08 PM »
what is this?
spam?

Charles Pegge

  • Guest
Re: Expression evaluator
« Reply #11 on: November 27, 2013, 09:00:38 PM »
Simple expression evaluator. No strings except for the source.

Code: OxygenBasic
  1. 'SIMPLE EVALUATOR
  2.  
  3. ' supporting:
  4. ' +-*/
  5. ' floating ppoint values
  6. ' variables a..z
  7. ' brackets
  8. ' multiple statements and lines
  9.  
  10.  
  11. function evalnm(sys *dp, double *v,sys b)
  12. =========================================
  13. b-=48
  14. if dp=0
  15.   v=v*10+b
  16. else
  17.   dp*=10
  18.   v=v+b/dp
  19. end if
  20. end function
  21.  
  22.  
  23. function evalop(sys op, double *a,v)
  24. ====================================
  25. select op
  26. case 0   : a=v
  27. case "+" : a+=v
  28. case "-" : a-=v
  29. case "*" : a*=v
  30. case "/" : a/=v
  31. case
  32. end select
  33. end function
  34.  
  35.  
  36. function eval(string s) as double
  37. =================================
  38. indexbase 0
  39. byte b at (strptr s) 'source string
  40. double a       'accum
  41. double v       'value
  42. double vv[256] 'variable store
  43. double st[16]  'stack value
  44. sys    sp[16]  'stack operator
  45. sys    op      'operator
  46. sys    ai      'accum index
  47. sys    si      'stack index
  48. sys    vi      'variable index
  49. sys    dp      'decimal point
  50. do
  51.   select b
  52.   case 0          : evalop(op,a,v) : return a
  53.   case 10 to 13   : evalop(op,a,v) : vv[ai]=a : a=0 : v=0 : op=0 : dp=0
  54.   case ":"        : evalop(op,a,v) : vv[ai]=a : a=0 : v=0 : op=0 : dp=0
  55.   case "0" to "9" : evalnm(dp,v,b)
  56.   case "A" to "Z" : vi=b : v=vv(vi) : dp=0
  57.   case "a" to "z" : vi=b : v=vv(vi) : dp=0
  58.   case "="        : ai=vi
  59.   case "."        : dp=1
  60.   case 42 to 47   : evalop(op,a,v) : op=b : v=0 : dp=0
  61.   case "("        : st[si]=a : sp[si]=op : a=0 : v=0 : op=0 : dp=0 : si++
  62.   case ")"        : evalop(op,a,v) : si-- : v=a : a=st[si] : op=sp[si] : dp=0
  63.   end select
  64.   @b++
  65. end do
  66. end function
  67.  
  68.  
  69. print eval("a=32 : b=16.25 : 2*(a+b) ") '96.5
  70.  
« Last Edit: November 27, 2013, 09:09:27 PM by Charles Pegge »

Aurel

  • Guest
Re: Expression evaluator
« Reply #12 on: November 27, 2013, 11:40:14 PM »
Thank you Charles... :)
This really look very interesting and i think simple to use.
I will try to use this method to check how work in loops and other things...

Aurel

Aurel

  • Guest
Re: Expression evaluator
« Reply #13 on: November 28, 2013, 11:37:30 AM »
Charles
I must say that evaluator work great ;)
Just one small thing...
I would like to use variable from my variable array not inside function Eval.
So what i need to do the evaluator see my external variable.

i look into case :
Code: [Select]
case "a" to "z"
     vi=b : v=vv[vi] : dp=0
     'vi=b  : v=GetIntValue(string ) :dp=0
    print

as you see i need string(variable name) in my function to return value to evaluator.
I tried with
v=getIntValue( @b)
but of course i receive just adress ... ::)
vi is just variable index
vv[vi] is numeric array

there is no strings anywhere...
any help ?

JRS

  • Guest
Re: Expression evaluator
« Reply #14 on: November 28, 2013, 10:26:28 PM »
what is this?
spam?

No, Spam is made of pork products. (and other unknown fillers) Turkey is the focus on the day before Black Friday.