|
Post by honkytonk on May 10, 2020 15:32:50 GMT
Hello, is there a way to fix this problem? Click on "Trans" and see !
NOMAINWIN WindowWidth = 400: WindowHeight = 400 UpperLeftX = 10: UpperLeftY = 20 TEXTBOX #w.entr, 20 , 20, 100, 25 TEXTBOX #w.a, 65 , 50, 50, 25 TEXTBOX #w.b, 65 , 80, 50, 25 TEXTBOX #w.c, 65 , 110, 50, 25 BUTTON #w.calc, "Calc", [calc], UL, 140, 20, 60, 25 TEXTBOX #w.res, 140 , 50, 80, 25 BUTTON #w.tr, "Trans", [trans], UL, 20, 150, 60, 25 TEXTBOX #w.tran, 90 , 150, 100, 25 GRAPHICBOX #w.m 5, 5, 385, 360 OPEN "Help" FOR window_nf AS #w #w, "TRAPCLOSE [closeHelp]" #w.m "down;fill darkgreen;color white;backcolor darkgreen" fo$="#w.entr #w.a #w.b #w.c #w.calc #w.tr #w.tran" for x=1 to 7 hand$=word$(fo$,x) #hand$ "!font courrier 12 bold" next x #w.m, "font courrier 12 bold" #w.entr, "(a+b)*c" #w.m, "place 5 60": #w.m, "\Val a =" #w.m, "place 5 90": #w.m, "\Val b =" #w.m, "place 5 120": #w.m, "\Val c =" #w.a, "3": #w.b, "4": #w.c, "2" #w.calc, "!disable" wait [trans] #w.a, "!contents? var$": a$=var$ #w.b, "!contents? var$": b$=var$ #w.c, "!contents? var$": c$=var$ #w.entr, "!contents? var$" tran$="" for x=1 to len(var$) u$=mid$(var$,x,1) if u$="(" or u$=")" or u$="+" or u$="-" or u$="*" or u$="/" then tran$=tran$+u$ else 'u$= tran$=tran$+str$(val(u$+"$")) '!?!?!?!?!GLOUPS!! end if next x #w.tran, tran$ #w.m, "place 5 190": #w.m, "\The goal is: (3+4)*2" #w.m, "place 5 220": #w.m, "\a,b and c values can be changed" wait [closeHelp] CLOSE #w END
|
|
|
Post by B+ on May 10, 2020 16:04:21 GMT
To do it with many nested parenthesis would most likely need an evaluate function that can substitute variable names with values. Both tsh73 and I have posted these in past, I might dig up mine but...
Without parenthesis just going from left to right on an expression, you can probably do it by selecting case on operators, substitution of variables as you go and keep a running calculation value.
Certainly NOT insoluble.
|
|
|
Post by honkytonk on May 10, 2020 16:45:26 GMT
The goal is to transfer the content of the textboxes into the expression according to their names. No to calculate the expression. I have your code (eval function) and a few others (THS73) who will serve later.
|
|
|
Post by B+ on May 10, 2020 17:41:53 GMT
And once you have the expression in a string you need to evaluate it, like this:
global evalErr$, pi, rad, deg, Dflag, globalx, vTopI pi = acs(-1) : rad = pi / 180 : deg = 180 / pi '<<<<<<<<<<< true constants Dflag = 1 : globalx = 5 : vTopI = 0 'changeable global variables change as needed
dim varNames$(100), varValues(100) 'test$ = "(3 + 4) * 2" 'result = evaluate(test$) 'print result OK so far 'end
scan call setVar "a", 3 call setVar "b", 4 call setVar "c", 2 'for i = 1 to vTopI 'print varName$(i), varValues(i) 'OK so far 'next 'end
test$ = "( a + b ) * c" copyTest$ = test$ call preEvalSubst test$ 'good! Finally 'print test$
result = evaluate(test$) print copyTest$;" evaluates to ";result
test$ = "( a + b ) * pi " copyTest$ = test$ call preEvalSubst test$ result = evaluate(test$) print copyTest$;" evaluates to ";result
for globalx = 0 to 100 step 10 'demo showing x built into evaluate through globalx Print "x = ";globalx test$ = "( a + b ) * x " copyTest$ = test$ call preEvalSubst test$ Print test$ result = evaluate(test$) print copyTest$;" evaluates to ";result next print : print "Test done"
function value(vName$) for i = 1 to vTopI scan if trim$(varName$(i)) = trim$(vName$) then value = varValues(i) exit function end if next value = -99.11 end function
sub preEvalSubst byref eString$ i = 1 while word$(eString$, i) <> "" scan v = value(word$(eString$, i)) if v <> -99.11 then call wsSub eString$, i, i, str$(v) 'print eString$ end if i = i + 1 wend end sub
sub setVar vName$, vValue 'simply store or update a variable and it's value 'try to find variable in array for i = 1 to vTopI if varName$(i) = vName$ then varValues(i) = vValue exit sub end if next 'if not found add it if vTopI + 1 <= 100 then vTopI = vTopI +1 varName$(vTopI) = vName$ varValues(vTopI) = vValue else print : print "Sorry, no more room for variables. Goodbye!" end if end sub
function evaluate(e$) 'make sure ( ) + * / % ^ are wrapped with spaces on your own with - for i = 1 to len(e$) 'filter chars and count () c$ = lower$(mid$(e$, i, 1)) select case case c$ = ")" : po = po - 1 : b$ = b$;" ) " case c$ = "(" : po = po + 1 : b$ = b$;" ( " case instr("+*/%^", c$) > 0 : b$ = b$;" ";c$;" " case instr(" -.0123456789abcdefghijklmnopqrstuvwxyz", c$) > 0 : b$ = b$;c$ end select if po < 0 then evalErr$ = "Too many )" : exit function next if po <> 0 then evalErr$ = "Unbalanced ()" : exit function e$ = b$ for i = 1 to 3 p = wIn(e$, word$("x e pi", i)) while p > 0 select case i case 1 : subst$ = str$(globalx) case 2 : subst$ = str$(exp(1)) case 3 : subst$ = str$(pi) end select call wsSub e$, p, p, subst$ p = wIn(e$, word$("x e pi", i)) wend next evaluate = evalW(e$) end function
function evalW(s$) scan pop = wIn(s$, "(") 'parenthesis open place while pop > 0 scan if pop = 1 then fun$ = "" : lPlace = 1 else test$ = word$(s$, pop - 1) funPlace = wIn("sin cos tan asin acos atan log exp sqr rad deg", test$) if funPlace > 0 then fun$ = test$ : lPlace = pop - 1 else fun$ = "" : lPlace = pop end if end if wc = wCnt(s$) : po = 1 for i = pop + 1 to wc if word$(s$, i) = "(" then po = po + 1 if word$(s$, i) = ")" then po = po - 1 if po = 0 then rPlace = i : exit for next inner$ = "" for i = (pop + 1) to (rPlace - 1) w$ = word$(s$, i) inner$ = inner$;w$;" " if wIn("( + - * / % ^", w$) > 0 then recurs = 1 next if recurs then inner = evalW(inner$) else inner = val(inner$) select case fun$ case "" : m = inner case "sin" : if Dflag then m = sin(rad * inner) else m = sin(inner) case "cos" : if Dflag then m = cos(rad * inner) else m = cos(inner) case "tan" : if Dflag then m = tan(rad * inner) else m = tan(inner) case "asin": if Dflag then m = deg * (asn(inner)) else m = asn(inner) case "acos": if Dflag then m = deg * (acs(inner)) else m = acs(inner) case "atan": if Dflag then m = deg * (atn(inner)) else m = atn(inner) case "log" if inner > 0 then m = log(inner) else evalErr$ = "LOG only works on numbers > 0." : exit function end if case "exp" 'the error limit is inconsistent!!!!!!!!!!!!!!!!! 'I had to readjust limit, memory problem ???????????????????????? 'this worked fine tested alone up to -708 +709
if -693 <= inner and inner <= 709 then 'your system may have different results m = exp(inner) else ' what the heck???? 708 works fine all alone as limit ????? evalErr$ = "EXP only works for ABS(number) <= ??? using 693." : exit function end if case "sqr" if inner >= 0 then m = sqr(inner) else evalErr$ = "SQR only works for numbers >= 0." : exit function end if case "rad" : m = inner * rad case "deg" : m = inner * deg case else : evalErr$ = "Unidentified function ";fun$ : exit function end select call wsSub s$, lPlace, rPlace, str$(m) pop = wIn(s$, "(") wend ops$ = "%^/*-+" 'all () cleared, now for binary ops for o = 1 to 6 op$ = mid$(ops$, o, 1) p = wIn(s$, op$) while p > 0 scan a = val(word$(s$, p - 1)) b = val(word$(s$, p + 1)) select case op$ case "%" if b >= 2 then middle$ = str$(int(a) mod int(b)) else evalErr$ = "For a Mod b, b value < 2." exit function end if case "^" if int(b) = b or a >= 0 then middle$ = str$(a ^ b) else evalErr$ = "For a ^ b, a needs to be >= 0 when b not integer." exit function end if case "/" if b <> 0 then middle$ = str$(a / b) else evalErr$ = "Div by 0" exit function end if case "*" : middle$ = str$(a * b) case "-" : middle$ = str$(a - b) case "+" : middle$ = str$(a + b) end select call wsSub s$, p - 1, p + 1, middle$ p = wIn(s$, op$) wend next evalW = val(s$) end function
sub wsSub byref s$, first, last, subst$ 'far more powerful wc = wCnt(s$) for i = 1 to wc if first <= i and i <= last then 'do this only once! if subF = 0 then b$ = b$;subst$;" " : subF = 1 else b$ = b$;word$(s$, i);" " end if next s$ = b$ end sub
function wIn(s$, w$) 'first in s$ that matches w$ (no spaces in w$!) wIn = 0 : wc = wCnt(s$) for i = 1 to wc if w$ = word$(s$, i) then wIn = i : exit function next end function
function wCnt(s$) 'of default space delimited string while word$(s$, wc + 1) <> "" : wc = wc + 1 : wend wCnt = wc end function
Now you can generalize with a textBox for the variable name AND a textBox for the variable value and plug in a math formula for calculations with the given variables.
|
|
|
Post by B+ on May 10, 2020 19:15:09 GMT
Now it's easy to use your form for evaluating formulas with up to 3 variables called a, b, c global evalErr$, pi, rad, deg, Dflag, globalx, vTopI pi = acs(-1) : rad = pi / 180 : deg = 180 / pi '<<<<<<<<<<< true constants Dflag = 1 : globalx = 5 : vTopI = 0 'changeable global variables change as needed
dim varNames$(100), varValues(100)
NOMAINWIN WindowWidth = 400: WindowHeight = 400 UpperLeftX = 10: UpperLeftY = 20 TEXTBOX #w.entr, 20 , 20, 200, 25 TEXTBOX #w.a, 65 , 50, 50, 25 TEXTBOX #w.b, 65 , 80, 50, 25 TEXTBOX #w.c, 65 , 110, 50, 25 BUTTON #w.calc, "Calc", [calc], UL, 540, 20, 60, 25 TEXTBOX #w.res, 140 , 50, 80, 25 BUTTON #w.tr, "Trans", [trans], UL, 20, 150, 60, 25 TEXTBOX #w.tran, 90 , 150, 100, 25 GRAPHICBOX #w.m 5, 5, 385, 360 OPEN "Help" FOR window_nf AS #w #w, "TRAPCLOSE [closeHelp]" #w.m "down;fill darkgreen;color white;backcolor darkgreen" fo$="#w.entr #w.a #w.b #w.c #w.calc #w.tr #w.tran" for x=1 to 7 hand$=word$(fo$,x) #hand$ "!font courrier 12 bold" next x #w.m, "font courrier 12 bold" #w.entr, "( a + b ) * c" #w.m, "place 5 60": #w.m, "\Val a =" #w.m, "place 5 90": #w.m, "\Val b =" #w.m, "place 5 120": #w.m, "\Val c =" #w.a, "3": #w.b, "4": #w.c, "2" #w.calc, "!disable" wait [trans] #w.a, "!contents? var$": call setVar "a", val(var$) #w.b, "!contents? var$": call setVar "b", val(var$) #w.c, "!contents? var$": call setVar "c", val(var$) #w.entr, "!contents? form$" call preEvalSubst form$ result = evaluate(form$) #w.tran, str$(result) wait [closeHelp] CLOSE #w END
function value(vName$) for i = 1 to vTopI scan if trim$(varName$(i)) = trim$(vName$) then value = varValues(i) exit function end if next value = -99.11 end function
sub preEvalSubst byref eString$ i = 1 while word$(eString$, i) <> "" scan v = value(word$(eString$, i)) if v <> -99.11 then call wsSub eString$, i, i, str$(v) 'print eString$ end if i = i + 1 wend end sub
sub setVar vName$, vValue 'simply store or update a variable and it's value 'try to find variable in array for i = 1 to vTopI if varName$(i) = vName$ then varValues(i) = vValue exit sub end if next 'if not found add it if vTopI + 1 <= 100 then vTopI = vTopI +1 varName$(vTopI) = vName$ varValues(vTopI) = vValue else print : print "Sorry, no more room for variables. Goodbye!" end if end sub
function evaluate(e$) 'make sure ( ) + * / % ^ are wrapped with spaces on your own with - for i = 1 to len(e$) 'filter chars and count () c$ = lower$(mid$(e$, i, 1)) select case case c$ = ")" : po = po - 1 : b$ = b$;" ) " case c$ = "(" : po = po + 1 : b$ = b$;" ( " case instr("+*/%^", c$) > 0 : b$ = b$;" ";c$;" " case instr(" -.0123456789abcdefghijklmnopqrstuvwxyz", c$) > 0 : b$ = b$;c$ end select if po < 0 then evalErr$ = "Too many )" : exit function next if po <> 0 then evalErr$ = "Unbalanced ()" : exit function e$ = b$ for i = 1 to 3 p = wIn(e$, word$("x e pi", i)) while p > 0 select case i case 1 : subst$ = str$(globalx) case 2 : subst$ = str$(exp(1)) case 3 : subst$ = str$(pi) end select call wsSub e$, p, p, subst$ p = wIn(e$, word$("x e pi", i)) wend next evaluate = evalW(e$) end function
function evalW(s$) scan pop = wIn(s$, "(") 'parenthesis open place while pop > 0 scan if pop = 1 then fun$ = "" : lPlace = 1 else test$ = word$(s$, pop - 1) funPlace = wIn("sin cos tan asin acos atan log exp sqr rad deg", test$) if funPlace > 0 then fun$ = test$ : lPlace = pop - 1 else fun$ = "" : lPlace = pop end if end if wc = wCnt(s$) : po = 1 for i = pop + 1 to wc if word$(s$, i) = "(" then po = po + 1 if word$(s$, i) = ")" then po = po - 1 if po = 0 then rPlace = i : exit for next inner$ = "" for i = (pop + 1) to (rPlace - 1) w$ = word$(s$, i) inner$ = inner$;w$;" " if wIn("( + - * / % ^", w$) > 0 then recurs = 1 next if recurs then inner = evalW(inner$) else inner = val(inner$) select case fun$ case "" : m = inner case "sin" : if Dflag then m = sin(rad * inner) else m = sin(inner) case "cos" : if Dflag then m = cos(rad * inner) else m = cos(inner) case "tan" : if Dflag then m = tan(rad * inner) else m = tan(inner) case "asin": if Dflag then m = deg * (asn(inner)) else m = asn(inner) case "acos": if Dflag then m = deg * (acs(inner)) else m = acs(inner) case "atan": if Dflag then m = deg * (atn(inner)) else m = atn(inner) case "log" if inner > 0 then m = log(inner) else evalErr$ = "LOG only works on numbers > 0." : exit function end if case "exp" 'the error limit is inconsistent!!!!!!!!!!!!!!!!! 'I had to readjust limit, memory problem ???????????????????????? 'this worked fine tested alone up to -708 +709
if -693 <= inner and inner <= 709 then 'your system may have different results m = exp(inner) else ' what the heck???? 708 works fine all alone as limit ????? evalErr$ = "EXP only works for ABS(number) <= ??? using 693." : exit function end if case "sqr" if inner >= 0 then m = sqr(inner) else evalErr$ = "SQR only works for numbers >= 0." : exit function end if case "rad" : m = inner * rad case "deg" : m = inner * deg case else : evalErr$ = "Unidentified function ";fun$ : exit function end select call wsSub s$, lPlace, rPlace, str$(m) pop = wIn(s$, "(") wend ops$ = "%^/*-+" 'all () cleared, now for binary ops for o = 1 to 6 op$ = mid$(ops$, o, 1) p = wIn(s$, op$) while p > 0 scan a = val(word$(s$, p - 1)) b = val(word$(s$, p + 1)) select case op$ case "%" if b >= 2 then middle$ = str$(int(a) mod int(b)) else evalErr$ = "For a Mod b, b value < 2." exit function end if case "^" if int(b) = b or a >= 0 then middle$ = str$(a ^ b) else evalErr$ = "For a ^ b, a needs to be >= 0 when b not integer." exit function end if case "/" if b <> 0 then middle$ = str$(a / b) else evalErr$ = "Div by 0" exit function end if case "*" : middle$ = str$(a * b) case "-" : middle$ = str$(a - b) case "+" : middle$ = str$(a + b) end select call wsSub s$, p - 1, p + 1, middle$ p = wIn(s$, op$) wend next evalW = val(s$) end function
sub wsSub byref s$, first, last, subst$ 'far more powerful wc = wCnt(s$) for i = 1 to wc if first <= i and i <= last then 'do this only once! if subF = 0 then b$ = b$;subst$;" " : subF = 1 else b$ = b$;word$(s$, i);" " end if next s$ = b$ end sub
function wIn(s$, w$) 'first in s$ that matches w$ (no spaces in w$!) wIn = 0 : wc = wCnt(s$) for i = 1 to wc if w$ = word$(s$, i) then wIn = i : exit function next end function
function wCnt(s$) 'of default space delimited string while word$(s$, wc + 1) <> "" : wc = wc + 1 : wend wCnt = wc end function
|
|
|
Post by B+ on May 10, 2020 19:29:51 GMT
Make sure you put spaces between everything in the formula. That's for the preEvalSubst SUB, it's just a quicky SUB I whipped up today to substitute variable names with their values into the formula string.
|
|
|
Post by honkytonk on May 10, 2020 23:24:47 GMT
I understand, but the goal is not to evaluate the expression; the goal is to transfer the content of the textboxes (values of a, b and c) into the expression by keeping it as it "(a + b) * c" -->result--> "(4 + 3) * 2" And let it be the program that does it for all textbox values.
|
|
|
Post by B+ on May 10, 2020 23:58:09 GMT
I understand, but the goal is not to evaluate the expression; the goal is to transfer the content of the textboxes (values of a, b and c) into the expression by keeping it as it "(a + b) * c" -->result--> "(4 + 3) * 2" And let it be the program that does it for all textbox values. Already done! just comment out the evaluate part and put form$ in textBox global evalErr$, pi, rad, deg, Dflag, globalx, vTopI pi = acs(-1) : rad = pi / 180 : deg = 180 / pi '<<<<<<<<<<< true constants Dflag = 1 : globalx = 5 : vTopI = 0 'changeable global variables change as needed
dim varNames$(100), varValues(100)
NOMAINWIN WindowWidth = 400: WindowHeight = 400 UpperLeftX = 10: UpperLeftY = 20 TEXTBOX #w.entr, 20 , 20, 200, 25 TEXTBOX #w.a, 65 , 50, 50, 25 TEXTBOX #w.b, 65 , 80, 50, 25 TEXTBOX #w.c, 65 , 110, 50, 25 BUTTON #w.calc, "Calc", [calc], UL, 540, 20, 60, 25 TEXTBOX #w.res, 140 , 50, 80, 25 BUTTON #w.tr, "Trans", [trans], UL, 20, 150, 60, 25 TEXTBOX #w.tran, 90 , 150, 100, 25 GRAPHICBOX #w.m 5, 5, 385, 360 OPEN "Help" FOR window_nf AS #w #w, "TRAPCLOSE [closeHelp]" #w.m "down;fill darkgreen;color white;backcolor darkgreen" fo$="#w.entr #w.a #w.b #w.c #w.calc #w.tr #w.tran" for x=1 to 7 hand$=word$(fo$,x) #hand$ "!font courrier 12 bold" next x #w.m, "font courrier 12 bold" #w.entr, "( a + b ) * c" #w.m, "place 5 60": #w.m, "\Val a =" #w.m, "place 5 90": #w.m, "\Val b =" #w.m, "place 5 120": #w.m, "\Val c =" #w.a, "3": #w.b, "4": #w.c, "2" #w.calc, "!disable" wait [trans] #w.a, "!contents? var$": call setVar "a", val(var$) #w.b, "!contents? var$": call setVar "b", val(var$) #w.c, "!contents? var$": call setVar "c", val(var$) #w.entr, "!contents? form$" call preEvalSubst form$ 'result = evaluate(form$) #w.tran, form$ wait [closeHelp] CLOSE #w END
function value(vName$) for i = 1 to vTopI scan if trim$(varName$(i)) = trim$(vName$) then value = varValues(i) exit function end if next value = -99.11 end function
sub preEvalSubst byref eString$ i = 1 while word$(eString$, i) <> "" scan v = value(word$(eString$, i)) if v <> -99.11 then call wsSub eString$, i, i, str$(v) 'print eString$ end if i = i + 1 wend end sub
sub setVar vName$, vValue 'simply store or update a variable and it's value 'try to find variable in array for i = 1 to vTopI if varName$(i) = vName$ then varValues(i) = vValue exit sub end if next 'if not found add it if vTopI + 1 <= 100 then vTopI = vTopI +1 varName$(vTopI) = vName$ varValues(vTopI) = vValue else print : print "Sorry, no more room for variables. Goodbye!" end if end sub
function evaluate(e$) 'make sure ( ) + * / % ^ are wrapped with spaces on your own with - for i = 1 to len(e$) 'filter chars and count () c$ = lower$(mid$(e$, i, 1)) select case case c$ = ")" : po = po - 1 : b$ = b$;" ) " case c$ = "(" : po = po + 1 : b$ = b$;" ( " case instr("+*/%^", c$) > 0 : b$ = b$;" ";c$;" " case instr(" -.0123456789abcdefghijklmnopqrstuvwxyz", c$) > 0 : b$ = b$;c$ end select if po < 0 then evalErr$ = "Too many )" : exit function next if po <> 0 then evalErr$ = "Unbalanced ()" : exit function e$ = b$ for i = 1 to 3 p = wIn(e$, word$("x e pi", i)) while p > 0 select case i case 1 : subst$ = str$(globalx) case 2 : subst$ = str$(exp(1)) case 3 : subst$ = str$(pi) end select call wsSub e$, p, p, subst$ p = wIn(e$, word$("x e pi", i)) wend next evaluate = evalW(e$) end function
function evalW(s$) scan pop = wIn(s$, "(") 'parenthesis open place while pop > 0 scan if pop = 1 then fun$ = "" : lPlace = 1 else test$ = word$(s$, pop - 1) funPlace = wIn("sin cos tan asin acos atan log exp sqr rad deg", test$) if funPlace > 0 then fun$ = test$ : lPlace = pop - 1 else fun$ = "" : lPlace = pop end if end if wc = wCnt(s$) : po = 1 for i = pop + 1 to wc if word$(s$, i) = "(" then po = po + 1 if word$(s$, i) = ")" then po = po - 1 if po = 0 then rPlace = i : exit for next inner$ = "" for i = (pop + 1) to (rPlace - 1) w$ = word$(s$, i) inner$ = inner$;w$;" " if wIn("( + - * / % ^", w$) > 0 then recurs = 1 next if recurs then inner = evalW(inner$) else inner = val(inner$) select case fun$ case "" : m = inner case "sin" : if Dflag then m = sin(rad * inner) else m = sin(inner) case "cos" : if Dflag then m = cos(rad * inner) else m = cos(inner) case "tan" : if Dflag then m = tan(rad * inner) else m = tan(inner) case "asin": if Dflag then m = deg * (asn(inner)) else m = asn(inner) case "acos": if Dflag then m = deg * (acs(inner)) else m = acs(inner) case "atan": if Dflag then m = deg * (atn(inner)) else m = atn(inner) case "log" if inner > 0 then m = log(inner) else evalErr$ = "LOG only works on numbers > 0." : exit function end if case "exp" 'the error limit is inconsistent!!!!!!!!!!!!!!!!! 'I had to readjust limit, memory problem ???????????????????????? 'this worked fine tested alone up to -708 +709
if -693 <= inner and inner <= 709 then 'your system may have different results m = exp(inner) else ' what the heck???? 708 works fine all alone as limit ????? evalErr$ = "EXP only works for ABS(number) <= ??? using 693." : exit function end if case "sqr" if inner >= 0 then m = sqr(inner) else evalErr$ = "SQR only works for numbers >= 0." : exit function end if case "rad" : m = inner * rad case "deg" : m = inner * deg case else : evalErr$ = "Unidentified function ";fun$ : exit function end select call wsSub s$, lPlace, rPlace, str$(m) pop = wIn(s$, "(") wend ops$ = "%^/*-+" 'all () cleared, now for binary ops for o = 1 to 6 op$ = mid$(ops$, o, 1) p = wIn(s$, op$) while p > 0 scan a = val(word$(s$, p - 1)) b = val(word$(s$, p + 1)) select case op$ case "%" if b >= 2 then middle$ = str$(int(a) mod int(b)) else evalErr$ = "For a Mod b, b value < 2." exit function end if case "^" if int(b) = b or a >= 0 then middle$ = str$(a ^ b) else evalErr$ = "For a ^ b, a needs to be >= 0 when b not integer." exit function end if case "/" if b <> 0 then middle$ = str$(a / b) else evalErr$ = "Div by 0" exit function end if case "*" : middle$ = str$(a * b) case "-" : middle$ = str$(a - b) case "+" : middle$ = str$(a + b) end select call wsSub s$, p - 1, p + 1, middle$ p = wIn(s$, op$) wend next evalW = val(s$) end function
sub wsSub byref s$, first, last, subst$ 'far more powerful wc = wCnt(s$) for i = 1 to wc if first <= i and i <= last then 'do this only once! if subF = 0 then b$ = b$;subst$;" " : subF = 1 else b$ = b$;word$(s$, i);" " end if next s$ = b$ end sub
function wIn(s$, w$) 'first in s$ that matches w$ (no spaces in w$!) wIn = 0 : wc = wCnt(s$) for i = 1 to wc if w$ = word$(s$, i) then wIn = i : exit function next end function
function wCnt(s$) 'of default space delimited string while word$(s$, wc + 1) <> "" : wc = wc + 1 : wend wCnt = wc end function
|
|
|
Post by honkytonk on May 11, 2020 0:07:35 GMT
Your code works, but it will cost me a lot of brain to understand it. Does it work by only modifying the number of extraction of textbox values with more than three textboxes ? What points must be modified to add a variable and a textbox,
For a number of textboxes fixed, this can work:
NOMAINWIN WindowWidth = 400: WindowHeight = 400 UpperLeftX = 10: UpperLeftY = 20 TEXTBOX #w.entr, 20 , 20, 100, 25 TEXTBOX #w.a, 65 , 50, 50, 25 TEXTBOX #w.b, 65 , 80, 50, 25 TEXTBOX #w.c, 65 , 110, 50, 25 BUTTON #w.calc, "Calc", [calc], UL, 140, 20, 60, 25 TEXTBOX #w.res, 140 , 50, 80, 25 BUTTON #w.tr, "Trans", [trans], UL, 20, 150, 60, 25 TEXTBOX #w.tran, 90 , 150, 150, 25 GRAPHICBOX #w.m 5, 5, 385, 360 OPEN "Help" FOR window_nf AS #w #w, "TRAPCLOSE [closeHelp]" #w.m "down;fill darkgreen;color white;backcolor darkgreen" fo$="#w.entr #w.a #w.b #w.c #w.calc #w.tr #w.tran" for x=1 to 7 hand$=word$(fo$,x) #hand$ "!font courrier 12 bold" next x #w.m, "font courrier 12 bold" #w.entr, "(a+b)*c" #w.m, "place 5 60": #w.m, "\Val a =" #w.m, "place 5 90": #w.m, "\Val b =" #w.m, "place 5 120": #w.m, "\Val c =" #w.a, "34": #w.b, "512": #w.c, "63" #w.calc, "!disable" wait [trans] nn=1 #w.a, "!contents? var$": a$=var$ #w.b, "!contents? var$": b$=var$ #w.c, "!contents? var$": c$=var$ p$=a$+" "+b$+" "+c$ #w.entr, "!contents? var$" tran$="" for x=1 to len(var$) u$=mid$(var$,x,1) if u$="(" or u$=")" or u$="+" or u$="-" or u$="*" or u$="/" then tran$=tran$+u$ else tran$=tran$+word$(p$,nn): nn=nn+1 end if next x #w.tran, tran$ wait [closeHelp] CLOSE #w END
|
|
|
Post by B+ on May 11, 2020 0:29:15 GMT
Yes 3 variables or 100, 100 just takes longer.
First this takes a variable name and value and stores or updates the value:
the arrays vName$(100) and vValue(100) store the variable names and values, vTopI tracks the amount of variables stored.
sub setVar vName$, vValue 'simply store or update a variable and it's value 'try to find variable in array for i = 1 to vTopI if varName$(i) = vName$ then varValues(i) = vValue exit sub end if next 'if not found add it if vTopI + 1 <= 100 then vTopI = vTopI +1 varName$(vTopI) = vName$ varValues(vTopI) = vValue else print : print "Sorry, no more room for variables. Goodbye!" end if end sub
This looks up the value of our variables just give it the name. -99.11 is unlikely number to signal a failed to find value, could not use 0 because that is much too likely to be needed.
function value(vName$) for i = 1 to vTopI scan if trim$(varName$(i)) = trim$(vName$) then value = varValues(i) exit function end if next value = -99.11 end function
This takes the string containing the variable names and substitutes back in the variable name's value, with the help of WORD$ we go through each word to see if it matches a variable name, if so it substitutes back in it's value with the wsSub SUB:
sub preEvalSubst byref eString$ i = 1 while word$(eString$, i) <> "" scan v = value(word$(eString$, i)) if v <> -99.11 then call wsSub eString$, i, i, str$(v) 'print eString$ end if i = i + 1 wend end sub
|
|
|
Post by honkytonk on May 11, 2020 7:37:10 GMT
Thank you for these explanations; the use of two joint arrays is very judicious, I had not thought of it. I have a little trouble with the functions and the subs but I will understand everything. Thank you for everything.
|
|
|
Post by B+ on May 11, 2020 15:32:18 GMT
honkytonk , thank you for this problem. I have been stuck on another program for ages and this was nice relief. Inspired by your app, I worked up a more general console version here: justbasiccom.proboards.com/thread/482/handy-formula-saverAnd discovered a naming error in code posted here (fixed now in link of course). dim varNames$(100), varValues(100) '<<<<<<<<<<< is how I DIM'd the variable arrays but the SUBs are using varName$ without the s. The error does not show up because you can run un-dimension-ed arrays up to 10 items. Because this app only ever uses 3 variables, it will never become a problem.
|
|
|
Post by honkytonk on May 11, 2020 23:33:36 GMT
I'm working to transform your functions and subs into gosub to see more clearly, I did half of it without breaking the code, it's not easy. I hate functions and subs because it is very difficult to get out except to go to other subs, it's very hellish. Question: Are there cases in which it is impossible to replace a function or a sub with a gosub?
|
|
|
Post by B+ on May 12, 2020 1:26:24 GMT
I'm working to transform your functions and subs into gosub to see more clearly, I did half of it without breaking the code, it's not easy. I hate functions and subs because it is very difficult to get out except to go to other subs, it's very hellish. Question: Are there cases in which it is impossible to replace a function or a sub with a gosub? You know, when you are using Just Basic all the keywords are SUBs and FUNCTIONs. Using your own hand made ones are just that same as using Just Basic's except you have to CALL subXYZ which is like GOSUB subXYZ. The RETURN of a GOSUB is the same as END SUB and that takes you exactly back to the next line after that CALL of the SUB name or the GOSUB of the line label. But if I had to change to GOSUBs here is how I would start sub setVar vName$, vValue 'simply store or update a variable and it's value 'try to find variable in array for i = 1 to vTopI if varName$(i) = vName$ then varValues(i) = vValue exit sub end if next 'if not found add it if vTopI + 1 <= 100 then vTopI = vTopI +1 varName$(vTopI) = vName$ varValues(vTopI) = vValue else print : print "Sorry, no more room for variables. Goodbye!" end if end sub change to [subSetVar] 'feed me vName$ = ???? and vValue = ???? to lookup or create 'try to find variable in array for i = 1 to vTopI if varName$(i) = vName$ then varValues(i) = vValue 'exit sub RETURN end if next 'if not found add it if vTopI + 1 <= 100 then vTopI = vTopI +1 varName$(vTopI) = vName$ varValues(vTopI) = vValue else print : print "Sorry, no more room for variables. Goodbye!" end if RETURN
converting Function value(vName$) to GOSUB 'function value(vName$) [fnValue] 'feed me vName$ = ????? for looking up it's value for i = 1 to vTopI scan if trim$(varName$(i)) = trim$(vName$) then value = varValues(i) 'exit function RETURN end if next value = -99.11 'end function RETURN
converting SUB preEvalSubst 'sub preEvalSubst byref eString$ [preEvalSubst] ' <<< feed me the eString$ = ???? to change with substitutions of values for variable names i = 1 while word$(eString$, i) <> "" scan v = value(word$(eString$, i)) if v <> -99.11 then call wsSub eString$, i, i, str$(v) 'print eString$ end if i = i + 1 wend 'end sub RETURN
The trouble GOSUBs cause is if you are using i or v or variables of same name in main code the variables used in GOSUBs could mess them up.
|
|
|
Post by honkytonk on May 12, 2020 11:07:41 GMT
For the first: "vName$" and "vValue" exist before calling the sub; it suffices to give the variables processed in the gosub the values before its call (same for the functions). The case for which it is impossible is when the sub calls itself with different parameters (I tried without success)
EDIT: But maybe with two separate gosub.
|
|