Designing Games with Xconq - Language Syntax

Go to the first, previous, next, last section, table of contents.

## Language Syntax

GDL resembles Lisp, but instead of defining functions, the contents of a file declare certain objects (such as units and unit types) to exist, and specify values for their properties. In other words, GDL is nonprocedural. This means that most of the time, you can list the various forms in any order you like. The main restriction is that any symbol, such as a variable or the name of a type, must be defined before it is used. Also, forms such as `set` and `add`, that set the value of a variable or property, always overwrite the previous data irreversibly, so ordering of these is very important.

- Lexical Elements
- Conventions Used
- Forms and Evaluation
- Tables
- Modifying Objects
- Symbols
- Lists

### Lexical Elements

Numbers are introduced by a decimal digit, plus, or minus signs. They may contain only decimal digits, a decimal point, and be followed (immediately, no whitespace allowed) by a percent sign.

Strings are sequences of characters enclosed by doublequotes (`"`). They may contain any character except ASCII NUL (`'\0'`). To include a doublequote, use backslash, as in `"a \"quoted\" string"`. To include a nonprinting or eight-bit character, use backslash followed by three octal digits, which will be interpreted as an eight-bit character code. (This is mostly the same syntax as in C.) Note that game design files may be passed over networks and between different kinds of computer systems, so non-ASCII characters should not be inserted verbatim into strings.

Symbols are sequences of characters that don't include any of the other special characters. If you wish to include such characters in a symbol, enclose it in vertical bars, for example `|foo bar|`. (The bars are not part of the symbol.) Symbols are case-sensitive, but this will be changed eventually.

Lists are a sequence of expressions enclosed in parentheses. The empty list is either `nil` or `()`. "Dotted pairs" are not allowed. Anything that is not a list is an atom.

All of these objects may range up to a very large size. (You may still run into bugs if you make strings or symbols over about 100 chars in length.)

Comments are enclosed either within `#| |#` (which nests properly, like Common Lisp and unlike C), or else extend from a semicolon `;` to the end of the line. A comment is equivalent to whitespace, so `(a#|bcd|#e)` is the same as `(a e)`, not `(ae)`.

`#` by itself is a normal token.

True/false values are just the integers 0 and 1, with no special characteristics.

GlobalConstant: `true`

GlobalConstant: `false`

These constants are symbolic forms for `1` and `0`. They are identical to numbers, but more descriptive for parameters that are boolean-valued.

Unit, material, and terrain types are distinct objects. However, they can be considered to have numeric "indices" assigned in order of the types' definition. These numbers are not directly visible in GDL, but they often affect sorting and ordering.

You may also supply numbers as dice specs, which are used in several tables. The syntax is the familiar `nndmm[+oo]`, where nn is the number of dice to throw, mm is the number of values on each die, and the optional oo is an value to be added to the result. The die are 0-based, so for instance `3d6` yields values between 0 and 15, while `3d6+3` is equivalent to the result of rolling 3 6-sided dice. The range of each value is severely limited; nn may range from 0 to 7, mm from 0 to 15, and oo from 0 to 127. Internally, dice specs are normal integers, in the range 16384 to 32767.

### Conventions Used

Descriptions of values in this manual follow the conventions listed here.

For parameters described as t/f, both `1`, `0` and `true`, `false` may be used. Parameters described as n and n% are numbers. Parameters described as dist or length are also numbers, but are in the unit of measure for lengths. Parameters described as str or string are strings.

Parameters described as u or ui, m or mi, and t or ti, are values that must be unit, material, or terrain types, respectively.

Parameters described as utype-value-list match unit types with values. They can have several forms:

- `(n1 n2 ...)` matches `n1` with type 0, etc in order.
- `((u1 n1) (u2 n2) ...)` evaluates `u1` to get a unit type, then matches it with `n1`. `u1` etc may also be a list of types, in which case all the types get matched with `n1`.

Other types of lists, such as those defined as side-value-list, are interpreted similarly. For all of these, multiple assignments to the same type etc will overwrite quietly.

List values described as interpolation-list are lists of pairs used to derive numerical values by interpolating between the listed values. The form of an interpolation list is always `((key1 val1) (key2 val2) ...))`, where keyi and vali are numbers. If the input value inp to an interpolation matches keyi, the result value is vali. If it is between keyi and keyi+1, then the result is gotten by linear interpolation, with the result value falling somewhere between vali and vali+1. Fractional values always round down. The keyi must occur in non-decreasing order; it is legitimate for two consecutive keys to be identical, in which the result value will be the value associated with the first key. If the input value is outside the domain specified by the keys, the result depends on the particular parameter; some will extrapolate in some appropriate fashion, while others will generate an error or warning.

Some values may be boolean expressions. Boolean expressions are lists headed by the keywords `and`, `or`, and `not`, and may nest recursively. For instance, the expression

    (and (or false (not false)) true)

is always true. In some contexts, values other than `true` and `false` may appear, in which case the interpretation of those values depends on the context.

Some numeric values are stochastic, meaning that they are partly fixed and partly probabilistic in effect. The most common form of this is values where the part > 100 is divided by 100, while the value mod 100 is the probability to add 1 to the first part. Thus a value of 425 works out to a value of 4, 3/4 of the time, and to 5, 1/4 of the time, on average.

Unless otherwise stated, all numeric values default to `0`, all string values default to `""`, and all form values default to `()`. If one of these defaults has a notable consequence, such as inability to perform some action, that will be mentioned.

### Forms and Evaluation

A form is either any single expression that appears in the file. A GDL file consists of a sequence of forms. Most forms of interest will be lists whose first element is a symbol identifying the form. For instance, a form beginning with the symbol `side` declares a side object. When the file containing such a form is read, Xconq will create a side object and fill in any properties as specified by the form. (Properties are like properties or attributes - most GDL objects have some.)

In most contexts, Xconq will evaluate an expression before using it, such as when filling in an object's property. Numbers and strings evaluate to themselves, while symbols evaluate to their bindings, as set by `set` or `define`. Lists evaluate to a list of the same length, but with all the elements evaluated, unless the first element of the list is a function. In that case, the remaining elements of the list are evaluated and given to the function, and its result will be the result.

### Tables

A table is a two-dimensional array of values indexed by types. Indices can be any pair of unit, material, or terrain type. The set of tables is fixed by Xconq, and all are described below.

Form: `table` table-name items...

This is the general form to fill in a table. The table named by table-name is filled in from the items. If an item is an atom, then every position in the table is filled in with that item, overwriting any previously-specified values. If an item is a list, it must be a three-element list of the form `(type1 type2 value)`. If both type1 and type2 are single types, then value will be put into the table at the position indexed by the two types. If one of type1 or type2 evaluates to a list, Xconq will iterate over all members of the list while keeping the other type constant, while if both type1 and type2 are lists, then Xconq will iterate over all pairs from the two lists. The values used during iteration depend on whether the value is a list. If value is an atom, then that value will just be used on every iteration. If a list, then Xconq will use successive elements of the list while iterating.

If the first member of items is the symbol `add`, then the rest of the items will add to the existing contents of the table rather than clearing to its default value first.

The following forms are all equivalent:

    (table foo (a y 1) (b y 2) (c y 3) (a z 9) (b z 9) (c z 9))

    (table foo ((a b c) y (1 2 3)) ((a b c) (z) 9))

    (define v1 (a b c))
    (table foo (v1 y (1 2 3)) (v1 z 9))

    (table foo ((a b c) (y z) ((1 2 3) (9 9 9))))

    (table foo (a y 1) (b y 2) (c y 3))
    (table foo add ((a b c) z 9))

### Modifying Objects

Since forms normally define or create new objects, GDL defines the `add` form to modify existing objects.

Form: `add` objects property new-values...

This form evaluates the atom or list objects to arrive at the set of objects to be modified. Then it uses the new-values to write new data into the property named property of those objects. The new-values may be a single number or string, or a list.

### Symbols

Most of the symbols used in a game module are the predefined ones described in this manual. Others are attached to types when the types are defined, and still others name objects like units and sides. You can also define and set your own symbols to arbitrary values.

Form: `define` symbol value

This form defines the symbol symbol to be bound to the result of evaluating value. If symbol is already defined, Xconq will issue a warning, and ignore this form.

Form: `set` symbol value

This form rebinds the already-bound symbol symbol to be bound to the result of evaluating value. If symbol is not bound already, then Xconq will issue a warning, but proceed anyway.

Form: `undefine` symbol

This form destroys any binding of the symbol. This is allowed for any symbol, including already-unbound symbols.

### Lists

Function: `quote` form...

This function prevents any evaluation of form. (This implies that the abovementioned evaluation of the argument list does not happen for this "function".)

Function: `list` form...

This function makes a list out of all the form.

Function: `append` form...

This function appends all the form (which may be lists or not) into a single list. Non-lists will appear as though they were single-element lists.

Function: `remove` list1 list2

This function removes the members of list1 from list2, returning the result.

Go to the first, previous, next, last section, table of contents.