ucDefineOperator

 

See Also: ucDefine, ucDefineFunction

 

Defines an operator.

 

ucDefineOperator(Definition [, FunctionAddress [, tHandle]])

 

Many of the details for defining operators are very closely related to the details for defining a function.  The ucDefineFunction topic covers those details.  This topic here focuses mainly on the unique aspects of defining operators.  The Definition part can take one of the following three forms, depending on whether the operator you are defining is Prefix, Postfix, or Infix (binary):

 

[Prec] Operator {Operand}   [ := Definition ]

[Prec] {Operand} Operator   [ := Definition ]

[Prec] {LeftOperand} Operator {RightOperand} }  [ := Definition ]

 

 

Definition parts

   Prec

Optional.  Though optional, it is highly recommended that all operator definitions include a specified precedence level.  If none is supplied, then a default precedence value is used.  Prec is an arbitrary positive integer value less than 2^31, which derives its meaning by whether this value is greater or less than the precedence levels of other given operators.  In addition to a literal numeric value, Prec can also be Precedence(Op); That is, the word Precedence followed by parentheses, enclosing a string argument containing the name of an already defined operator, as in Example 2.

 

Operator

Required.  Unlike function names which can only be alphanumeric, operator names can also consist of symbols, such as +, -, **, etc...

 

Operand, or LeftOperand, RightOperand

Required.  Operands are defined the same way as function arguments, in terms of using directives like ByRef, ByVal, and specified data types.  Optional arguments or indefinite number of arguments do not apply in this context.

 

Definition

Optional.  If the definition is not a callback, then you can supply a self-contained definition.  It is important to note that unlike function definitions which use the equal sign, "=", operator definitions use a colon followed by an equal sign, ":=".  This allows the equal sign to be defined as an operator.  Nothing is hard-coded.  So should you need to define ":=" itself as an operator, you can modify the include file and change ":=" to something else.

 

Remarks

 

ucDefineOperator returns a 32-bit value representing the handle of the operator definition.  You can use this later to release the operator definition if necessary.

 

Operator definitions can be overloaded, bootstrapped, or recursive, just like function definitions.  See ucDefineFunction for details.

 

Overloaded operators definitions that share the same name can have different precedence levels, as long as they are of a different prefix-postfix-infix category.  So for instance, a postfix + operator can have a different precedence level than an infix + operator.  However, if they are both postfix, or both infix, they should have the same precedence level.

 

Non-alphanumeric operators names behave differently than alphanumeric names.  An expression such as "3+++5" could be evaluated any number of ways, depending on how you have defined things.  For instance, you might have defined a prefix + operator, a postfix + operator, and an infix + operator.  In that case, this would be parsed as "3+  +  +5".  Or maybe you've defined an infix + operator, and a postfix ++ operator.  So it would be parsed as "3++  +  5".  If you had also defined a prefix ++ operator, another possible combination might be "3  +  ++5".  However, since longer symbols are considered first, in this case it would still parse as "3++  +  5".

 

Precedence levels play a role in determining which expression subgroups are evaluated first.  Operations involving an operator with higher precedence are evaluated prior to adjacent sub-expressions with an operator of lower precedence.

 

A function named Precedence is provided to simplify the task of defining an operator with the same precedence level as a pre-existing operator.

 

 

Example 1:

 

' This example demonstrates various self-contained definitions

 

ucDefineOperator("20 {x} ShiftLeft {y} := x * 2^y") ' Infix

ucDefineOperator("50 {x}%  :=  x / 100") ' Postfix

ucDefineOperator("60 !{x}  :=  x - 1") ' Prefix

ucDefineOperator("30 {x}!  :=  x * 2") ' This one hides the pre-defined factorial op

ucDefineOperator("10 {x} ! {y} := x * y")

 

Print ucEvalStr("2 ShiftLeft 3")   ' returns 16

Print ucEvalStr("25%")             ' returns 0.25

Print ucEvalStr("!5")              ' returns 4

Print ucEvalStr("!5!")             ' (!5)!  returns 8

Print ucEvalStr("!5!4")            ' (!5) ! 4 --> returns 16

 

 

' Here the precedence levels are switched

 

ucDefineOperator("30 !{x}  :=  x - 1")

ucDefineOperator("60 {x}!  :=  x * 2")

ucDefineOperator("50 {x} ! {y} := x * y")

 

Print ucEvalStr("2 ShiftLeft 3")   ' returns 16

Print ucEvalStr("25%")             ' returns 0.25

Print ucEvalStr("!5")              ' returns 4

Print ucEvalStr("!5!")             ' !(5!)  returns 9

Print ucEvalStr("!5!4")            ' !(5 ! 4) --> returns 19

 

 

Example 2:

 

' This example demonstrates an operator callback definition in VB classic

 

Function StringMult(ByRef MyString As String, ByVal Number As Long) As String

   Dim x As Long, TotalString As String

 

   For x = 1 To Number

      TotalString = TotalString + MyString

   Next

 

   StringMult = TotalString

End Function

 

ucDefineOperator "Precedence('*') {ByRef MyString As WideString} * {ByVal Number As Long} As WideString", AddressOf StringMult

 

Print ucEvalStr("'Hello ' * 3") ' Returns:  Hello Hello Hello

 

 

New or Enhanced

 

Issues for users migrating from version 2.0