Author Topic: Just a primitive program to parse arithmetic expressions.  (Read 4295 times)

0 Members and 1 Guest are viewing this topic.

Offline CharlieJV

  • Newbie
  • Posts: 89
    • View Profile
Just a primitive program to parse arithmetic expressions.
« on: March 14, 2022, 03:10:07 pm »
The code below (pretty roughly tweaked) based on the BASIC Anywhere Machine version (source code here, run it here).

BASIC Anywhere Machine version based on BBC BASIC version found at rosettacode.org.

Code: QB64: [Select]
  1. dim shared Expr$
  2. ' This program based on https://rosettacode.org/wiki/Arithmetic_evaluation#BBC_BASIC
  3. '
  4. ' FUNCTION DECLARATIONS
  5.     declare function fNast$()
  6.     declare function fNast1$()
  7.     declare function fNastDeux$()
  8.     declare function fNumber$()
  9. ' MAIN PROGRAM
  10.     Expr$ = "1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10"
  11.     'Expr$ = "(1 + 2) * 3"
  12.     PRINT "Input = " + Expr$
  13.     print "fNast$ = " + fNast$
  14.     'AST$ = fNast$()
  15.     'PRINT "AST =   " +  AST$
  16.     'PRINT "Value = " ;EVAL(AST$)
  17.     END
  18. '
  19. ' FUNCTION DEFINITIONS
  20. function fNast$()
  21. ast$ = ""
  22.     fNast_repeat:
  23.         ast$ = ast$ + fNast1$
  24.         WHILE ASC(Expr$)=32
  25.         print "Expr$ = " + Expr$
  26.             Expr$ = MID$(Expr$,2,len(Expr$)-1)
  27.         wend
  28.         oper$ = LEFT$(Expr$,1)
  29.         IF oper$="+" OR oper$="-" THEN
  30.             ast$ = ast$ + oper$
  31.             Expr$ = MID$(Expr$,2,len(Expr$)-1)
  32.             goto fNast_repeat
  33.         end if
  34.     fNast$ = "(" + ast$ + ")"
  35. function fNast1$()
  36.     ast$ = ""
  37.     fNast1_repeat:
  38.         ast$= ast$ + fNastDeux$
  39.         WHILE ASC(Expr$)=32
  40.             Expr$ = MID$(Expr$,2,len(Expr$)-1)
  41.         wend
  42.         oper$ = LEFT$(Expr$,1)
  43.         IF oper$="*" OR oper$="/" THEN
  44.             ast$ = ast$ + oper$
  45.             Expr$ = MID$(Expr$,2,len(Expr$)-1)
  46.             goto fNast1_repeat
  47.         end if
  48.     fNast1$ = "(" + ast$ + ")"
  49. function fNastDeux$()
  50.     WHILE ASC(Expr$)=32
  51.         Expr$ = MID$(Expr$,2,len(Expr$)-1)
  52.     wend
  53.     IF ASC(Expr$)=40 THEN
  54.         Expr$ = MID$(Expr$, 2, len(Expr$)-1)
  55.         ast$ = fNastDeux$
  56.         Expr$ = MID$(Expr$,2, len(Expr$)-1)
  57.     ELSE
  58.         ast$ = fNumber$
  59.     end if
  60.     fNastDeux$ = ast$
  61. function fNumber$()
  62.     num$ = ""
  63.     fNumber_repeat:
  64.         ch$ = left$(Expr$, 1)
  65.         ' 🚨 wwwBASIC: issues with instr breaking app when the character is a parenthesis
  66.         if ch$ <> "" and instr("0123456789.", ch$) then
  67.             num$ = num$ + ch$
  68.             Expr$ = mid$(Expr$,2,len(Expr$)-1)
  69.             goto fNumber_repeat
  70.         end if
  71.     fNumber$ = num$
  72.  
  73.  
  74.  

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Just a primitive program to parse arithmetic expressions.
« Reply #1 on: March 18, 2022, 08:59:31 pm »
Guess I will show you how it's done :)
Code: QB64: [Select]
  1. _Title "Eval by bplus translated from FB 2018-02-05"
  2. ' from: EVAL  2 bplus.bas for FB (B+=MGA) 2017-07-04
  3. 'based on successful: evalW 2.txt for JB [B+=MGA] 2017-03-11 repost with edits
  4. ' EVAL 1 - Just Basic Eval code translated and = > < >= <= <> binary's added
  5. 'EVAL  2 - add And and Or, Not
  6.  
  7. Const XMAX = 1200
  8. Const YMAX = 720
  9.  
  10. Screen _NewImage(XMAX, YMAX, 32)
  11.  
  12. Common Shared DFlag, EvalErr$, GlobalX, RAD, DEG
  13.  
  14. EvalErr$ = ""
  15. DFlag = 1
  16. GlobalX = 5 'changeable
  17. RAD = _Pi / 180.0
  18. DEG = 180 / _Pi
  19. 'debug
  20. 'PRINT RAD, DEG, DFlag, GlobalX
  21.  
  22. '  tests
  23. e$ = "log(0)" 'err
  24. e$ = "exp(-745) " 'no err! -746 err!
  25. 'e$ = "exp(-693) " ' FB -693 limit 1.0812... E-301 bottom limit no error on my system, -708 on another test
  26. e$ = "exp( 709) " ' no err , FB 707 limit 8.21840... E+307no error on my system
  27. e$ = "sqr(-10)" 'err
  28. e$ = "-5 ^ 1.9" 'err
  29. e$ = "2*-3 - -4+-0.25" ' returns -2.25 OK but must  isolate - meant for subtraction OK
  30.  
  31. e$ = "1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10" ' returns 71 OK  OK fixed!
  32.  
  33. 'e$ = " 1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1" ' returns 60 OK
  34. 'e$ = "1+1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1/15)/14)/13)/12)/11)/10)/9)/8)/7)/6)/5)/4)/3)/2"
  35. ' returns euler's 2.718 281 828 458 994 464 285 469 58 OK for as far as it goes 2.718 281 828 458 995 last digit off by 1  OK!!!
  36. 'e$ = "(1.4 + 2^(19%4))/2" ' > 4.7 OK OK
  37. 'e$ = "e^2" ' > 7.3890...
  38. 'e$ = "PI/6" ' > .52...
  39. 'e$ = "x ^ (200/400)" ' > 2.23606 when sqr(x) x = 5
  40. 'e$ = "x^2 - 2*x - 15" ' > 0 when x = 5 good!
  41. 'e$ = "e^ 8" ' > 2980.958
  42. 'e$ = " log(2980.958)" ' > 8.000..
  43. 'e$ = "sin(x)^2 + cos(x)^2" ' > 1
  44. 'e$ = "atan(sin(30)/cos(30))" ' > 30 with DFlag = 1
  45. 'e$ = ".3 + 2*10^-8"
  46. 'e$ = "pi/6 < pi" 'yeah my first Boolean!
  47. 'e$ = "99 % 11 = 0"
  48. 'e$ = "23 <= 22"
  49. 'e$ = "(99 % 9 = 0) and (not 23 < 22 or 5 < 3)"
  50.  
  51. 'IMPORTANT NOTE: wrap - sign with spaces if meant for subtraction,
  52. 'if meant to signal neg number leave no space between it and number
  53.  
  54. R = Evaluate(e$)
  55. If EvalErr$ <> "" Then Print "Error: "; EvalErr$ Else Print "Expression = "; R
  56. Print "Done"
  57.  
  58. 'this preps e$ string for actual evaluation function and makes call to it,
  59. 'checks results for error returns that or number if no error.
  60. Function Evaluate (e$)
  61.     'Dim As String c, b, subst
  62.     'Dim As Integer i, po, p
  63.     b$ = "" 'rebuild string with padded spaces
  64.     'this makes sure ( ) + * / % ^ are wrapped with spaces, on your own with - sign
  65.     For i = 1 To Len(e$) 'filter chars and count ()
  66.         c$ = LCase$(Mid$(e$, i, 1))
  67.         If c$ = ")" Then
  68.             po = po - 1: b$ = b$ + " ) "
  69.         ElseIf c$ = "(" Then
  70.             po = po + 1: b$ = b$ + " ( "
  71.         ElseIf InStr("+*/%^", c$) > 0 Then
  72.             b$ = b$ + " " + c$ + " "
  73.         ElseIf InStr(" -.0123456789abcdefghijklmnopqrstuvwxyz<>=", c$) > 0 Then
  74.             b$ = b$ + c$
  75.         End If
  76.         If po < 0 Then EvalErr$ = "Too many )": Exit Function
  77.     Next
  78.     If po <> 0 Then EvalErr$ = "Unbalanced ()": Exit Function
  79.     e$ = wPrep(b$)
  80.     For i = 1 To 3
  81.         p = wIn(e$, Wrd$("x e pi", i))
  82.         While p > 0
  83.             Select Case i
  84.                 Case 1: subst$ = LTrim$(Str$(GlobalX)) ': PRINT "subst "; subst$, GlobalX
  85.                 Case 2: subst$ = LTrim$(Str$(Exp(1)))
  86.                 Case 3: subst$ = LTrim$(Str$(_Pi))
  87.             End Select
  88.             e$ = wSubst$(e$, p, p, subst$)
  89.             p = wIn(e$, Wrd("x e pi", i))
  90.         Wend
  91.     Next
  92.     Evaluate = evalW(e$)
  93.  
  94. ' the recursive part of EVAL
  95. Function evalW (s$)
  96.     Dim pop As Integer, lPlace As Integer, i As Integer, rPlace As Integer, wc As Integer
  97.     Dim po As Integer, funPlace As Integer, recurs As Integer, p As Integer, o As Integer
  98.     'Dim As String fun, w, test, inner, ops, op, middle
  99.     'Dim As Double a, b, innerV, m
  100.  
  101.     Print "EvalW gets: "; s$ 'debug or fun$ to watch recursive calls in reverse
  102.     pop = wIn(s$, "(") 'parenthesis open place
  103.     While pop > 0
  104.         If pop = 1 Then
  105.             fun$ = "": lPlace = 1
  106.         Else
  107.             test$ = Wrd$(s$, pop - 1)
  108.             funPlace = wIn("sin cos tan atan log exp sqr rad deg", test$) 'no asin or acos in QB64
  109.             If funPlace > 0 Then
  110.                 fun$ = test$: lPlace = pop - 1
  111.             Else
  112.                 fun$ = "": lPlace = pop
  113.             End If
  114.         End If
  115.         wc = wCnt(s$): po = 1
  116.         For i = pop + 1 To wc
  117.             If Wrd$(s$, i) = "(" Then po = po + 1
  118.             If Wrd$(s$, i) = ")" Then po = po - 1
  119.             If po = 0 Then rPlace = i: Exit For
  120.         Next
  121.         inner$ = ""
  122.         For i = (pop + 1) To (rPlace - 1)
  123.             w$ = Wrd$(s$, i)
  124.             inner$ = inner$ + w$ + " "
  125.             If wIn("( and or = < > <= >= <> + - * / % ^", w$) > 0 Then recurs = 1
  126.         Next
  127.         If recurs Then innerV = evalW(inner$) Else innerV = Val(inner$)
  128.         Select Case fun$
  129.             Case "": m = innerV
  130.             Case "sin": If DFlag Then m = Sin(RAD * innerV) Else m = Sin(innerV)
  131.             Case "cos": If DFlag Then m = Cos(RAD * innerV) Else m = Cos(innerV)
  132.             Case "tan": If DFlag Then m = Tan(RAD * innerV) Else m = Tan(innerV)
  133.                 'CASE "asin": IF DFlag THEN m = DEG * (Asin(innerV)) ELSE m = Asin(innerV)
  134.                 ' CASE "acos": IF DFlag THEN m = DEG * (acos(innerV)) ELSE m = acos(innerV)
  135.             Case "atan": If DFlag Then m = DEG * (Atn(innerV)) Else m = Atn(innerV)
  136.             Case "log"
  137.                 If innerV > 0 Then
  138.                     m = Log(innerV)
  139.                 Else
  140.                     EvalErr$ = "LOG only works on numbers > 0.": Exit Function
  141.                 End If
  142.             Case "exp" 'the error limit is inconsistent in JB
  143.                 If -745 <= innerV And innerV <= 709 Then 'your system may have different results
  144.                     m = Exp(innerV)
  145.                 Else
  146.                     'what the heck???? 708 works fine all alone as limit ?????
  147.                     EvalErr$ = "EXP(n) only works for n = -745 to 709.": Exit Function
  148.                 End If
  149.             Case "sqr"
  150.                 If innerV >= 0 Then
  151.                     m = Sqr(innerV)
  152.                 Else
  153.                     EvalErr$ = "SQR only works for numbers >= 0.": Exit Function
  154.                 End If
  155.             Case "rad": m = innerV * RAD
  156.             Case "deg": m = innerV * DEG
  157.             Case Else: EvalErr$ = "Unidentified function " + fun$: Exit Function
  158.         End Select
  159.         s$ = wSubst(s$, lPlace, rPlace, LTrim$(Str$(m)))
  160.         pop = wIn(s$, "(")
  161.     Wend
  162.  
  163.     ops$ = "% ^ / * - + = < > <= >= <> and or not" 'all () cleared, now for binary ops (not not binary but is last!)
  164.     For o = 1 To 15
  165.         op$ = Wrd$(ops$, o)
  166.         p = wIn(s$, op$)
  167.         While p > 0
  168.             a = Val(Wrd$(s$, p - 1))
  169.             b = Val(Wrd$(s$, p + 1))
  170.             Select Case op$
  171.                 Case "%"
  172.                     If b >= 2 Then
  173.                         middle$ = LTrim$(Str$(Int(a) Mod Int(b)))
  174.                     Else
  175.                         EvalErr$ = "For a Mod b, b value < 2."
  176.                         Exit Function
  177.                     End If
  178.                 Case "^"
  179.                     If Int(b) = b Or a >= 0 Then
  180.                         middle$ = LTrim$(Str$(a ^ b))
  181.                     Else
  182.                         EvalErr$ = "For a ^ b, a needs to be >= 0 when b not integer."
  183.                         Exit Function
  184.                     End If
  185.                 Case "/"
  186.                     If b <> 0 Then
  187.                         middle$ = LTrim$(Str$(a / b))
  188.                     Else
  189.                         EvalErr$ = "Div by 0"
  190.                         Exit Function
  191.                     End If
  192.                 Case "*": middle$ = LTrim$(Str$(a * b))
  193.                 Case "-": middle$ = LTrim$(Str$(a - b))
  194.                 Case "+": middle$ = LTrim$(Str$(a + b))
  195.                 Case "=": If a = b Then middle$ = "1" Else middle$ = "0"
  196.                 Case "<": If a < b Then middle$ = "1" Else middle$ = "0"
  197.                 Case ">": If a > b Then middle$ = "1" Else middle$ = "0"
  198.                 Case "<=": If a <= b Then middle$ = "1" Else middle$ = "0"
  199.                 Case ">=": If a >= b Then middle$ = "1" Else middle$ = "0"
  200.                 Case "<>": If a <> b Then middle$ = "1" Else middle$ = "0"
  201.                 Case "and": If a <> 0 And b <> 0 Then middle$ = "1" Else middle$ = "0"
  202.                 Case "or": If a <> 0 Or b <> 0 Then middle$ = "1" Else middle$ = "0"
  203.                 Case "not": If b = 0 Then middle$ = "1" Else middle$ = "0" 'use b as nothing should be left of not
  204.             End Select
  205.             s$ = wSubst$(s$, p - 1, p + 1, middle$)
  206.             'PRINT s$
  207.             p = wIn(s$, op$)
  208.         Wend
  209.     Next
  210.     evalW = Val(s$)
  211.     'PRINT evalW
  212.  
  213. 'return trimmed  source string s with one space between each word
  214. Function wPrep$ (ss$)
  215.  
  216.     s$ = LTrim$(RTrim$(ss$))
  217.     If Len(s$) = 0 Then wPrep$ = "": Exit Function
  218.     'remove all double or more spaces
  219.     p = InStr(s$, "  ")
  220.     While p > 0
  221.         s$ = Mid$(s$, 1, p) + Mid$(s$, p + 2, Len(s$) - p - 1)
  222.         p = InStr(s$, "  ")
  223.     Wend
  224.     wPrep$ = s$
  225.  
  226. ' This duplicates JB word(string, wordNumber) base 1, space as default delimiter
  227. ' by returning the Nth word of source string s
  228. ' this function assumes s has been through wPrep
  229. Function Wrd$ (ss$, wNumber)
  230.     's$ = wPrep(ss$)
  231.     s$ = ss$ 'don't change ss$
  232.     If Len(s$) = 0 Then Wrd$ = "": Exit Function
  233.     w$ = "": c = 1
  234.     For i = 1 To Len(s$)
  235.         If Mid$(s$, i, 1) = " " Then
  236.             If c = wNumber Then Wrd$ = w$: Exit Function
  237.             w$ = "": c = c + 1
  238.         Else
  239.             w$ = w$ + Mid$(s$, i, 1)
  240.         End If
  241.     Next
  242.     If c <> wNumber Then Wrd$ = " " Else Wrd$ = w$
  243.  
  244. 'This function counts the words in source string s
  245. 'this function assumes s has been thru wPrep
  246. Function wCnt (s$)
  247.     Dim c As Integer, p As Integer, ip As Integer
  248.     's = wPrep(s)
  249.     If Len(s$) = 0 Then wCnt = 0: Exit Function
  250.     c = 1: p = 1: ip = InStr(p, s$, " ")
  251.     While ip
  252.         c = c + 1: p = ip + 1: ip = InStr(p, s$, " ")
  253.     Wend
  254.     wCnt = c
  255.  
  256. 'Where is word In source s, 0 = Not In source
  257. 'this function assumes s has been thru wPrep
  258. Function wIn (s$, wd$)
  259.     Dim wc As Integer, i As Integer
  260.     wc = wCnt(s$): wIn = 0
  261.     For i = 1 To wc
  262.         If Wrd$(s$, i) = wd$ Then wIn = i: Exit Function
  263.     Next
  264.  
  265. ' substitute string in s to replace section first to last words inclusive
  266. 'this function assumes s has been thru wPrep
  267. Function wSubst$ (s$, first, last, subst$)
  268.     Dim wc As Integer, i As Integer, subF As Integer
  269.     wc = wCnt(s$): b$ = ""
  270.     For i = 1 To wc
  271.         If first <= i And i <= last Then 'do this only once!
  272.             If subF = 0 Then b$ = b$ + subst$ + " ": subF = 1
  273.         Else
  274.             b$ = b$ + Wrd$(s$, i) + " "
  275.         End If
  276.     Next
  277.     wSubst$ = LTrim$(RTrim$(b$))
  278.  
  279.  
  280.  

Offline CharlieJV

  • Newbie
  • Posts: 89
    • View Profile
Re: Just a primitive program to parse arithmetic expressions.
« Reply #2 on: March 19, 2022, 11:50:44 am »
Guess I will show you how it's done :)
(snip!)

That's quite fantastic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Just a primitive program to parse arithmetic expressions.
« Reply #3 on: March 19, 2022, 12:07:23 pm »
Guess I will show you how it's done :)
Code: QB64: [Select]
  1. _Title "Eval by bplus translated from FB 2018-02-05"
  2. ' from: EVAL  2 bplus.bas for FB (B+=MGA) 2017-07-04
  3. 'based on successful: evalW 2.txt for JB [B+=MGA] 2017-03-11 repost with edits
  4. ' EVAL 1 - Just Basic Eval code translated and = > < >= <= <> binary's added
  5. 'EVAL  2 - add And and Or, Not
  6.  
  7. Const XMAX = 1200
  8. Const YMAX = 720
  9.  
  10. Screen _NewImage(XMAX, YMAX, 32)
  11.  
  12. Common Shared DFlag, EvalErr$, GlobalX, RAD, DEG
  13.  
  14. EvalErr$ = ""
  15. DFlag = 1
  16. GlobalX = 5 'changeable
  17. RAD = _Pi / 180.0
  18. DEG = 180 / _Pi
  19. 'debug
  20. 'PRINT RAD, DEG, DFlag, GlobalX
  21.  
  22. '  tests
  23. e$ = "log(0)" 'err
  24. e$ = "exp(-745) " 'no err! -746 err!
  25. 'e$ = "exp(-693) " ' FB -693 limit 1.0812... E-301 bottom limit no error on my system, -708 on another test
  26. e$ = "exp( 709) " ' no err , FB 707 limit 8.21840... E+307no error on my system
  27. e$ = "sqr(-10)" 'err
  28. e$ = "-5 ^ 1.9" 'err
  29. e$ = "2*-3 - -4+-0.25" ' returns -2.25 OK but must  isolate - meant for subtraction OK
  30.  
  31. e$ = "1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10" ' returns 71 OK  OK fixed!
  32.  
  33. 'e$ = " 1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1" ' returns 60 OK
  34. 'e$ = "1+1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1/15)/14)/13)/12)/11)/10)/9)/8)/7)/6)/5)/4)/3)/2"
  35. ' returns euler's 2.718 281 828 458 994 464 285 469 58 OK for as far as it goes 2.718 281 828 458 995 last digit off by 1  OK!!!
  36. 'e$ = "(1.4 + 2^(19%4))/2" ' > 4.7 OK OK
  37. 'e$ = "e^2" ' > 7.3890...
  38. 'e$ = "PI/6" ' > .52...
  39. 'e$ = "x ^ (200/400)" ' > 2.23606 when sqr(x) x = 5
  40. 'e$ = "x^2 - 2*x - 15" ' > 0 when x = 5 good!
  41. 'e$ = "e^ 8" ' > 2980.958
  42. 'e$ = " log(2980.958)" ' > 8.000..
  43. 'e$ = "sin(x)^2 + cos(x)^2" ' > 1
  44. 'e$ = "atan(sin(30)/cos(30))" ' > 30 with DFlag = 1
  45. 'e$ = ".3 + 2*10^-8"
  46. 'e$ = "pi/6 < pi" 'yeah my first Boolean!
  47. 'e$ = "99 % 11 = 0"
  48. 'e$ = "23 <= 22"
  49. 'e$ = "(99 % 9 = 0) and (not 23 < 22 or 5 < 3)"
  50.  
  51. 'IMPORTANT NOTE: wrap - sign with spaces if meant for subtraction,
  52. 'if meant to signal neg number leave no space between it and number
  53.  
  54. R = Evaluate(e$)
  55. If EvalErr$ <> "" Then Print "Error: "; EvalErr$ Else Print "Expression = "; R
  56. Print "Done"
  57.  
  58. 'this preps e$ string for actual evaluation function and makes call to it,
  59. 'checks results for error returns that or number if no error.
  60. Function Evaluate (e$)
  61.     'Dim As String c, b, subst
  62.     'Dim As Integer i, po, p
  63.     b$ = "" 'rebuild string with padded spaces
  64.     'this makes sure ( ) + * / % ^ are wrapped with spaces, on your own with - sign
  65.     For i = 1 To Len(e$) 'filter chars and count ()
  66.         c$ = LCase$(Mid$(e$, i, 1))
  67.         If c$ = ")" Then
  68.             po = po - 1: b$ = b$ + " ) "
  69.         ElseIf c$ = "(" Then
  70.             po = po + 1: b$ = b$ + " ( "
  71.         ElseIf InStr("+*/%^", c$) > 0 Then
  72.             b$ = b$ + " " + c$ + " "
  73.         ElseIf InStr(" -.0123456789abcdefghijklmnopqrstuvwxyz<>=", c$) > 0 Then
  74.             b$ = b$ + c$
  75.         End If
  76.         If po < 0 Then EvalErr$ = "Too many )": Exit Function
  77.     Next
  78.     If po <> 0 Then EvalErr$ = "Unbalanced ()": Exit Function
  79.     e$ = wPrep(b$)
  80.     For i = 1 To 3
  81.         p = wIn(e$, Wrd$("x e pi", i))
  82.         While p > 0
  83.             Select Case i
  84.                 Case 1: subst$ = LTrim$(Str$(GlobalX)) ': PRINT "subst "; subst$, GlobalX
  85.                 Case 2: subst$ = LTrim$(Str$(Exp(1)))
  86.                 Case 3: subst$ = LTrim$(Str$(_Pi))
  87.             End Select
  88.             e$ = wSubst$(e$, p, p, subst$)
  89.             p = wIn(e$, Wrd("x e pi", i))
  90.         Wend
  91.     Next
  92.     Evaluate = evalW(e$)
  93.  
  94. ' the recursive part of EVAL
  95. Function evalW (s$)
  96.     Dim pop As Integer, lPlace As Integer, i As Integer, rPlace As Integer, wc As Integer
  97.     Dim po As Integer, funPlace As Integer, recurs As Integer, p As Integer, o As Integer
  98.     'Dim As String fun, w, test, inner, ops, op, middle
  99.     'Dim As Double a, b, innerV, m
  100.  
  101.     Print "EvalW gets: "; s$ 'debug or fun$ to watch recursive calls in reverse
  102.     pop = wIn(s$, "(") 'parenthesis open place
  103.     While pop > 0
  104.         If pop = 1 Then
  105.             fun$ = "": lPlace = 1
  106.         Else
  107.             test$ = Wrd$(s$, pop - 1)
  108.             funPlace = wIn("sin cos tan atan log exp sqr rad deg", test$) 'no asin or acos in QB64
  109.             If funPlace > 0 Then
  110.                 fun$ = test$: lPlace = pop - 1
  111.             Else
  112.                 fun$ = "": lPlace = pop
  113.             End If
  114.         End If
  115.         wc = wCnt(s$): po = 1
  116.         For i = pop + 1 To wc
  117.             If Wrd$(s$, i) = "(" Then po = po + 1
  118.             If Wrd$(s$, i) = ")" Then po = po - 1
  119.             If po = 0 Then rPlace = i: Exit For
  120.         Next
  121.         inner$ = ""
  122.         For i = (pop + 1) To (rPlace - 1)
  123.             w$ = Wrd$(s$, i)
  124.             inner$ = inner$ + w$ + " "
  125.             If wIn("( and or = < > <= >= <> + - * / % ^", w$) > 0 Then recurs = 1
  126.         Next
  127.         If recurs Then innerV = evalW(inner$) Else innerV = Val(inner$)
  128.         Select Case fun$
  129.             Case "": m = innerV
  130.             Case "sin": If DFlag Then m = Sin(RAD * innerV) Else m = Sin(innerV)
  131.             Case "cos": If DFlag Then m = Cos(RAD * innerV) Else m = Cos(innerV)
  132.             Case "tan": If DFlag Then m = Tan(RAD * innerV) Else m = Tan(innerV)
  133.                 'CASE "asin": IF DFlag THEN m = DEG * (Asin(innerV)) ELSE m = Asin(innerV)
  134.                 ' CASE "acos": IF DFlag THEN m = DEG * (acos(innerV)) ELSE m = acos(innerV)
  135.             Case "atan": If DFlag Then m = DEG * (Atn(innerV)) Else m = Atn(innerV)
  136.             Case "log"
  137.                 If innerV > 0 Then
  138.                     m = Log(innerV)
  139.                 Else
  140.                     EvalErr$ = "LOG only works on numbers > 0.": Exit Function
  141.                 End If
  142.             Case "exp" 'the error limit is inconsistent in JB
  143.                 If -745 <= innerV And innerV <= 709 Then 'your system may have different results
  144.                     m = Exp(innerV)
  145.                 Else
  146.                     'what the heck???? 708 works fine all alone as limit ?????
  147.                     EvalErr$ = "EXP(n) only works for n = -745 to 709.": Exit Function
  148.                 End If
  149.             Case "sqr"
  150.                 If innerV >= 0 Then
  151.                     m = Sqr(innerV)
  152.                 Else
  153.                     EvalErr$ = "SQR only works for numbers >= 0.": Exit Function
  154.                 End If
  155.             Case "rad": m = innerV * RAD
  156.             Case "deg": m = innerV * DEG
  157.             Case Else: EvalErr$ = "Unidentified function " + fun$: Exit Function
  158.         End Select
  159.         s$ = wSubst(s$, lPlace, rPlace, LTrim$(Str$(m)))
  160.         pop = wIn(s$, "(")
  161.     Wend
  162.  
  163.     ops$ = "% ^ / * - + = < > <= >= <> and or not" 'all () cleared, now for binary ops (not not binary but is last!)
  164.     For o = 1 To 15
  165.         op$ = Wrd$(ops$, o)
  166.         p = wIn(s$, op$)
  167.         While p > 0
  168.             a = Val(Wrd$(s$, p - 1))
  169.             b = Val(Wrd$(s$, p + 1))
  170.             Select Case op$
  171.                 Case "%"
  172.                     If b >= 2 Then
  173.                         middle$ = LTrim$(Str$(Int(a) Mod Int(b)))
  174.                     Else
  175.                         EvalErr$ = "For a Mod b, b value < 2."
  176.                         Exit Function
  177.                     End If
  178.                 Case "^"
  179.                     If Int(b) = b Or a >= 0 Then
  180.                         middle$ = LTrim$(Str$(a ^ b))
  181.                     Else
  182.                         EvalErr$ = "For a ^ b, a needs to be >= 0 when b not integer."
  183.                         Exit Function
  184.                     End If
  185.                 Case "/"
  186.                     If b <> 0 Then
  187.                         middle$ = LTrim$(Str$(a / b))
  188.                     Else
  189.                         EvalErr$ = "Div by 0"
  190.                         Exit Function
  191.                     End If
  192.                 Case "*": middle$ = LTrim$(Str$(a * b))
  193.                 Case "-": middle$ = LTrim$(Str$(a - b))
  194.                 Case "+": middle$ = LTrim$(Str$(a + b))
  195.                 Case "=": If a = b Then middle$ = "1" Else middle$ = "0"
  196.                 Case "<": If a < b Then middle$ = "1" Else middle$ = "0"
  197.                 Case ">": If a > b Then middle$ = "1" Else middle$ = "0"
  198.                 Case "<=": If a <= b Then middle$ = "1" Else middle$ = "0"
  199.                 Case ">=": If a >= b Then middle$ = "1" Else middle$ = "0"
  200.                 Case "<>": If a <> b Then middle$ = "1" Else middle$ = "0"
  201.                 Case "and": If a <> 0 And b <> 0 Then middle$ = "1" Else middle$ = "0"
  202.                 Case "or": If a <> 0 Or b <> 0 Then middle$ = "1" Else middle$ = "0"
  203.                 Case "not": If b = 0 Then middle$ = "1" Else middle$ = "0" 'use b as nothing should be left of not
  204.             End Select
  205.             s$ = wSubst$(s$, p - 1, p + 1, middle$)
  206.             'PRINT s$
  207.             p = wIn(s$, op$)
  208.         Wend
  209.     Next
  210.     evalW = Val(s$)
  211.     'PRINT evalW
  212.  
  213. 'return trimmed  source string s with one space between each word
  214. Function wPrep$ (ss$)
  215.  
  216.     s$ = LTrim$(RTrim$(ss$))
  217.     If Len(s$) = 0 Then wPrep$ = "": Exit Function
  218.     'remove all double or more spaces
  219.     p = InStr(s$, "  ")
  220.     While p > 0
  221.         s$ = Mid$(s$, 1, p) + Mid$(s$, p + 2, Len(s$) - p - 1)
  222.         p = InStr(s$, "  ")
  223.     Wend
  224.     wPrep$ = s$
  225.  
  226. ' This duplicates JB word(string, wordNumber) base 1, space as default delimiter
  227. ' by returning the Nth word of source string s
  228. ' this function assumes s has been through wPrep
  229. Function Wrd$ (ss$, wNumber)
  230.     's$ = wPrep(ss$)
  231.     s$ = ss$ 'don't change ss$
  232.     If Len(s$) = 0 Then Wrd$ = "": Exit Function
  233.     w$ = "": c = 1
  234.     For i = 1 To Len(s$)
  235.         If Mid$(s$, i, 1) = " " Then
  236.             If c = wNumber Then Wrd$ = w$: Exit Function
  237.             w$ = "": c = c + 1
  238.         Else
  239.             w$ = w$ + Mid$(s$, i, 1)
  240.         End If
  241.     Next
  242.     If c <> wNumber Then Wrd$ = " " Else Wrd$ = w$
  243.  
  244. 'This function counts the words in source string s
  245. 'this function assumes s has been thru wPrep
  246. Function wCnt (s$)
  247.     Dim c As Integer, p As Integer, ip As Integer
  248.     's = wPrep(s)
  249.     If Len(s$) = 0 Then wCnt = 0: Exit Function
  250.     c = 1: p = 1: ip = InStr(p, s$, " ")
  251.     While ip
  252.         c = c + 1: p = ip + 1: ip = InStr(p, s$, " ")
  253.     Wend
  254.     wCnt = c
  255.  
  256. 'Where is word In source s, 0 = Not In source
  257. 'this function assumes s has been thru wPrep
  258. Function wIn (s$, wd$)
  259.     Dim wc As Integer, i As Integer
  260.     wc = wCnt(s$): wIn = 0
  261.     For i = 1 To wc
  262.         If Wrd$(s$, i) = wd$ Then wIn = i: Exit Function
  263.     Next
  264.  
  265. ' substitute string in s to replace section first to last words inclusive
  266. 'this function assumes s has been thru wPrep
  267. Function wSubst$ (s$, first, last, subst$)
  268.     Dim wc As Integer, i As Integer, subF As Integer
  269.     wc = wCnt(s$): b$ = ""
  270.     For i = 1 To wc
  271.         If first <= i And i <= last Then 'do this only once!
  272.             If subF = 0 Then b$ = b$ + subst$ + " ": subF = 1
  273.         Else
  274.             b$ = b$ + Wrd$(s$, i) + " "
  275.         End If
  276.     Next
  277.     wSubst$ = LTrim$(RTrim$(b$))
  278.  
  279.  
  280.  

I've got one of these floating around somewhere also!  :P

Code: QB64: [Select]
  1. Screen _NewImage(1024, 720, 32)
  2. ReDim Shared OName(0) As String 'Operation Name
  3. ReDim Shared PL(0) As Integer 'Priority Level
  4. ReDim Shared PP_TypeMod(0) As String, PP_ConvertedMod(0) As String 'Prepass Name Conversion variables.
  5.  
  6.  
  7.     Cls
  8.  
  9.     Print "Formula to Evaluate => ";
  10.     i$ = Input$(1)
  11.     Select Case i$
  12.         Case Chr$(8)
  13.             eval$ = Left$(eval$, Len(eval$) - 1)
  14.         Case Chr$(13)
  15.             eval$ = ""
  16.         Case Chr$(27)
  17.             System
  18.         Case Else
  19.             eval$ = eval$ + i$
  20.     End Select
  21.     Print eval$
  22.     result$ = Evaluate_Expression(eval$)
  23.     Print "Result: "; result$
  24.     _Clipboard$ = eval$ + " = " + result$
  25.     _Display
  26.  
  27.  
  28. 'Steve Subs/Functins for _MATH support with CONST
  29. Function Evaluate_Expression$ (e$)
  30.     t$ = e$ 'So we preserve our original data, we parse a temp copy of it
  31.     PreParse t$
  32.  
  33.  
  34.     If Left$(t$, 5) = "ERROR" Then Evaluate_Expression$ = t$: Exit Function
  35.  
  36.     'Deal with brackets first
  37.     exp$ = "(" + t$ + ")" 'Starting and finishing brackets for our parse routine.
  38.  
  39.     Do
  40.         Eval_E = InStr(exp$, ")")
  41.         If Eval_E > 0 Then
  42.             c = 0
  43.             Do Until Eval_E - c <= 0
  44.                 c = c + 1
  45.                 If Eval_E Then
  46.                     If Mid$(exp$, Eval_E - c, 1) = "(" Then Exit Do
  47.                 End If
  48.             Loop
  49.             s = Eval_E - c + 1
  50.             If s < 1 Then Evaluate_Expression$ = "ERROR -- BAD () Count": Exit Function
  51.             eval$ = " " + Mid$(exp$, s, Eval_E - s) + " " 'pad with a space before and after so the parser can pick up the values properly.
  52.  
  53.             'PRINT "Before ParseExpression: "; eval$
  54.             ParseExpression eval$
  55.             'PRINT "After ParseExpression: "; eval$
  56.             eval$ = LTrim$(RTrim$(eval$))
  57.             If Left$(eval$, 5) = "ERROR" Then Evaluate_Expression$ = eval$: Exit Function
  58.             exp$ = DWD(Left$(exp$, s - 2) + eval$ + Mid$(exp$, Eval_E + 1))
  59.             'PRINT exp$
  60.             If Mid$(exp$, 1, 1) = "N" Then Mid$(exp$, 1) = "-"
  61.  
  62.             'temppp$ = DWD(LEFT$(exp$, s - 2) + " ## " + eval$ + " ## " + MID$(exp$, e + 1))
  63.         End If
  64.     Loop Until Eval_E = 0
  65.     c = 0
  66.     Do
  67.         c = c + 1
  68.         Select Case Mid$(exp$, c, 1)
  69.             Case "0" To "9", ".", "-" 'At this point, we should only have number values left.
  70.             Case Else: Evaluate_Expression$ = "ERROR - Unknown Diagnosis: (" + exp$ + ") ": Exit Function
  71.         End Select
  72.     Loop Until c >= Len(exp$)
  73.  
  74.     Evaluate_Expression$ = exp$
  75.  
  76.  
  77.  
  78. Sub ParseExpression (exp$)
  79.     Dim num(10) As String
  80.     'PRINT exp$
  81.     exp$ = DWD(exp$)
  82.     'We should now have an expression with no () to deal with
  83.     'IF MID$(exp$, 2, 1) = "-" THEN exp$ = "0+" + MID$(exp$, 2)
  84.     For J = 1 To 250
  85.         lowest = 0
  86.         Do Until lowest = Len(exp$)
  87.             lowest = Len(exp$): OpOn = 0
  88.             For P = 1 To UBound(OName)
  89.                 'Look for first valid operator
  90.                 If J = PL(P) Then 'Priority levels match
  91.                     If Left$(exp$, 1) = "-" Then op = InStr(2, exp$, OName(P)) Else op = InStr(exp$, OName(P))
  92.                     If op > 0 And op < lowest Then lowest = op: OpOn = P
  93.                 End If
  94.             Next
  95.             If OpOn = 0 Then Exit Do 'We haven't gotten to the proper PL for this OP to be processed yet.
  96.             If Left$(exp$, 1) = "-" Then op = InStr(2, exp$, OName(OpOn)) Else op = InStr(exp$, OName(OpOn))
  97.             numset = 0
  98.  
  99.             '*** SPECIAL OPERATION RULESETS
  100.             If OName(OpOn) = "-" Then 'check for BOOLEAN operators before the -
  101.                 Select Case Mid$(exp$, op - 3, 3)
  102.                     Case "NOT", "XOR", "AND", "EQV", "IMP"
  103.                         Exit Do 'Not an operator, it's a negative
  104.                 End Select
  105.                 If Mid$(exp$, op - 3, 2) = "OR" Then Exit Do 'Not an operator, it's a negative
  106.             End If
  107.  
  108.             If op Then
  109.                 c = Len(OName(OpOn)) - 1
  110.                 Do
  111.                     Select Case Mid$(exp$, op + c + 1, 1)
  112.                         Case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "N": numset = -1 'Valid digit
  113.                         Case "-" 'We need to check if it's a minus or a negative
  114.                             If OName(OpOn) = "_PI" Or numset Then Exit Do
  115.                         Case ",": numset = 0
  116.                         Case Else 'Not a valid digit, we found our separator
  117.                             Exit Do
  118.                     End Select
  119.                     c = c + 1
  120.                 Loop Until op + c >= Len(exp$)
  121.                 e = op + c
  122.  
  123.                 c = 0
  124.                 Do
  125.                     c = c + 1
  126.                     Select Case Mid$(exp$, op - c, 1)
  127.                         Case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "N" 'Valid digit
  128.                         Case "-" 'We need to check if it's a minus or a negative
  129.                             c1 = c
  130.                             bad = 0
  131.                             Do
  132.                                 c1 = c1 + 1
  133.                                 Select Case Mid$(exp$, op - c1, 1)
  134.                                     Case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."
  135.                                         bad = -1
  136.                                         Exit Do 'It's a minus sign
  137.                                     Case Else
  138.                                         'It's a negative sign and needs to count as part of our numbers
  139.                                 End Select
  140.                             Loop Until op - c1 <= 0
  141.                             If bad Then Exit Do 'We found our seperator
  142.                         Case Else 'Not a valid digit, we found our separator
  143.                             Exit Do
  144.                     End Select
  145.                 Loop Until op - c <= 0
  146.                 s = op - c
  147.                 num(1) = Mid$(exp$, s + 1, op - s - 1) 'Get our first number
  148.                 num(2) = Mid$(exp$, op + Len(OName(OpOn)), e - op - Len(OName(OpOn)) + 1) 'Get our second number
  149.                 If Mid$(num(1), 1, 1) = "N" Then Mid$(num(1), 1) = "-"
  150.                 If Mid$(num(2), 1, 1) = "N" Then Mid$(num(2), 1) = "-"
  151.                 If num(1) = "-" Then
  152.                     num(3) = "N" + EvaluateNumbers(OpOn, num())
  153.                 Else
  154.                     num(3) = EvaluateNumbers(OpOn, num())
  155.                 End If
  156.                 If Mid$(num(3), 1, 1) = "-" Then Mid$(num(3), 1) = "N"
  157.                 'PRINT "*************"
  158.                 'PRINT num(1), OName(OpOn), num(2), num(3), exp$
  159.                 If Left$(num(3), 5) = "ERROR" Then exp$ = num(3): Exit Sub
  160.                 exp$ = LTrim$(N2S(DWD(Left$(exp$, s) + RTrim$(LTrim$(num(3))) + Mid$(exp$, e + 1))))
  161.                 'PRINT exp$
  162.             End If
  163.             op = 0
  164.         Loop
  165.     Next
  166.  
  167.  
  168.  
  169.  
  170. Sub Set_OrderOfOperations
  171.     'PL sets our priortity level. 1 is highest to 65535 for the lowest.
  172.     'I used a range here so I could add in new priority levels as needed.
  173.     'OName ended up becoming the name of our commands, as I modified things.... Go figure!  LOL!
  174.     ReDim OName(10000) As String, PL(10000) As Integer
  175.     'Constants get evaluated first, with a Priority Level of 1
  176.  
  177.     i = i + 1: OName(i) = "C_UOF": PL(i) = 5 'convert to unsigned offset
  178.     i = i + 1: OName(i) = "C_OF": PL(i) = 5 'convert to offset
  179.     i = i + 1: OName(i) = "C_UBY": PL(i) = 5 'convert to unsigned byte
  180.     i = i + 1: OName(i) = "C_BY": PL(i) = 5 'convert to byte
  181.     i = i + 1: OName(i) = "C_UIN": PL(i) = 5 'convert to unsigned integer
  182.     i = i + 1: OName(i) = "C_IN": PL(i) = 5 'convert to integer
  183.     i = i + 1: OName(i) = "C_UIF": PL(i) = 5 'convert to unsigned int64
  184.     i = i + 1: OName(i) = "C_IF": PL(i) = 5 'convert to int64
  185.     i = i + 1: OName(i) = "C_ULO": PL(i) = 5 'convert to unsigned long
  186.     i = i + 1: OName(i) = "C_LO": PL(i) = 5 'convert to long
  187.     i = i + 1: OName(i) = "C_SI": PL(i) = 5 'convert to single
  188.     i = i + 1: OName(i) = "C_FL": PL(i) = 5 'convert to float
  189.     i = i + 1: OName(i) = "C_DO": PL(i) = 5 'convert to double
  190.     i = i + 1: OName(i) = "C_UBI": PL(i) = 5 'convert to unsigned bit
  191.     i = i + 1: OName(i) = "C_BI": PL(i) = 5 'convert to bit
  192.  
  193.     'Then Functions with PL 10
  194.     i = i + 1:: OName(i) = "_PI": PL(i) = 10
  195.     i = i + 1: OName(i) = "_ACOS": PL(i) = 10
  196.     i = i + 1: OName(i) = "_ASIN": PL(i) = 10
  197.     i = i + 1: OName(i) = "_ARCSEC": PL(i) = 10
  198.     i = i + 1: OName(i) = "_ARCCSC": PL(i) = 10
  199.     i = i + 1: OName(i) = "_ARCCOT": PL(i) = 10
  200.     i = i + 1: OName(i) = "_SECH": PL(i) = 10
  201.     i = i + 1: OName(i) = "_CSCH": PL(i) = 10
  202.     i = i + 1: OName(i) = "_COTH": PL(i) = 10
  203.     i = i + 1: OName(i) = "COS": PL(i) = 10
  204.     i = i + 1: OName(i) = "SIN": PL(i) = 10
  205.     i = i + 1: OName(i) = "TAN": PL(i) = 10
  206.     i = i + 1: OName(i) = "LOG": PL(i) = 10
  207.     i = i + 1: OName(i) = "EXP": PL(i) = 10
  208.     i = i + 1: OName(i) = "ATN": PL(i) = 10
  209.     i = i + 1: OName(i) = "_D2R": PL(i) = 10
  210.     i = i + 1: OName(i) = "_D2G": PL(i) = 10
  211.     i = i + 1: OName(i) = "_R2D": PL(i) = 10
  212.     i = i + 1: OName(i) = "_R2G": PL(i) = 10
  213.     i = i + 1: OName(i) = "_G2D": PL(i) = 10
  214.     i = i + 1: OName(i) = "_G2R": PL(i) = 10
  215.     i = i + 1: OName(i) = "ABS": PL(i) = 10
  216.     i = i + 1: OName(i) = "SGN": PL(i) = 10
  217.     i = i + 1: OName(i) = "INT": PL(i) = 10
  218.     i = i + 1: OName(i) = "_ROUND": PL(i) = 10
  219.     i = i + 1: OName(i) = "_CEIL": PL(i) = 10
  220.     i = i + 1: OName(i) = "FIX": PL(i) = 10
  221.     i = i + 1: OName(i) = "_SEC": PL(i) = 10
  222.     i = i + 1: OName(i) = "_CSC": PL(i) = 10
  223.     i = i + 1: OName(i) = "_COT": PL(i) = 10
  224.     i = i + 1: OName(i) = "ASC": PL(i) = 10
  225.     i = i + 1: OName(i) = "CHR$": PL(i) = 10
  226.     i = i + 1: OName(i) = "C_RG": PL(i) = 10 '_RGB32 converted
  227.     i = i + 1: OName(i) = "C_RA": PL(i) = 10 '_RGBA32 converted
  228.     i = i + 1: OName(i) = "_RGB": PL(i) = 10
  229.     i = i + 1: OName(i) = "_RGBA": PL(i) = 10
  230.     i = i + 1: OName(i) = "C_RX": PL(i) = 10 '_RED32 converted
  231.     i = i + 1: OName(i) = "C_GR": PL(i) = 10 ' _GREEN32 converted
  232.     i = i + 1: OName(i) = "C_BL": PL(i) = 10 '_BLUE32 converted
  233.     i = i + 1: OName(i) = "C_AL": PL(i) = 10 '_ALPHA32 converted
  234.     i = i + 1: OName(i) = "_RED": PL(i) = 10
  235.     i = i + 1: OName(i) = "_GREEN": PL(i) = 10
  236.     i = i + 1: OName(i) = "_BLUE": PL(i) = 10
  237.     i = i + 1: OName(i) = "_ALPHA": PL(i) = 10
  238.  
  239.     'Exponents with PL 20
  240.     i = i + 1: OName(i) = "^": PL(i) = 20
  241.     i = i + 1: OName(i) = "SQR": PL(i) = 20
  242.     i = i + 1: OName(i) = "ROOT": PL(i) = 20
  243.     'Multiplication and Division PL 30
  244.     i = i + 1: OName(i) = "*": PL(i) = 30
  245.     i = i + 1: OName(i) = "/": PL(i) = 30
  246.     'Integer Division PL 40
  247.     i = i + 1: OName(i) = "\": PL(i) = 40
  248.     'MOD PL 50
  249.     i = i + 1: OName(i) = "MOD": PL(i) = 50
  250.     'Addition and Subtraction PL 60
  251.     i = i + 1: OName(i) = "+": PL(i) = 60
  252.     i = i + 1: OName(i) = "-": PL(i) = 60
  253.  
  254.     'Relational Operators =, >, <, <>, <=, >=   PL 70
  255.     i = i + 1: OName(i) = "<>": PL(i) = 70 'These next three are just reversed symbols as an attempt to help process a common typo
  256.     i = i + 1: OName(i) = "><": PL(i) = 70
  257.     i = i + 1: OName(i) = "<=": PL(i) = 70
  258.     i = i + 1: OName(i) = ">=": PL(i) = 70
  259.     i = i + 1: OName(i) = "=<": PL(i) = 70 'I personally can never keep these things straight.  Is it < = or = <...
  260.     i = i + 1: OName(i) = "=>": PL(i) = 70 'Who knows, check both!
  261.     i = i + 1: OName(i) = ">": PL(i) = 70
  262.     i = i + 1: OName(i) = "<": PL(i) = 70
  263.     i = i + 1: OName(i) = "=": PL(i) = 70
  264.     'Logical Operations PL 80+
  265.     i = i + 1: OName(i) = "NOT": PL(i) = 80
  266.     i = i + 1: OName(i) = "AND": PL(i) = 90
  267.     i = i + 1: OName(i) = "OR": PL(i) = 100
  268.     i = i + 1: OName(i) = "XOR": PL(i) = 110
  269.     i = i + 1: OName(i) = "EQV": PL(i) = 120
  270.     i = i + 1: OName(i) = "IMP": PL(i) = 130
  271.     i = i + 1: OName(i) = ",": PL(i) = 1000
  272.  
  273.     ReDim _Preserve OName(i) As String, PL(i) As Integer
  274.  
  275. Function EvaluateNumbers$ (p, num() As String)
  276.     Dim n1 As _Float, n2 As _Float, n3 As _Float
  277.     'PRINT "EVALNUM:"; OName(p), num(1), num(2)
  278.     If InStr(num(1), ",") Then
  279.         EvaluateNumbers$ = "ERROR - Invalid comma (" + num(1) + ")": Exit Function
  280.     End If
  281.     l2 = InStr(num(2), ",")
  282.     If l2 Then
  283.         Select Case OName(p) 'only certain commands should pass a comma value
  284.             Case "C_RG", "C_RA", "_RGB", "_RGBA", "_RED", "_GREEN", "C_BL", "_ALPHA"
  285.             Case Else
  286.                 C$ = Mid$(num(2), l2)
  287.                 num(2) = Left$(num(2), l2 - 1)
  288.         End Select
  289.     End If
  290.  
  291.     Select Case PL(p) 'divide up the work so we want do as much case checking
  292.         Case 5 'Type conversions
  293.             'Note, these are special cases and work with the number BEFORE the command and not after
  294.             Select Case OName(p) 'Depending on our operator..
  295.                 Case "C_UOF": n1~%& = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1~%&)))
  296.                 Case "C_ULO": n1%& = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1%&)))
  297.                 Case "C_UBY": n1~%% = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1~%%)))
  298.                 Case "C_UIN": n1~% = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1~%)))
  299.                 Case "C_BY": n1%% = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1%%)))
  300.                 Case "C_IN": n1% = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1%)))
  301.                 Case "C_UIF": n1~&& = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1~&&)))
  302.                 Case "C_OF": n1~& = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1~&)))
  303.                 Case "C_IF": n1&& = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1&&)))
  304.                 Case "C_LO": n1& = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1&)))
  305.                 Case "C_UBI": n1~` = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1~`)))
  306.                 Case "C_BI": n1` = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1`)))
  307.                 Case "C_FL": n1## = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1##)))
  308.                 Case "C_DO": n1# = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1#)))
  309.                 Case "C_SI": n1! = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1!)))
  310.             End Select
  311.             Exit Function
  312.         Case 10 'functions
  313.             Select Case OName(p) 'Depending on our operator..
  314.                 Case "_PI"
  315.                     n1 = 3.14159265358979323846264338327950288## 'Future compatable in case something ever stores extra digits for PI
  316.                     If num(2) <> "" Then n1 = n1 * Val(num(2))
  317.                 Case "_ACOS": n1 = _Acos(Val(num(2)))
  318.                 Case "_ASIN": n1 = _Asin(Val(num(2)))
  319.                 Case "_ARCSEC": n1 = _Arcsec(Val(num(2)))
  320.                 Case "_ARCCSC": n1 = _Arccsc(Val(num(2)))
  321.                 Case "_ARCCOT": n1 = _Arccot(Val(num(2)))
  322.                 Case "_SECH": n1 = _Sech(Val(num(2)))
  323.                 Case "_CSCH": n1 = _Csch(Val(num(2)))
  324.                 Case "_COTH": n1 = _Coth(Val(num(2)))
  325.                 Case "C_RG"
  326.                     n$ = num(2)
  327.                     If n$ = "" Then EvaluateNumbers$ = "ERROR - Invalid null _RGB32": Exit Function
  328.                     c1 = InStr(n$, ",")
  329.                     If c1 Then c2 = InStr(c1 + 1, n$, ",")
  330.                     If c2 Then c3 = InStr(c2 + 1, n$, ",")
  331.                     If c3 Then c4 = InStr(c3 + 1, n$, ",")
  332.                     If c1 = 0 Then 'there's no comma in the command to parse.  It's a grayscale value
  333.                         n = Val(num(2))
  334.                         n1 = _RGB32(n, n, n)
  335.                     ElseIf c2 = 0 Then 'there's one comma and not 2.  It's grayscale with alpha.
  336.                         n = Val(Left$(num(2), c1))
  337.                         n2 = Val(Mid$(num(2), c1 + 1))
  338.                         n1 = _RGBA32(n, n, n, n2)
  339.                     ElseIf c3 = 0 Then 'there's two commas.  It's _RGB values
  340.                         n = Val(Left$(num(2), c1))
  341.                         n2 = Val(Mid$(num(2), c1 + 1))
  342.                         n3 = Val(Mid$(num(2), c2 + 1))
  343.                         n1 = _RGB32(n, n2, n3)
  344.                     ElseIf c4 = 0 Then 'there's three commas.  It's _RGBA values
  345.                         n = Val(Left$(num(2), c1))
  346.                         n2 = Val(Mid$(num(2), c1 + 1))
  347.                         n3 = Val(Mid$(num(2), c2 + 1))
  348.                         n4 = Val(Mid$(num(2), c3 + 1))
  349.                         n1 = _RGBA32(n, n2, n3, n4)
  350.                     Else 'we have more than three commas.  I have no idea WTH type of values got passed here!
  351.                         EvaluateNumbers$ = "ERROR - Invalid comma count (" + num(2) + ")": Exit Function
  352.                     End If
  353.                 Case "C_RA"
  354.                     n$ = num(2)
  355.                     If n$ = "" Then EvaluateNumbers$ = "ERROR - Invalid null _RGBA32": Exit Function
  356.                     c1 = InStr(n$, ",")
  357.                     If c1 Then c2 = InStr(c1 + 1, n$, ",")
  358.                     If c2 Then c3 = InStr(c2 + 1, n$, ",")
  359.                     If c3 Then c4 = InStr(c3 + 1, n$, ",")
  360.                     If c3 = 0 Or c4 <> 0 Then EvaluateNumbers$ = "ERROR - Invalid comma count (" + num(2) + ")": Exit Function
  361.                     'we have to have 3 commas; not more, not less.
  362.                     n = Val(Left$(num(2), c1))
  363.                     n2 = Val(Mid$(num(2), c1 + 1))
  364.                     n3 = Val(Mid$(num(2), c2 + 1))
  365.                     n4 = Val(Mid$(num(2), c3 + 1))
  366.                     n1 = _RGBA32(n, n2, n3, n4)
  367.                 Case "_RGB"
  368.                     n$ = num(2)
  369.                     If n$ = "" Then EvaluateNumbers$ = "ERROR - Invalid null _RGB": Exit Function
  370.                     c1 = InStr(n$, ",")
  371.                     If c1 Then c2 = InStr(c1 + 1, n$, ",")
  372.                     If c2 Then c3 = InStr(c2 + 1, n$, ",")
  373.                     If c3 Then c4 = InStr(c3 + 1, n$, ",")
  374.                     If c3 = 0 Or c4 <> 0 Then EvaluateNumbers$ = "ERROR - Invalid comma count (" + num(2) + "). _RGB requires 4 parameters for Red, Green, Blue, ScreenMode.": Exit Function
  375.                     'we have to have 3 commas; not more, not less.
  376.                     n = Val(Left$(num(2), c1))
  377.                     n2 = Val(Mid$(num(2), c1 + 1))
  378.                     n3 = Val(Mid$(num(2), c2 + 1))
  379.                     n4 = Val(Mid$(num(2), c3 + 1))
  380.                     Select Case n4
  381.                         Case 0 To 2, 7 To 13, 256, 32 'these are the good screen values
  382.                         Case Else
  383.                             EvaluateNumbers$ = "ERROR - Invalid Screen Mode (" + Str$(n4) + ")": Exit Function
  384.                     End Select
  385.                     t = _NewImage(1, 1, n4)
  386.                     n1 = _RGB(n, n2, n3, t)
  387.                     _FreeImage t
  388.                 Case "_RGBA"
  389.                     n$ = num(2)
  390.                     If n$ = "" Then EvaluateNumbers$ = "ERROR - Invalid null _RGBA": Exit Function
  391.                     c1 = InStr(n$, ",")
  392.                     If c1 Then c2 = InStr(c1 + 1, n$, ",")
  393.                     If c2 Then c3 = InStr(c2 + 1, n$, ",")
  394.                     If c3 Then c4 = InStr(c3 + 1, n$, ",")
  395.                     If c4 Then c5 = InStr(c4 + 1, n$, ",")
  396.                     If c4 = 0 Or c5 <> 0 Then EvaluateNumbers$ = "ERROR - Invalid comma count (" + num(2) + "). _RGBA requires 5 parameters for Red, Green, Blue, Alpha, ScreenMode.": Exit Function
  397.                     'we have to have 4 commas; not more, not less.
  398.                     n = Val(Left$(num(2), c1))
  399.                     n2 = Val(Mid$(num(2), c1 + 1))
  400.                     n3 = Val(Mid$(num(2), c2 + 1))
  401.                     n4 = Val(Mid$(num(2), c3 + 1))
  402.                     n5 = Val(Mid$(num(2), c4 + 1))
  403.                     Select Case n5
  404.                         Case 0 To 2, 7 To 13, 256, 32 'these are the good screen values
  405.                         Case Else
  406.                             EvaluateNumbers$ = "ERROR - Invalid Screen Mode (" + Str$(n5) + ")": Exit Function
  407.                     End Select
  408.                     t = _NewImage(1, 1, n5)
  409.                     n1 = _RGBA(n, n2, n3, n4, t)
  410.                     _FreeImage t
  411.                 Case "_RED", "_GREEN", "_BLUE", "_ALPHA"
  412.                     n$ = num(2)
  413.                     If n$ = "" Then EvaluateNumbers$ = "ERROR - Invalid null " + OName(p): Exit Function
  414.                     c1 = InStr(n$, ",")
  415.                     If c1 = 0 Then EvaluateNumbers$ = "ERROR - " + OName(p) + " requires 2 parameters for Color, ScreenMode.": Exit Function
  416.                     If c1 Then c2 = InStr(c1 + 1, n$, ",")
  417.                     If c2 Then EvaluateNumbers$ = "ERROR - " + OName(p) + " requires 2 parameters for Color, ScreenMode.": Exit Function
  418.                     n = Val(Left$(num(2), c1))
  419.                     n2 = Val(Mid$(num(2), c1 + 1))
  420.                     Select Case n2
  421.                         Case 0 To 2, 7 To 13, 256, 32 'these are the good screen values
  422.                         Case Else
  423.                             EvaluateNumbers$ = "ERROR - Invalid Screen Mode (" + Str$(n2) + ")": Exit Function
  424.                     End Select
  425.                     t = _NewImage(1, 1, n4)
  426.                     Select Case OName(p)
  427.                         Case "_RED": n1 = _Red(n, t)
  428.                         Case "_BLUE": n1 = _Blue(n, t)
  429.                         Case "_GREEN": n1 = _Green(n, t)
  430.                         Case "_ALPHA": n1 = _Alpha(n, t)
  431.                     End Select
  432.                     _FreeImage t
  433.                 Case "C_RX", "C_GR", "C_BL", "C_AL"
  434.                     n$ = num(2)
  435.                     If n$ = "" Then EvaluateNumbers$ = "ERROR - Invalid null " + OName(p): Exit Function
  436.                     n = Val(num(2))
  437.                     Select Case OName(p)
  438.                         Case "C_RX": n1 = _Red32(n)
  439.                         Case "C_BL": n1 = _Blue32(n)
  440.                         Case "C_GR": n1 = _Green32(n)
  441.                         Case "C_AL": n1 = _Alpha32(n)
  442.                     End Select
  443.                 Case "COS": n1 = Cos(Val(num(2)))
  444.                 Case "SIN": n1 = Sin(Val(num(2)))
  445.                 Case "TAN": n1 = Tan(Val(num(2)))
  446.                 Case "LOG": n1 = Log(Val(num(2)))
  447.                 Case "EXP": n1 = Exp(Val(num(2)))
  448.                 Case "ATN": n1 = Atn(Val(num(2)))
  449.                 Case "_D2R": n1 = 0.0174532925 * (Val(num(2)))
  450.                 Case "_D2G": n1 = 1.1111111111 * (Val(num(2)))
  451.                 Case "_R2D": n1 = 57.2957795 * (Val(num(2)))
  452.                 Case "_R2G": n1 = 0.015707963 * (Val(num(2)))
  453.                 Case "_G2D": n1 = 0.9 * (Val(num(2)))
  454.                 Case "_G2R": n1 = 63.661977237 * (Val(num(2)))
  455.                 Case "ABS": n1 = Abs(Val(num(2)))
  456.                 Case "SGN": n1 = Sgn(Val(num(2)))
  457.                 Case "INT": n1 = Int(Val(num(2)))
  458.                 Case "_ROUND": n1 = _Round(Val(num(2)))
  459.                 Case "_CEIL": n1 = _Ceil(Val(num(2)))
  460.                 Case "FIX": n1 = Fix(Val(num(2)))
  461.                 Case "_SEC": n1 = _Sec(Val(num(2)))
  462.                 Case "_CSC": n1 = _Csc(Val(num(2)))
  463.                 Case "_COT": n1 = _Cot(Val(num(2)))
  464.             End Select
  465.         Case 20 To 60 'Math Operators
  466.             Select Case OName(p) 'Depending on our operator..
  467.                 Case "^": n1 = Val(num(1)) ^ Val(num(2))
  468.                 Case "SQR": n1 = Sqr(Val(num(2)))
  469.                 Case "ROOT"
  470.                     n1 = Val(num(1)): n2 = Val(num(2))
  471.                     If n2 = 1 Then EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1))): Exit Function
  472.                     If n1 < 0 And n2 >= 1 Then sign = -1: n1 = -n1 Else sign = 1
  473.                     n3 = 1## / n2
  474.                     If n3 <> Int(n3) And n2 < 1 Then sign = Sgn(n1): n1 = Abs(n1)
  475.                     n1 = sign * (n1 ^ n3)
  476.                 Case "*": n1 = Val(num(1)) * Val(num(2))
  477.                 Case "/": n1 = Val(num(1)) / Val(num(2))
  478.                 Case "\"
  479.                     If Val(num(2)) <> 0 Then
  480.                         n1 = Val(num(1)) \ Val(num(2))
  481.                     Else
  482.                         EvaluateNumbers$ = "ERROR - Bad operation (We shouldn't see this)"
  483.                         Exit Function
  484.                     End If
  485.                 Case "MOD": n1 = Val(num(1)) Mod Val(num(2))
  486.                 Case "+": n1 = Val(num(1)) + Val(num(2))
  487.                 Case "-":
  488.                     n1 = Val(num(1)) - Val(num(2))
  489.             End Select
  490.         Case 70 'Relational Operators =, >, <, <>, <=, >=
  491.             Select Case OName(p) 'Depending on our operator..
  492.                 Case "=": n1 = Val(num(1)) = Val(num(2))
  493.                 Case ">": n1 = Val(num(1)) > Val(num(2))
  494.                 Case "<": n1 = Val(num(1)) < Val(num(2))
  495.                 Case "<>", "><": n1 = Val(num(1)) <> Val(num(2))
  496.                 Case "<=", "=<": n1 = Val(num(1)) <= Val(num(2))
  497.                 Case ">=", "=>": n1 = Val(num(1)) >= Val(num(2))
  498.             End Select
  499.         Case Else 'a value we haven't processed elsewhere
  500.             Select Case OName(p) 'Depending on our operator..
  501.                 Case "NOT": n1 = Not Val(num(2))
  502.                 Case "AND": n1 = Val(num(1)) And Val(num(2))
  503.                 Case "OR": n1 = Val(num(1)) Or Val(num(2))
  504.                 Case "XOR": n1 = Val(num(1)) Xor Val(num(2))
  505.                 Case "EQV": n1 = Val(num(1)) Eqv Val(num(2))
  506.                 Case "IMP": n1 = Val(num(1)) Imp Val(num(2))
  507.             End Select
  508.     End Select
  509.  
  510.     EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1))) + C$
  511.  
  512.     'PRINT "AFTEREVN:"; EvaluateNumbers$
  513.  
  514. Function DWD$ (exp$) 'Deal With Duplicates
  515.     'To deal with duplicate operators in our code.
  516.     'Such as --  becomes a +
  517.     '++ becomes a +
  518.     '+- becomes a -
  519.     '-+ becomes a -
  520.     t$ = exp$
  521.     Do
  522.         bad = 0
  523.         Do
  524.             l = InStr(t$, "++")
  525.             If l Then t$ = Left$(t$, l - 1) + "+" + Mid$(t$, l + 2): bad = -1
  526.         Loop Until l = 0
  527.         Do
  528.             l = InStr(t$, "+-")
  529.             If l Then t$ = Left$(t$, l - 1) + "-" + Mid$(t$, l + 2): bad = -1
  530.         Loop Until l = 0
  531.         Do
  532.             l = InStr(t$, "-+")
  533.             If l Then t$ = Left$(t$, l - 1) + "-" + Mid$(t$, l + 2): bad = -1
  534.         Loop Until l = 0
  535.         Do
  536.             l = InStr(t$, "--")
  537.             If l Then t$ = Left$(t$, l - 1) + "+" + Mid$(t$, l + 2): bad = -1
  538.         Loop Until l = 0
  539.         'PRINT "FIXING: "; t$
  540.     Loop Until Not bad
  541.     DWD$ = t$
  542.  
  543. Sub PreParse (e$)
  544.     Dim f As _Float
  545.  
  546.     If PP_TypeMod(0) = "" Then
  547.         ReDim PP_TypeMod(100) As String, PP_ConvertedMod(100) As String 'Large enough to hold all values to begin with
  548.         PP_TypeMod(0) = "Initialized" 'Set so we don't do this section over and over, as we keep the values in shared memory.
  549.         Set_OrderOfOperations 'Call this once to set up our proper order of operations and variable list
  550.         'and the below is a conversion list so symbols don't get cross confused.
  551.         i = i + 1: PP_TypeMod(i) = "~`": PP_ConvertedMod(i) = "C_UBI" 'unsigned bit
  552.         i = i + 1: PP_TypeMod(i) = "~%%": PP_ConvertedMod(i) = "C_UBY" 'unsigned byte
  553.         i = i + 1: PP_TypeMod(i) = "~%&": PP_ConvertedMod(i) = "C_UOF" 'unsigned offset
  554.         i = i + 1: PP_TypeMod(i) = "~%": PP_ConvertedMod(i) = "C_UIN" 'unsigned integer
  555.         i = i + 1: PP_TypeMod(i) = "~&&": PP_ConvertedMod(i) = "C_UIF" 'unsigned integer64
  556.         i = i + 1: PP_TypeMod(i) = "~&": PP_ConvertedMod(i) = "C_ULO" 'unsigned long
  557.         i = i + 1: PP_TypeMod(i) = "`": PP_ConvertedMod(i) = "C_BI" 'bit
  558.         i = i + 1: PP_TypeMod(i) = "%%": PP_ConvertedMod(i) = "C_BY" 'byte
  559.         i = i + 1: PP_TypeMod(i) = "%&": PP_ConvertedMod(i) = "C_OF" 'offset
  560.         i = i + 1: PP_TypeMod(i) = "%": PP_ConvertedMod(i) = "C_IN" 'integer
  561.         i = i + 1: PP_TypeMod(i) = "&&": PP_ConvertedMod(i) = "C_IF" 'integer64
  562.         i = i + 1: PP_TypeMod(i) = "&": PP_ConvertedMod(i) = "C_LO" 'long
  563.         i = i + 1: PP_TypeMod(i) = "!": PP_ConvertedMod(i) = "C_SI" 'single
  564.         i = i + 1: PP_TypeMod(i) = "##": PP_ConvertedMod(i) = "C_FL" 'float
  565.         i = i + 1: PP_TypeMod(i) = "#": PP_ConvertedMod(i) = "C_DO" 'double
  566.         i = i + 1: PP_TypeMod(i) = "_RGB32": PP_ConvertedMod(i) = "C_RG" 'rgb32
  567.         i = i + 1: PP_TypeMod(i) = "_RGBA32": PP_ConvertedMod(i) = "C_RA" 'rgba32
  568.         i = i + 1: PP_TypeMod(i) = "_RED32": PP_ConvertedMod(i) = "C_RX" 'red32
  569.         i = i + 1: PP_TypeMod(i) = "_GREEN32": PP_ConvertedMod(i) = "C_GR" 'green32
  570.         i = i + 1: PP_TypeMod(i) = "_BLUE32": PP_ConvertedMod(i) = "C_BL" 'blue32
  571.         i = i + 1: PP_TypeMod(i) = "_ALPHA32": PP_ConvertedMod(i) = "C_AL" 'alpha32
  572.         ReDim _Preserve PP_TypeMod(i) As String, PP_ConvertedMod(i) As String 'And then resized to just contain the necessary space in memory
  573.     End If
  574.     t$ = e$
  575.  
  576.     'First strip all spaces
  577.     t$ = ""
  578.     For i = 1 To Len(e$)
  579.         If Mid$(e$, i, 1) <> " " Then t$ = t$ + Mid$(e$, i, 1)
  580.     Next
  581.  
  582.     t$ = UCase$(t$)
  583.     If t$ = "" Then e$ = "ERROR -- NULL string; nothing to evaluate": Exit Sub
  584.  
  585.     'ERROR CHECK by counting our brackets
  586.     l = 0
  587.     Do
  588.         l = InStr(l + 1, t$, "("): If l Then c = c + 1
  589.     Loop Until l = 0
  590.     l = 0
  591.     Do
  592.         l = InStr(l + 1, t$, ")"): If l Then c1 = c1 + 1
  593.     Loop Until l = 0
  594.     If c <> c1 Then e$ = "ERROR -- Bad Parenthesis:" + Str$(c) + "( vs" + Str$(c1) + ")": Exit Sub
  595.  
  596.     'Modify so that NOT will process properly
  597.     l = 0
  598.     Do
  599.         l = InStr(l + 1, t$, "NOT")
  600.         If l Then
  601.             'We need to work magic on the statement so it looks pretty.
  602.             ' 1 + NOT 2 + 1 is actually processed as 1 + (NOT 2 + 1)
  603.             'Look for something not proper
  604.             l1 = InStr(l + 1, t$, "AND")
  605.             If l1 = 0 Or (InStr(l + 1, t$, "OR") > 0 And InStr(l + 1, t$, "OR") < l1) Then l1 = InStr(l + 1, t$, "OR")
  606.             If l1 = 0 Or (InStr(l + 1, t$, "XOR") > 0 And InStr(l + 1, t$, "XOR") < l1) Then l1 = InStr(l + 1, t$, "XOR")
  607.             If l1 = 0 Or (InStr(l + 1, t$, "EQV") > 0 And InStr(l + 1, t$, "EQV") < l1) Then l1 = InStr(l + 1, t$, "EQV")
  608.             If l1 = 0 Or (InStr(l + 1, t$, "IMP") > 0 And InStr(l + 1, t$, "IMP") < l1) Then l1 = InStr(l + 1, t$, "IMP")
  609.             If l1 = 0 Then l1 = Len(t$) + 1
  610.             t$ = Left$(t$, l - 1) + "(" + Mid$(t$, l, l1 - l) + ")" + Mid$(t$, l + l1 - l)
  611.             l = l + 3
  612.             'PRINT t$
  613.         End If
  614.     Loop Until l = 0
  615.  
  616.     For j = 1 To UBound(PP_TypeMod)
  617.         l = 0
  618.         Do
  619.             l = InStr(l + 1, t$, PP_TypeMod(j))
  620.             If l = 0 Then Exit Do
  621.             i = 0: l1 = 0: l2 = 0: lo = Len(PP_TypeMod(j))
  622.             Do
  623.                 If PL(i) > 10 Then
  624.                     l2 = _InStrRev(l, t$, OName$(i))
  625.                     If l2 > 0 And l2 > l1 Then l1 = l2
  626.                 End If
  627.                 i = i + lo
  628.             Loop Until i > UBound(PL)
  629.             'PRINT "L1:"; l1; "L"; l
  630.             l$ = Left$(t$, l1)
  631.             m$ = Mid$(t$, l1 + 1, l - l1 - 1)
  632.             r$ = PP_ConvertedMod(j) + Mid$(t$, l + lo)
  633.             'PRINT "Y$: "; TypeMod(j)
  634.             'PRINT "L$: "; l$
  635.             'PRINT "M$: "; m$
  636.             'PRINT "R$: "; r$
  637.             If j > 15 Then
  638.                 t$ = l$ + m$ + r$ 'replacement routine for commands which might get confused with others, like _RGB and _RGB32
  639.             Else
  640.                 'the first 15 commands need to properly place the parenthesis around the value we want to convert.
  641.                 t$ = l$ + "(" + m$ + ")" + r$
  642.             End If
  643.             'PRINT "T$: "; t$
  644.             l = l + 2 + Len(PP_TypeMod(j)) 'move forward from the length of the symbol we checked + the new "(" and  ")"
  645.         Loop
  646.     Next
  647.     '    PRINT "HERE: "; t$
  648.  
  649.  
  650.  
  651.     'Check for bad operators before a ( bracket
  652.     l = 0
  653.     Do
  654.         l = InStr(l + 1, t$, "(")
  655.         If l And l > 2 Then 'Don't check the starting bracket; there's nothing before it.
  656.             good = 0
  657.             'PRINT "BEFORE: "; t$; l
  658.             For i = 1 To UBound(OName)
  659.                 m$ = Mid$(t$, l - Len(OName(i)), Len(OName(i)))
  660.                 'IF OName(i) = "C_SI" THEN PRINT "CONVERT TO SINGLE", m$
  661.                 If m$ = OName(i) Then good = -1: Exit For 'We found an operator after our ), and it's not a CONST (like PI)
  662.             Next
  663.             'PRINT t$; l
  664.             If Not good Then e$ = "ERROR - Improper operations before (.": Exit Sub
  665.             l = l + 1
  666.         End If
  667.     Loop Until l = 0
  668.  
  669.     'Check for bad operators after a ) bracket
  670.     l = 0
  671.     Do
  672.         l = InStr(l + 1, t$, ")")
  673.         If l And l < Len(t$) Then
  674.             good = 0
  675.             For i = 1 To UBound(OName)
  676.                 m$ = Mid$(t$, l + 1, Len(OName(i)))
  677.                 If m$ = OName(i) Then good = -1: Exit For 'We found an operator after our ), and it's not a CONST (like PI
  678.             Next
  679.             If Mid$(t$, l + 1, 1) = ")" Then good = -1
  680.             If Not good Then e$ = "ERROR - Improper operations after ).": Exit Sub
  681.             l = l + 1
  682.         End If
  683.     Loop Until l = 0 Or l = Len(t$) 'last symbol is a bracket
  684.  
  685.     'Turn all &H (hex) numbers into decimal values for the program to process properly
  686.     l = 0
  687.     Do
  688.         l = InStr(t$, "&H")
  689.         If l Then
  690.             E = l + 1: finished = 0
  691.             Do
  692.                 E = E + 1
  693.                 comp$ = Mid$(t$, E, 1)
  694.                 Select Case comp$
  695.                     Case "0" To "9", "A" To "F" 'All is good, our next digit is a number, continue to add to the hex$
  696.                     Case Else
  697.                         good = 0
  698.                         For i = 1 To UBound(OName)
  699.                             If Mid$(t$, E, Len(OName(i))) = OName(i) And PL(i) > 1 And PL(i) <= 250 Then good = -1: Exit For 'We found an operator after our ), and it's not a CONST (like PI)
  700.                         Next
  701.                         If Not good Then e$ = "ERROR - Improper &H value. (" + comp$ + ")": Exit Sub
  702.                         E = E - 1
  703.                         finished = -1
  704.                 End Select
  705.             Loop Until finished Or E = Len(t$)
  706.             t$ = Left$(t$, l - 1) + LTrim$(RTrim$(Str$(Val(Mid$(t$, l, E - l + 1))))) + Mid$(t$, E + 1)
  707.         End If
  708.     Loop Until l = 0
  709.  
  710.     'Turn all &B (binary) numbers into decimal values for the program to process properly
  711.     l = 0
  712.     Do
  713.         l = InStr(t$, "&B")
  714.         If l Then
  715.             E = l + 1: finished = 0
  716.             Do
  717.                 E = E + 1
  718.                 comp$ = Mid$(t$, E, 1)
  719.                 Select Case comp$
  720.                     Case "0", "1" 'All is good, our next digit is a number, continue to add to the hex$
  721.                     Case Else
  722.                         good = 0
  723.                         For i = 1 To UBound(OName)
  724.                             If Mid$(t$, E, Len(OName(i))) = OName(i) And PL(i) > 1 And PL(i) <= 250 Then good = -1: Exit For 'We found an operator after our ), and it's not a CONST (like PI)
  725.                         Next
  726.                         If Not good Then e$ = "ERROR - Improper &B value. (" + comp$ + ")": Exit Sub
  727.                         E = E - 1
  728.                         finished = -1
  729.                 End Select
  730.             Loop Until finished Or E = Len(t$)
  731.             bin$ = Mid$(t$, l + 2, E - l - 1)
  732.             For i = 1 To Len(bin$)
  733.                 If Mid$(bin$, i, 1) = "1" Then f = f + 2 ^ (Len(bin$) - i)
  734.             Next
  735.             t$ = Left$(t$, l - 1) + LTrim$(RTrim$(Str$(f))) + Mid$(t$, E + 1)
  736.         End If
  737.     Loop Until l = 0
  738.  
  739.     'PRINT "ALMOST:"; t$
  740.  
  741.     t$ = N2S(t$)
  742.     'PRINT "ALMOST2:"; t$
  743.     VerifyString t$
  744.     'PRINT "Out of PreParse: "; e$
  745.     e$ = t$
  746.  
  747.  
  748.  
  749. Sub VerifyString (t$)
  750.     'ERROR CHECK for unrecognized operations
  751.     j = 1
  752.     Do
  753.         comp$ = Mid$(t$, j, 1)
  754.         Select Case comp$
  755.             Case "0" To "9", ".", "(", ")", ",": j = j + 1
  756.             Case Else
  757.                 good = 0
  758.                 For i = 1 To UBound(OName)
  759.                     If Mid$(t$, j, Len(OName(i))) = OName(i) Then good = -1: Exit For 'We found an operator after our ), and it's not a CONST (like PI)
  760.                 Next
  761.                 If Not good Then t$ = "ERROR - Bad Operational value. (" + comp$ + ")": Exit Sub
  762.                 j = j + Len(OName(i))
  763.         End Select
  764.     Loop Until j > Len(t$)
  765.  
  766. Function N2S$ (exp$) 'scientific Notation to String
  767.  
  768.     'PRINT "Before notation:"; exp$
  769.  
  770.     t$ = LTrim$(RTrim$(exp$))
  771.     If Left$(t$, 1) = "-" Or Left$(t$, 1) = "N" Then sign$ = "-": t$ = Mid$(t$, 2)
  772.  
  773.     dp = InStr(t$, "D+"): dm = InStr(t$, "D-")
  774.     ep = InStr(t$, "E+"): em = InStr(t$, "E-")
  775.     check1 = Sgn(dp) + Sgn(dm) + Sgn(ep) + Sgn(em)
  776.     If check1 < 1 Or check1 > 1 Then N2S = exp$: Exit Function 'If no scientic notation is found, or if we find more than 1 type, it's not SN!
  777.  
  778.     Select Case l 'l now tells us where the SN starts at.
  779.         Case Is < dp: l = dp
  780.         Case Is < dm: l = dm
  781.         Case Is < ep: l = ep
  782.         Case Is < em: l = em
  783.     End Select
  784.  
  785.     l$ = Left$(t$, l - 1) 'The left of the SN
  786.     r$ = Mid$(t$, l + 1): r&& = Val(r$) 'The right of the SN, turned into a workable long
  787.  
  788.  
  789.     If InStr(l$, ".") Then 'Location of the decimal, if any
  790.         If r&& > 0 Then
  791.             r&& = r&& - Len(l$) + 2
  792.         Else
  793.             r&& = r&& + 1
  794.         End If
  795.         l$ = Left$(l$, 1) + Mid$(l$, 3)
  796.     End If
  797.  
  798.     Select Case r&&
  799.         Case 0 'what the heck? We solved it already?
  800.             'l$ = l$
  801.         Case Is < 0
  802.             For i = 1 To -r&&
  803.                 l$ = "0" + l$
  804.             Next
  805.             l$ = "0." + l$
  806.         Case Else
  807.             For i = 1 To r&&
  808.                 l$ = l$ + "0"
  809.             Next
  810.     End Select
  811.  
  812.     N2S$ = sign$ + l$
  813.     'PRINT "After notation:"; N2S$
  814.  
  815.  
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Just a primitive program to parse arithmetic expressions.
« Reply #4 on: March 19, 2022, 12:16:36 pm »
If you notice with the above, all you get is the answer to your formula, but if you remove some of the remarked out PRINT statements, you can follow the process as it calculates everything out step by step for us, such as below:

Code: QB64: [Select]
  1. Screen _NewImage(1024, 720, 32)
  2. ReDim Shared OName(0) As String 'Operation Name
  3. ReDim Shared PL(0) As Integer 'Priority Level
  4. ReDim Shared PP_TypeMod(0) As String, PP_ConvertedMod(0) As String 'Prepass Name Conversion variables.
  5.  
  6.  
  7.     Cls
  8.  
  9.     Print "Formula to Evaluate => ";
  10.     i$ = Input$(1)
  11.     Select Case i$
  12.         Case Chr$(8)
  13.             eval$ = Left$(eval$, Len(eval$) - 1)
  14.         Case Chr$(13)
  15.             eval$ = ""
  16.         Case Chr$(27)
  17.             System
  18.         Case Else
  19.             eval$ = eval$ + i$
  20.     End Select
  21.     Print eval$
  22.     result$ = Evaluate_Expression(eval$)
  23.     Print "Result: "; result$
  24.     _Clipboard$ = eval$ + " = " + result$
  25.     _Display
  26.  
  27.  
  28. 'Steve Subs/Functins for _MATH support with CONST
  29. Function Evaluate_Expression$ (e$)
  30.     t$ = e$ 'So we preserve our original data, we parse a temp copy of it
  31.     PreParse t$
  32.  
  33.  
  34.     If Left$(t$, 5) = "ERROR" Then Evaluate_Expression$ = t$: Exit Function
  35.  
  36.     'Deal with brackets first
  37.     exp$ = "(" + t$ + ")" 'Starting and finishing brackets for our parse routine.
  38.  
  39.     Do
  40.         Eval_E = InStr(exp$, ")")
  41.         If Eval_E > 0 Then
  42.             c = 0
  43.             Do Until Eval_E - c <= 0
  44.                 c = c + 1
  45.                 If Eval_E Then
  46.                     If Mid$(exp$, Eval_E - c, 1) = "(" Then Exit Do
  47.                 End If
  48.             Loop
  49.             s = Eval_E - c + 1
  50.             If s < 1 Then Evaluate_Expression$ = "ERROR -- BAD () Count": Exit Function
  51.             eval$ = " " + Mid$(exp$, s, Eval_E - s) + " " 'pad with a space before and after so the parser can pick up the values properly.
  52.  
  53.             'PRINT "Before ParseExpression: "; eval$
  54.             ParseExpression eval$
  55.             'PRINT "After ParseExpression: "; eval$
  56.             eval$ = LTrim$(RTrim$(eval$))
  57.             If Left$(eval$, 5) = "ERROR" Then Evaluate_Expression$ = eval$: Exit Function
  58.             exp$ = DWD(Left$(exp$, s - 2) + eval$ + Mid$(exp$, Eval_E + 1))
  59.             'PRINT exp$
  60.             If Mid$(exp$, 1, 1) = "N" Then Mid$(exp$, 1) = "-"
  61.  
  62.             'temppp$ = DWD(LEFT$(exp$, s - 2) + " ## " + eval$ + " ## " + MID$(exp$, e + 1))
  63.         End If
  64.     Loop Until Eval_E = 0
  65.     c = 0
  66.     Do
  67.         c = c + 1
  68.         Select Case Mid$(exp$, c, 1)
  69.             Case "0" To "9", ".", "-" 'At this point, we should only have number values left.
  70.             Case Else: Evaluate_Expression$ = "ERROR - Unknown Diagnosis: (" + exp$ + ") ": Exit Function
  71.         End Select
  72.     Loop Until c >= Len(exp$)
  73.  
  74.     Evaluate_Expression$ = exp$
  75.  
  76.  
  77.  
  78. Sub ParseExpression (exp$)
  79.     Dim num(10) As String
  80.     Print exp$
  81.     exp$ = DWD(exp$)
  82.     'We should now have an expression with no () to deal with
  83.     'IF MID$(exp$, 2, 1) = "-" THEN exp$ = "0+" + MID$(exp$, 2)
  84.     For J = 1 To 250
  85.         lowest = 0
  86.         Do Until lowest = Len(exp$)
  87.             lowest = Len(exp$): OpOn = 0
  88.             For P = 1 To UBound(OName)
  89.                 'Look for first valid operator
  90.                 If J = PL(P) Then 'Priority levels match
  91.                     If Left$(exp$, 1) = "-" Then op = InStr(2, exp$, OName(P)) Else op = InStr(exp$, OName(P))
  92.                     If op > 0 And op < lowest Then lowest = op: OpOn = P
  93.                 End If
  94.             Next
  95.             If OpOn = 0 Then Exit Do 'We haven't gotten to the proper PL for this OP to be processed yet.
  96.             If Left$(exp$, 1) = "-" Then op = InStr(2, exp$, OName(OpOn)) Else op = InStr(exp$, OName(OpOn))
  97.             numset = 0
  98.  
  99.             '*** SPECIAL OPERATION RULESETS
  100.             If OName(OpOn) = "-" Then 'check for BOOLEAN operators before the -
  101.                 Select Case Mid$(exp$, op - 3, 3)
  102.                     Case "NOT", "XOR", "AND", "EQV", "IMP"
  103.                         Exit Do 'Not an operator, it's a negative
  104.                 End Select
  105.                 If Mid$(exp$, op - 3, 2) = "OR" Then Exit Do 'Not an operator, it's a negative
  106.             End If
  107.  
  108.             If op Then
  109.                 c = Len(OName(OpOn)) - 1
  110.                 Do
  111.                     Select Case Mid$(exp$, op + c + 1, 1)
  112.                         Case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "N": numset = -1 'Valid digit
  113.                         Case "-" 'We need to check if it's a minus or a negative
  114.                             If OName(OpOn) = "_PI" Or numset Then Exit Do
  115.                         Case ",": numset = 0
  116.                         Case Else 'Not a valid digit, we found our separator
  117.                             Exit Do
  118.                     End Select
  119.                     c = c + 1
  120.                 Loop Until op + c >= Len(exp$)
  121.                 e = op + c
  122.  
  123.                 c = 0
  124.                 Do
  125.                     c = c + 1
  126.                     Select Case Mid$(exp$, op - c, 1)
  127.                         Case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "N" 'Valid digit
  128.                         Case "-" 'We need to check if it's a minus or a negative
  129.                             c1 = c
  130.                             bad = 0
  131.                             Do
  132.                                 c1 = c1 + 1
  133.                                 Select Case Mid$(exp$, op - c1, 1)
  134.                                     Case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."
  135.                                         bad = -1
  136.                                         Exit Do 'It's a minus sign
  137.                                     Case Else
  138.                                         'It's a negative sign and needs to count as part of our numbers
  139.                                 End Select
  140.                             Loop Until op - c1 <= 0
  141.                             If bad Then Exit Do 'We found our seperator
  142.                         Case Else 'Not a valid digit, we found our separator
  143.                             Exit Do
  144.                     End Select
  145.                 Loop Until op - c <= 0
  146.                 s = op - c
  147.                 num(1) = Mid$(exp$, s + 1, op - s - 1) 'Get our first number
  148.                 num(2) = Mid$(exp$, op + Len(OName(OpOn)), e - op - Len(OName(OpOn)) + 1) 'Get our second number
  149.                 If Mid$(num(1), 1, 1) = "N" Then Mid$(num(1), 1) = "-"
  150.                 If Mid$(num(2), 1, 1) = "N" Then Mid$(num(2), 1) = "-"
  151.                 If num(1) = "-" Then
  152.                     num(3) = "N" + EvaluateNumbers(OpOn, num())
  153.                 Else
  154.                     num(3) = EvaluateNumbers(OpOn, num())
  155.                 End If
  156.                 If Mid$(num(3), 1, 1) = "-" Then Mid$(num(3), 1) = "N"
  157.                 'PRINT "*************"
  158.                 'PRINT num(1), OName(OpOn), num(2), num(3), exp$
  159.                 If Left$(num(3), 5) = "ERROR" Then exp$ = num(3): Exit Sub
  160.                 exp$ = LTrim$(N2S(DWD(Left$(exp$, s) + RTrim$(LTrim$(num(3))) + Mid$(exp$, e + 1))))
  161.                 Print exp$
  162.             End If
  163.             op = 0
  164.         Loop
  165.     Next
  166.  
  167.  
  168.  
  169.  
  170. Sub Set_OrderOfOperations
  171.     'PL sets our priortity level. 1 is highest to 65535 for the lowest.
  172.     'I used a range here so I could add in new priority levels as needed.
  173.     'OName ended up becoming the name of our commands, as I modified things.... Go figure!  LOL!
  174.     ReDim OName(10000) As String, PL(10000) As Integer
  175.     'Constants get evaluated first, with a Priority Level of 1
  176.  
  177.     i = i + 1: OName(i) = "C_UOF": PL(i) = 5 'convert to unsigned offset
  178.     i = i + 1: OName(i) = "C_OF": PL(i) = 5 'convert to offset
  179.     i = i + 1: OName(i) = "C_UBY": PL(i) = 5 'convert to unsigned byte
  180.     i = i + 1: OName(i) = "C_BY": PL(i) = 5 'convert to byte
  181.     i = i + 1: OName(i) = "C_UIN": PL(i) = 5 'convert to unsigned integer
  182.     i = i + 1: OName(i) = "C_IN": PL(i) = 5 'convert to integer
  183.     i = i + 1: OName(i) = "C_UIF": PL(i) = 5 'convert to unsigned int64
  184.     i = i + 1: OName(i) = "C_IF": PL(i) = 5 'convert to int64
  185.     i = i + 1: OName(i) = "C_ULO": PL(i) = 5 'convert to unsigned long
  186.     i = i + 1: OName(i) = "C_LO": PL(i) = 5 'convert to long
  187.     i = i + 1: OName(i) = "C_SI": PL(i) = 5 'convert to single
  188.     i = i + 1: OName(i) = "C_FL": PL(i) = 5 'convert to float
  189.     i = i + 1: OName(i) = "C_DO": PL(i) = 5 'convert to double
  190.     i = i + 1: OName(i) = "C_UBI": PL(i) = 5 'convert to unsigned bit
  191.     i = i + 1: OName(i) = "C_BI": PL(i) = 5 'convert to bit
  192.  
  193.     'Then Functions with PL 10
  194.     i = i + 1:: OName(i) = "_PI": PL(i) = 10
  195.     i = i + 1: OName(i) = "_ACOS": PL(i) = 10
  196.     i = i + 1: OName(i) = "_ASIN": PL(i) = 10
  197.     i = i + 1: OName(i) = "_ARCSEC": PL(i) = 10
  198.     i = i + 1: OName(i) = "_ARCCSC": PL(i) = 10
  199.     i = i + 1: OName(i) = "_ARCCOT": PL(i) = 10
  200.     i = i + 1: OName(i) = "_SECH": PL(i) = 10
  201.     i = i + 1: OName(i) = "_CSCH": PL(i) = 10
  202.     i = i + 1: OName(i) = "_COTH": PL(i) = 10
  203.     i = i + 1: OName(i) = "COS": PL(i) = 10
  204.     i = i + 1: OName(i) = "SIN": PL(i) = 10
  205.     i = i + 1: OName(i) = "TAN": PL(i) = 10
  206.     i = i + 1: OName(i) = "LOG": PL(i) = 10
  207.     i = i + 1: OName(i) = "EXP": PL(i) = 10
  208.     i = i + 1: OName(i) = "ATN": PL(i) = 10
  209.     i = i + 1: OName(i) = "_D2R": PL(i) = 10
  210.     i = i + 1: OName(i) = "_D2G": PL(i) = 10
  211.     i = i + 1: OName(i) = "_R2D": PL(i) = 10
  212.     i = i + 1: OName(i) = "_R2G": PL(i) = 10
  213.     i = i + 1: OName(i) = "_G2D": PL(i) = 10
  214.     i = i + 1: OName(i) = "_G2R": PL(i) = 10
  215.     i = i + 1: OName(i) = "ABS": PL(i) = 10
  216.     i = i + 1: OName(i) = "SGN": PL(i) = 10
  217.     i = i + 1: OName(i) = "INT": PL(i) = 10
  218.     i = i + 1: OName(i) = "_ROUND": PL(i) = 10
  219.     i = i + 1: OName(i) = "_CEIL": PL(i) = 10
  220.     i = i + 1: OName(i) = "FIX": PL(i) = 10
  221.     i = i + 1: OName(i) = "_SEC": PL(i) = 10
  222.     i = i + 1: OName(i) = "_CSC": PL(i) = 10
  223.     i = i + 1: OName(i) = "_COT": PL(i) = 10
  224.     i = i + 1: OName(i) = "ASC": PL(i) = 10
  225.     i = i + 1: OName(i) = "CHR$": PL(i) = 10
  226.     i = i + 1: OName(i) = "C_RG": PL(i) = 10 '_RGB32 converted
  227.     i = i + 1: OName(i) = "C_RA": PL(i) = 10 '_RGBA32 converted
  228.     i = i + 1: OName(i) = "_RGB": PL(i) = 10
  229.     i = i + 1: OName(i) = "_RGBA": PL(i) = 10
  230.     i = i + 1: OName(i) = "C_RX": PL(i) = 10 '_RED32 converted
  231.     i = i + 1: OName(i) = "C_GR": PL(i) = 10 ' _GREEN32 converted
  232.     i = i + 1: OName(i) = "C_BL": PL(i) = 10 '_BLUE32 converted
  233.     i = i + 1: OName(i) = "C_AL": PL(i) = 10 '_ALPHA32 converted
  234.     i = i + 1: OName(i) = "_RED": PL(i) = 10
  235.     i = i + 1: OName(i) = "_GREEN": PL(i) = 10
  236.     i = i + 1: OName(i) = "_BLUE": PL(i) = 10
  237.     i = i + 1: OName(i) = "_ALPHA": PL(i) = 10
  238.  
  239.     'Exponents with PL 20
  240.     i = i + 1: OName(i) = "^": PL(i) = 20
  241.     i = i + 1: OName(i) = "SQR": PL(i) = 20
  242.     i = i + 1: OName(i) = "ROOT": PL(i) = 20
  243.     'Multiplication and Division PL 30
  244.     i = i + 1: OName(i) = "*": PL(i) = 30
  245.     i = i + 1: OName(i) = "/": PL(i) = 30
  246.     'Integer Division PL 40
  247.     i = i + 1: OName(i) = "\": PL(i) = 40
  248.     'MOD PL 50
  249.     i = i + 1: OName(i) = "MOD": PL(i) = 50
  250.     'Addition and Subtraction PL 60
  251.     i = i + 1: OName(i) = "+": PL(i) = 60
  252.     i = i + 1: OName(i) = "-": PL(i) = 60
  253.  
  254.     'Relational Operators =, >, <, <>, <=, >=   PL 70
  255.     i = i + 1: OName(i) = "<>": PL(i) = 70 'These next three are just reversed symbols as an attempt to help process a common typo
  256.     i = i + 1: OName(i) = "><": PL(i) = 70
  257.     i = i + 1: OName(i) = "<=": PL(i) = 70
  258.     i = i + 1: OName(i) = ">=": PL(i) = 70
  259.     i = i + 1: OName(i) = "=<": PL(i) = 70 'I personally can never keep these things straight.  Is it < = or = <...
  260.     i = i + 1: OName(i) = "=>": PL(i) = 70 'Who knows, check both!
  261.     i = i + 1: OName(i) = ">": PL(i) = 70
  262.     i = i + 1: OName(i) = "<": PL(i) = 70
  263.     i = i + 1: OName(i) = "=": PL(i) = 70
  264.     'Logical Operations PL 80+
  265.     i = i + 1: OName(i) = "NOT": PL(i) = 80
  266.     i = i + 1: OName(i) = "AND": PL(i) = 90
  267.     i = i + 1: OName(i) = "OR": PL(i) = 100
  268.     i = i + 1: OName(i) = "XOR": PL(i) = 110
  269.     i = i + 1: OName(i) = "EQV": PL(i) = 120
  270.     i = i + 1: OName(i) = "IMP": PL(i) = 130
  271.     i = i + 1: OName(i) = ",": PL(i) = 1000
  272.  
  273.     ReDim _Preserve OName(i) As String, PL(i) As Integer
  274.  
  275. Function EvaluateNumbers$ (p, num() As String)
  276.     Dim n1 As _Float, n2 As _Float, n3 As _Float
  277.     'PRINT "EVALNUM:"; OName(p), num(1), num(2)
  278.     If InStr(num(1), ",") Then
  279.         EvaluateNumbers$ = "ERROR - Invalid comma (" + num(1) + ")": Exit Function
  280.     End If
  281.     l2 = InStr(num(2), ",")
  282.     If l2 Then
  283.         Select Case OName(p) 'only certain commands should pass a comma value
  284.             Case "C_RG", "C_RA", "_RGB", "_RGBA", "_RED", "_GREEN", "C_BL", "_ALPHA"
  285.             Case Else
  286.                 C$ = Mid$(num(2), l2)
  287.                 num(2) = Left$(num(2), l2 - 1)
  288.         End Select
  289.     End If
  290.  
  291.     Select Case PL(p) 'divide up the work so we want do as much case checking
  292.         Case 5 'Type conversions
  293.             'Note, these are special cases and work with the number BEFORE the command and not after
  294.             Select Case OName(p) 'Depending on our operator..
  295.                 Case "C_UOF": n1~%& = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1~%&)))
  296.                 Case "C_ULO": n1%& = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1%&)))
  297.                 Case "C_UBY": n1~%% = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1~%%)))
  298.                 Case "C_UIN": n1~% = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1~%)))
  299.                 Case "C_BY": n1%% = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1%%)))
  300.                 Case "C_IN": n1% = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1%)))
  301.                 Case "C_UIF": n1~&& = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1~&&)))
  302.                 Case "C_OF": n1~& = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1~&)))
  303.                 Case "C_IF": n1&& = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1&&)))
  304.                 Case "C_LO": n1& = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1&)))
  305.                 Case "C_UBI": n1~` = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1~`)))
  306.                 Case "C_BI": n1` = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1`)))
  307.                 Case "C_FL": n1## = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1##)))
  308.                 Case "C_DO": n1# = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1#)))
  309.                 Case "C_SI": n1! = Val(num(1)): EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1!)))
  310.             End Select
  311.             Exit Function
  312.         Case 10 'functions
  313.             Select Case OName(p) 'Depending on our operator..
  314.                 Case "_PI"
  315.                     n1 = 3.14159265358979323846264338327950288## 'Future compatable in case something ever stores extra digits for PI
  316.                     If num(2) <> "" Then n1 = n1 * Val(num(2))
  317.                 Case "_ACOS": n1 = _Acos(Val(num(2)))
  318.                 Case "_ASIN": n1 = _Asin(Val(num(2)))
  319.                 Case "_ARCSEC": n1 = _Arcsec(Val(num(2)))
  320.                 Case "_ARCCSC": n1 = _Arccsc(Val(num(2)))
  321.                 Case "_ARCCOT": n1 = _Arccot(Val(num(2)))
  322.                 Case "_SECH": n1 = _Sech(Val(num(2)))
  323.                 Case "_CSCH": n1 = _Csch(Val(num(2)))
  324.                 Case "_COTH": n1 = _Coth(Val(num(2)))
  325.                 Case "C_RG"
  326.                     n$ = num(2)
  327.                     If n$ = "" Then EvaluateNumbers$ = "ERROR - Invalid null _RGB32": Exit Function
  328.                     c1 = InStr(n$, ",")
  329.                     If c1 Then c2 = InStr(c1 + 1, n$, ",")
  330.                     If c2 Then c3 = InStr(c2 + 1, n$, ",")
  331.                     If c3 Then c4 = InStr(c3 + 1, n$, ",")
  332.                     If c1 = 0 Then 'there's no comma in the command to parse.  It's a grayscale value
  333.                         n = Val(num(2))
  334.                         n1 = _RGB32(n, n, n)
  335.                     ElseIf c2 = 0 Then 'there's one comma and not 2.  It's grayscale with alpha.
  336.                         n = Val(Left$(num(2), c1))
  337.                         n2 = Val(Mid$(num(2), c1 + 1))
  338.                         n1 = _RGBA32(n, n, n, n2)
  339.                     ElseIf c3 = 0 Then 'there's two commas.  It's _RGB values
  340.                         n = Val(Left$(num(2), c1))
  341.                         n2 = Val(Mid$(num(2), c1 + 1))
  342.                         n3 = Val(Mid$(num(2), c2 + 1))
  343.                         n1 = _RGB32(n, n2, n3)
  344.                     ElseIf c4 = 0 Then 'there's three commas.  It's _RGBA values
  345.                         n = Val(Left$(num(2), c1))
  346.                         n2 = Val(Mid$(num(2), c1 + 1))
  347.                         n3 = Val(Mid$(num(2), c2 + 1))
  348.                         n4 = Val(Mid$(num(2), c3 + 1))
  349.                         n1 = _RGBA32(n, n2, n3, n4)
  350.                     Else 'we have more than three commas.  I have no idea WTH type of values got passed here!
  351.                         EvaluateNumbers$ = "ERROR - Invalid comma count (" + num(2) + ")": Exit Function
  352.                     End If
  353.                 Case "C_RA"
  354.                     n$ = num(2)
  355.                     If n$ = "" Then EvaluateNumbers$ = "ERROR - Invalid null _RGBA32": Exit Function
  356.                     c1 = InStr(n$, ",")
  357.                     If c1 Then c2 = InStr(c1 + 1, n$, ",")
  358.                     If c2 Then c3 = InStr(c2 + 1, n$, ",")
  359.                     If c3 Then c4 = InStr(c3 + 1, n$, ",")
  360.                     If c3 = 0 Or c4 <> 0 Then EvaluateNumbers$ = "ERROR - Invalid comma count (" + num(2) + ")": Exit Function
  361.                     'we have to have 3 commas; not more, not less.
  362.                     n = Val(Left$(num(2), c1))
  363.                     n2 = Val(Mid$(num(2), c1 + 1))
  364.                     n3 = Val(Mid$(num(2), c2 + 1))
  365.                     n4 = Val(Mid$(num(2), c3 + 1))
  366.                     n1 = _RGBA32(n, n2, n3, n4)
  367.                 Case "_RGB"
  368.                     n$ = num(2)
  369.                     If n$ = "" Then EvaluateNumbers$ = "ERROR - Invalid null _RGB": Exit Function
  370.                     c1 = InStr(n$, ",")
  371.                     If c1 Then c2 = InStr(c1 + 1, n$, ",")
  372.                     If c2 Then c3 = InStr(c2 + 1, n$, ",")
  373.                     If c3 Then c4 = InStr(c3 + 1, n$, ",")
  374.                     If c3 = 0 Or c4 <> 0 Then EvaluateNumbers$ = "ERROR - Invalid comma count (" + num(2) + "). _RGB requires 4 parameters for Red, Green, Blue, ScreenMode.": Exit Function
  375.                     'we have to have 3 commas; not more, not less.
  376.                     n = Val(Left$(num(2), c1))
  377.                     n2 = Val(Mid$(num(2), c1 + 1))
  378.                     n3 = Val(Mid$(num(2), c2 + 1))
  379.                     n4 = Val(Mid$(num(2), c3 + 1))
  380.                     Select Case n4
  381.                         Case 0 To 2, 7 To 13, 256, 32 'these are the good screen values
  382.                         Case Else
  383.                             EvaluateNumbers$ = "ERROR - Invalid Screen Mode (" + Str$(n4) + ")": Exit Function
  384.                     End Select
  385.                     t = _NewImage(1, 1, n4)
  386.                     n1 = _RGB(n, n2, n3, t)
  387.                     _FreeImage t
  388.                 Case "_RGBA"
  389.                     n$ = num(2)
  390.                     If n$ = "" Then EvaluateNumbers$ = "ERROR - Invalid null _RGBA": Exit Function
  391.                     c1 = InStr(n$, ",")
  392.                     If c1 Then c2 = InStr(c1 + 1, n$, ",")
  393.                     If c2 Then c3 = InStr(c2 + 1, n$, ",")
  394.                     If c3 Then c4 = InStr(c3 + 1, n$, ",")
  395.                     If c4 Then c5 = InStr(c4 + 1, n$, ",")
  396.                     If c4 = 0 Or c5 <> 0 Then EvaluateNumbers$ = "ERROR - Invalid comma count (" + num(2) + "). _RGBA requires 5 parameters for Red, Green, Blue, Alpha, ScreenMode.": Exit Function
  397.                     'we have to have 4 commas; not more, not less.
  398.                     n = Val(Left$(num(2), c1))
  399.                     n2 = Val(Mid$(num(2), c1 + 1))
  400.                     n3 = Val(Mid$(num(2), c2 + 1))
  401.                     n4 = Val(Mid$(num(2), c3 + 1))
  402.                     n5 = Val(Mid$(num(2), c4 + 1))
  403.                     Select Case n5
  404.                         Case 0 To 2, 7 To 13, 256, 32 'these are the good screen values
  405.                         Case Else
  406.                             EvaluateNumbers$ = "ERROR - Invalid Screen Mode (" + Str$(n5) + ")": Exit Function
  407.                     End Select
  408.                     t = _NewImage(1, 1, n5)
  409.                     n1 = _RGBA(n, n2, n3, n4, t)
  410.                     _FreeImage t
  411.                 Case "_RED", "_GREEN", "_BLUE", "_ALPHA"
  412.                     n$ = num(2)
  413.                     If n$ = "" Then EvaluateNumbers$ = "ERROR - Invalid null " + OName(p): Exit Function
  414.                     c1 = InStr(n$, ",")
  415.                     If c1 = 0 Then EvaluateNumbers$ = "ERROR - " + OName(p) + " requires 2 parameters for Color, ScreenMode.": Exit Function
  416.                     If c1 Then c2 = InStr(c1 + 1, n$, ",")
  417.                     If c2 Then EvaluateNumbers$ = "ERROR - " + OName(p) + " requires 2 parameters for Color, ScreenMode.": Exit Function
  418.                     n = Val(Left$(num(2), c1))
  419.                     n2 = Val(Mid$(num(2), c1 + 1))
  420.                     Select Case n2
  421.                         Case 0 To 2, 7 To 13, 256, 32 'these are the good screen values
  422.                         Case Else
  423.                             EvaluateNumbers$ = "ERROR - Invalid Screen Mode (" + Str$(n2) + ")": Exit Function
  424.                     End Select
  425.                     t = _NewImage(1, 1, n4)
  426.                     Select Case OName(p)
  427.                         Case "_RED": n1 = _Red(n, t)
  428.                         Case "_BLUE": n1 = _Blue(n, t)
  429.                         Case "_GREEN": n1 = _Green(n, t)
  430.                         Case "_ALPHA": n1 = _Alpha(n, t)
  431.                     End Select
  432.                     _FreeImage t
  433.                 Case "C_RX", "C_GR", "C_BL", "C_AL"
  434.                     n$ = num(2)
  435.                     If n$ = "" Then EvaluateNumbers$ = "ERROR - Invalid null " + OName(p): Exit Function
  436.                     n = Val(num(2))
  437.                     Select Case OName(p)
  438.                         Case "C_RX": n1 = _Red32(n)
  439.                         Case "C_BL": n1 = _Blue32(n)
  440.                         Case "C_GR": n1 = _Green32(n)
  441.                         Case "C_AL": n1 = _Alpha32(n)
  442.                     End Select
  443.                 Case "COS": n1 = Cos(Val(num(2)))
  444.                 Case "SIN": n1 = Sin(Val(num(2)))
  445.                 Case "TAN": n1 = Tan(Val(num(2)))
  446.                 Case "LOG": n1 = Log(Val(num(2)))
  447.                 Case "EXP": n1 = Exp(Val(num(2)))
  448.                 Case "ATN": n1 = Atn(Val(num(2)))
  449.                 Case "_D2R": n1 = 0.0174532925 * (Val(num(2)))
  450.                 Case "_D2G": n1 = 1.1111111111 * (Val(num(2)))
  451.                 Case "_R2D": n1 = 57.2957795 * (Val(num(2)))
  452.                 Case "_R2G": n1 = 0.015707963 * (Val(num(2)))
  453.                 Case "_G2D": n1 = 0.9 * (Val(num(2)))
  454.                 Case "_G2R": n1 = 63.661977237 * (Val(num(2)))
  455.                 Case "ABS": n1 = Abs(Val(num(2)))
  456.                 Case "SGN": n1 = Sgn(Val(num(2)))
  457.                 Case "INT": n1 = Int(Val(num(2)))
  458.                 Case "_ROUND": n1 = _Round(Val(num(2)))
  459.                 Case "_CEIL": n1 = _Ceil(Val(num(2)))
  460.                 Case "FIX": n1 = Fix(Val(num(2)))
  461.                 Case "_SEC": n1 = _Sec(Val(num(2)))
  462.                 Case "_CSC": n1 = _Csc(Val(num(2)))
  463.                 Case "_COT": n1 = _Cot(Val(num(2)))
  464.             End Select
  465.         Case 20 To 60 'Math Operators
  466.             Select Case OName(p) 'Depending on our operator..
  467.                 Case "^": n1 = Val(num(1)) ^ Val(num(2))
  468.                 Case "SQR": n1 = Sqr(Val(num(2)))
  469.                 Case "ROOT"
  470.                     n1 = Val(num(1)): n2 = Val(num(2))
  471.                     If n2 = 1 Then EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1))): Exit Function
  472.                     If n1 < 0 And n2 >= 1 Then sign = -1: n1 = -n1 Else sign = 1
  473.                     n3 = 1## / n2
  474.                     If n3 <> Int(n3) And n2 < 1 Then sign = Sgn(n1): n1 = Abs(n1)
  475.                     n1 = sign * (n1 ^ n3)
  476.                 Case "*": n1 = Val(num(1)) * Val(num(2))
  477.                 Case "/": n1 = Val(num(1)) / Val(num(2))
  478.                 Case "\"
  479.                     If Val(num(2)) <> 0 Then
  480.                         n1 = Val(num(1)) \ Val(num(2))
  481.                     Else
  482.                         EvaluateNumbers$ = "ERROR - Bad operation (We shouldn't see this)"
  483.                         Exit Function
  484.                     End If
  485.                 Case "MOD": n1 = Val(num(1)) Mod Val(num(2))
  486.                 Case "+": n1 = Val(num(1)) + Val(num(2))
  487.                 Case "-":
  488.                     n1 = Val(num(1)) - Val(num(2))
  489.             End Select
  490.         Case 70 'Relational Operators =, >, <, <>, <=, >=
  491.             Select Case OName(p) 'Depending on our operator..
  492.                 Case "=": n1 = Val(num(1)) = Val(num(2))
  493.                 Case ">": n1 = Val(num(1)) > Val(num(2))
  494.                 Case "<": n1 = Val(num(1)) < Val(num(2))
  495.                 Case "<>", "><": n1 = Val(num(1)) <> Val(num(2))
  496.                 Case "<=", "=<": n1 = Val(num(1)) <= Val(num(2))
  497.                 Case ">=", "=>": n1 = Val(num(1)) >= Val(num(2))
  498.             End Select
  499.         Case Else 'a value we haven't processed elsewhere
  500.             Select Case OName(p) 'Depending on our operator..
  501.                 Case "NOT": n1 = Not Val(num(2))
  502.                 Case "AND": n1 = Val(num(1)) And Val(num(2))
  503.                 Case "OR": n1 = Val(num(1)) Or Val(num(2))
  504.                 Case "XOR": n1 = Val(num(1)) Xor Val(num(2))
  505.                 Case "EQV": n1 = Val(num(1)) Eqv Val(num(2))
  506.                 Case "IMP": n1 = Val(num(1)) Imp Val(num(2))
  507.             End Select
  508.     End Select
  509.  
  510.     EvaluateNumbers$ = RTrim$(LTrim$(Str$(n1))) + C$
  511.  
  512.     'PRINT "AFTEREVN:"; EvaluateNumbers$
  513.  
  514. Function DWD$ (exp$) 'Deal With Duplicates
  515.     'To deal with duplicate operators in our code.
  516.     'Such as --  becomes a +
  517.     '++ becomes a +
  518.     '+- becomes a -
  519.     '-+ becomes a -
  520.     t$ = exp$
  521.     Do
  522.         bad = 0
  523.         Do
  524.             l = InStr(t$, "++")
  525.             If l Then t$ = Left$(t$, l - 1) + "+" + Mid$(t$, l + 2): bad = -1
  526.         Loop Until l = 0
  527.         Do
  528.             l = InStr(t$, "+-")
  529.             If l Then t$ = Left$(t$, l - 1) + "-" + Mid$(t$, l + 2): bad = -1
  530.         Loop Until l = 0
  531.         Do
  532.             l = InStr(t$, "-+")
  533.             If l Then t$ = Left$(t$, l - 1) + "-" + Mid$(t$, l + 2): bad = -1
  534.         Loop Until l = 0
  535.         Do
  536.             l = InStr(t$, "--")
  537.             If l Then t$ = Left$(t$, l - 1) + "+" + Mid$(t$, l + 2): bad = -1
  538.         Loop Until l = 0
  539.         'PRINT "FIXING: "; t$
  540.     Loop Until Not bad
  541.     DWD$ = t$
  542.  
  543. Sub PreParse (e$)
  544.     Dim f As _Float
  545.  
  546.     If PP_TypeMod(0) = "" Then
  547.         ReDim PP_TypeMod(100) As String, PP_ConvertedMod(100) As String 'Large enough to hold all values to begin with
  548.         PP_TypeMod(0) = "Initialized" 'Set so we don't do this section over and over, as we keep the values in shared memory.
  549.         Set_OrderOfOperations 'Call this once to set up our proper order of operations and variable list
  550.         'and the below is a conversion list so symbols don't get cross confused.
  551.         i = i + 1: PP_TypeMod(i) = "~`": PP_ConvertedMod(i) = "C_UBI" 'unsigned bit
  552.         i = i + 1: PP_TypeMod(i) = "~%%": PP_ConvertedMod(i) = "C_UBY" 'unsigned byte
  553.         i = i + 1: PP_TypeMod(i) = "~%&": PP_ConvertedMod(i) = "C_UOF" 'unsigned offset
  554.         i = i + 1: PP_TypeMod(i) = "~%": PP_ConvertedMod(i) = "C_UIN" 'unsigned integer
  555.         i = i + 1: PP_TypeMod(i) = "~&&": PP_ConvertedMod(i) = "C_UIF" 'unsigned integer64
  556.         i = i + 1: PP_TypeMod(i) = "~&": PP_ConvertedMod(i) = "C_ULO" 'unsigned long
  557.         i = i + 1: PP_TypeMod(i) = "`": PP_ConvertedMod(i) = "C_BI" 'bit
  558.         i = i + 1: PP_TypeMod(i) = "%%": PP_ConvertedMod(i) = "C_BY" 'byte
  559.         i = i + 1: PP_TypeMod(i) = "%&": PP_ConvertedMod(i) = "C_OF" 'offset
  560.         i = i + 1: PP_TypeMod(i) = "%": PP_ConvertedMod(i) = "C_IN" 'integer
  561.         i = i + 1: PP_TypeMod(i) = "&&": PP_ConvertedMod(i) = "C_IF" 'integer64
  562.         i = i + 1: PP_TypeMod(i) = "&": PP_ConvertedMod(i) = "C_LO" 'long
  563.         i = i + 1: PP_TypeMod(i) = "!": PP_ConvertedMod(i) = "C_SI" 'single
  564.         i = i + 1: PP_TypeMod(i) = "##": PP_ConvertedMod(i) = "C_FL" 'float
  565.         i = i + 1: PP_TypeMod(i) = "#": PP_ConvertedMod(i) = "C_DO" 'double
  566.         i = i + 1: PP_TypeMod(i) = "_RGB32": PP_ConvertedMod(i) = "C_RG" 'rgb32
  567.         i = i + 1: PP_TypeMod(i) = "_RGBA32": PP_ConvertedMod(i) = "C_RA" 'rgba32
  568.         i = i + 1: PP_TypeMod(i) = "_RED32": PP_ConvertedMod(i) = "C_RX" 'red32
  569.         i = i + 1: PP_TypeMod(i) = "_GREEN32": PP_ConvertedMod(i) = "C_GR" 'green32
  570.         i = i + 1: PP_TypeMod(i) = "_BLUE32": PP_ConvertedMod(i) = "C_BL" 'blue32
  571.         i = i + 1: PP_TypeMod(i) = "_ALPHA32": PP_ConvertedMod(i) = "C_AL" 'alpha32
  572.         ReDim _Preserve PP_TypeMod(i) As String, PP_ConvertedMod(i) As String 'And then resized to just contain the necessary space in memory
  573.     End If
  574.     t$ = e$
  575.  
  576.     'First strip all spaces
  577.     t$ = ""
  578.     For i = 1 To Len(e$)
  579.         If Mid$(e$, i, 1) <> " " Then t$ = t$ + Mid$(e$, i, 1)
  580.     Next
  581.  
  582.     t$ = UCase$(t$)
  583.     If t$ = "" Then e$ = "ERROR -- NULL string; nothing to evaluate": Exit Sub
  584.  
  585.     'ERROR CHECK by counting our brackets
  586.     l = 0
  587.     Do
  588.         l = InStr(l + 1, t$, "("): If l Then c = c + 1
  589.     Loop Until l = 0
  590.     l = 0
  591.     Do
  592.         l = InStr(l + 1, t$, ")"): If l Then c1 = c1 + 1
  593.     Loop Until l = 0
  594.     If c <> c1 Then e$ = "ERROR -- Bad Parenthesis:" + Str$(c) + "( vs" + Str$(c1) + ")": Exit Sub
  595.  
  596.     'Modify so that NOT will process properly
  597.     l = 0
  598.     Do
  599.         l = InStr(l + 1, t$, "NOT")
  600.         If l Then
  601.             'We need to work magic on the statement so it looks pretty.
  602.             ' 1 + NOT 2 + 1 is actually processed as 1 + (NOT 2 + 1)
  603.             'Look for something not proper
  604.             l1 = InStr(l + 1, t$, "AND")
  605.             If l1 = 0 Or (InStr(l + 1, t$, "OR") > 0 And InStr(l + 1, t$, "OR") < l1) Then l1 = InStr(l + 1, t$, "OR")
  606.             If l1 = 0 Or (InStr(l + 1, t$, "XOR") > 0 And InStr(l + 1, t$, "XOR") < l1) Then l1 = InStr(l + 1, t$, "XOR")
  607.             If l1 = 0 Or (InStr(l + 1, t$, "EQV") > 0 And InStr(l + 1, t$, "EQV") < l1) Then l1 = InStr(l + 1, t$, "EQV")
  608.             If l1 = 0 Or (InStr(l + 1, t$, "IMP") > 0 And InStr(l + 1, t$, "IMP") < l1) Then l1 = InStr(l + 1, t$, "IMP")
  609.             If l1 = 0 Then l1 = Len(t$) + 1
  610.             t$ = Left$(t$, l - 1) + "(" + Mid$(t$, l, l1 - l) + ")" + Mid$(t$, l + l1 - l)
  611.             l = l + 3
  612.             'PRINT t$
  613.         End If
  614.     Loop Until l = 0
  615.  
  616.     For j = 1 To UBound(PP_TypeMod)
  617.         l = 0
  618.         Do
  619.             l = InStr(l + 1, t$, PP_TypeMod(j))
  620.             If l = 0 Then Exit Do
  621.             i = 0: l1 = 0: l2 = 0: lo = Len(PP_TypeMod(j))
  622.             Do
  623.                 If PL(i) > 10 Then
  624.                     l2 = _InStrRev(l, t$, OName$(i))
  625.                     If l2 > 0 And l2 > l1 Then l1 = l2
  626.                 End If
  627.                 i = i + lo
  628.             Loop Until i > UBound(PL)
  629.             'PRINT "L1:"; l1; "L"; l
  630.             l$ = Left$(t$, l1)
  631.             m$ = Mid$(t$, l1 + 1, l - l1 - 1)
  632.             r$ = PP_ConvertedMod(j) + Mid$(t$, l + lo)
  633.             'PRINT "Y$: "; TypeMod(j)
  634.             'PRINT "L$: "; l$
  635.             'PRINT "M$: "; m$
  636.             'PRINT "R$: "; r$
  637.             If j > 15 Then
  638.                 t$ = l$ + m$ + r$ 'replacement routine for commands which might get confused with others, like _RGB and _RGB32
  639.             Else
  640.                 'the first 15 commands need to properly place the parenthesis around the value we want to convert.
  641.                 t$ = l$ + "(" + m$ + ")" + r$
  642.             End If
  643.             'PRINT "T$: "; t$
  644.             l = l + 2 + Len(PP_TypeMod(j)) 'move forward from the length of the symbol we checked + the new "(" and  ")"
  645.         Loop
  646.     Next
  647.     '    PRINT "HERE: "; t$
  648.  
  649.  
  650.  
  651.     'Check for bad operators before a ( bracket
  652.     l = 0
  653.     Do
  654.         l = InStr(l + 1, t$, "(")
  655.         If l And l > 2 Then 'Don't check the starting bracket; there's nothing before it.
  656.             good = 0
  657.             'PRINT "BEFORE: "; t$; l
  658.             For i = 1 To UBound(OName)
  659.                 m$ = Mid$(t$, l - Len(OName(i)), Len(OName(i)))
  660.                 'IF OName(i) = "C_SI" THEN PRINT "CONVERT TO SINGLE", m$
  661.                 If m$ = OName(i) Then good = -1: Exit For 'We found an operator after our ), and it's not a CONST (like PI)
  662.             Next
  663.             'PRINT t$; l
  664.             If Not good Then e$ = "ERROR - Improper operations before (.": Exit Sub
  665.             l = l + 1
  666.         End If
  667.     Loop Until l = 0
  668.  
  669.     'Check for bad operators after a ) bracket
  670.     l = 0
  671.     Do
  672.         l = InStr(l + 1, t$, ")")
  673.         If l And l < Len(t$) Then
  674.             good = 0
  675.             For i = 1 To UBound(OName)
  676.                 m$ = Mid$(t$, l + 1, Len(OName(i)))
  677.                 If m$ = OName(i) Then good = -1: Exit For 'We found an operator after our ), and it's not a CONST (like PI
  678.             Next
  679.             If Mid$(t$, l + 1, 1) = ")" Then good = -1
  680.             If Not good Then e$ = "ERROR - Improper operations after ).": Exit Sub
  681.             l = l + 1
  682.         End If
  683.     Loop Until l = 0 Or l = Len(t$) 'last symbol is a bracket
  684.  
  685.     'Turn all &H (hex) numbers into decimal values for the program to process properly
  686.     l = 0
  687.     Do
  688.         l = InStr(t$, "&H")
  689.         If l Then
  690.             E = l + 1: finished = 0
  691.             Do
  692.                 E = E + 1
  693.                 comp$ = Mid$(t$, E, 1)
  694.                 Select Case comp$
  695.                     Case "0" To "9", "A" To "F" 'All is good, our next digit is a number, continue to add to the hex$
  696.                     Case Else
  697.                         good = 0
  698.                         For i = 1 To UBound(OName)
  699.                             If Mid$(t$, E, Len(OName(i))) = OName(i) And PL(i) > 1 And PL(i) <= 250 Then good = -1: Exit For 'We found an operator after our ), and it's not a CONST (like PI)
  700.                         Next
  701.                         If Not good Then e$ = "ERROR - Improper &H value. (" + comp$ + ")": Exit Sub
  702.                         E = E - 1
  703.                         finished = -1
  704.                 End Select
  705.             Loop Until finished Or E = Len(t$)
  706.             t$ = Left$(t$, l - 1) + LTrim$(RTrim$(Str$(Val(Mid$(t$, l, E - l + 1))))) + Mid$(t$, E + 1)
  707.         End If
  708.     Loop Until l = 0
  709.  
  710.     'Turn all &B (binary) numbers into decimal values for the program to process properly
  711.     l = 0
  712.     Do
  713.         l = InStr(t$, "&B")
  714.         If l Then
  715.             E = l + 1: finished = 0
  716.             Do
  717.                 E = E + 1
  718.                 comp$ = Mid$(t$, E, 1)
  719.                 Select Case comp$
  720.                     Case "0", "1" 'All is good, our next digit is a number, continue to add to the hex$
  721.                     Case Else
  722.                         good = 0
  723.                         For i = 1 To UBound(OName)
  724.                             If Mid$(t$, E, Len(OName(i))) = OName(i) And PL(i) > 1 And PL(i) <= 250 Then good = -1: Exit For 'We found an operator after our ), and it's not a CONST (like PI)
  725.                         Next
  726.                         If Not good Then e$ = "ERROR - Improper &B value. (" + comp$ + ")": Exit Sub
  727.                         E = E - 1
  728.                         finished = -1
  729.                 End Select
  730.             Loop Until finished Or E = Len(t$)
  731.             bin$ = Mid$(t$, l + 2, E - l - 1)
  732.             For i = 1 To Len(bin$)
  733.                 If Mid$(bin$, i, 1) = "1" Then f = f + 2 ^ (Len(bin$) - i)
  734.             Next
  735.             t$ = Left$(t$, l - 1) + LTrim$(RTrim$(Str$(f))) + Mid$(t$, E + 1)
  736.         End If
  737.     Loop Until l = 0
  738.  
  739.     'PRINT "ALMOST:"; t$
  740.  
  741.     t$ = N2S(t$)
  742.     'PRINT "ALMOST2:"; t$
  743.     VerifyString t$
  744.     'PRINT "Out of PreParse: "; e$
  745.     e$ = t$
  746.  
  747.  
  748.  
  749. Sub VerifyString (t$)
  750.     'ERROR CHECK for unrecognized operations
  751.     j = 1
  752.     Do
  753.         comp$ = Mid$(t$, j, 1)
  754.         Select Case comp$
  755.             Case "0" To "9", ".", "(", ")", ",": j = j + 1
  756.             Case Else
  757.                 good = 0
  758.                 For i = 1 To UBound(OName)
  759.                     If Mid$(t$, j, Len(OName(i))) = OName(i) Then good = -1: Exit For 'We found an operator after our ), and it's not a CONST (like PI)
  760.                 Next
  761.                 If Not good Then t$ = "ERROR - Bad Operational value. (" + comp$ + ")": Exit Sub
  762.                 j = j + Len(OName(i))
  763.         End Select
  764.     Loop Until j > Len(t$)
  765.  
  766. Function N2S$ (exp$) 'scientific Notation to String
  767.  
  768.     'PRINT "Before notation:"; exp$
  769.  
  770.     t$ = LTrim$(RTrim$(exp$))
  771.     If Left$(t$, 1) = "-" Or Left$(t$, 1) = "N" Then sign$ = "-": t$ = Mid$(t$, 2)
  772.  
  773.     dp = InStr(t$, "D+"): dm = InStr(t$, "D-")
  774.     ep = InStr(t$, "E+"): em = InStr(t$, "E-")
  775.     check1 = Sgn(dp) + Sgn(dm) + Sgn(ep) + Sgn(em)
  776.     If check1 < 1 Or check1 > 1 Then N2S = exp$: Exit Function 'If no scientic notation is found, or if we find more than 1 type, it's not SN!
  777.  
  778.     Select Case l 'l now tells us where the SN starts at.
  779.         Case Is < dp: l = dp
  780.         Case Is < dm: l = dm
  781.         Case Is < ep: l = ep
  782.         Case Is < em: l = em
  783.     End Select
  784.  
  785.     l$ = Left$(t$, l - 1) 'The left of the SN
  786.     r$ = Mid$(t$, l + 1): r&& = Val(r$) 'The right of the SN, turned into a workable long
  787.  
  788.  
  789.     If InStr(l$, ".") Then 'Location of the decimal, if any
  790.         If r&& > 0 Then
  791.             r&& = r&& - Len(l$) + 2
  792.         Else
  793.             r&& = r&& + 1
  794.         End If
  795.         l$ = Left$(l$, 1) + Mid$(l$, 3)
  796.     End If
  797.  
  798.     Select Case r&&
  799.         Case 0 'what the heck? We solved it already?
  800.             'l$ = l$
  801.         Case Is < 0
  802.             For i = 1 To -r&&
  803.                 l$ = "0" + l$
  804.             Next
  805.             l$ = "0." + l$
  806.         Case Else
  807.             For i = 1 To r&&
  808.                 l$ = l$ + "0"
  809.             Next
  810.     End Select
  811.  
  812.     N2S$ = sign$ + l$
  813.     'PRINT "After notation:"; N2S$
  814.  
  815.  

 
math process at work.png
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!