Up Previous Next Title Page Index Contents

5.3.6 String and number commands

The commands in this category are used to store temporary information into variables, translate strings and evaluate mathematical expressions. Whilst these thus provide functions familiar from other programming languages, it should be stressed that they should be used sparingly. The navigation and stream functions in MERL provide powerful and concise ways to generate the necessary output in almost all cases. You should first become expert in using those fundamentals of MERL before starting to use the commands in this section. Otherwise, you run the risk of doing something similar to programming with an ANSI C style in an object-oriented programming language.

Simple variable use

As elsewhere in MERL, all variables are simply strings; some operations will allow them to be treated like numbers or collections of lines.

To assign a simple variable with a fixed string, simple command, chain clause (e.g. :Name, explosions) or other variable’s value:
$variableName1 = 'variableValue'
$variableName2 = id
$variableName3 = $variableName2
$variableName4 = $variableName5 = $variableName6 = ''
To output the value of a variable, or use it in an if condition etc., use:
$variableName

Variable write and append

To set the value of a variable, you can also use the template:
variable 'variableName' write
   'variableValue'
close
This sets the value of the variable 'variableName' to ‘variableValue’. Similarly to filename clause, the variable value can be overwritten or appended by using the write or append after variable name. For example,
variable 'variableName' append
   'appendedValue'
close
appends the ‘appendedValue’ to the ‘variableValue’, thus the new value of variable ‘variableName’ is ‘variableValueappendedValue’.

Similarly to filename..write..close between filename and write there can be any generator commands, all of whose output goes to building up the variable name to be used. The same applies to forming the variable value.

By forming the variable name at run-time, rather than having it as a fixed element in the generator definition, it is possible to create associative variables. For instance, you can create a variable for each type, and append to it the names of each object of that type. You can also add numbers to the end of the variable name, effectively giving you indexed collections: a variable called “Name3” is equivalent to the C syntax “name[3]”.

Variable read

To output the value of a variable, you can also use the template:
variable 'variableName' read
This outputs the value of the variable ‘variableName’ to the current output. The variable name can again be formed by other generator commands, allowing associative variables. Note that if the variable name is fixed, you can use the more concise variable referencing syntax above.

Variable incrementing and decrementing

To increment and output the value of a variable as a number use the syntax:
$++variableName
To first output and then increment the value of a variable, use the syntax:
$variableName++
The value of a variable may also be decremented by using “--“ in place of “++” in the above examples. Note that if the variable value is not a number it will be interpreted as 0 for the increment or decrement operation.

If you do not want the result output, you can add a string translation to it to map all characters (or just all digits) to nothing. The translator would normally be defined just once at the start of the outermost generator, but we include it inline here for completeness:
to '%null' newline '* $' endto
$variableName++%null
More complex calculations with variables can be done by using the math..evaluate clause.

Translating strings: to translate endto

To replace characters or substrings in a string use the template:
to 
   'A-Z a-z'
translate
   'Foo'
endto
which outputs ‘foo’. The clauses between to and translate form the translator, and those between translate and endto form the output to which that translator is applied. For example, the rule ‘A-Z a-z’ above means that each uppercase letter is converted into the corresponding lowercase letter.

Translators can be named and used many times. For example
to 
   '%lower' newline 'A-Z a-z'
endto 
defines a translator named ‘lower’ whose rule is ‘A-Z a-z’. The clauses between to and endto form the translator definition: the first line sets the translator name and the next lines contain the rules. This translator can be used later many times:
to '%lower' translate 'Foo' endto
There is also a shortcut syntax for using named translators with simple commands, design element output commands, variables and literal strings:
id;2;%lower
:myName%lower
$variable%lower
A translator definition can contain multiple rules, each one line of text that maps a left-hand side to a right-hand side. There are several different kinds of rule, such as character to character, or string to string. The different kinds of rules available are explained in the table below. Special characters (newline space \ / $ % - *) must be escaped with backslash, e.g. to map spaces to underscores use: '\ _' (backslash, space, space, underscore). Remember too that if the translator definition is expressed in a literal string, a single quote ' must of course be escaped by doubling it.
Name or comment
'%myName' as the first line in a translator definition gives the translator a name “myName”. Lines starting with % later in the translator are ignored as comments.
Character
'a b' maps each occurrence of character a to character b.

Range

'1-9 a-i' maps each character in the range on the left to the corresponding character in the range on the right. In this example numbers are mapped to letters: 1 becomes a, 2 becomes b and so on. Note that ranges must be of equal size, thus ‘a-c 1-4’ is not legal.

Note: range can be reversed, e.g. "a-z z-a".
Multiple character
'123 abc' maps each number to a letter: 1 to a, 2 to b, 3 to c. The difference from range is that each character is specified explicitly.
String
'$dog $cat' means replace each occurrence of the string ‘dog’ with ‘cat’.
Mixed
'aeiou $VOWEL' means replace each vowel with the string "VOWEL". This is applied with the character translations.
Asterisk
An asterisk on the left is the default mapping – what to map all unspecified characters to (the default is to leave them unchanged): '* $abc' means replace each character with the string "abc"

An asterisk on the right means leave the characters on the left unchanged: ‘abc *’ do not change a, b and c.
Regular expression
'/[A-Z][a-z]*/ $NAME' means replace each occurrence of a capital letter followed by lowercase letters with NAME. The left-hand side need not escape special translation characters, but can use the normal regular expression escapes; / must be escaped by doubling it.

The right-hand side (after the initial $) can use $0 to refer to the whole matched string, $1 for the substring matching the first parenthesized subexpression etc. E.g. the following rule (which should be on one line) would turn “Fred Bloggs and John Doe” into “Bloggs, Fred and Doe, John”

/([A-Z][a-z]*) ([A-Z][a-z]*)/
$$2,\ $1
All rules that apply to single characters are collected together first to build one large character mapping, which is applied to the input text in one operation. After that all rules that apply to strings, including regular expression rules, are applied in order, one at a time, to the whole text. If you need to change this order, e.g. to translate strings first then characters, you can use two translators. The first will translate just strings and the second just characters, and you can apply the first and then the second to achieve the desired result.

Some useful translators such as %lower can be found from the _translators generator in the Graph metatype. To be able to use these translators in your own generators, use “subreport ‘_translators’ run” somewhere near the start of your outermost generator.

Math evaluate

To evaluate a mathematical expression use the template:
math '1+3*2' evaluate
which outputs 7. The expression between math and evaluate keywords forms the evaluated expression. The rules for forming the expression are:
Numbers
The number format in the input stream is integer, float, or scientific format 3e10. Leading zeroes are allowed (e.g. 001), and float must have an integer part (e.g. 0.3 not .3).

Operations

The operations are + - * / and ^ for power, all binary, and unary plus and minus. Also // (division without remainder) and \\ (modulo).
Precedence
Precedence is as normal: parentheses, ^ / * - +.

math '5+4*3^2' evaluate

outputs 41, i.e. 5 + (4 * (3 ^ 2))

math '3^2*4+5' evaluate

outputs 41, i.e. ((3 ^ 2) * 4) + 5).

Precedence of unary minus and plus is higher than exponentiation:

-2^-2 = (-2)^(-2), not -(2^-2)
Associativity
Binary operators are left associative, except ^ which is right associative:

100/10/5 outputs 2, i.e. (100 / 10) / 5

3-4-5 outputs -6, i.e. (3 - 4) - 5

4^3^2 outputs 262144, i.e. 4 ^ (3 ^ 2)
Output formats
Integers (3, unbounded range)

Fractions (3/4, unbounded range and precision. If you want to turn this into a float, 0.75, use a float as part of the calculation, e.g. 3/4.0)

Floats (3.0 or, if the absolute value is larger than 1,000,000 or smaller than 0.001, in scientific format 1.0e-4. Precision is 8 or 9 digits. Range is plus and minus 1.0e38 (an error will be raised if the range is exceeded).


Up Previous Next Title Page Index Contents