Author Topic: Running numeric functions from a string  (Read 4313 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Running numeric functions from a string
« on: October 16, 2020, 11:24:44 pm »
Sorta like Evaluate, here is a test very simple code$ = "X ^ 2" developed from Steve's suggestion for writing, compiling, running, killing code inside another running QB64 program.

Code: QB64: [Select]
  1. _TITLE "Write Compile Run Kill test2 clip" 'b+ 2020-10-17
  2.  
  3. ' Can we "Evaluate" FUNCTIONs from just a string??? by writing, compiling, running and recording answer
  4. ' then killing all the files involved?
  5.  
  6. ' Yes! sorta but the thrill is gone because it is so compromised by a big restriction and numerous delays.
  7.  
  8. ' BIG RESTRICTION:
  9.  
  10. ' !!!!   If QB64.exe is not in your PATH, you have to run this in the QB64.EXE Folder  !!!!
  11.  
  12.  
  13. start = 1: finish = 10: increment = 1
  14. FOR X = start TO finish STEP increment
  15.     IF r$ = "" THEN
  16.         r$ = _TRIM$(STR$(X ^ 2))
  17.     ELSE
  18.         r$ = r$ + CHR$(10) + _TRIM$(STR$(X ^ 2))
  19.     END IF
  20. PRINT: PRINT " and now the hard way ;-))"
  21.  
  22. DoCode$ = "X ^ 2"
  23. REDIM result$(0)
  24. forXEqual 1, 10, 1, DoCode$, result$()
  25. FOR i = LBOUND(result$) TO UBOUND(result$)
  26.     PRINT result$(i)
  27.  
  28. SUB forXEqual (start, toFinish, incStep, DoCode$, outputArr$())
  29.  
  30.     ' write this:
  31.  
  32.     'FOR X = start TO finish STEP increment
  33.     '    IF r$ = "" THEN
  34.     '        'r$ = _trim$(str$(doCode$))
  35.     '    ELSE
  36.     '        'r$ = r$ + chr$(10)+ _trim$(str$(doCode$))
  37.     '    END IF
  38.     'NEXT
  39.     '_CLIPBOARD$ = r$
  40.  
  41.     OPEN "temp.bas" FOR OUTPUT AS #1
  42.     PRINT #1, "FOR X =" + STR$(start) + " TO" + STR$(toFinish) + " STEP" + STR$(incStep)
  43.     PRINT #1, "IF r$ = " + CHR$(34) + CHR$(34) + " THEN"
  44.     PRINT #1, "r$ = _TRIM$(STR$(" + DoCode$ + "))"
  45.     PRINT #1, "ELSE"
  46.     PRINT #1, "r$ = r$ + chr$(10) + _trim$(str$(" + DoCode$ + "))"
  47.     PRINT #1, "END IF"
  48.     PRINT #1, "NEXT"
  49.     PRINT #1, "OPEN " + CHR$(34) + "clip.txt" + CHR$(34) + " FOR OUTPUT AS #5"
  50.     PRINT #1, "PRINT #5, r$"
  51.     PRINT #1, "CLOSE #5"
  52.     CLOSE #1
  53.  
  54.     _DELAY 1 'make sure done with file writing
  55.     SHELL _HIDE "qb64 -c " + CHR$(34) + "temp.bas" + CHR$(34)
  56.     _DELAY 3 ' sometimes it compiles in time sometimes not, 3 reduces the nots
  57.     SHELL _DONTWAIT "temp.exe"
  58.     _DELAY 2 ' give it time to find and run
  59.     SHELL _HIDE "taskkill /F /IM temp.exe"
  60.     _DELAY .5 'give it time to close before kill
  61.     IF _FILEEXISTS("temp.bas") THEN KILL "temp.bas"
  62.     IF _FILEEXISTS("temp.exe") THEN KILL "temp.exe"
  63.     IF _FILEEXISTS("clip.txt") THEN ' we got it written up
  64.         OPEN "clip.txt" FOR INPUT AS #1 ' read out our answer
  65.         WHILE NOT EOF(1)
  66.             LINE INPUT #1, s$
  67.             sAppend outputArr$(), s$
  68.         WEND
  69.         CLOSE #1
  70.         KILL "clip.txt"
  71.     END IF
  72.  
  73. ''append to the string array the string item
  74. SUB sAppend (arr() AS STRING, addItem$)
  75.     REDIM _PRESERVE arr(LBOUND(arr) TO UBOUND(arr) + 1) AS STRING
  76.     arr(UBOUND(arr)) = addItem$
  77.  
  78.  

Offline SpriggsySpriggs

  • Forum Resident
  • Posts: 1145
  • Larger than life
    • View Profile
    • GitHub
Re: Running numeric functions from a string
« Reply #1 on: October 16, 2020, 11:48:21 pm »
I get the idea of compiling and running another instance and read back output from it but why not just make a program that accepts commands in SHELL that is already compiled? It would be much quicker.
Shuwatch!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Running numeric functions from a string
« Reply #2 on: October 17, 2020, 12:03:36 am »
I am evaluating string functions over a range neither of which are hard coded.

I can do X^2 or X^5+X^3+X for 1 to 10 or 500 to -1000 without having to write up a new function. I just say
DoCode$ = "X^5+X^3+X" or "X ^ 2" or any other function involving X.

BTW currently it doesn't work for string literals, need the string stored in a variable before making the call to
ForXEqual...

« Last Edit: October 17, 2020, 12:07:52 am by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Running numeric functions from a string
« Reply #3 on: October 17, 2020, 02:00:14 pm »
BTW this was just testing proof of concept and did not pass with flying colors.

It might be useful for something but not for plotting 20 different functions. I was hoping for a one liner tables generator  to run so many functions given by user at run time.

Actually I was hoping for more advanced code results like a built in Interpreter and string functions was just a stepping stone.
« Last Edit: October 17, 2020, 02:39:38 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Running numeric functions from a string
« Reply #4 on: October 20, 2020, 11:17:11 am »
I get the idea of compiling and running another instance and read back output from it but why not just make a program that accepts commands in SHELL that is already compiled? It would be much quicker.

Yep! I am moving on to this, back to work on my Shorthand Basic project, then, I think I don't even need SHELL.

I seem to loose my _CLIPBOARD$ contents when I run something in SHELL and put something in _CLIPBOARD$. It's not there after SHELL.

Offline carloscordeiro

  • Forum Regular
  • Posts: 102
    • View Profile
Re: Running numeric functions from a string
« Reply #5 on: October 22, 2020, 08:30:13 pm »
Hi Bplus
Taking advantage of the post, I'm trying to make a percentage of a number to show the two digits after the comma. I got it with the LEFT $ command. So with CSNG you can show 4 digits after the comma, I believe you can do the same without using LEFT $.
Attached image shows better.

'Accurate percentage



DIM a(1 TO 4) AS _FLOAT
b = 2062
a(1) = 1273
a(2) = 1266
a(3) = 1260
a(4) = 1174

FOR i = 1 TO 4
    Porc = CSNG(a(i) / b) * 100
    PRINT (a(i) / b) * 100,
    PRINT CSNG(a(i) / b) * 100, ' Line using CSNG
    PRINT LEFT$(STR$(Porc), 6) + "%" '   Mude esta linha
NEXT

Carlos again. ;)
Accurate percentage_01.jpg
* Accurate percentage_01.jpg (Filesize: 33.69 KB, Dimensions: 656x440, Views: 258)
« Last Edit: October 22, 2020, 08:32:47 pm by carloscordeiro »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Running numeric functions from a string
« Reply #6 on: October 22, 2020, 10:22:09 pm »
Going off on a tangent about rounding, Carlos you might like this:
Code: QB64: [Select]
  1. PRINT "1 to 20  rounded to 5's;"
  2. FOR i = 1 TO 20
  3.     PRINT INT(i / 5) * 5
  4. PRINT "press any for 1 to 1000 rounded to 20's.."
  5. FOR i = 1 TO 20
  6.     r = INT(RND * 1000) + 1
  7.     PRINT r, INT(r / 20) * 20
  8.  
  9.  
  10.  

One more, rounded to 1/100ths :
Code: QB64: [Select]
  1. FOR i = 1 TO 20
  2.     r = RND * 100
  3.     PRINT r, INT((r + .005) * 100) / 100
  4.  
« Last Edit: October 22, 2020, 10:29:55 pm by bplus »

Offline carloscordeiro

  • Forum Regular
  • Posts: 102
    • View Profile
Re: Running numeric functions from a string
« Reply #7 on: October 23, 2020, 07:42:29 am »
Very good Bplus
I really liked:

FOR i = 1 TO 20
    r = RND * 100
    PRINT r, INT((r + .005) * 100) / 100
NEXT

I'll use it on:

DIM a(1 TO 4) AS _FLOAT
b = 2062
a(1) = 1273
a(2) = 1266
a(3) = 1260
a(4) = 1174
FOR i = 1 TO 4
    Porc = (a(i) / b) * 100
    PRINT Porc, INT((Porc + .005) * 100) / 100
NEXT

Thank you
Carlos
« Last Edit: October 23, 2020, 07:45:59 am by carloscordeiro »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Running numeric functions from a string
« Reply #8 on: October 23, 2020, 09:58:24 pm »
OK now I have a much soooother operation with the Tabulator:

Code: QB64: [Select]
  1. _TITLE "Tabulator" ' B+ 2020-10-23  from Formula Saver
  2. ' More Evaluate.txt bplus started 2020-05-10 inspired by honkytonk app
  3. ' 2020-10-23 translate from JB but install latest Evaluate
  4. ' copy of Evaluate subs used in this Forumla Saver Project Folder
  5. ' Should be able to do all this without Word$ tools
  6. ' OK everything seems to be working now start Tabulator
  7. ' OK Had to rearrnge th eorder the formula string gets prepped, ie
  8. ' put spaces around all the "words", replace variable for their values
  9. ' or replace constants like pi and e. THEN running x in a FOR loop update
  10. ' only the X variable with it's value.
  11.  
  12. ' The Tabulator.exe opens the file: TableIn.txt
  13. ' reads lines formated as:
  14. ' first line holds the start value of a FOR Loop
  15. ' 2nd the end value of same FOR loop
  16. ' 3rd the increament to STEP
  17. ' 4th the formula eg, X ^ 2 + b * X + pi
  18. ' 5th the dFlag use 0 for Radian units any other for Degrees units
  19. ' 6+ the variables separated by CHR$(10) eg
  20. ' a = 1
  21. ' b = 6
  22. ' c = 5
  23. ' inches = 42
  24.  
  25. ' Tabulator runs the formula in a for loop and generates a table in the
  26. ' file  TableOut.txt.
  27.  
  28. ' So you can edit TableIn.txt in your favorite Text Editor and Run Tabulator
  29. ' and it will rewrite the TableOut.txt with the list of x and f(x).
  30.  
  31. ' Or you can use Calling the Tabulator sub to write the TableIn.txt file,
  32. ' Shell and Run Tabulator then read the file into an array top use:
  33. ' SUB forXEqual (start, toFinish, incStep, formula$, dFlag%, variablesCHR10$, outputArr$())
  34. ' Calling the Tabulator.bas is a demo for the SUB mainly.
  35.  
  36. ' BTW Tabulator does everything in background you will have no idea the TableOut.txt file
  37. ' has been rewritten or not!
  38.  
  39.  
  40. 'evaluate$ and evalW setup
  41. DIM SHARED evalErr$, pi, rad, deg, Dflag, vTopI AS INTEGER, debug
  42. debug = 0 ' this is for checking the Evaluate stuff
  43.  
  44. pi = _PI: rad = pi / 180: deg = 180 / pi '<<<<<<<<<<< true constants
  45. vTopI = 0 'track variables and functions we have changeable global variables change as needed
  46.  
  47. Dflag = 0 ' degrees flag
  48. evalErr$ = ""
  49. rad = _PI / 180.0
  50. deg = 180 / _PI
  51. REDIM SHARED fList(1 TO 1) AS STRING
  52. Split "int, sin, cos, tan, asin, acos, atan, log, exp, sqr, rad, deg,", ", ", fList()
  53. REDIM SHARED oList(1 TO 1) AS STRING
  54. Split "^, %, /, *, -, +, =, <, >, <=, >=, <>, or, and, not", ", ", oList()
  55.  
  56. DIM SHARED varNames$(1 TO 100), varValues(1 TO 100)
  57.  
  58. IF _FILEEXISTS("TableIn.txt") THEN ' 5 lines max to read
  59.     OPEN "TableIn.txt" FOR INPUT AS #1
  60.     FOR i = 1 TO 5
  61.         LINE INPUT #1, fline$
  62.         SELECT CASE i '                     format first 5 lines set variables, more than 5 sets variable names and values
  63.             CASE 1: start = VAL(fline$)
  64.             CASE 2: finish = VAL(fline$)
  65.             CASE 3: inc = VAL(fline$)
  66.             CASE 4: frml$ = fline$
  67.             CASE 5: Dflag = VAL(fline$)
  68.         END SELECT
  69.     NEXT
  70.     WHILE NOT EOF(1) ' read in additional varaibles and values
  71.         LINE INPUT #1, fline$
  72.         IF INSTR(fline$, "=") THEN '                        collect variable names and values
  73.             vTopI = vTopI + 1
  74.             varNames$(vTopI) = _TRIM$(leftOf$(fline$, "=")): varValues(vTopI) = VAL(_TRIM$(rightOf$(fline$, "=")))
  75.         END IF
  76.     WEND
  77.     CLOSE #1
  78.     PRINT " Sorry, TableIn.txt file is missing, goodbye!"
  79.     END
  80. OPEN "TableOut.txt" FOR OUTPUT AS #1
  81. e$ = prepEval$(frml$)
  82. IF evalErr$ = "" THEN 'debug
  83.     'PRINT "prep formula: "; e$
  84.     'INPUT " OK "; w$
  85.     PRINT #1, "Error: " + evalErr$
  86.     CLOSE #1
  87.     SYSTEM
  88. preEvalSubst e$ 'OK inject variable values into formula
  89. ' debug
  90. 'PRINT "Replace variables with values, except x: "; e$
  91. 'INPUT "After preEvalSubst OK "; w$
  92.  
  93. FOR x = start TO finish STEP inc
  94.     REDIM ev$(1 TO 1)
  95.     copy$ = e$
  96.     Split copy$, " ", ev$()
  97.     FOR i = LBOUND(ev$) TO UBOUND(ev$) 'look for x
  98.         IF LCASE$(ev$(i)) = "x" THEN ev$(i) = _TRIM$(STR$(x))
  99.     NEXT
  100.     'rebuild eString$
  101.     FOR i = LBOUND(ev$) TO UBOUND(ev$) ' rejoin as b$
  102.         IF i = LBOUND(ev$) THEN b$ = ev$(1) ELSE b$ = b$ + " " + ev$(i)
  103.     NEXT
  104.     copy$ = b$
  105.     result$ = _TRIM$(Evaluate$(copy$))
  106.     IF evalErr$ = "" THEN
  107.         PRINT #1, ts$(x); " "; result$
  108.     ELSE
  109.         PRINT #1, ts$(x); " Error: " + evalErr$
  110.     END IF
  111.  
  112. FUNCTION value (vName$) ' find vName$ index to get value of variable
  113.     FOR i = 1 TO vTopI
  114.         IF _TRIM$(varNames$(i)) = _TRIM$(vName$) THEN
  115.             value = varValues(i)
  116.             EXIT FUNCTION
  117.         END IF
  118.     NEXT
  119.     value = -99.11 ' no value found can't be -1 or 0 too common
  120.  
  121. SUB preEvalSubst (eString$) ' this is meant to modify eString$ inserting values for variables
  122.     REDIM ev$(1 TO 1)
  123.     Split eString$, " ", ev$()
  124.     FOR i = LBOUND(ev$) TO UBOUND(ev$) 'replace variables for values
  125.         IF LCASE$(ev$(i)) = "pi" THEN
  126.             ev$(i) = ts$(_PI)
  127.         ELSEIF LCASE$(ev$(i)) = "e" THEN
  128.             ev$(i) = ts$(EXP(1))
  129.         ELSEIF LCASE$(ev$(i)) <> "x" THEN
  130.             v = value(ev$(i))
  131.             IF v <> -99.11 THEN ev$(i) = ts$(v)
  132.         END IF
  133.     NEXT
  134.     'rebuild eString$
  135.     FOR i = LBOUND(ev$) TO UBOUND(ev$) ' rejoin as b$
  136.         IF i = LBOUND(ev$) THEN b$ = ev$(1) ELSE b$ = b$ + " " + ev$(i)
  137.     NEXT
  138.     eString$ = b$
  139.  
  140. FUNCTION leftOf$ (source$, of$)
  141.     IF INSTR(source$, of$) > 0 THEN leftOf$ = MID$(source$, 1, INSTR(source$, of$) - 1)
  142.  
  143. FUNCTION rightOf$ (source$, of$)
  144.     IF INSTR(source$, of$) > 0 THEN rightOf$ = MID$(source$, INSTR(source$, of$) + LEN(of$))
  145.  
  146. FUNCTION prepEval$ (e$)
  147.     DIM b$, c$
  148.     DIM i AS INTEGER, po AS INTEGER ', isolateNeg AS _BIT
  149.     ' isolateNeg = 0
  150.     b$ = "" 'rebuild string with padded spaces
  151.     'this makes sure ( ) + * / % ^ are wrapped with spaces,  ??????????? on your own with - sign fixed?
  152.     FOR i = 1 TO LEN(e$) 'filter chars and count ()
  153.         c$ = LCASE$(MID$(e$, i, 1))
  154.         IF c$ = ")" THEN
  155.             po = po - 1: b$ = b$ + " ) "
  156.         ELSEIF c$ = "(" THEN
  157.             po = po + 1: b$ = b$ + " ( "
  158.         ELSEIF INSTR("+*/%^", c$) > 0 THEN
  159.             b$ = b$ + " " + c$ + " "
  160.         ELSEIF c$ = "-" THEN
  161.             IF LEN(b$) > 0 THEN
  162.                 IF INSTR(".0123456789abcdefghijklmnopqrstuvwxyz)", RIGHT$(RTRIM$(b$), 1)) > 0 THEN
  163.                     b$ = b$ + " " + c$ + " "
  164.                 ELSE
  165.                     b$ = b$ + " " + c$
  166.                 END IF
  167.             ELSE
  168.                 b$ = b$ + " " + c$
  169.             END IF
  170.         ELSEIF INSTR(" .0123456789abcdefghijklmnopqrstuvwxyz<>=", c$) > 0 THEN
  171.             b$ = b$ + c$
  172.         END IF
  173.         IF po < 0 THEN evalErr$ = "Too many )": EXIT FUNCTION
  174.     NEXT
  175.     IF po <> 0 THEN evalErr$ = "Unbalanced ()": EXIT FUNCTION
  176.     prepEval$ = b$
  177.  
  178. ' ================================================================================ from Evaluate
  179. 'this preps e$ string for actual evaluation function and makes call to it,
  180. 'checks results for error returns that or string form of result calculation
  181. 'the new goal is to do string functions along side math
  182. FUNCTION Evaluate$ (e$)
  183.     REDIM ev(1 TO 1) AS STRING
  184.     Split e$, " ", ev()
  185.     c$ = evalW$(ev())
  186.     IF evalErr$ <> "" THEN Evaluate$ = evalErr$ ELSE Evaluate$ = c$
  187.  
  188. ' the recursive part of EVAL
  189. FUNCTION evalW$ (a() AS STRING)
  190.     IF evalErr$ <> "" THEN EXIT FUNCTION
  191.  
  192.     DIM fun$, test$, innerV$, m$, op$
  193.     DIM pop AS INTEGER, lPlace AS INTEGER, i AS INTEGER, rPlace AS INTEGER
  194.     DIM po AS INTEGER, p AS INTEGER, o AS INTEGER, index AS INTEGER
  195.     DIM recurs AS INTEGER
  196.     DIM innerVal AS _FLOAT, a AS _FLOAT, b AS _FLOAT
  197.     IF debug THEN
  198.         PRINT "evalW rec'd a() as:"
  199.         FOR i = LBOUND(a) TO UBOUND(a)
  200.             PRINT a(i); ", ";
  201.         NEXT
  202.         PRINT: INPUT "OK enter"; test$: PRINT
  203.     END IF
  204.     pop = find%(a(), "(") 'parenthesis open place
  205.     WHILE pop > 0
  206.         IF pop = 1 THEN
  207.             fun$ = "": lPlace = 1
  208.         ELSE
  209.             test$ = a(pop - 1)
  210.             IF find%(fList(), test$) > 0 THEN
  211.                 fun$ = test$: lPlace = pop - 1
  212.             ELSE
  213.                 fun$ = "": lPlace = pop
  214.             END IF
  215.         END IF
  216.         po = 1
  217.         FOR i = pop + 1 TO UBOUND(a)
  218.             IF a(i) = "(" THEN po = po + 1
  219.             IF a(i) = ")" THEN po = po - 1
  220.             IF po = 0 THEN rPlace = i: EXIT FOR
  221.         NEXT
  222.         REDIM inner(1 TO 1) AS STRING: index = 0: recurs = 0
  223.         FOR i = (pop + 1) TO (rPlace - 1)
  224.             index = index + 1
  225.             REDIM _PRESERVE inner(1 TO index) AS STRING
  226.             inner(index) = a(i)
  227.             IF find%(oList(), a(i)) > 0 THEN recurs = -1
  228.         NEXT
  229.         IF recurs THEN innerV$ = evalW$(inner()) ELSE innerV$ = a(pop + 1)
  230.         innerVal = VAL(innerV$)
  231.  
  232.         SELECT CASE fun$
  233.             CASE "": m$ = innerV$
  234.             CASE "int": m$ = ts$(INT(innerVal))
  235.             CASE "sin": IF Dflag THEN m$ = ts$(SIN(rad * innerVal)) ELSE m$ = ts$(SIN(innerVal))
  236.             CASE "cos": IF Dflag THEN m$ = ts$(COS(rad * innerVal)) ELSE m$ = ts$(COS(innerVal))
  237.             CASE "tan": IF Dflag THEN m$ = ts$(TAN(rad * innerVal)) ELSE m$ = ts$(TAN(innerVal))
  238.             CASE "asin": IF Dflag THEN m$ = ts$(_ASIN(rad * innerVal)) ELSE m$ = ts$(_ASIN(innerVal))
  239.             CASE "acos": IF Dflag THEN m$ = ts$(_ACOS(rad * innerVal)) ELSE m$ = ts$(_ACOS(innerVal))
  240.             CASE "atan": IF Dflag THEN m$ = ts$(ATN(rad * innerVal)) ELSE m$ = ts$(ATN(innerVal))
  241.             CASE "log"
  242.                 IF innerVal > 0 THEN
  243.                     m$ = ts$(LOG(innerVal))
  244.                 ELSE
  245.                     evalErr$ = "LOG only works on numbers > 0.": EXIT FUNCTION
  246.                 END IF
  247.             CASE "exp" 'the error limit is inconsistent in JB
  248.                 IF -745 <= innerVal AND innerVal <= 709 THEN 'your system may have different results
  249.                     m$ = ts$(EXP(innerVal))
  250.                 ELSE
  251.                     'what the heck???? 708 works fine all alone as limit ?????
  252.                     evalErr$ = "EXP(n) only works for n = -745 to 709.": EXIT FUNCTION
  253.                 END IF
  254.             CASE "sqr"
  255.                 IF innerVal >= 0 THEN
  256.                     m$ = ts$(SQR(innerVal))
  257.                 ELSE
  258.                     evalErr$ = "SQR only works for numbers >= 0.": EXIT FUNCTION
  259.                 END IF
  260.             CASE "rad": m$ = ts$(innerVal * rad)
  261.             CASE "deg": m$ = ts$(innerVal * deg)
  262.             CASE ELSE: evalErr$ = "Unidentified function " + fun$: EXIT FUNCTION
  263.         END SELECT
  264.         IF debug THEN
  265.             PRINT "lPlace, rPlace"; lPlace, rPlace
  266.         END IF
  267.         arrSubst a(), lPlace, rPlace, m$
  268.         IF debug THEN
  269.             PRINT "After arrSubst a() is:"
  270.             FOR i = LBOUND(a) TO UBOUND(a)
  271.                 PRINT a(i); " ";
  272.             NEXT
  273.             PRINT: PRINT
  274.         END IF
  275.         pop = find%(a(), "(")
  276.     WEND
  277.  
  278.     'all parenthesis cleared
  279.     'ops$ = "% ^ / * + - = < > <= >= <> and or not" 'all () cleared, now for binary ops (not not binary but is last!)
  280.     FOR o = 1 TO 15
  281.         op$ = oList(o)
  282.         p = find%(a(), op$)
  283.         WHILE p > 0
  284.             a = VAL(a(p - 1))
  285.             b = VAL(a(p + 1))
  286.             IF debug THEN
  287.                 PRINT STR$(a) + op$ + STR$(b)
  288.             END IF
  289.             SELECT CASE op$
  290.                 CASE "%"
  291.                     IF b >= 2 THEN
  292.                         m$ = ts$(INT(a) MOD INT(b))
  293.                     ELSE
  294.                         evalErr$ = "For a Mod b, b value < 2."
  295.                         EXIT FUNCTION
  296.                     END IF
  297.                 CASE "^"
  298.                     IF INT(b) = b OR a >= 0 THEN
  299.                         m$ = ts$(a ^ b)
  300.                     ELSE
  301.                         evalErr$ = "For a ^ b, a needs to be >= 0 when b not integer."
  302.                         EXIT FUNCTION
  303.                     END IF
  304.                 CASE "/"
  305.                     IF b <> 0 THEN
  306.                         m$ = ts$(a / b)
  307.                     ELSE
  308.                         evalErr$ = "Div by 0"
  309.                         EXIT FUNCTION
  310.                     END IF
  311.                 CASE "*": m$ = ts$(a * b)
  312.                 CASE "-": m$ = ts$(a - b)
  313.                 CASE "+": m$ = ts$(a + b)
  314.                 CASE "=": IF a = b THEN m$ = "-1" ELSE m$ = "0"
  315.                 CASE "<": IF a < b THEN m$ = "-1" ELSE m$ = "0"
  316.                 CASE ">": IF a > b THEN m$ = "-1" ELSE m$ = "0"
  317.                 CASE "<=": IF a <= b THEN m$ = "-1" ELSE m$ = "0"
  318.                 CASE ">=": IF a >= b THEN m$ = "-1" ELSE m$ = "0"
  319.                 CASE "<>": IF a <> b THEN m$ = "-1" ELSE m$ = "0"
  320.                 CASE "and": IF a <> 0 AND b <> 0 THEN m$ = "-1" ELSE m$ = "0"
  321.                 CASE "or": IF a <> 0 OR b <> 0 THEN m$ = "-1" ELSE m$ = "0"
  322.                 CASE "not": IF b = 0 THEN m$ = "-1" ELSE m$ = "0" 'use b as nothing should be left of not
  323.             END SELECT
  324.             arrSubst a(), p - 1, p + 1, m$
  325.  
  326.             IF debug THEN
  327.                 PRINT "a() reloaded after " + op$ + " as:"
  328.                 FOR i = LBOUND(a) TO UBOUND(a)
  329.                     PRINT a(i); ", ";
  330.                 NEXT
  331.                 PRINT: PRINT
  332.             END IF
  333.  
  334.             p = find%(a(), op$)
  335.         WEND
  336.     NEXT
  337.     fun$ = ""
  338.     FOR i = LBOUND(a) TO UBOUND(a)
  339.         fun$ = fun$ + " " + a(i)
  340.     NEXT
  341.     evalW$ = LTRIM$(fun$)
  342.  
  343. SUB arrSubst (a() AS STRING, substLow AS LONG, substHigh AS LONG, subst AS STRING)
  344.     DIM i AS LONG, index AS LONG
  345.     a(substLow) = subst: index = substLow + 1
  346.     FOR i = substHigh + 1 TO UBOUND(a)
  347.         a(index) = a(i): index = index + 1
  348.     NEXT
  349.     REDIM _PRESERVE a(LBOUND(a) TO UBOUND(a) + substLow - substHigh)
  350.  
  351. 'notes: REDIM the array(0) to be loaded before calling Split '<<<<<<<<<<<<<<<<<<<<<<< IMPORTANT!!!!
  352. SUB Split (mystr AS STRING, delim AS STRING, arr() AS STRING)
  353.     ' bplus modifications of Galleon fix of Bulrush Split reply #13
  354.     ' http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index.php?topic=1612.0
  355.     ' this sub further developed and tested here: \test\Strings\Split test.bas
  356.     ' 2018-09-16 modified for base 1 arrays
  357.     DIM copy AS STRING, p AS LONG, curpos AS LONG, arrpos AS LONG, lc AS LONG, dpos AS LONG
  358.     copy = mystr 'make copy since we are messing with mystr
  359.     'special case if delim is space, probably want to remove all excess space
  360.     IF delim = " " THEN
  361.         copy = RTRIM$(LTRIM$(copy))
  362.         p = INSTR(copy, "  ")
  363.         WHILE p > 0
  364.             copy = MID$(copy, 1, p - 1) + MID$(copy, p + 1)
  365.             p = INSTR(copy, "  ")
  366.         WEND
  367.     END IF
  368.     REDIM arr(1 TO 1) 'clear it
  369.     curpos = 1
  370.     arrpos = 1
  371.     lc = LEN(copy)
  372.     dpos = INSTR(curpos, copy, delim)
  373.     DO UNTIL dpos = 0
  374.         arr(arrpos) = MID$(copy, curpos, dpos - curpos)
  375.         arrpos = arrpos + 1
  376.         REDIM _PRESERVE arr(1 TO arrpos + 1) AS STRING
  377.         curpos = dpos + LEN(delim)
  378.         dpos = INSTR(curpos, copy, delim)
  379.     LOOP
  380.     arr(arrpos) = MID$(copy, curpos)
  381.     REDIM _PRESERVE arr(1 TO arrpos) AS STRING
  382.  
  383. 'assume a() is base 1 array so if find comes back as 0 then found nothing
  384. FUNCTION find% (a() AS STRING, s$)
  385.     DIM i%
  386.     FOR i% = LBOUND(a) TO UBOUND(a)
  387.         IF a(i%) = s$ THEN find% = i%: EXIT FUNCTION
  388.     NEXT
  389.  
  390. 'ltrim a number float
  391. FUNCTION ts$ (n)
  392.     ts$ = _TRIM$(STR$(n))
  393.  
  394.  

Run this file in a folder you can play around with, it will tell you it can't find the TableIn.txt file. That's OK we just need the exe made so we can call it from a SHELL.

Now here is demo code for the SUB in it to make the TableIn.txt file place it in same test area folder as the Tabulator
and run the Tabulator in a SHELL, and then gets the lines generated and loads them in an array to be used as needed.

Code: QB64: [Select]
  1. _TITLE "Calling the Tabulator" 'b+ 2020-10-23
  2. ' mod "Write Compile Run Kill test2 clip.bas" 'b+ 2020-10-17
  3.  
  4. ' Can we "Evaluate" FUNCTIONs from just a string???
  5.  
  6. start = 1: finish = 10: increment = 1: a = 2: b = 6: c = _PI
  7. FOR X = start TO finish STEP increment
  8.     IF r$ = "" THEN
  9.         r$ = TS$(X) + " " + TS$(a * X ^ 2 + b * X + c)
  10.     ELSE
  11.         r$ = r$ + CHR$(10) + TS$(X) + " " + TS$(a * X ^ 2 + b * X + c)
  12.     END IF
  13. PRINT " and now the hard way ;-))"
  14.  
  15. f$ = "a*X^2+b*X+pi" ' our formula
  16. v$ = "a=2" + CHR$(10) + "b=6" + CHR$(10) + "c= pi" 'some variables
  17. REDIM result$(0) ' output array, notice it's dynamic
  18.  
  19. '   Make the call...
  20. ' start, finish, step increment, formula$, degreeFlag True (radians = 0 or False), variables list in formula$, outputArray$()
  21. forXEqual 1, 10, 1, f$, 0, v$, result$()
  22.  
  23. ' show results
  24. FOR i = LBOUND(result$) TO UBOUND(result$)
  25.     PRINT result$(i)
  26. PRINT "Run is done."
  27.  
  28. SUB forXEqual (start, toFinish, incStep, formula$, dFlag%, variablesCHR10$, outputArr$())
  29.     OPEN "TableIn.txt" FOR OUTPUT AS #1
  30.     PRINT #1, TS$(start)
  31.     PRINT #1, TS$(toFinish)
  32.     PRINT #1, TS$(incStep)
  33.     PRINT #1, formula$
  34.     PRINT #1, TS$(dFlag)
  35.     PRINT #1, variablesCHR10$
  36.     CLOSE #1
  37.     REDIM outputArr$(0)
  38.     SHELL _HIDE "Tabulator.exe"
  39.     _DELAY .5 ' sometimes it compiles in time sometimes not, 3 reduces the nots
  40.     IF _FILEEXISTS("TableOut.txt") THEN
  41.         OPEN "TableOut.txt" FOR INPUT AS #1
  42.         WHILE NOT EOF(1)
  43.             LINE INPUT #1, fline$
  44.             sAppend outputArr$(), fline$
  45.         WEND
  46.     END IF
  47.  
  48. ''append to the string array the string item
  49. SUB sAppend (arr() AS STRING, addItem$)
  50.     REDIM _PRESERVE arr(LBOUND(arr) TO UBOUND(arr) + 1) AS STRING
  51.     arr(UBOUND(arr)) = addItem$
  52.  
  53. FUNCTION TS$ (n)
  54.     TS$ = _TRIM$(STR$(n))
  55.  

Now you can run functions in code and generate arrays of values without having to write a separate code for each function. How 'bout them apples?

BTW c=pi does not work, must use number literals on the right side of = sign. But pi will work in the Formula string.

« Last Edit: October 23, 2020, 10:08:12 pm by bplus »