Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Simple script for evaluating arithmetic expressions


  • Please log in to reply
37 replies to this topic
guest3456
  • Guests
  • Last active:
  • Joined: --
can you update the new RegEx version to support in-program variables?

i think that might be a solution to my problem:
http://www.autohotke...ost-329565.html

guest3456
  • Guests
  • Last active:
  • Joined: --
oh whoops, maybe it already supports vars? i was glancing quickly for the old syntax [var] and didnt see the brackets

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
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:
; 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))

}


  • Guests
  • Last active:
  • Joined: --
This is just Great!!!!

oldbrother
  • Members
  • 149 posts
  • Last active: Nov 09 2014 07:36 PM
  • Joined: 06 Jul 2005
This is just Great!!!!

lamed
  • Guests
  • Last active:
  • Joined: --
I just logged in to say thanks for the code :)

I needed something that can calculate a global variable with the expression, and this solved my problem right away!

PatrickS
  • Members
  • 14 posts
  • Last active: Jul 20 2019 01:08 AM
  • Joined: 21 Mar 2010
Here's a script for simple arithmetic that I wrote a while back. It makes heavy use of regular expressions and I think with very little effort can be extended to support more operations.
The script may look a bit long, but mostly because of the large comment block at the front ... it is otherwise pretty short, I think.

Enjoy!
Patrick


;; -----------------------------------------------------------------------
;; Expression Evaluator
;;
;; Evaluate a simple arithmetic integer expression contained in the function's
;; (string) parameter.
;;
;; The supported expression elements include:
;;	=> Signed integer numbers, such as 5, -7 or +19
;;	=> Addition and subtraction of numbers
;;	=> Multiplication and (integer) division of numbers
;;	=> Modulus (a%b = remainder when a is divided by b)
;;	=> Parenthesized sub-expressions, nested to any depth
;;
;; The expression evaluator obeys the precedence rules of arithmetic, which
;; means that it evaluates sub-expressions in the following order:
;;	1. Parenthesis
;;	2. Multiplication or Division
;;	3. Modulus
;;	4. Addition or Subtraction
;;
;; Examples of valid expressions:
;;	a) 12 + 33
;;	b) 42 - 8
;;	c) 42 - -8
;;	d) 10 + 7 * (8 / (18 % 7)) - 18 / (11-8)
;;
;; Any unrecognized characters are left in the expression as-is. This can be used
;; to compute multiple expressions at the same time. For example, the input string
;; "3+5, 3*5" would evaluate to the pair "8, 15".


Gen__Evaluate(Expression)
{
	; Recursively evaluate parenthesized expressions first, starting at the innermost layer.
	While RegExMatch(Expression, "\(([^()]*)\)", Terms)
	{
		Value := Gen__Evaluate(Terms1)
		StringReplace, Expression, Expression, %Terms%, %Value%, All
	}

	; Evaluate multiplication and (integer) division.
	While RegExMatch(Expression, "([-+]?\d+)\s*([*/])\s*([-+]?\d+)", Terms)
	{
		if Terms2 = *
		{
			Value := Terms1 * Terms3
		}
		else
		{
			Value := Terms1 // Terms3
		}

		StringReplace, Expression, Expression, %Terms%, %Value%
	}

	; Evaluate modulus operations with syntax "a % b".
	While RegExMatch(Expression, "([-+]?\d+)\s*%\s*([-+]?\d+)", Terms)
	{
		Value := Mod(Terms1, Terms2)
		StringReplace, Expression, Expression, %Terms%, %Value%
	}

	; Evaluate addition and subtraction.
	While RegExMatch(Expression, "([-+]?\d+)\s*([-+])\s*([-+]?\d+)", Terms)
	{
		if Terms2 = +
		{
			Value := Terms1 + Terms3
		}
		else
		{
			Value := Terms1 - Terms3
		}

		StringReplace, Expression, Expression, %Terms%, %Value%
	}

	return Expression
}


bruno
  • Members
  • 635 posts
  • Last active: Nov 04 2015 02:26 PM
  • Joined: 07 Mar 2011

edit: sorry, my bug report (deleted) was not related to this thread! ;)