From dc776b547a9b837dbd053d59657ddef31705075a Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 25 May 2025 23:36:37 -0500 Subject: [PATCH] Update CALC expression documentation Doxygen changes in postfix.h mostly formatting & adding tags. Rec-ref changes regrouped the operators to match the order in postfix.h, formatting, and added some missing operators. Updated description of calcout.OEVT for named events. --- .../database/src/std/rec/calcRecord.dbd.pod | 341 +++++++++------- .../src/std/rec/calcoutRecord.dbd.pod | 371 ++++++++++-------- modules/libcom/src/calc/postfix.h | 346 ++++++++-------- 3 files changed, 595 insertions(+), 463 deletions(-) diff --git a/modules/database/src/std/rec/calcRecord.dbd.pod b/modules/database/src/std/rec/calcRecord.dbd.pod index 4203555da..d46b7c525 100644 --- a/modules/database/src/std/rec/calcRecord.dbd.pod +++ b/modules/database/src/std/rec/calcRecord.dbd.pod @@ -49,31 +49,35 @@ for information on how to specify database links. =head3 Expression -At the core of the Calc record lies the CALC and RPCL fields. The CALC field -contains the infix expresion which the record routine will use when it -processes the record. The resulting value is placed in the VAL field and -can be accessed from there. The CALC expression is actually converted to -opcode and stored as Reverse Polish Notation in the RPCL field. It is this -expression which is actually used to calculate VAL. The Reverse Polish -expression is evaluated more efficiently during run-time than an infix -expression. CALC can be changed at run-time, and a special record routine -calls a function to convert it to Reverse Polish Notation. +At the core of the Calc record lies the CALC and RPCL fields. +The CALC field holds an infix expression to be evaluated whenever the record is +processed. +The calculated value is placed in the VAL field and can be accessed from there. + +The CALC expression gets compiled into a stream of Reverse Polish Notation (RPN) +opcodes for a stack-based machine, and stored in the RPCL field. +The RPN opcodes are used to calculate VAL at run-time, and are more efficient +than evaluating the infix expression. +The CALC expression can be replaced at run-time, triggering a special record +routine to compile the new expression into Reverse Polish Notation. The infix expressions that can be used are very similar to the C expression -syntax, but with some additions and subtle differences in operator meaning -and precedence. The string may contain a series of expressions separated by -a semi-colon character ";" any one of which may actually provide the -calculation result; however, all of the other expressions included must -assign their result to a variable. All alphabetic elements described below -are case independent, so upper and lower case letters may be used and mixed -in the variable and function names as desired. Spaces may be used anywhere -within an expression except between characters that make up a single -expression element. +syntax, but with some additions and subtle differences in operator meaning and +precedence. +The string may contain a series of expressions separated by a semi-colon +character C<;>, any one of which may provide the calculation result. +All other expressions included in the string must assign their result to a +variable. +All alphabetic elements described below are case independent, so upper and lower +case letters may be used and mixed in the variable and function names as +desired. +Spaces may be used anywhere within an expression except between characters that +make up a single expression element. -The range of expressions supported by the calculation record are separated -into literals, constants, operands, algebraic operators, trigonometric operators, -relational operators, logical operators, the assignment operator, -parentheses and commas, and the question mark or '?:' operator. +The range of expressions supported by the calculation record are separated into +literals, constants, operands, algebraic operators, trigonometric operators, +relational operators, logical operators, the assignment operator, parentheses +and commas, and the question mark colon or C operator. =fields CALC, RPCL @@ -127,112 +131,205 @@ The keyword VAL returns the current contents of the VAL field (which can be written to by a CA put, so it might I be the result from the last time the expression was evaluated). -=head3 Algebraic Operators +=head3 Arithmetic Operators + +Except for unary minus these are infix binary operators. =over 1 =item * -C: Absolute value (unary) +C<+> : Addition =item * -C: Square root (unary) +C<-> : Subtraction =item * -C: Minimum (any number of args) +C<-> : Minus (unary) =item * -C: Maximum (any number of args) +C<*> : Multiplication =item * -C: returns non-zero if none of the arguments are NaN or Inf (any -number of args) +C : Division =item * -C: returns non-zero if any of the arguments is NaN or Inf (any number -of args) +C<%> : Modulo =item * -C: Ceiling (unary) +C<^> : Exponential =item * -C: Floor (unary) - -=item * -C: Floating point modulo (binary) Added in 7.0.8 - -=item * -C: Log base 10 (unary) - -=item * -C: Natural log (unary) - -=item * -C: Natural log (unary) - -=item * -C: Exponential function (unary) - -=item * -C<^> : Exponential (binary) - -=item * -C<**> : Exponential (binary) - -=item * -C<+> : Addition (binary) - -=item * -C<-> : Subtraction (binary) - -=item * -C<*> : Multiplication (binary) - -=item * -C : Division (binary) - -=item * -C<%> : Modulo (binary) - -=item * -C: Negate (unary) +C<**> : Exponential =back -=head3 Trigonometric Operators +=head3 Algebraic Functions + +When functions take more than one argument, a comma separator must appear +between them. =over 1 =item * -C: Sine +C : Absolute value =item * -C: Hyperbolic sine +C : Exponential function =item * -C: Arc sine +C : Floating point modulo. Added in 7.0.8 =item * -C: Cosine +C : Natural log =item * -C: Hyperbolic cosine +C : Log base 10 =item * -C: Arc cosine +C : Natural log =item * -C: Tangent +C : Minimum =item * -C: Hyperbolic tangent +C : Maximum =item * -C: Arc tangent +C : Square root + +=item * +C : Square root + +=back + +=head3 Trigonometric Functions + +=over 1 + +=item * +C : Sine + +=item * +C : Arc sine + +=item * +C : Cosine + +=item * +C : Arc cosine + +=item * +C : Tangent + +=item * +C : Arc tangent + +=item * +C : 2-parameter Arc tangent. Arg's are reversed to ANSI C + +=back + +=head3 Hyperbolic Trigonometry Functions + +=over 1 + +=item * +C : Hyperbolic sine + +=item * +C : Hyperbolic cosine + +=item * +C : Hyperbolic tangent + +=back + +=head3 Numeric Functions + +=over 1 + +=item * +C : Ceiling + +=item * +C : Floor + +=item * +C : Round to nearest integer + +=item * +C : returns non-zero if any argument is Inf + +=item * +C : returns non-zero (true) if any argument is NaN +or Inf + +=item * +C : returns non-zero (true) if none of the +arguments are NaN or Inf + +=back + +=head3 Boolean/Logical Operators + +These operators use their arguments as a true (non-zero) or false (zero) value. + +=over 1 + +=item * +C<&&> : And, infix binary + +=item * +C<||> : Or, infix binary + +=item * +C : Not, unary prefix + +=back + +=head3 Bitwise Operators + +Mostly infix binary, the arguments are converted to a 32-bit integer, the +operator is applied, and the result converted back into a double. + +=over 1 + +=item * +C<&> : Bitwise and + +=item * +C<|> : Bitwise or + +=item * +C<~> : Bitwise not or one's complement, unary prefix + +=item * +C<<< << >>> : Arithmetic shift left + +=item * +C<<< >> >>> : Arithmetic shift right + +=item * +C<<<< >>> >>>> : Logical shift right + +=item * +C : Bitwise and + +=item * +C : Bitwise or + +=item * +C : Bitwise exclusive or + +=item * +C : Bitwise not or one's complement, unary prefix =back =head3 Relational Operators +These are all infix binary operators. + =over 1 =item * @@ -247,59 +344,17 @@ C<<< <= >>> : Less than or equal to =item * C<<< < >>> : Less than +=item * +C<<< != >>> : Not equal to + =item * C<<< # >>> : Not equal to =item * -C<<< = >>> : Equal to - -=back - -=head3 Logical Operators - -=over 1 +C<<< == >>> : Equal to =item * -C<&&> : And - -=item * -C<||> : Or - -=item * -C : Not - -=back - -=head3 Bitwise Operators - -=over 1 - -=item * -C<|> : Bitwise Or - -=item * -C<&> : Bitwise And - -=item * -C : Bitwise Or - -=item * -C : Bitwise And - -=item * -C : Bitwise Exclusive Or - -=item * -C<~> : One's Complement - -=item * -C<<< << >>> : Arithmetic Left Shift - -=item * -C<<< >> >>> : Arithmetic Right Shift - -=item * -C<<<< >>> >>>> : Logical Right Shift +C<<< = >>> : Equal to (not assignment) =back @@ -314,22 +369,24 @@ C<:=> : assigns a value (right hand side) to a variable (i.e. field) =head3 Parantheses, Comma, and Semicolon -The open and close parentheses are supported. Nested parentheses are -supported. +The open C<(> and close parentheses C<)> are supported to override precedence +rules in a sub-expression. +Nested parentheses are supported to significant depth. -The comma is supported when used to separate the arguments of a binary -function. +The comma C<,> is required to separate the arguments of a function. -The semicolon is used to separate expressions. Although only one -traditional calculation expression is allowed, multiple assignment -expressions are allowed. +The semicolon C<;> is used to value separate expressions. +Exactly one value expression must be present, but multiple assignment +expressions may be included before and/or after the value expression. -=head3 Conditional Expression +=head3 Conditional Operator -The C language's question mark operator is supported. The format is: -C +The C language's question mark colon C ternary operator is supported. +The format is: -=head3 Expression Examples +I C I C<:> I + +=head2 Expression Examples =head3 Algebraic @@ -370,8 +427,8 @@ Result is C if C<<< (A + B) >= (C + D) >>> =back -Prior to Base 3.14.9 it was legal to omit the : and the second (else) part -of the conditional, like this: +Prior to Base 3.14.9 it was legal to omit the colon C<:> and the second (else) +part of the conditional, like this: C<<< (A + B)<(C + D) ? E >>> diff --git a/modules/database/src/std/rec/calcoutRecord.dbd.pod b/modules/database/src/std/rec/calcoutRecord.dbd.pod index 3e1dbd4a9..d427d28f2 100644 --- a/modules/database/src/std/rec/calcoutRecord.dbd.pod +++ b/modules/database/src/std/rec/calcoutRecord.dbd.pod @@ -70,38 +70,45 @@ fields. =fields INPA - INPL -=head3 Expression +=head3 Expressions -Like the Calc record, the Calcout record has a CALC field in which the -developer can enter an infix expression which the record routine will -evaluate when it processes the record. The resulting value is placed in the -VAL field. This value can then be used by the OOPT field (see -L) to determine whether or not to write to the output -link or post an output event. It can also be the value that is written to -the output link. The CALC expression is actually converted to opcode and -stored in Reverse Polish Notation in the RPCL field. It is this expression -which is actually used to calculate VAL. The Reverse Polish expression is -evaluated more efficiently during run-time than an infix expression. CALC -can be changes at run-time, and a special record routine will call a -function to convert it to Reverse Polish Notation. +Like the Calc record, the Calcout record's CALC field holds an infix expression +to be evaluated whenever the record is processed. +The resulting value is placed in the VAL field. + +The OOPT field condition is applied to VAL (see L) and +controls whether to write to the output link (or post a named event), and the +DOPT field selects whether VAL should be written, or another expression from +the OCAL field should be evaluated and used instead. + +The CALC and OCAL expressions get compiled into streams of Reverse Polish +Notation (RPN) opcodes for a stack-based machine, and stored in the RPCL and +ORPC fields respectively. + +The RPN opcodes are used to calculate VAL at run-time, and are more efficient +than evaluating the infix expression. +The CALC and OCAL expressions can be replaced at run-time, triggering a special +record routine to compile the new expression into Reverse Polish Notation. The infix expressions that can be used are very similar to the C expression -syntax, but with some additions and subtle differences in operator meaning -and precedence. The string may contain a series of expressions separated by -a semi-colon character ';' any one of which may actually provide the -calculation result; however all of the other expressions included must -assign their result to a variable. All alphabetic elements described below -are case independent, so upper and lower case letters may be used and mixed -in the variable and function names as desired. Spaces may be used anywhere -within an expression except between the characters that make up a single -expression element. +syntax, but with some additions and subtle differences in operator meaning and +precedence. +The string may contain a series of expressions separated by a semi-colon +character C<;>, any one of which may provide the calculation result. +All other expressions included in the string must assign their result to a +variable. +All alphabetic elements described below are case independent, so upper and lower +case letters may be used and mixed in the variable and function names as +desired. +Spaces may be used anywhere within an expression except between characters that +make up a single expression element. The range of expressions supported by the calculation record are separated into literals, constants, operands, algebraic operators, trigonometric operators, -relational operators, logical operator, the assignment operator, -parentheses and commas, and the question mark or '?:' operator. +relational operators, logical operators, the assignment operator, parentheses +and commas, and the question mark colon or C operator. -=fields CALC, VAL, RPCL +=fields CALC, VAL, OVAL, RPCL, ORPC =head3 Literals @@ -153,112 +160,205 @@ field, i.e. the VAL field for the CALC expression and the OVAL field for the OCAL expression. (These fields can be written to by CA put, so it might I be the result from the last time the expression was evaluated). -=head3 Algebraic Operations +=head3 Arithmetic Operators + +Except for unary minus these are infix binary operators. =over 1 =item * -C: Absolute value (unary) +C<+> : Addition =item * -C: Square root (unary) +C<-> : Subtraction =item * -C: Minimum (any number of args) +C<-> : Minus (unary) =item * -C: Maximum (any number of args) +C<*> : Multiplication =item * -C: returns non-zero if none of the arguments are NaN or Inf (any -number of args) +C : Division =item * -C: returns non-zero if any of the arguments is NaN or Inf (any number -of args) +C<%> : Modulo =item * -C: Ceiling (unary) +C<^> : Exponential =item * -C: Floor (unary) - -=item * -C: Floating point modulo (binary) **Added in 7.0.8** - -=item * -C: Log base 10 (unary) - -=item * -C: Natural log (unary) - -=item * -C: Natural log (unary) - -=item * -C: Exponential function (unary) - -=item * -C<^> : Exponential (binary) - -=item * -C<**> : Exponential (binary) - -=item * -C<+> : Addition (binary) - -=item * -C<-> : Subtraction (binary) - -=item * -C<*> : Multiplication (binary) - -=item * -C : Division (binary) - -=item * -C<%> : Modulo (binary) - -=item * -C: Negate (unary) +C<**> : Exponential =back -=head3 Trigonometric Operators +=head3 Algebraic Functions + +When functions take more than one argument, a comma separator must appear +between them. =over 1 =item * -C: Sine +C : Absolute value =item * -C: Hyperbolic sine +C : Exponential function =item * -C: Arc sine +C : Floating point modulo. Added in 7.0.8 =item * -C: Cosine +C : Natural log =item * -C: Hyperbolic cosine +C : Log base 10 =item * -C: Arc cosine +C : Natural log =item * -C: Tangent +C : Minimum =item * -C: Hyperbolic tangent +C : Maximum =item * -C: Arc tangent +C : Square root + +=item * +C : Square root + +=back + +=head3 Trigonometric Functions + +=over 1 + +=item * +C : Sine + +=item * +C : Arc sine + +=item * +C : Cosine + +=item * +C : Arc cosine + +=item * +C : Tangent + +=item * +C : Arc tangent + +=item * +C : 2-parameter Arc tangent. Arg's are reversed to ANSI C + +=back + +=head3 Hyperbolic Trigonometry Functions + +=over 1 + +=item * +C : Hyperbolic sine + +=item * +C : Hyperbolic cosine + +=item * +C : Hyperbolic tangent + +=back + +=head3 Numeric Functions + +=over 1 + +=item * +C : Ceiling + +=item * +C : Floor + +=item * +C : Round to nearest integer + +=item * +C : returns non-zero if any argument is Inf + +=item * +C : returns non-zero (true) if any argument is NaN +or Inf + +=item * +C : returns non-zero (true) if none of the +arguments are NaN or Inf + +=back + +=head3 Boolean/Logical Operators + +These operators use their arguments as a true (non-zero) or false (zero) value. + +=over 1 + +=item * +C<&&> : And, infix binary + +=item * +C<||> : Or, infix binary + +=item * +C : Not, unary prefix + +=back + +=head3 Bitwise Operators + +Mostly infix binary, the arguments are converted to a 32-bit integer, the +operator is applied, and the result converted back into a double. + +=over 1 + +=item * +C<&> : Bitwise and + +=item * +C<|> : Bitwise or + +=item * +C<~> : Bitwise not or one's complement, unary prefix + +=item * +C<<< << >>> : Arithmetic shift left + +=item * +C<<< >> >>> : Arithmetic shift right + +=item * +C<<<< >>> >>>> : Logical shift right + +=item * +C : Bitwise and + +=item * +C : Bitwise or + +=item * +C : Bitwise exclusive or + +=item * +C : Bitwise not or one's complement, unary prefix =back =head3 Relational Operators +These are all infix binary operators. + =over 1 =item * @@ -273,59 +373,17 @@ C<<< <= >>> : Less than or equal to =item * C<<< < >>> : Less than +=item * +C<<< != >>> : Not equal to + =item * C<<< # >>> : Not equal to =item * -C<<< = >>> : Equal to - -=back - -=head3 Logical Operators - -=over 1 +C<<< == >>> : Equal to =item * -C< && >: And - -=item * -C<||> : Or - -=item * -C : Not - -=back - -=head3 Bitwise Operators - -=over 1 - -=item * -C<|> : Bitwise Or - -=item * -C<&> : Bitwise And - -=item * -C : Bitwise Or - -=item * -C : Bitwise And - -=item * -C : Bitwise Exclusive Or - -=item * -C<~> : One's Complement - -=item * -C<<< << >>> : Arithmetic Left Shift - -=item * -C<<< >> >>> : Arithmetic Right Shift - -=item * -C<<<< >>> >>>> : Logical Right Shift +C<<< = >>> : Equal to (not assignment) =back @@ -338,24 +396,26 @@ C<:=> : assigns a value (right hand side) to a variable (i.e. field) =back -=head3 Parentheses, Comma, and Semicolon +=head3 Parantheses, Comma, and Semicolon -The open and close parentheses are supported. Nested parentheses are -supported. +The open C<(> and close parentheses C<)> are supported to override precedence +rules in a sub-expression. +Nested parentheses are supported to significant depth. -The comma is supported when used to separate the arguments of a binary -function. +The comma C<,> is required to separate the arguments of a function. -The semicolon is used to separate expressions. Although only one -traditional calculation expression is allowed, multiple assignment -expressions are allowed. +The semicolon C<;> is used to value separate expressions. +Exactly one value expression must be present, but multiple assignment +expressions may be included before and/or after the value expression. -=head3 Conditional Expression +=head3 Conditional Operator -The C language's question mark operator is supported. The format is: -C +The C language's question mark colon C ternary operator is supported. +The format is: -=head3 Expression Examples +I C I C<:> I + +=head2 Expression Examples =head3 Algebraic @@ -396,8 +456,8 @@ Result is C if C<<< (A + B) >= (C + D) >>> =back -Prior to Base 3.14.9 it was legal to omit the : and the second (else) part -of the conditional, like this: +Prior to Base 3.14.9 it was legal to omit the colon C<:> and the second (else) +part of the conditional, like this: C<<< (A + B)<(C + D) ? E >>> @@ -511,13 +571,14 @@ necessary, the record can use the result of the CALC expression to determine if data should be written and can use the result of the OCAL expression as the data to write. -If the OEVT field specifies a non-zero integer and the condition in the -OOPT field is met, the record will post a corresponding event. If the ODLY -field is non-zero, the record pauses for the specified number of seconds -before executing the OUT link or posting the output event. During this -waiting period the record is "active" and will not be processed again until -the wait is over. The field DLYA is equal to 1 during the delay period. The -resolution of the delay entry system dependent. +If the OEVT field isn't empty and the condition in the OOPT field is met, the +record will post the corresponding named event. +If the ODLY field is non-zero, the record pauses for the specified number of +seconds before executing the OUT link or posting the output event. +During this waiting period the record is "active" and will not be processed +again until the wait is over. +The field DLYA is equal to 1 during the delay period. The resolution of the +delay entry system dependent. The IVOA field specifies what action to take with the OUT link if the Calcout record enters an INVALID alarm status. The options are @@ -1277,8 +1338,8 @@ field IVOA. =item 3. The Alarm Severity is not INVALID or IVOA specifies "Continue Normally", -put the value of OVAL to the OUT link and post the event in OEVT (if -non-zero). +put the value of OVAL to the OUT link and post the event named in OEVT (if +not empty). =item 4. diff --git a/modules/libcom/src/calc/postfix.h b/modules/libcom/src/calc/postfix.h index 5d75a7ddf..07d9d6847 100644 --- a/modules/libcom/src/calc/postfix.h +++ b/modules/libcom/src/calc/postfix.h @@ -41,20 +41,18 @@ * few bytes smaller for some sizes. * * The maximum expansion from infix to postfix is for the sub-expression - \code - .1?.1: -\endcode - * which is 6 characters long and results in 21 bytes of postfix: -\code + * .1?.1: which is 6 characters long and results in 21 bytes of + * postfix: +\verbatim .1 => LITERAL_DOUBLE + 8 byte value ? => COND_IF .1 => LITERAL_DOUBLE + 8 byte value : => COND_ELSE ... => COND_END -\endcode +\endverbatim * For other short expressions the factor 21/6 always gives a big enough - * postfix buffer (proven by hand, look at '1+' and '.1+' as well). + * postfix buffer (proven by hand, look at \c 1+ and .1+ as well). */ #define INFIX_TO_POSTFIX_SIZE(n) ((n)*21/6) @@ -115,193 +113,207 @@ extern "C" { /** \brief Compile an infix expression into postfix byte-code * - * Converts an expression from an infix string to postfix byte-code + * Converts an expression from an infix string to postfix byte-code. * * \param pinfix Pointer to the infix string * \param ppostfix Pointer to the postfix buffer * \param perror Place to return an error code * \return Non-zero value in event of error * - * It is the caller's responsibility to ensure that \c ppostfix points - * to sufficient storage to hold the postfix expression. The macro - * INFIX_TO_POSTFIX_SIZE(n) can be used to calculate an appropriate - * postfix buffer size from the length of the infix buffer. + * It is the caller's responsibility to ensure that \p ppostfix points to + * sufficient storage to hold the postfix expression. + * The macro INFIX_TO_POSTFIX_SIZE(n) can be used to calculate an + * appropriate postfix buffer size from the length of the infix buffer. + * The macro's parameter \p n must count the terminating nil byte too. * - * \note "n" must count the terminating nil byte too. + * -# The **infix expressions** that can be used are very similar to the + * C expression syntax, but with some additions and subtle differences in + * operator meaning and precedence. + * The expression string may contain a series of expressions separated by + * a semi-colon character ; any one of which may actually provide + * the calculation result. + * However all of the other expressions included must assign their result + * to a variable. + * All alphabetic elements described below are case independent, so upper + * and lower case letters may be used and mixed in the variable and + * function names as desired. + * Spaces may be used anywhere within an expression except between the + * characters that make up a single expression element. + + * -# The simplest expression element is a **numeric literal,** any + * (positive) number expressed using the standard floating point syntax + * that can be stored as a double precision value. + * This now includes the values Infinity and NaN (not a number). + * Note that negative numbers will be encoded as a positive literal, to + * which the unary negate operator is applied. * - * -# The **infix expressions** that can be used are very similar - * to the C expression syntax, but with some additions and subtle - * differences in operator meaning and precedence. The string may - * contain a series of expressions separated by a semi-colon character ';' - * any one of which may actually provide the calculation result; however - * all of the other expressions included must assign their result to - * a variable. All alphabetic elements described below are case independent, - * so upper and lower case letters may be used and mixed in the variable - * and function names as desired. Spaces may be used anywhere within an - * expression except between the characters that make up a single expression element. + * Examples: + * - \c 1 + * - \c 2.718281828459 + * - \c Inf * - * -# ***Numeric Literals*** - * The simplest expression element is a numeric literal, any (positive) - * number expressed using the standard floating point syntax that can be stored - * as a double precision value. This now includes the values Infinity and - * NaN (not a number). Note that negative numbers will be encoded as a - * positive literal to which the unary negate operator is applied. - * - * - Examples: - * - 1 - * - 2.718281828459 - * - Inf - * - * -# ***Constants*** - * There are three trigonometric constants available to any expression + * -# There are three **trigonometric constants** available to any expression * which return a value: - * - pi returns the value of the mathematical constant pi. - * - D2R evaluates to pi/180 which, when used as a multiplier, - * converts an angle from degrees to radians. - * - R2D evaluates to 180/pi which as a multiplier converts an angle - * from radians to degrees. + * - \c pi returns the value of the mathematical constant pi. + * - \c D2R evaluates to pi/180 which, when used as a multiplier, + * converts an angle from degrees to radians. + * - \c R2D evaluates to 180/pi which as a multiplier converts an + * angle from radians to degrees. * - * -# ***Variables*** - * Variables are used to provide inputs to an expression, and are named - * using the single letters A through L inclusive or the keyword VAL which - * refers to the previous result of this calculation. The software that - * makes use of the expression evaluation code should document how the - * individual variables are given values; for the calc record type the input - * links INPA through INPL can be used to obtain these from other record fields, - * and VAL refers to the the VAL field (which can be overwritten from outside - * the record via Channel Access or a database link). + * -# **Variables** are used to provide inputs to an expression, and are + * named using the single letters \c A through \c L inclusive or the + * keyword \c VAL which refers to the previous result of this + * calculation. + * The software that makes use of the expression evaluation code should + * document how the individual variables are given values. + * For the calc and calcout record types the input links \c INPA through + * \c INPL can be used to obtain values from other record fields, and \c + * VAL refers to the the VAL field (which can be overwritten from + * outside the record via Channel Access or a database link). * - * -# ***Variable Assignment Operator*** - * Recently added is the ability to assign the result of a sub-expression to - * any of the single letter variables, which can then be used in another - * sub-expression. The variable assignment operator is the character pair - * := and must immediately follow the name of the variable to receive the - * expression value. Since the infix string must return exactly one value, every + * -# The **Variable Assignment Operator** was added in 3.14.9 and + * provides the ability to assign the result of a sub-expression to any + * of the single letter variables, which can then be used in later + * sub-expressions. + * The variable assignment operator is the character pair := and + * must immediately follow the name of the variable to receive the + * expression value. + * Since the infix string must return exactly one value, every * expression string must have exactly one sub-expression that is not an - * assignment, which can appear anywhere in the string. Sub-expressions within - * the string are separated by a semi-colon character. + * assignment, which can appear anywhere in the string. + * Sub-expressions within the string are separated by a semi-colon + * character ; . * - * - Examples: - * - B; B:=A - * - i:=i+1; a*sin(i*D2R) + * Examples: + * - B; B:=A + * - i:=i+1; a*sin(i*D2R) * - * -# ***Arithmetic Operators*** - * The usual binary arithmetic operators are provided: + - * and / with their - * usual relative precedence and left-to-right associativity, and - may also - * be used as a unary negate operator where it has a higher precedence and - * associates from right to left. There is no unary plus operator, so numeric - * literals cannot begin with a + sign. + * -# The standard binary **Arithmetic Operators** are provided: + - + * * and \c / with their usual relative precedence and + * left-to-right associativity. + * A minus sign \c - may also be used as a unary negate operator where + * it has a higher precedence and associates from right to left. + * There is no unary plus operator, so numeric literals cannot begin + * with a plus sign \c + . * - * - Examples: - * - a*b + c - * - a/-4 - b + * Examples: + * - a*b + c + * - a/-4 - b * - * Three other binary operators are also provided: % is the integer modulo operator, - * while the synonymous operators ** and ^ raise their left operand to the power of - * the right operand. % has the same precedence and associativity as * and /, while - * the power operators associate left-to-right and have a precedence in between * and - * unary minus. + * Three other binary operators are also provided: + * \c % is the integer modulo operator, while the synonymous operators + * \c ** and \c ^ raise their left operand to the power of the right + * operand. + * \c % has the same precedence and associativity as \c * and \c /, + * while the power operators associate left-to-right and have a + * precedence in between \c * and unary minus \c - . * - * - Examples: - * - e:=a%10 - * - d:=a/10%10 - * - c:=a/100%10 - * - b:=a/1000%10 - * - b*4096+c*256+d*16+e - * - sqrt(a**2 + b**2) + * Examples: + * - e:=a%10 + * - d:=a/10%10 + * - c:=a/100%10 + * - b:=a/1000%10 + * - b*4096+c*256+d*16+e + * - sqrt(a**2 + b**2) * - * -# ***Algebraic Functions*** - * Various algebraic functions are available which take parameters inside - * parentheses. The parameter separator is a comma. + * -# Various **Algebraic Functions** are available which take parameters + * inside parentheses. + * The parameter separator is a comma , . * - * - Absolute value: abs(a) - * - Exponential ea: exp(a) - * - Logarithm, base 10: log(a) - * - Natural logarithm (base e): ln(a) or loge(a) - * - n parameter maximum value: max(a, b, ...) - * - n parameter minimum value: min(a, b, ...) - * - Square root: sqr(a) or sqrt(a) - * - Floating point modulo: fmod(num, den) - * \since The fmod() function was added in 7.0.8 + * - Absolute value: \c abs(a) + * - Exponential ea: \c exp(a) + * - Logarithm, base 10: \c log(a) + * - Natural logarithm (base e): \c ln(a) or \c loge(a) + * - n parameter maximum value: max(a, b, ...) + * - n parameter minimum value: min(a, b, ...) + * - Square root: \c sqr(a) or \c sqrt(a) + * - Floating point modulo: fmod(num, den) + *
The \c fmod() function was added in 7.0.8 * - * -# ***Trigonometric Functions*** - * Standard circular trigonometric functions, with angles expressed in radians: - * - Sine: sin(a) - * - Cosine: cos(a) - * - Tangent: tan(a) - * - Arcsine: asin(a) - * - Arccosine: acos(a) - * - Arctangent: atan(a) - * - 2 parameter arctangent: atan2(a, b) - * \note Note that these arguments are the reverse of the ANSI C function, - * so while C would return arctan(a/b) the calc expression engine returns arctan(b/a) + * -# Standard circular **Trigonometric Functions** exist with angles + * expressed in radians: * - * -# ***Hyperbolic Trigonometry*** - * The basic hyperbolic functions are provided, but no inverse functions - * (which are not provided by the ANSI C math library either). - * - Hyperbolic sine: sinh(a) - * - Hyperbolic cosine: cosh(a) - * - Hyperbolic tangent: tanh(a) + * - Sine: \c sin(a) + * - Cosine: \c cos(a) + * - Tangent: \c tan(a) + * - Arcsine: \c asin(a) + * - Arccosine: \c acos(a) + * - Arctangent: \c atan(a) + * - 2 parameter arctangent: atan2(a, b) + *
Note that the \c atan2 arguments are the reverse of the ANSI C + * function, so while C would return \c arctan(a/b) the calc + * expression engine returns \c arctan(b/a) * - * -# ***Numeric Functions*** - * The numeric functions perform operations related to the floating point - * numeric representation and truncation or rounding. - * - Round up to next integer: ceil(a) - * - Round down to next integer: floor(a) - * - Round to nearest integer: nint(a) - * - Test for infinite result: isinf(a) - * - Test for any non-numeric values: isnan(a, ...) - * - Test for all finite, numeric values: finite(a, ...) - * - Random number between 0 and 1: rndm + * -# The basic **Hyperbolic Trigonometry** functions are provided, but + * no inverse functions (which aren't provided by the ANSI C math + * library either). * - * -# ***Boolean Operators*** - * These operators regard their arguments as true or false, where 0.0 is - * false and any other value is true. + * - Hyperbolic sine: \c sinh(a) + * - Hyperbolic cosine: \c cosh(a) + * - Hyperbolic tangent: \c tanh(a) * - * - Boolean and: a && b - * - Boolean or: a || b - * - Boolean not: !a + * -# These **Numeric Functions** perform operations related to the + * floating point numeric representation and truncation or rounding. * - * -# ***Bitwise Operators*** - * Most bitwise operators convert their arguments to 32-bit signed integer (by - * truncation), perform the appropriate bitwise operation, then convert back - * to a floating point value. The arithmetic right shift operator >> thus - * retains the sign bit of the left-hand argument. The logical right shift - * operator >>> is performed on an unsigned integer though, so injects zeros - * while shifting. The right-hand shift argument is masked so only the lower - * 5 bits are used. Unlike in C, ^ is not a bitwise exclusive-or operator. + * - Round up to next integer: \c ceil(a) + * - Round down to next integer: \c floor(a) + * - Round to nearest integer: \c nint(a) + * - Test for infinite result: \c isinf(a) + * - Test for any non-numeric values: isnan(a, ...) + * - Test for all finite, numeric values: finite(a, ...) + * - Random number between 0 and 1: \c rndm * - * - Bitwise and: a & b or a and b - * - Bitwise or: a | b or a or b - * - Bitwise exclusive or: a xor b - * - Bitwise not (ones complement): ~a or not a - * - Arithmetic left shift: a << b - * - Arithmetic right shift: a >> b - * - Logical right shift: a >>> b + * -# The **Boolean Operators** evaluate their arguments as true or + * false, where \c 0.0 is false and any other value is true. * - * -# ***Relational Operators*** - * Standard numeric comparisons between two values: + * - Boolean and: a && b + * - Boolean or: a || b + * - Boolean not: \c !a * - * - Less than: a < b - * - Less than or equal to: a <= b - * - Equal to: a = b or a == b - * - Greater than or equal to: a >= b - * - Greater than: a > b - * - Not equal to: a != b or a # b + * -# Most **Bitwise Operators** convert their arguments to 32-bit signed + * integer (by truncation), perform the appropriate bitwise operation, + * then convert back to a floating point value. + * The arithmetic right shift operator \c >> thus retains the sign bit of + * the left-hand argument. + * The logical right shift operator \c >>> is performed on an unsigned + * integer though, so it injects zeros while shifting. + * The right-hand shift argument is masked so only the lower 5 bits are + * used. + * Unlike in C, \c ^ is not a bitwise exclusive-or operator. * - * -# ***Conditional Operator*** - * Expressions can use the C conditional operator, which has a lower - * precedence than all of the other operators except for the assignment operator. + * - Bitwise and: a & b or a and b + * - Bitwise or: a | b or a or b + * - Bitwise exclusive or: a xor b + * - Bitwise not (ones complement): ~a or not a + * - Arithmetic left shift: a << b + * - Arithmetic right shift: a >> b + * - Logical right shift: a >>> b * - * - condition ? true result : false result - * - Example: - * - a < 360 ? a+1 : 0 + * -# The **Relational Operators** perform numeric comparisons between + * two double-precision values: * - * -# ***Parentheses*** - * Sub-expressions can be placed within parentheses to override operator presence rules. - * Parentheses can be nested to any depth, but the intermediate value stack used by - * the expression evaluation engine is limited to 80 results (which require an - * expression at least 321 characters long to reach). + * - Less than: a < b + * - Less than or equal to: a <= b + * - Equal to: a = b or a == b + * - Greater than or equal to: a >= b + * - Greater than: a > b + * - Not equal to: a != b or a # b + * + * -# Expressions can use the C **Conditional Operator**, which has a + * lower precedence than all of the other operators except for the + * assignment operator. + * + * - \a condition ? \a true-expression : + * \a false-expression + * - Example: + * a < 360 ? a+1 : 0 + * + * -# Sub-expressions can be placed within **Parentheses** () + * to override operator presence rules. + * Parentheses can be nested to any depth, but the intermediate value + * stack used by the expression evaluation engine is limited to 80 + * results (which takes an expression at least 321 characters long to + * reach). */ LIBCOM_API long postfix(const char *pinfix, char *ppostfix, short *perror); @@ -310,10 +322,12 @@ LIBCOM_API long * * Evaluates the postfix expression against a set ot input values. * - * \param parg Pointer to an array of double values for the arguments A-L - * that can appear in the expression. Note that the argument values may be - * modified if the expression uses the assignment operator. - * \param presult Where to put the calculated result, which may be a NaN or Infinity. + * \param parg Pointer to an array of double values for the arguments + * \c A-L that can appear in the expression. + * Note that the argument values may be modified if the expression uses + * the assignment operator. + * \param presult Where to put the calculated result, which may be a NaN + * or Infinity. * \param ppostfix The postfix expression created by postfix(). * \return Status value 0 for OK, or non-zero if an error is discovered * during the evaluation process.