Oxygen Basic

Programming => Example Code => Data Processing => Topic started by: Aurel on June 19, 2012, 08:04:08 AM

Title: Expression evaluator
Post by: Aurel 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 ?
Title: Re: Expression evaluator
Post by: Aurel 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 ?
Title: Re: Expression evaluator
Post by: Aurel 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 
Title: Re: Expression evaluator
Post by: Aurel on November 26, 2013, 04:09:36 PM
Hi Charles...
Do you have maybe somewhere better ...
i mean faster expression evaluator example ?
Title: Re: Expression evaluator
Post by: Charles Pegge 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).
Title: Re: Expression evaluator
Post by: Aurel 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.
Title: Re: Expression evaluator
Post by: Peter on November 27, 2013, 07:30:17 AM
My lunch today.  Bought it by Lidl. Cost 0.99 Cent

.
Title: Re: Expression evaluator
Post by: JRS on November 27, 2013, 09:21:06 AM
Our southern friends are getting ready for Thanksgiving with this famous dish.  :D

(http://files.allbasic.info/O2/bubba_buger.png)

Title: Re: Expression evaluator
Post by: Peter on November 27, 2013, 09:54:01 AM
Yes,  all natural, not synthetic.
Title: Re: Expression evaluator
Post by: JRS on November 27, 2013, 09:59:49 AM
Yes, and Bubba approved.
Title: Re: Expression evaluator
Post by: Aurel on November 27, 2013, 12:41:08 PM
what is this?
spam?
Title: Re: Expression evaluator
Post by: Charles Pegge 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.  
Title: Re: Expression evaluator
Post by: Aurel 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
Title: Re: Expression evaluator
Post by: Aurel 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 ?
Title: Re: Expression evaluator
Post by: JRS 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.

Title: Re: Expression evaluator
Post by: Peter on November 29, 2013, 03:01:46 AM
Code: [Select]
Turkey is the focus on the day before Black Friday.
Turkey

It's really funny.

Turkey    =   Pute   <  German
to roast a turkey

Turkey    =  Türkei  < German
therewith, Berlin is the largest Turkish community outside of Turkey.

What is now 'TURKEY' ?
Title: Re: Expression evaluator
Post by: Charles Pegge on November 29, 2013, 03:52:59 AM
ThanksGiving survivors, special edition:

(http://cdn1.tabletmag.com/wp-content/files_mf/turkey620.jpg)


This version supports variable names, and lookup array.

Code: [Select]
'SIMPLE EVALUATOR

' supporting:
' +-*/
' floating ppoint values
' variables a..z
' brackets
' multiple statements and lines

indexbase 0

% maxvar 1024

string vn[maxvar] ' variable name
double vv[maxvar] ' variable store
double st[16]     ' stack value
sys    sp[16]     ' stack operator

sys    vnb=1      ' base of var lists
sys    vne=1      ' end of var lists


function wordbound(byte*b) as sys
=================================
do
  select b
  case "0" to "9"
  case "A" to "Z"
  case "a" to "z"
  case else : exit do
  end select
  @b++
end do
return @b
end function


function newvar(string wr,double v) as sys
==========================================
vn[vne]=wr 'new variable name
vv[vne]=0  'value
vne++
if vne>maxvar then vne=maxvar 'clamp
return vne-1
end function


function lookup(string wr) as sys
=================================
sys i=vnb,f=0
do
  if i>=vne then exit do 'end of var list
  if wr=vn[i] then f=i : exit do
  i++
end do
return f
end function


function lookupv(sys p) as sys
==============================
byte b at (*p)
byte e at (wordbound b)
sys lw=@e-@b
if lw=0 then return 0 'empty word
*p=@e-1 'update source position
string wr=nuls lw
copy strptr(wr),@b,lw
sys f=lookup(wr)
if not f then f=newvar(wr,0)
return f
end function


function evalnm(sys *dp, double *v,sys b)
=========================================
b-=48
if dp=0
  v=v*10+b
else
  dp*=10
  v=v+b/dp
end if
end function


function evalop(sys op, double *a,v)
====================================
select op
case 0   : a=v
case "+" : a+=v
case "-" : a-=v
case "*" : a*=v
case "/" : a/=v
case
end select
end function


function eval(string s) as double
=================================
byte b at (strptr s) 'source string
double a       'accum
double v       'value
sys    op      'operator
sys    ai      'accum index
sys    si      'stack index
sys    vi      'variable index
sys    dp      'decimal point
do
  select b
  case 0          : evalop(op,a,v) : return a
  case 10 to 13   : evalop(op,a,v) : vv[ai]=a : a=0 : v=0 : op=0 : dp=0
  case ":"        : evalop(op,a,v) : vv[ai]=a : a=0 : v=0 : op=0 : dp=0
  case "0" to "9" : evalnm(dp,v,b)
  case "A" to "Z" : vi=lookupv(@@b) : v=vv(vi) : dp=0
  case "a" to "z" : vi=lookupv(@@b) : v=vv(vi) : dp=0
  case "="        : ai=vi
  case "."        : dp=1
  case 42 to 47   : evalop(op,a,v) : op=b : v=0 : dp=0
  case "("        : st[si]=a : sp[si]=op : a=0 : v=0 : op=0 : dp=0 : si++
  case ")"        : evalop(op,a,v) : si-- : v=a : a=st[si] : op=sp[si] : dp=0
  end select
  @b++
end do
end function

print eval("av=32 : bv=16.25 : 2*(av+bv) ") '96.5

Title: Re: Expression evaluator
Post by: JRS on November 29, 2013, 09:44:06 AM
Quote
What is now 'TURKEY' ?

That definition is determined by the number of credit cards in your wallet, what you think is a deal and how much you like crowded stores.
Title: Re: Expression evaluator
Post by: Aurel on November 29, 2013, 10:08:43 AM
Hi Charles..
Wow it is cool piece of code and i need some time to figure what is what
it looks that most important operation here is :
Code: [Select]
string wr=nuls lw
copy strptr(wr),@b,lw
print "WORD:" + wr
so finally i get string (word)..i don't know nothing about copy command  ???
if i understand this ...
this function copy byte @b with len of word lw into string(pointer) wr ...right?
and of course i add:
Code: [Select]
string wr=nuls lw
copy strptr(wr),@b,lw
print "WORD:" + wr
float f = GetIntValue(wr)
'print "F:" + f
return f

and change in Eval()

Code: [Select]
case "a" to "z"     
     v=lookupv(@@b) :dp=0
and variable value is properly calculated...

thanks  :)

PS.
source code for my interpreter look like this:
Code: [Select]
defINT n,start1,e,i,x,r
Set n=1,start1 = 2,e=3
wForm 100,0,400,400,#MMS,0,"New Window!"
Set r = start1*(3+5)
wtext 10,50,"Result is: "
wtext 140,50,r
Title: Re: Expression evaluator
Post by: Peter on November 30, 2013, 03:14:43 AM
Quote
That definition is determined by the number of credit cards in your wallet, what you think is a deal and how much you like crowded stores.

Sir John,

Are you feeling well?  :D
Title: Re: Expression evaluator
Post by: JRS on November 30, 2013, 08:52:54 AM
I have learned my lesson.

Don't try to be funny on international forums. You will spend your whole life explaining the joke.  :-\
Title: Re: Expression evaluator
Post by: Charles Pegge on November 30, 2013, 10:17:30 AM
People go shopping-mad after eating all those turkeys:

(http://i.dailymail.co.uk/i/pix/2013/11/29/article-2515454-19B699DB00000578-701_634x398.jpg)
Title: Re: Expression evaluator
Post by: JRS on November 30, 2013, 10:33:03 AM
Dictionary:

Turkey

Slang
a. A person considered inept or undesirable.
b. A failure, especially a failed theatrical production or movie.

On another note. (pun intended)

Quote from: Charles - JRS forum
I suspect the Bitcoin market is vulnerable to price manipulation - for instance, indirect purchase of own bitcoins at a high price to inflate the perceived market value.

I think Theo sold his cow for a few magic beans. Fools breed like rabbits.

It doesn't get much sadder than this. Why would anyone buy EZGUI when there are plenty of free libraries (with source) available that do a much better job? EZGUI is the Windows 3.1 (http://codinghorror.typepad.com/.a/6a0120a85dcdae970b0120a86d4df2970b-pi) of GUI toolkits.

Quote
Sorry if this is an inappropriate post, but I'm at the end of my rope.

Just to say I'm a long term customer of PowerBASIC from using Turbo Basic in the Borland days, to PowerBASIC when it was Spectra publishing and then PowerBASIC 3.5 for DOS, PowerBASIC Console Compiler 3 and Classic PowerBASIC 8 Windows Compiler.

On the 8th November I ordered PowerBASIC Console Compiler 5, on the 13th November I had an Invoice which I duly paid, then nothing....

I tried emailing sales@powerbasic.com, and again nothing. After mailing again and hearing nothing I raised a dispute through PayPal, this at least seem to do something as I had a reply from PowerBASIC on the 25th November apologising for the delay and now nothing again.

My emails are still going unanswered. Now before I escalate the dispute further I'm hoping someone in PowerBASIC will see this post and try and resolve whatever the issue is. The order number is 388264.

Thanks

Rob

Chris,

It makes it a little hard to sell add-ons when your potential customers are unable to buy the compiler. Really, find something else to do and stop abusing yourself.

(http://files.allbasic.info/AllBasic/ezgui.png)

A metaphor for effect.

(http://robertredus.files.wordpress.com/2009/12/magcollectivinvention34.gif)
 
Title: Re: Expression evaluator
Post by: Aurel on December 05, 2013, 08:07:48 AM
Back to topic ..please  :)

Charles...
I have a question for you.
I tried few methods for expression evaluator and all of them in my case( in my interpreter)...
when expression is inside FOR/looop constantly increase memory usage.
If loop is  bigger,i mean more iteration use more memory .
Why is that?
If is anything else inside loop like (like printing counter on window) then there is no
memory up.
Is this maybe because string operations or something else( recursion maybe ???)  ???
Title: Re: Expression evaluator
Post by: Charles Pegge on December 05, 2013, 09:30:10 PM
Your code may be dumping lots of old strings.

If you can avoid string expressions like s=s+t in iterations, and use a buffer expression, it will make a big difference in performance:

string s=nuls(1000)
sys i=1
...
mid(s,i)=t : i+=len(t)
...
return left(s,i-1)

Title: Re: Expression evaluator
Post by: Aurel on December 06, 2013, 09:40:38 AM
ok i see
But how explain that if i use your evaluator or few other methods all of them
produce memory usage growth when calculation is inside loop.
If this same loop just show counter then there is no change in memory consuption ::)
it looks like mistery to me ::)
Title: Re: Expression evaluator
Post by: Charles Pegge on December 07, 2013, 01:32:33 AM
Are you returning eval() into a string?
Title: Re: Expression evaluator
Post by: Aurel on December 07, 2013, 03:25:13 AM
No Charles...
I return to float
it is under subroutine ParseExpr()
float rf
string cExpr
rf = Eval(cExpr)

ok i add code into attachment so you can try...
here is example;
Code: [Select]
defINT n,s
Set n = 1,s=2
wForm 100,0,400,400,#MMS,0,"New Window!"
LoopTo n,1,120000,1
  set s = n+1
wtext 100,100,s
Shift n
wtext 250,40,"Test TEXT"
Title: Re: Expression evaluator
Post by: Aurel on December 07, 2013, 06:00:15 AM
Charles
what you mean ...is maybe a problem in recursion,because in most cases those
functions are called recursive.?
i have also found this:
Quote
Assigning an empty string to a variable

PA This is the usual way to clear a string variable.

Text$ = ""

What a waste! First of all, the string "" takes 6 bytes of RAM each time you use it. Consider the alternative:

Text$ = vbNullString

So what is this? vbNullString is a special VB constant that denotes a null string. The "" literal is an empty string. There's an important difference. An empty string is a real string. A null string is not. It is just a zero. If you know the C language, vbNullString is the equivalent of NULL.
Title: Re: Expression evaluator
Post by: Charles Pegge on December 08, 2013, 01:55:23 AM
Hi Aurel,

No problem with recursion.

Oxygen accepts null strings as well as empty strings.
dim'ed strings are initially null.

string s
print strptr s 'result: 0


I found two potential memory leaks in OxygenBasic:

  autoconverting from a numeric function to a string

  autoconverting from a string to a number

I should have both of these fixed later today
Title: Re: Expression evaluator
Post by: Aurel on December 08, 2013, 04:46:36 AM
Hi Charles...
So you look in interpreter source code and try i think.
I hope that you find same memory leak connected with expression evaluation like me.
Because it is really strange that loop without calculation don't produce
mem leak ,when loop with calc inside loop produce mem leak proprtional with number
of iteration... ::)
Title: Re: Expression evaluator
Post by: Charles Pegge on December 08, 2013, 03:28:13 PM
Hi Aurel,

I have not had time to test your code. I've plugged the 2 identified memory leaks. If it still leaks, then perhaps you can isolate the line where this occurs.

http://www.oxygenbasic.org/forum/index.php?topic=749
Title: Re: Expression evaluator
Post by: Aurel on December 08, 2013, 03:57:47 PM
Ok Charles...
I will try ;)
Title: Re: Expression evaluator
Post by: Aurel on December 15, 2013, 10:48:47 AM
Hi Charles
After two days of hunt and fight with mem leak i think that i found what is problem.
There is no difference with last version of oxygen and one i used before.
Problem i have found in local string array which is not released after RETURN is executed.
Your expression evaluator work perfect and very fast in my case also as few others
without producing any mem leak...which is good i think.
so ..here is code where memory growe...

Code: [Select]
SUB exec_SET
'STRING arg[20]  'after RETURN this LOCAL string array is NOT released
INT n=1
'count
'arg[n]=arg1[PC]
'If arg[n]=""
' Return
     'Else
   if n=1   
       ParseExpr(arg1[PC])
          ' true if is not empty
           ' because is true RETURN must work ?
    End If
' do i must use EXIT SUB ? why is next line executed after RETURN?
If arg2[PC] = "" then Return

this string array is constantly invoked inside loop and that is my mistake
because i think that should be relesed after exiting subroutine but is not...
is this normal ? ...i don't know  ::)
( i will also remove some similar parts in interpreter too)

Another thing which i often see is that print(messagebox) ignore RETURN command and is
executed ...
Is EXIT SUB same as RETURN ?
I mean is EXIT SUB return execution to position from where is called specific subroutine?

thanks Aurel ;)
Title: Re: Expression evaluator
Post by: JRS on December 15, 2013, 11:40:42 AM
Quote
Is EXIT SUB same as RETURN ?

Aurel,

My understanding is that EXIT SUB is a way to prematurely exit a SUBroutine (function with no return value). Same as the EXIT FUNCTION related directive. Keep in mind the GOSUB/RETURN must respect the scope it's within. You can't jump out of a FUNCTION/SUB with a GOTO/GOSUB directive. You can do a GOTO/GOSUB within the scope of a FUNCTION/SUB. (or MAIN)

Hope this helps.

John
Title: Re: Expression evaluator
Post by: Peter on December 15, 2013, 11:51:47 AM
Is EXIT SUB same as RETURN ?

Yes.
Title: Re: Expression evaluator
Post by: Aurel on December 15, 2013, 11:53:36 AM
John
This is not the point of my question for Charles.
I want to know if EXIT SUB work as RETURN or in another words
RETURN must work as EXIT SUB ...right?
without executing any code after RETURN is executed..ok...
There are some quirks but it is not problem for me at all
i use in many places EXIT DO ,EXIT FOR,EXIT WHILE etc..etc
Title: Re: Expression evaluator
Post by: Aurel on December 15, 2013, 11:54:53 AM
Quote
Is EXIT SUB same as RETURN ?
Yes.

hi Peter ..thanks  ;)
Title: Re: Expression evaluator
Post by: Peter on December 15, 2013, 12:15:46 PM
Hi Aurel,
Code: [Select]
include "sw.inc"
window 320,240,1

Sub MyExitSub()
    static sys count
    iF count >=100
       Cls RGB(Rnd(128,255),Rnd(128,255),Rnd(128,255))
       Return
    End iF
    Text 50,50,"Wait.. " + count,0
    count +=1
End Sub   
   
while Key(27)=0
  Cls sw_white
  MyExitSub
  Sync
  SetFps (24)
wend
CloseWindow
   
Title: Re: Expression evaluator
Post by: Charles Pegge on December 16, 2013, 03:36:26 AM
Hi Aurel,

In a sub, return produces the same machine code as exit sub. local and temporary strings are always cleared before the routine terminates.

Could you try this code and see what memory consumption you get:

Code: [Select]
string arg[100]


sub f()
  sys n=2
  arg[16]=space 1000
  arg[n]=arg[16]
  if arg[n]="" then return
  return
end sub


function g(sys a)
  for i=1 to a
    f
  next
end function


print "" 'check for mem in task manager
g 10000
print "" 'check for mem in task manager: max increase: ~16k (Vista PC)
Title: Re: Expression evaluator
Post by: Aurel on December 16, 2013, 04:08:51 AM
Ok Charles..
I try and after first message i get 1.928 K
after second ........................... 1.956 K

is your  result same ?
It looks that is some increase of memory..right ?
just after 2 turn 
Title: Re: Expression evaluator
Post by: Peter on December 16, 2013, 05:20:44 AM
I got this here:  2 empty messageboxes



.
Title: Re: Expression evaluator
Post by: Charles Pegge on December 16, 2013, 08:53:36 AM
Okay, that looks like OS working-memory. No leaks.

Turn arg[] into a bstring, and you will get a memory accumulation of about 18 meg. (g 10000)
Title: Re: Expression evaluator
Post by: Aurel on December 18, 2013, 01:56:53 PM
Hi Charles...
I try replace string arg[] with bstring arg[] and
there is no any change in memory consumption but maybe i'm wrong.

However ...
After long fight with memory leaks in expr parser (by joske)
i figured that i can free string with frees s
and i also replace all input strings (inside function definition) with local strings
like this:
Code: [Select]
FUNCTION Eval_Expr(string in) as FLOAT

STRING expr,op
frees expr

expr = in


and it looks that memory leak gone probably because this function is used many times
inside loops and string expr accumulate lot of space...right?
thanks again on suggestions... ;)
Title: Re: Expression evaluator
Post by: Aurel on February 18, 2015, 01:37:47 AM
and this is crazy evaluator... ;D

Code: [Select]
Function VisibleToken(STRING s) as string
  Select s
    Case CR
'      s = "newline"
    Case LF
    '  s = "newline"
    Case ""
    '  s = "nothing"
  End Select
  Return s
End Function

';Cleanup then end
Function Finish()
  perr=1
Return 0
End Function

';Report an error
Function Error(string s)
  print "Error: " + s + "."
End Function

';Report an error and abort
Function Abort(STRING s)
  Error(s)
  Finish()
End Function

';Report what was expected
Function Expected(STRING expect)
  Abort("Expected: " + expect + ", got '" + VisibleToken(Look) + "'")
Return 0
End Function

';Read a character into Look
Goto GetChar_End
sub GetChar
'print "SUB->GETCHAR"
  Look = Mid (Stream ,StreamPos,1)
  'print "LOOK:" + Look
  StreamPos =  StreamPos + 1
  Return
end sub
GetChar_End:


';Match a specific input character
Function Match(STRING s)
'print "MATCH<s>" + s
  If Look <> s
'print "MATCH<Look>" + Look
    Expected("'"+ s +"'")
  Else
'print "MATCH<else>"
    Gosub getchar
  End If
End Function

';Get a number-----------------------------------------------------
Function GetNum() As Float

  STRING Temp
 
    If Asc(look) > 47 and Asc(look) < 58  ' read chars as numbers
       'print "need number"
    End if

While (Asc(Look) > 47 And Asc(Look) < 58) Or Asc(Look) = 46' dec.point
Temp = Temp + Look
Gosub getchar
         
Wend
       
  Return Val(Temp)
End Function

';Get variable ----------------------------------------------------------
Function GetVar() as float
'print "SUB->GETVAR"
  STRING Temp,func,expr
  FLOAT tempv
 
    'If Asc(look) < 96 and Asc(look) > 123  ' read chars as variable
      ' print ("need variable")
    'end if

While (Asc(Look) > 64 And Asc(Look) < 95) OR  (Asc(Look) > 96 And Asc(Look) < 123) OR  (Asc(Look) > 47 And Asc(Look) < 58)                             '; Works
Temp = Temp + Look
Gosub getchar
         'print "GetVar-TEMP:" + Temp 
        'IF         
Wend
'test variable value .........GetIntValue (byref vName as string) As FLOAT
'print "LOOK:" + Look
 IF Look <> "("
    If instr(Temp,"[") = 0
tempv = GetIntValue(Temp) 'not Array
    Else  ' is array
    ' print "TEMP:is array:" + Temp
     tempv = GetArrayValue(Temp)
    End if
'Return tempv
 END IF

'expected function..................
IF Look = "("
 'temp = sin(90)
'print "fTemp:" + temp   ' sin
 Gosub getchar  'skip bracket (  Look +1
While Look <> ""  ' ->...)
  expr = expr + Look
  Gosub getchar
Wend
'print "F->TEMP:" + expr  ' 90
 tempv=GetFunc(temp,expr)
 'Return tempv
 Gosub getchar
END IF
'...................................

Return tempv
 
End Function

Declare function Expression() as float
'==============================================================
Function Factor() as float

'print "SUB->FACTOR"
  FLOAT Value
'get number ----------------------------
  If Asc(Look) > 47 And Asc(Look) < 58
    Return GetNum()
  End if
'get variable -------------------------- 
  If Asc(look) > 96 and asc(look) < 123 OR (Asc(Look) > 64 And Asc(Look) < 91)
     return GetVar()
  End if
'get parens ---------------------------
If look <> ""
    Match("(")
  Value = Expression()
    Match(")")
End If

  Return Value
End Function
'==============================================================
Function Term() as float
  FLOAT Value
  Value = Factor()
  While (Look = "*" Or Look = "/")
    If Look = "*"
      Gosub getchar
      Value = Value * Factor()
    Else
      Gosub getchar
      Value = Value / Factor()
    End If
  Wend
  Return Value
End Function

Function Expression() as float
 FLOAT Value
  If (Look = "-")
    Gosub getchar
    Value = -(Term())
  Else
    Value = Term()
  End If

  While (Look = "+") Or (Look = "-")
    If Look = "+"
      Gosub getchar
      Value = Value + Term()
    Else
      Gosub getchar
      Value = Value - Term()
    End If
  Wend

  Return Value
End Function

Function EvaLLine(byval s as string) as float
  Stream = Replace(s, " ", "")
  StreamPos = 1
  Gosub getchar
'string out
Float Tempv
  Tempv = Expression()
  'If StreamPos < Len(Stream) '; Error check, you
    'Expected("nothing")      '; can remove them if you don't
  'EndIf
  'out=str(Temp)                   '; need the check
  Return Tempv
End Function
Title: Re: Expression evaluator
Post by: Charles Pegge on February 18, 2015, 01:49:10 PM

Hi Aurel,

Use bstrings if you are going to free them explicitly. Normal strings are garbage-collected.

Cases won't work with strings, only numbers.

Ruben2 needs to be set indexbase 0[/b] since some of your array iterations start with 0.