; 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
|