zMUD Programming Language

This document describes the zMUD programming language. I am using this to document the new zMUD parser and prepare for writing the chapter on programming for the zMUD book. It will also be a reference for any future changes to the language parser. I want this document to be a complete reference of syntax, so if I miss something, please send email to zugg@zuggsoft.com

This is for zMUD versions 4.42 and higher
Last updated: July 23, 2001

Overview

There are three modes within zMUD:

  1. Verbatim mode
  2. Parse mode
  3. Script mode
  4. Trigger pattern mode

Modes 1 and 2 are accessible from the zMUD command line. Mode 3 is only accessible within a script or running command. When you enter a command into the zMUD command line, it is parsed in mode (1) if the Parse setting is turned off (as indicated by the computer icon to the left of the command line), and is parsed in mode (2) if the Parse setting is turned on. Commands executed by reading a script file with the #READ command, or the commands associated with executing a trigger or alias all run in mode (3)

In Mode (1), all text is sent to the MUD without any change or other interpretation. This is called Verbatim mode.

In Mode (2), the text is parsed as a series of commands separated by the command separator character (defaults to ;). Each command consists of the command name as the first word, preceeded by the command character (defaults to #). Command separators used within quotes ("" or '') or brackets ([] <> or {}) are ignored in breaking up the individual commands. For example

#SAY {a;b}

is a single command, where as

#SAY a;b

is two commands

Mode (3) is very similar to mode (2), with one difference. Before the text is sent to the MUD, any variable references within the text are expanded.

Mode (4) is used by zMUD when parsing trigger patterns. The syntax for trigger patterns is different than normal zMUD commands. In particular, trigger patterns use [] for set matching, while the normal parser uses [] to force evaluation. Within trigger patterns, only variables beginning with the variable character (@) are expanded.

While modeless systems are preferred, there are strong reasons for having these three modes within zMUD. Obviously, the Verbatim Mode (1) is very important for MUD users, especially coders and builders, that need their commands to go to the MUD exactly as typed. The reasons for modes 2 and 3 is that normally, the MUD user is sending text to the MUD and does not want it to be processed. However, these users want access to zMUD commands. In script processing, you want to ensure that variables and functions are properly expanded. As an example for the difference, consider the line

chat my email address is zugg@zuggsoft.com

When a user types this line, they probably do not want the @zuggsoft expanded as a variable...they want it to go to the MUD verbatim. Also, when they type:

#ALIAS drink {drink @container}

They do not want @container expanded immediately when the line is typed, they want it expanded when the drink alias is executed. However, in a script or trigger, the command

drink @container

is expected to be expanded immediately.

Expansion vs Evaluation

There are two very important concepts to understand and distinguish in programming zMUD: expansion and evaluation.

Expansion means parsing the text and looking for references to built-in (%name) or user-defined (@name) variables and functions. The default % and @ variable/function expansion characters are ignored within quotes ("" and ''). Normally, a variable reference starts with an expansion character (% or @), followed by the name of the variable, followed by a space or other non-alphanumeric character. A special syntax of @{name} (or %{name}) can be used in which the closing } delimits the end of the variable name. This allows other alphanumeric text to be appended to a variable reference without disturbing the name of the variable. For example, if @test contains the string abc, then

@{test}def

expands to abcdef. If @testdef was used, a variable named testdef would be expanded instead.

After the name of a variable, an optional parameter list enclosed in parentheses can be given to specify parameters for a built-in or user-defined function. For example

@test(a,b,c)

expands the test function, with a assigned to parameter 1 (%1), b assigned to parameter 2 (%2), etc.

When expanding variables, expansion proceeds recursively. That is, after expanding the contents of a variable, the contents are itself expanded. Thus, if variable @a contained the value abc, and @b contained @a 123 and @c contained xyz @b @a, the following happens when @c is expanded within a string:

First, @c is expanded to xyz @b @a

Next, the above result is recuresively expanded...@b is expanded to @a 123 and @a is expanded to abc, resulting in xyz @a 123 abc

Next, recursive expansion is performed again, resulting in xyz abc 123 abc

Expansion can be delayed by adding additional @ or % characters. In the above example, changing the value of @b to @@a 123 would result in xyz @a 123 abc when @c is expanded.

In variable evaluation, expansion is performed, but the results are then evaluated as mathematical expressions. Mathematical expressions use operations such as + - * / > < =, etc to form numeric, string, or boolean expressions. An example of where evaluation is used is in the test expression for the #IF command

#IF (expression) {true-commands} {false-commands}

When a variable or function is encountered within an expression, it is recursively expanded as in the expansion section above, but then it is also evaluated. As an example, if @a contains 1+1 and the expression (@a*10) is evaluated, first @a is expanded to 1+1, then it is evaluated as a mathematical expression, resulting in the value of 2, which results in an expression of (2*10) which finally evaluates to 20.

To properly program zMUD, it is crucial to understand whether a statement will be evaluated, or merely expanded. If @a has the value of 100, and @b has the value of 20, expansion of @a/@b results in 100/20, while evaluation of @a/@b results in 5. If you want the evaluation to produce the same output as the expansion, you would have to form it into a proper expression, such as %concat(@a,"/",@b)

To determine whether a parameter for a particular command is expanded or evaluated, open the Command or Function Wizards within zMUD. For each command or built-in function, each parameter is described, and labelled with a type (such as string, number, expression, etc). Parameters of type Expression, or FileNumber are evaluated. Parameters of type String, and Color are fully expanded. Parameters of type Name, Filename, WindowName, and TriggerClass are expanded one level (non-recursive expansion).

zMUD also has a syntax to force expansion, evaluation, or nothing at all. For verbatim text, enclose it in quotes (""). This prevents any expansion or evaluation. For expansion, enclose the text in angle brackets <>. For evaluation, enclose the text in square brackets []. In all of these cases, the delimiters are removed after the expansion or evaluation. In Mode 3, quotes are also removed, but they are not removed in Mode 2 unless they enclose the entire command. Thus, if @a is 100 and @b is 5, here are some examples:

"The answer is @a/@b"

sends the text The answer is @a/@b to the MUD in both mode 2 and 3 since quotes around the entire string are always stripped.

The answer is "@a/@b"

sends the text The answer is @a/@b to the MUD when in Script mode (mode 3), but sends The answer is "@a/@b" when in mode 2.

The answer is <@a/@b>

sends the text The answer is 100/5 to the MUD in both mode 2 and 3.

The answer is [@a/@b]

sends the text The answer is 20 to the MUD in both mode 2 and 3.

In mode 2, to avoid expanding or evaluating with <> and [], just escape the initial brace or bracket. For example

The answer is ~[@a/@b]

sends the text The answer is [@a/@b] to the MUD. You can escape the closing brace/bracket if you like, but it is not needed. Notes that curly braces {} have no parsing meaning and are just used to group values into single parameters. When in mode 3 (script), the final command sent to the MUD is always expanded. Thus, the above example would send The answer is [100/5] to the MUD in mode 3.

Normally, single quotes ' work like double quotes ". However, single quotes are not normally stripped like the other delimiters. You can make ' and " identical by turning on the Strip ' quote option in the General Preferences.

Variables and Functions

Let's look at some examples of expanding and evaluation using the #VAR command as an example. There has been much confusion regarding the #VAR command in various versions of zMUD, so this section should clarify how #VAR is used.

In the Command Wizard, you will notice that #VAR takes three parameters. The first is the name of the variable and is a name type. The second is the value for the variable, and is also a name. The third is the default value for the variable to have when the setting file is initially loaded, and is also a name. The third parameter is optional.

Since all three of the parameters are names, they are all expanded. Thus, if @a has the value of 100, then

#VAR b @a

assigns the value of 100 to b since @a is expanded. If @x has the value of y, then

#VAR @x @a

assigns the value of 100 to y, since @x expands to y and @a expands to 100.

Using the force operations, we can do the following. If @a has the value of 100 and @b has the value of 5, then

#VAR c @a/@b

assigns the string 100/5 to c.

#VAR c [@a/@b]

assigns the value of 20 to c, and

#VAR c "@a/@b"

assigns the string @a/@b to c. Finally,

#VAR c <@a/@b>

does the same as the first case with no delimiters, since #VAR expands the second parameter anyway (because it has a type of name).

To avoid using the force operators shown above, additional commands were added to zMUD. The #MATH command is equivalent to the #VAR command using the [] syntax. Thus #MATH c @a/@b assigns 20 to c. The #FUNCTION command is equivalent to the #VAR command using the "" syntax. Thus

#FUNC c @a/@b

assigns @a/@b to c.

Using these different commands or operations can produce different results, so it is very important to keep track of what you are doing. Some very powerful operations are possible with this syntax. Consider the following example to contrast these commands:

As an example, let's keep track of hitpoints on the status line using the #STATUS hp: @hp command. If we do

#VAR hp 100

then hp: 100 is displayed on the status line. If @a is 100 and @b is 5, then

#VAR hp @a/@b

displays hp: 100/5 on the command line. If we now change the value of b to 10, the status line continues to display 100/5 because the value of hp is still 100/5. However, if we now do

#FUNC hp @a/@b (or #VAR hp "@a/@b")

then the status line displays hp: 100/10 and if we change @b back to 5, then the status line automatically updates to hp: 100/5. This is because hp has the value @a/@b so each time @b changes, this function results in a different expansion. Finally, if we say

#MATH hp @a/@b (or #VAR hp [@a/@b])

then the status line shows hp: 20 and changing @b does not change the status line since hp now has the fixed value of 20.

Keep in mind that when using the force operations, the delimiters ([] <> or "") are stripped from the parameter. Thus,

#VAR hp "@a/@b"

assigns @a/@b to hp. Since the #FUNC operation does not require the force delimiters,

#FUNC hp @a/@b

also assigns @a/@b to hp. If you do

#FUNC hp "@a/@b"

then "@a/@b" is assigned to hp. If you then expand @hp, it will always evaluate to @a/@b and the @a and @b will not be expanded because of the extra set of quotes. In the above example, #FUNC hp "@a/@b" will display hp: @a/@b on the status line, and it will not change when @a or @b are changed. This is the same as doing

#VAR hp ""@a/@b""

Single quotes are not normally stripped, unless the Strip ' quote option in the General Preferences is turned on.

Another thing to keep in mind is the number of parameters taken by the #VAR command, vs the #MATH and #FUNC commands. #VAR takes 3 parameters, and the third optional parameter is the default value of the variable, while #MATH and #FUNC only take two parameters (the name of the variable and the value). Thus, if you say

#VAR a one two

then one is assigned to a, not one two. What you really wanted was probably

#VAR a {one two}

The {} do not change how something is parsed, but can be used just to group the parameters together. Since #FUNC only takes 2 parameters, saying

#FUNC a one two

properly stores one two into @a. For clarity, you can still use the braces to group:

#FUNC a {one two}

You should generally not use the "", '', <>, or [] delimiters to group text unless you are aware of the parse mode that will be caused

Function Calls

A variable that uses parameters (%1, %2, etc) is called a function in zMUD. Try not to confuse this with the #FUNCTION command, although you will normally use the #FUNCTION command to create zMUD functions.

Let's compare the creation of a function with #VAR and a function with #FUNCTION. Assume @a has the value of 100

#VAR test {@a %1 %2}

Since #VAR expands its variables, this results in #VAR test {100 %1 %2}. So, test(1,2) results in 100 1 2. If we change @a to 50, then test(1,2) will still evaluate to 100 1 2 because the @a was expanded when the function was defined. However, if we use #FUNCTION

#FUNC test @a %1 %2

and @a is 100, then test(1,2) will still return 100 1 2. However, if @a now changes to 50, test(1,2) will return 50 1 2. Using the #FUNC command delays variable expansion until the function is used, rather than when it was defined. Both of these types of functions will be useful in programming zMUD.

For user-defined functions, each parameter is expanded before sending it to the function. Thus, if @temp has the value of 50, then test(@temp,2) would return 100 50 2. For built-in functions, expansion or evaluation of the parameter depends upon the type of the parameter. In the Function Wizard, the type of each parameter is shown. Parameters of type String, or Color are fully expanded. Parameters of type Name, FileName, WindowName, TriggerClass are expanded only one level (non-recursive expansion). Parameters of type Expression, FileNumber, and Range are evaluated.

Some functions, such as %min and %max also display a line at the bottom of the Function Wizard indicating that the parameter list is Pre Expanded. In these cases, zMUD first expands the entire parameter list, before breaking it into individual parameters on the commas. This allows the following

#VAR a 1,2,3
#VAR b 4,5,6
%min(@a,@b)

will return 1, and

%max(@a,@b)

will return 6. This is because, the parameter list (@a,@b) is first exanded, resulting in (1,2,3,4,5,6), and then the %min or %max function is called with this new parameter list. Using extra parentheses prevents this operation:

%min((@a),(@b))

expands to

%min((1,2,3),(4,5,6))

which gives a result of 1,2,3.

Aliases

If you look at the #ALIAS command in the Command Wizard, you will see that the first parameter is the name of the alias, and is of type name (which means it is expanded), while the second parameter is the list of commands is is of type literal instead of command. This means that the second parameter of the #ALIAS command is not expanded. So,

#ALIAS dr {drink @container}

assigns drink @container to the alias dr. When you then use the dr alias later, the value of @container is expanded when the alias is used. Again, you can force expansion using the force operation

#ALIAS dr {drink <@container>}

which, if @container has the value of jug, will assign drink jug to the dr alias. Now dr will not change when @container changes.