INVISIBLE CALCULATOR

Author Bruce Switzer
Message No.

http://groups.yahoo.com/group/power-pro/messages/8262

File Name Calc.powerpro
Requirements Vector Plugin, Float Plugin
Description: On running this script you will be prompted to enter the expression you want the calculator to evaluate. The result will be displayed in a message box.

;  Codes used for operators:
;   -- priority is first digit
;   -- unique code is next two digits

OP_PLUS = 501
OP_MINUS=502
OP_DIV=803
OP_MUL=804

;left parenthesis lower than any operator
OP_LEFT=305
; lowest priority operator marks bottom of operator stack
OP_BOTTOM = 100

; cleanup any older stack memory and create new stacks
if(snum gt 0)
   vec.destroy(snum)
if (sop gt 0)
   vec.destroy(sop)
snum = vec.create(10,10,16)
sop = vec.create(10,10,16)
fop=0
fnum=0
.calc@push_op(OP_BOTTOM)

; set input expression
line = input("enter expression")
len=length(line)
i=1

; flags whether number or operator expected next
NextIsNum=1

res=0

for (;i le len;)
    if (i>len)
        break

    .calc@skipblanks
    if (NextIsNum)  Do
        if (select(line,i,i)=="(") do
            i=i+1
            .calc@push_op(OP_LEFT)
        else
            num = .calc@getnum
            .calc@push_num(num)
            NextIsNum=0
        endif            
    else
        if (select(line,i,i)==")") do
            for (1)
                op = .calc@pop_op
                if (op==OP_LEFT)
                    break
                .calc@eval(op)
            endfor
        else
            op = .calc@getop
            for (1)
                optop = .calc@peek_op
                if (optop/100 lt op/100)
                    break
                optop = .calc@pop_op
                .calc@eval(optop)
            endfor
            .calc@push_op(op)
            NextIsNum=1
        endif
        i=i+1
    endif
endfor

;  evaluate any ops still on stack and exit
for (1)
    op = .calc@pop_op
    if (op==OP_BOTTOM)
        break
    .calc@eval(op)
endfor

res = .calc@pop_num
MessageBox("ok",line++"'requals "++res)
sop = vec.destroy(sop)
snum = vec.destroy(snum)
quit
        
;---------------------------------------------
; skip blanks

@skipblanks
for (;i le len ;i=i+1)
    if ( select(line,i,i) ne " ")
        quit
endfor
quit

;---------------------------------------------
; return number starting at current pos in line

@getnum
if (i>len)
   quit(0)
num = ""

if (select(line,i,i)=="-") do
   num = "-"
   i=i+1
endif

for (;i le len;i=i+1)
    if (index("0123456789.",select(line,i,i)) == 0) do
        quit (num)
    endif
    num = num++select(line,i,i)
endfor

quit(num)
   
;---------------------------------------------
; return code for operator at current pos in line

@getop  
c = select(line,i,i)
if (c == "+")
   quit(OP_PLUS)
if (c == "-")
   quit(OP_MINUS)
if (c == "*")
   quit(OP_MUL)
if (c == "/")
   quit(OP_DIV)
MessageBox("ok","Invalid operator'r" ++ line)
quit(OP_PLUS)   

;---------------------------------------------
; apply operator to top two numbers on num stack

@eval
n2 = .calc@pop_num
n1 = .calc@pop_num
n3=0
if (arg(1) == OP_PLUS) do
    n3 = float.add(n1,n2)
elseif (arg(1) == OP_MINUS) do
    n3 = float.sub(n1,n2)
elseif (arg(1) == OP_MUL) do
    n3 = float.mul(n1,n2)
elseif (arg(1) == OP_DIV) do
    n3 = float.divide(n1,n2)
else
    MessageBox("ok", "internal error")
endif
.calc@push_num(n3)
quit
   
;---------------------------------------------
; pop top element from operator stack

@pop_op
if (fop>0) do
    fop = fop-1
    quit (vec.get(sop,fop))
endif
MessageBox("ok","Invalid Expression:'r"++line)
quit (OP_PLUS)

;---------------------------------------------
; push operator onto stack

@push_op
vec.set(sop, fop, arg(1))
fop = fop+1
quit

;---------------------------------------------
; return top operator from stack without popping it

@peek_op
if (fop>0)
    quit (vec.get(sop,fop-1))
MessageBox("ok","Invalid Expression:'r"++line)
quit (OP_PLUS)

;---------------------------------------------
; pop top number from number stack

@pop_num
if (fnum>0) do
    fnum = fnum-1
    quit (vec.get(snum,fnum))
endif
MessageBox("ok","Invalid Expression:'r"++line)
quit (0)

;---------------------------------------------
; push number onto number stack

@push_num
vec.set(snum,fnum, arg(1))
fnum=fnum+1
quit

@dump_num
for (j=1; j<fnum; j=j+1)
   debug dump num &(vec.get(snum,j))
endfor