Mapping String Calculation Operands


Topics


Specifying a calculation operand

Introduction to the calculator

Specifying numeric literals

Specifying large numeric literals

Expression Operators

Operation and use of calculations in mapping strings

Calculator command-line test program


Specifying a calculation operand


For the sequence items SD and SX, and the numeric conversion items DD, DX, XD and XX, you are allowed to perform arithmetic operations on the value before it is formatted as a numeric value.  This is done by specifying a calculation operand, which is a string operand containing an arithmetic expression string.  The expression string is processed by a calculation function, which evaluates the expression and produces a numeric result, which in turn is formatted by the SD, SX, DD, DX, XD and XX mapping items.


You can invoke an SPFLite primary command from an SPFLite macro, using the built-in macro function SPF_Cmd().  When you do this, and your SPFLite command is a CHANGE command with a mapping string (a string-2 operand with an M string), the mapping string can contain one or more SD, SX, DD, DX, XD or XX mapping items, which in turn may have calculation operands.


You can also invoke the calculation function directly from an edit macro, using the built-in function SPF_Calc().  See the macro documentation for more information, by issuing the command HELP MACRO from the SPFLite primary command line.


You are likely to find the calculation function will allow you to perform any calculations you might need in connection with your use of mapping strings, and then some.  The design of the calculation features was made with future enhancements and developments of SPFLite in mind.




Introduction to the calculator


The calculation function has the following features.


    1. The calculation function accepts a calculation operand as a string value, containing one or more arithmetic expressions.  It processes this string and produces a numeric result.  Only integer calculations are performed.  The string is treated as case-insensitive.


    1. The calculation operand may contain one or more expressions, separated by ; semicolons.  The main reason to specify more than one expression is to perform assignments to more than one variable, as generally only one variable is assigned per expression.  In this sense, “expressions” are somewhat like “statements” in a programming language, although as used in the calculation function, it is not quite so formal.  The last or only expression may optionally omit the final ; semicolon.  Extra semicolons are ignored.


    1. The calculation function operates with 64-bit integer arithmetic, which has a capacity of 19 decimal digits or 16 hex digits.  The highest decimal value is 9,223,372,036,854,775,807 and so there are actually 18 full decimal digits available.  Note that no check is made for numeric overflow. For applications involving the editor, it is unlikely you would exceed this limit.


    1. When the calculation function is called, it is provided with an initial value.  For the numeric conversion items DD, DX, XD and XX, the initial value is the number acquired by the mapping item, and for the sequence items SD and SX, the initial value is the sequence number.  When you invoke the calculation function from an edit macro using the built-in function SPF_Calc(), the initial value is one of the supplied arguments.


    1. The calculation function provides 26 variables named A through Z, which you can use like variables in a conventional program.  These variables are 64-bit integer values, which can be read and modified.  A variable is read by its appearance as a term in an expression, and is modified by being on the left side of an assignment or swap operator.  The variable names are case insensitive.


    1. When the calculation function begins, the variables are pre-initialized as follows:


    1. For variable S, the sequence number value associated with it is the ordinal number of the order in which a string was found during a CHANGE ALL command.  During the course of a CHANGE ALL operation that contains a mapping string, which in turn contains a calculation operand, the first string so found has a sequence number of 1, the second has a sequence number of 2, etc.  You can use this information to tailor the way you calculate the value returned from your expression.  For instance, you may wish to develop a sequence number as a prefix or suffix of some name or string, or, you may wish to enumerate paragraphs or sections of a document that are not amenable to the use of the Enumeration keyboard functions (which require aligned columns of numbers).  If you use the calculation function in a context for which there is no defined sequence number, variable S will contain zero.


    1. After you perform your calculations, the calculation function determines and returns a final value as follows:



Because the calculation function will often be used for very simple calculations, a further expression simplification is supported.  When the leftmost part of the calculation operand is a binary operator, it is assumed that the expression is preceded by an implied X variable.  When the calculation operand begins with + or these are assumed to be binary operators (not unary), with an implied X on the left.  For instance, a calculation operand of +5 will be assumed to mean X+5, and then this will be treated as described in the preceding paragraph


When you use this shortcut, you must ensure that the resulting expression, including the implied X variable, is syntactically correct.


The X variable is not implied when the calculation operand has a leading operator that is only used as unary.  For example, a calculation operand of !4 would not imply X!4 because ! is the unary NOT operator.  Thus, !4 would calculate the value of !4 without reference to variable X.


The only case where this could be an issue is if you needed a leading + or unary operator, since the implied X rules would be used, and a calculation adding to or subtracting from X would be performed.  An actual unary + operator is never algebraically required, and can be omitted.  However, if you needed an expression like ‑4*S and did not want this to mean, X-4*S, you would need to change your calculation operand.  For the unary operator, if you really need to begin your expression this way, you can do any of the following:


- Precede the initial unary operator with a ; semicolon.

       example:  ;-4*S


- Precede the initial unary operator with a 0, which is numerically the same.

       example:  0-4*S


- Enclose the term having the initial unary operator in parentheses.

       example:  (-4)*S    or    (-4*S)


- Rewrite the expression so it does not begin with an initial unary operator.

       example:  S*-4    or    4*-S


- Rewrite the expression so it explicitly assigns variable R or X.

       example:  R=-4*S











Specifying numeric literals


Literals may be specified in decimal or hex.  You can optionally use underscores for readability with large numbers, and these will be ignored.





Specifying large numeric literals


The calculation function provides a means to concisely specify large decimal and hex values that have repeating digits.  It is somewhat similar to E notation commonly used for floating point numbers, but the same syntax provided will work in both decimal and hex integers (the E notation would not work in hex, since E is a hex digit) and is more flexible.


Large numbers may be required in applications involving calculations of checksums, hash keys or encryption values on your user data.


If your work does not involve large numbers, you can skip the rest of this section.


The large number syntax relies on three suffixes, comparable to floating-point E notation, namely a “Low Suffix”, a “High Suffix” and a “Repeated Suffix”.  These are used the same as you might specify a floating point value of 5E4 to mean 50000.0.  A number may have only one suffix, which appears at the end of the number without any intervening blanks.  These suffixes operate as follows:







The decimal number in a suffix is limited to 2 digits.  Its value may not exceed 19 for a decimal number or 16 for a hex number; the minimum value is 1 in both cases.  Additionally, the suffix cannot cause the final number of digits to exceed 19 for a decimal number or 16 for a hex number.  If the decimal number in a suffix is outside these limits, a syntax error is detected and the calculation halts.  For the mapping string, the returned value will be unchanged from the initial value.  Readability underscores in numbers are ignored and do not affect the maximum number of digits allowed.




Expression Operators


The following table describes the operators, their precedence and associativity.  Operators with higher precedence are performed ones with lower precedence.  Higher-precedence operators are listed with higher precedence numbers.  Operators at level 15, if present, are performed first, while operators at level 1, if present, are performed last.


This precedence follows the traditional C language expression syntax and semantics.  As is true of many beginning C programmers, some may find the extensive number of operators and precedence levels to be intimidating.  However, experience has shown that this arrangement actually implements the most frequently desired choice of actions, in cases where specifying the fewest number of parentheses is desired.  Of course, whenever in doubt, you are free to use parentheses as needed to clarify to the calculation function and to yourself what your intentions are.


Headings:


LTR = Left to Right

RTL = Right to Left

NON = Non-Associative.  Some operators are non-associative, because allowing two or more such operators in a row (without using parentheses) may be ambiguous or confusing.


Note:  Even where operators may be LTR or RTL, expressions must still be written carefully and properly.  For example, R = X < Y < Z is a “valid” expression, but it probably will not do what you want.  First, X < Y is evaluated; if true, its value 1, else 0.  Then, Z is compared to that result, so that you would be either be comparing 0 < Z or 1 < Z.  If your intent was to determine if X, Y and Z were in numeric order, the right way to do that is with R = (X < Y) && (Y < Z).




Oper

Prec

Assoc

Description

Asgn

+

15

RTL

Unary arithmetic positive, ignored except to clarify an expression.  Not needed, but supported to conform to conventional usage.

n/a

-

15

RTL

Unary arithmetic negation

n/a

!

15

RTL

Unary logical not

If X = 0, !X = 1

If X not = 0, !X = 0

n/a

~

15

RTL

Unary bitwise negation (one’s complement)

n/a

@

15

RTL

Unary absolute value, like ABS function in Basic

If X < 0, @X = –X

If X >= 0, @X = X

n/a

$

15

RTL

Unary sign function, like SGN function in Basic

If X < 0, $X = –1

If X = 0, $X = 0

If X > 0, $X = 1

n/a

$$

15

RTL

Unary sign index function, like 2+SGN function in Basic

If X < 0, $X = 1

If X = 0, $X = 2

If X > 0, $X = 3

n/a






*

14

LTR

Multiply


/

14

LTR

Integer divide


%

\

14

14

LTR

LTR

Modulus (remainder)

% is the C language operator, \ is a common alternative notation.  Both have same meaning and are interchangeable.


Note that Integer Divide and Modulus (remainder) operators calculate in such a way that the quotient and remainder will have the same absolute values regardless of the signs of the dividend and divisor.  This is done by doing a preliminary Divide or Modulus using the absolute values of the numeric terms, and then correcting the signs afterwards.  Attempting a Divide or Modulus with a right-hand term of zero is an error which will halt the calculation and the mapping string that contains it.

Yes






+

13

LTR

Add

Yes

-

13

LTR

Subtract

Yes






<<

12

LTR

Bitwise (unsigned) shift left.  Zero bits are filled on the right.


If you shift with a negative shift amount, it will reverse the direction of the shift.  An expression of X << 4 will shift left 4 bits, while an expression of X << –4 will operate the same as X >> 4.  The determination of a negative shift amount is not just a matter of an explicit minus sign operator, but is based on the evaluation of the expression.

Yes

>>

12

LTR

Bitwise (unsigned) shift right.  Zero bits are propagated on the left.


If you shift with a negative shift amount, it will reverse the direction of the shift.  An expression of X >> 4 will shift right 4 bits, while an expression of X >> –4 will operate the same as X << 4.  The determination of a negative shift amount is not just a matter of an explicit minus sign operator, but is based on the evaluation of the expression.

Yes

+>

12

LTR

Numeric (signed) shift right.  The sign bit is propagated on the left.


If you shift with a negative shift amount, it will reverse the direction of the shift.  An expression of X +> 4 will shift right 4 bits, while an expression of X +> –4 will operate the same as X << 4.  The determination of a negative shift amount is not just a matter of an explicit minus sign operator, but is based on the evaluation of the expression.


The operator +> is equivalent to the >>> operator in Java.

Yes






#

12

LTR

Numeric scale


In the expression X # S, the value X is divided by S.  Each division operation is counted, with the first one treated as division number 1.  After division, a test is made to see if the result is 0; if so, the # operator halts; otherwise, the quotient is divided again and process repeats.  The result of the # operator is the count of the number of divisions performed.  If S < 2, X # S produces 0.


When S is 10, X # S  is the number of decimal digits required to represent X.  For example, 123456 # 10 will produce 6.  


When X is zero and S >= 2, X # S will produce 1.

Yes






##

12

LTR

Bitwise scale


In the expression X ## S, the value X is unsigned-shifted right by S, the same as done by X >> S.  Each shift operation is counted, with the first one treated as shift number 1.  After a shift, a test is made to see if the result is 0; if so, the ## operator halts; otherwise, the result is shifted again and process repeats.  The result of the ## operator is the count of the number of shifts performed.  


If S < 1 or S > 63, X ## S produces 0.


When S is 4, X ## S will report the number of hex digits required to represent X.    For example, .FF123 ## 4 will produce 5.  When S is 1, X ## S  is the number of binary digits (bits) required to represent X.  


When X is zero, and 1<=S<=63 , X ## S will produce 1.

Yes






>

11

LTR

Greater Than.


If X is > Y, the value of X > Y is 1.

If X is not > Y, the value of X > Y is 0.

No

<

11

LTR

Less Than.


If X is < Y, the value of X < Y is 1.

If X is not < Y, the value of X < Y is 0.

No

>=

11

LTR

Greater Than or Equal To.


If X is >= Y, the value of X >= Y is 1.

If X is not >= Y, the value of X >= Y is 0.

No

<=

11

LTR

Less Than or Equal To.


If X is <= Y, the value of X <= Y is 1.

If X is not <= Y, the value of X <= Y is 0.

No






!>

11

LTR

Not Greater Than.  This operator is equivalent to a MIN function in some programming languages.


In the expression X !> Y, the intent is to limit the value of X such that it is not greater than Y.  


If X is > Y, the value of X !> Y is Y.  

If X is not > Y, the value of X !> Y is X.

No

!<

11

LTR

Not Less Than.  This operator is equivalent to a MAX function in some programming languages.


In the expression X !< Y, the intent is to limit the value of X such that it is not less than Y.  


If X is < Y, the value of X !< Y is Y.  

If X is not < Y, the value of X !< Y is X.

No

!>=

11

LTR

Not Greater Than or Equal To


In the expression X !>= Y, the intent is to limit the value of X such that it is not greater than or equal to Y.  


If X is >= Y, the value of X !>= Y is Y1 .  

If X is not >= Y, the value of X !>= Y is X.

No

!<=

11

LTR

Not Less Than or Equal To


In the expression X !<= Y, the intent is to limit the value of X such that it is not less than or equal to Y.  


If X is <= Y, the value of X !<= Y is Y+1.  

If X is not <= Y, the value of X !=< Y is X.

No






!=

<>

10

10

LTR

LTR

Not Equal To


!= is the C language operator, <> is a common alternative notation.  Both have same meaning and are interchangeable.


If X is equal to Y, the value of X <> Y is 0.

If X is not equal Y, the value of X <> Y is 1.

No

==

10

LTR

Equal To.   == is the C language operator.


If X is not equal to Y, the value of X == Y is 0.

If X is equal Y, the value of X == Y is 1.

No






=

10

LTR

Equal To.  The calculation function defines the = operator by context.  When it appears enclosed within () parentheses , the = operator is treated as an alias for the == comparison operator, meaning it has the same priority and associativity.  


When = appears with [] set enclosures or is not enclosed, it is treated the same as the := explicit assignment operator.  Only one unenclosed = may appear in a given statement or set clause.  This means that expressions like  X = Y = Z are illegal.


The calculation function performs this context determination in order to prevent common misuse of = and == inside of comparison sub-expressions, to help prevent errors.


Because a plain = outside of parentheses is assumed to be an assignment, if you wanted to perform a comparison instead, you must either use an explicit == comparison operator, or put the expression with = in parentheses.

No






&

9

LTR

Bitwise AND

Yes

^

8

LTR

Bitwise XOR

Yes

|

7

LTR

Bitwise OR

Yes

&&

6

LTR

Logical AND.  X && Y  is equivalent to !!X & !!Y.

If X=0 or Y=0, X && Y = 0

If X not = 0 and Y not = 0, X && Y = 1

Yes

^^

5

LTR

Logical XOR.   X ^^ Y is equivalent to  !!X ^ !!Y.  The operator returns 1 if X and Y are logically different.


If X=0 and Y=0, X ^^ Y = 0

If X = 0 and Y not = 0, X ^^ Y = 1

If X not = 0 and Y = 0, X ^^ Y = 1

If X not = 0 and Y not = 0, X ^^ Y = 0

Yes

||

4

LTR

Logical OR.  X || Y  is equivalent to !!X | !!Y.


If X=0 and Y=0, X || Y = 0

If X not = 0 or Y not = 0, X || Y = 1

Yes






::

3

NON

Swap variables.  Both the left-hand operand and the right-hand operand must be variables.  The contents of the two variables are swapped.  


It is not an error if the two variables are the same, but this would serve no purpose.


Once the operator is executed, the value of the expression as a whole is the value of the variable on the left side after the swap occurs.  That is, after X :: Y is performed, the value of the expression will be the new value of X which will be the former value of Y.

No






<:

3

NON

Conditional swap variables for <=


Both the left-hand operand and the right-hand operand must be variables.  The operator implements a “sorting” or “ordering” function.  In the expression X <: Y, the intent is to conditionally swap the contents of the two variables, if necessary, so that the relationship  X <= Y holds true.  If X <= Y is already true, no swap occurs.    If X <= Y is false, a swap occurs.


It is not an error if the two variables are the same, but this would serve no purpose.


Once the operator is executed, the value of the expression as a whole is the value of the variable on the left side, whether swapped or not.  That is, after X <: Y is performed, the value of the expression will be the new value of X which will be the former value of Y if a swap occurred, otherwise it will be the former value of X.

No






>:

3

NON

Conditional swap variables for >=


Both the left-hand operand and the right-hand operand must be variables.  The operator implements a “sorting” or “ordering” function.  In the expression X >: Y, the intent is to conditionally swap the contents of the two variables, if necessary, so that the relationship  X >= Y holds true.  If X >= Y is already true, no swap occurs.    If X >= Y is false, a swap occurs.


It is not an error if the two variables are the same, but this would serve no purpose.


Once the operator is executed, the value of the expression as a whole is the value of the variable on the left side, whether swapped or not.  That is, after X >: Y is performed, the value of the expression will be the new value of X which will be the former value of Y if a swap occurred, otherwise it will be the former value of X.

No






[ ]

2

RTL

Set expression


A set expression provides a means both to evaluate expressions conditionally, and to do a simple table-lookup operation.


The general form of a set expression is:


expr select [ expr 1 , expr 2 ,expr n ]


Each expression inside the brackets is called a set clause.


The selector expression is evaluated.


  • If the value of the selector expression expr select is 1, then expr 1 becomes the value of the set clause.    


  • If the value of the selector expression expr select is 2, then expr 2 becomes the value of the set clause, etc.  


  • If the value of the selector expression expr select is < 1 or > n then expr n becomes the value of the set clause.


If your selector expression is a conditional operator, in which true expressions evaluate to 1 and false expressions evaluate to 0, you would write an expression that used such a condition like this:


conditionalExpression [ truePart , falsePart ]


For example, if you wanted a value of 123 if X is greater than 5, otherwise a value of 456, you would use:


X > 5 [123, 456]


Here, if X>5 is true, the condition evaluates to 1, and the first set clause (123) is selected. If X>5 is false, the condition evaluates to 0, which is an out-of-bounds set selector, resulting in the last set clause of the set expression (456) being selected by default.


Suppose you wanted to set the return variable R (or other variable) to one of these two values.  In a programming language, you might do this with a statement something like,


if x > 5 then r = 123 else r = 456 endif


In a calculation operand, you could do the same thing with:


R = X > 5 [123, 456]


You are allowed to use assignment operators within a set expression.  For example, if you wanted a value of 123 assigned to variable R if X is greater than 5, otherwise a value of 456, you can rewrite the expression above as:


X > 5 [R=123, R=456]


When you use such expressions, only the selected set clause is executed, including any variable assignments within it; the remainder is skipped.  Variable assignment operators in set clauses that are not selected are not performed.


If you want to use a set expression to look up values, you write the set clauses in the order you want the selector expression to choose them.  Suppose variable X was supposed to be from 1 to 3, and you wanted this converted to some special values, but set to 0 if it was out of range.  You could do that with a set expression like this:


X[123,456,789,0]


n/a






=

1

NON

Assignment.  The calculation function defines the = operator by context.  When it appears within parentheses, the = operator is treated as an alias for the == comparison operator.  When = appears with [] set enclosures or not enclosed, it is treated the same as the := operator.  Only one unenclosed = may appear in a given statement or set clause.  


This means that expressions like  X = Y = Z are illegal, because when the = operator is considered an assignment operator, it is non-associative.  That means the second equal sign has neither higher nor lower precedence than the first one, but is simply illegal.  The first = equal sign between X and Y is valid, but the one between Y and Z is invalid.  The reason this is done is to prevent confusing the intent of the expression.


If the intent is to compare Y and Z for equality, and assign the comparison result to X, use X = (Y = Z)  or  X = Y == Z.  


If the intent is to first assign Z to Y, then assign Y to X, use X = Y := Z  or  X := Y := Z.


The calculation function performs this context determination in order to prevent common misuse of = and == inside of comparison sub-expressions.


The left-hand operand must be a variable name.  The value of an assignment expression is the value assigned to the variable.

n/a






:=

1

RTL

Assignment.  The left-hand operand must be a variable name.  The value of an assignment expression is the value assigned to the variable.  


The := operator may be used in chained assignments (as shown above) and inside of parentheses and set expressions.

n/a




Operation and use of calculations in mapping strings


As noted in the beginning of this article, calculation operands can be used with the sequence mapping items SD and SX, and the numeric conversion mapping items DD, DX, XD and XX in mapping strings.


For a complete description of mapping strings, see Working with Mapping Strings.  For concise information on specific mapping commands, see Mapping Strings Quick Reference Syntax and Examples.


Here are some brief examples.



1.  Suppose you want to find some “words” and append a dash and a decimal numeric suffix to them.   The first “word” gets a sequence number 1, the second get 2, etc.  Let’s say your data looks like this:


000151 *****    one    +++

000152 *****    two    +++

000153 *****    three   +++

000154 *****    four    +++


You can find “word” strings of varying length with a Regular Expression of R'[a-z]+'.   In order for the sequence number mechanism of mapping strings to function, you will have to use ALL in your CHANGE command.


For the M string portion, you will want to do the following:


If you want the shortest possible number used as the numeric suffix, you would use the Varying length format, with SDV or just SD alone.  If you wanted a fixed number of digits (say, 4) you would specify a command like SD4F.


Put that all together, and your CHANGE command would look like this:


       CHANGE ALL R'[a-z]+' M"1+ '-' SD4F"


That would change your data as follows:


000151 *****    one-0001    +++

000152 *****    two-0002    +++

000153 *****    three-0003   +++

000154 *****    four-0004    +++


You will note that you can do all the above without the need of a calculation operand.   But, suppose you didn’t want the suffix to be a value from 1 by 1, but a value from 0 by 20 plus a constant of 5.  The SD command alone can’t do that, but used with a calculation operand, it can.  


Recall from the description of the pre-initialized values for calculation variables, variable S will contain the value of the original sequence number.  In this example, that original sequence number ranges from 1 to 4.  To get the numbers the way you want, you would have to subtract one from the sequence number, multiply it by 20, and then add 5.  To make that the returned value, you would then assign the result to variable R.  You would specify this in a calculation operand as R=(S-1)*20+5.  You incorporate the calculation operand into the mapping string and issue your command like this:


       CHANGE ALL R'[a-z]+' M"1+ '-' SD4F'R=(S-1)*20+5'"


That would change your data as follows:


000151 *****    one-0005    +++

000152 *****    two-0025    +++

000153 *****    three-0045   +++

000154 *****    four-0065    +++



2.  Continuing with the first example, suppose what you wanted was, not to append a sequential number, but the actual line number where the data lines are found.  Let’s say our data is similar to the first example, but there are excluded lines between them:


****** ****************** Top of Data *******************

------ -------------------------------- < 000150 > ------

000151 *****    one    +++

------ -------------------------------- < 000010 > ------

000162 *****    two    +++

------ -------------------------------- < 000012 > ------

000175 *****    three   +++

------ -------------------------------- < 000014 > ------

000190 *****    four    +++

****** ***************** Bottom of Data *****************



We can accomplish this basically the same way as in example 1.  We will again use the SD command.  


You might wonder how we can use SD if we are not going to use the sequence number in the value.  The answer is that when SD has a calculation operand, the calculation function is called and variables get pre-initialized as described above.  However, there is no requirement that SD or any of the other mapping commands that can use a calculation operand must reference variable S or any other variable.  For our second example here, we will simply ignore variable S.  The reason SD is the right command to use is that we want to “generate” a number that is not based on our input data – which here consists of words, rather than numbers.


The calculation operand here will be very simple.  Variable L contains the line number where the CHANGE command finds the words in question.  We just have to make sure than only non-excluded lines are affected, and change the calculation operand to copy the value of variable L to variable R.


You would issue your command like this:


       CHANGE ALL NX R'[a-z]+' M"1+ '-' SD4F'R=L'"


That would change your data as follows:


****** ****************** Top of Data *******************

------ -------------------------------- < 000150 > ------

000151 *****    one-0151    +++

------ -------------------------------- < 000010 > ------

000162 *****    two-0162    +++

------ -------------------------------- < 000012 > ------

000175 *****    three-0175   +++

------ -------------------------------- < 000014 > ------

000190 *****    four-0190    +++

****** ***************** Bottom of Data *****************



3.  Converting data to a hash key.  This is just a made-up example, but it may give you some idea of what you can do with calculation operands, when you have an elaborate computation to perform.  


Suppose you had a series of 5-digit numbers, and you want to calculate a hash value.  You have various issues to contend with:


Since we want to process original numeric data, this requires a DD command instead of SD.  To keep the example simple, the data will be in fixed columns:


****** ****************** Top of Data *******************

000001 19453

000002 48470

000003 03085

000004 66247

****** ***************** Bottom of Data *****************


The numbers themselves are found with a picture of P'#####' 1 5, and variable X is set to this value.  The result string will be 4 digits, so the basic DD command will appear as DD4F.



This gives us the following calculation:


       A=X\1L5;B=100003\(A+(A=0));((R:=B\9973)=0)[R=9973,0]


The complete CHANGE command would be:


C P'#####' 1 5 M"DD4F'A=X\1L5;B=100003\(A+(A=0));((R:=B\9973)=0)[R=9973,0]'"


Of course, a command this long is something you would prepare ahead of time.  You can place the mapping string into an SPFLite SET variable, like this:


SET MYMAP = `M"DD4F'A=X\1L5;B=100003\(A+(A=0));((R:=B\9973)=0)[R=9973,0]']`


Then, issue the command as:


       C P'#####' 1 5 =MYMAP


You can also compose long mapping strings in an SPFLite edit macro, and issue them using the SPF_Cmd() built-in function.  The results of the CHANGE command would appear as follows.  Note that these results were tested using the actual calculation function, and verified with an Excel spreadsheet:


****** ****************** Top of Data *******************

000001 2738  

000002 3063  

000003 1283  

000004 3837  

****** ***************** Bottom of Data *****************




Calculator command-line test program


Because the use of a calculator in a text editor is a somewhat novel feature, you may need a little practice working with it to be sure you understand how it works.  One way to do that is by creating experimental mapping strings with calculation operands, and observing how they operate on test data. However, that process could be somewhat time-consuming.  


An easier way to explore this is with a small command-line test program called  mapping_calc.exe.  


This program will first prompt you for an initial sequence number (seq -‑>).  If you use expressions that reference variable S, this will provide an incrementing value for each calc expression you supply, starting with the number you enter.  If you just press Enter, the starting number will be 1.  If you provide a starting number of 0, variable S will be set to 0 each time the calculation function is called, and the value will not be incremented.


You cannot directly set the values of the Line-number variable L or the Column-number variable C.  Instead, mapping_calc.exe will assign random numbers to these values for testing purposes, with variable L receiving random numbers between 1 and 1000, and variable C receiving random numbers between 1 and 80.


The program will then prompt you for an initial value (init ‑>) and a calculation operand (calc ‑>).  The initial value is used to initialize variables R and X.


You type these in as you would in a mapping string (just the calculation part).  It will then return the calculated result in decimal (dec -‑>) and hex (hex -‑>), and report any errors it may have found.  


If a specific column is associated with an error, it will appear at the beginning of the error message in parentheses.  For example, if you specified a calculation operand of R=X/\2 this would be an error, since both / and \ are binary operators, and there is no such operator as /\.  Since the error would be detected when the \ was reached in position 5 of the expression, you would see the error message  (5): Calc operand has syntax error at \.


To terminate the program, simply press Enter twice at the (init ‑>) prompt, or click on the [x] Windows button.  In this program, hex values are entered and displayed with a leading . dot notation.  You can use this hex format for both the initial value and in the calculation expression itself, as described above in the section Specifying numeric literals.


The mapping_calc.exe program is distributed with the SPFLite installation.


Created with the Personal Edition of HelpNDoc: Easily create HTML Help documents