Yes, the RegEx version handles global variables, too. The only problem is if they collide with local variables: i, y, y0, y1, y2, y3; or the parameter name: x. To reduce the chance of such collisions, here is a version which uses the following forbidden names, instead: _, __, ___, _0, _1, _2 and _3:
Code:
; Arithmetic expressions evaluator, handling
; unary +,- (-2*3; +3)
; +,-,*,/,\(or % = mod); **(or @ = power)
; (..); constants (pi,e); Global variables (not starting with '_'); abs(),sqrt(),floor()
abs := 3, b := 2, c := 1
MsgBox % Eval("abs*b-c") ; 5
x := 10, y2 := 100
MsgBox % Eval("x+y2") ; 110
MsgBox % Eval("-floor(abs(sqrt(1))) * (+pi -((3%5))) +pi+ 2-1-1 + e-abs(sqrt(floor(2)))**2-e") ; 1
Eval(__) { ; expression preprocessing
Static pi = 3.141592653589793, e = 2.718281828459045
StringReplace __, __,`%, \, All ; % -> \ for MOD
__ := RegExReplace(__,"\s*") ; remove whitespace
__ := RegExReplace(__,"([a-zA-Z]\w*)([^\w\(]|$)","%$1%$2") ; var -> %var%
Transform __, Deref, %__% ; dereference all %var%
StringReplace __, __, -, #, All ; # = subtraction
StringReplace __, __, (#, (0#, All ; (-x -> (0-x
If (Asc(__) = Asc("#"))
__ = 0%__% ; leading -x -> 0-x
StringReplace __, __, (+, (, All ; (+x -> (x
If (Asc(__) = Asc("+"))
StringTrimLeft __, __, 1 ; leading +x -> x
StringReplace __, __, **, @, All ; ** -> @ for easier process
Loop { ; find innermost (..)
If !RegExMatch(__, "(.*)\(([^\(\)]*)\)(.*)", _)
Break
__ := _1 . Eval@(_2) . _3 ; replace "(x)" with value of x
}
Return Eval@(__) ; no more (..)
}
Eval@(__) {
RegExMatch(__, "(.*)(\+|\#)(.*)", _) ; execute rightmost +- operator
IfEqual _2,+, Return Eval@(_1) + Eval@(_3)
IfEqual _2,#, Return Eval@(_1) - Eval@(_3)
; execute rightmost */% operator
RegExMatch(__, "(.*)(\*|\/|\\)(.*)", _)
IfEqual _2,*, Return Eval@(_1) * Eval@(_3)
IfEqual _2,/, Return Eval@(_1) / Eval@(_3)
IfEqual _2,\, Return Mod(Eval@(_1),Eval@(_3))
; execute rightmost power
StringGetPos ___, __, @, R
IfGreaterOrEqual ___,0, Return Eval@(SubStr(__,1,___)) ** Eval@(SubStr(__,2+___))
; execute rightmost function
If !RegExMatch(__,".*(abs|floor|sqrt)(.*)", _)
Return __ ; no more function
IfEqual _1,abs, Return abs( Eval@(_2))
IfEqual _1,floor,Return floor(Eval@(_2))
IfEqual _1,sqrt, Return sqrt( Eval@(_2))
}