PCC2 Interpreter Quick Documentation

This document contains a brief introduction into the scripting language as implemented so far. See PCC2 Quick Documentation for documentation about PCC2 as a whole.

Introduction

Like PCC 1.x, PCC2 now contains a script interpreter. The script interpreter understands a simple programming language remotely based upon newer BASIC dialects, and extended to be useful in a VGAP context.

The scripting language is intended to be mostly identical to the PCC 1.x language. However, the underlying implementation is completely different (and, as I hope, more logical and consistent).

As of beta 8, PCC2 is able to evaluate expressions. You can therefore use the search function, the console ("calculator"), and unit labels. Execution of commands and scripts (canned command sequences) is scheduled for beta 9. Auto tasks are scheduled for beta 10.

! This document is still incomplete. In particular, it is missing the description of object properties. You can refer to the PCC 1.x scripting manual for those. However, please be aware that it is not yet 100% implemented yet. Use the console to try out expressions if in doubt.
Remarks about future features of PCC2 have been formatted in this style.

Basics

Names and Context

Names identify things. Many programming languages therefore call them identifiers. A name can contain letters, digits, and the special characters "." (dot), "$" (dollar), and "_" (underscore); it may not start with a digit or dot, and may not end with a dot, though. PCC2 predefines many names you can use in various ways. Those are called properties (properties of objects, such as the name of a ship) and functions. Future versions of PCC2 will also allow you to define your own names, variables and subroutines.

The meaning of a name depends on the current context. For example, the word Mission can stand for the mission of a ship or for the mission of a starbase, which are governed by completely different rules. However, names have been chosen in such a way that similar things are represented by similar names. For example, you can use Name="Ares" to search for ships and planets having that name, and Owner$=7 searches for everything owned by player 7.

The current context is determined by the place you're invoking a script from. For example, a planet label expression is always evaluated in the context of the planet.

Contexts stack. You can temporarily open another context. For example, using the Find function to find a ship, as in Find(Ship, Name="Ares", Id), will evaluate the test and return expressions (second and third parameter) in ship context. However, names not found in that context will be looked up in the previous contexts.

There are important exceptions to these rules. For example, in Sin(30), Sin always means the sine function, no matter what context is active. Those exceptions are:

Naming Conventions

Property names follow some simple guidelines that aim to help you memorize properties.

The shortest name always gives a nice human-readable summary of an item. For example, Mission yields a ship's mission in text form ("Tow a ship"). By adding more words, you can ask for details. For example, Mission.Tow yields the "Tow" parameter of the mission. Alternatively, adding a dollar sign gives the internal representation. For example, Mission$ yields the mission number (7).

For programming, writing search queries, etc., you will probably use the "$" forms most often. For formatting text, you will most likely use the short standard form.

Types

All names, values and expressions have a type. The type defines what you can do with the thing. PCC2 internally tracks these types. If you use a value in a way its type does not allow, PCC2 will show you an appropriate error message. The following types exist:

Numbers
PCC2 supports fractional and whole numbers (integer). Those can be used to compute new values using the well-known arithmetic operators and functions. PCC internally tracks for each value whether it's fractional or integer. In general, operations between integers yield integers, whereas operations involving a fractional number yield a fractional number. Some operations require their operands to be integers.
For techno-geeks: fractional numbers are 64-bit double precision numbers, and integers are 32-bit signed numbers.
Boolean
Boolean values can be True or False and are used to represent yes/no answers.
Whenever PCC2 needs a boolean value, it also accepts numbers (0 means False, other values mean True) or strings (the empty string "" means False, other values mean True).
Likewise, PCC2 also accepts booleans when it needs a number, False converts into zero, True converts into 1.
Strings
Strings can contain arbitrary text, such as the name of a starship. Strings can be concatenated (appended) or split using various functions.
At most places where PCC2 needs a string, it will also accept a value of any other type. That value will be converted into its textual representation.
Arrays
Arrays contain other objects. For example, Ship is an array containing all ships. You can access individual array elements using notation like Ship(17), and you can iterate over arrays containing objects (see below) using functions like Find.
Functions
Functions compute values from other values. For example, Sqrt is a function, and Sqrt(9) computes square-root-of-9.
Objects
The result of an array reference like Ship(17) is the object, ship #17. You can access that object's properties by adding a dot followed by a property name, as in Ship(17).Name. As of beta 8, this is the only thing you can do with an object, beta 9 will contain a command With to activate an object's context.

A very special value is Empty. This value is used for unknown values. For example, when you don't own a ship, it will yield Empty for its Cargo.N (fuel amount). As a general rule, an operation will yield Empty if one of their operands are Empty, but exceptions exist. In a boolean context, Empty counts as False.

Expressions

Expressions compute values. They do so by combining elementary values (literals, properties, variables) using operators and functions. The following sections describe expressions in an informal style. For people who prefer it, there's a formal grammar at the end.

Literals

Decimal numbers can be used to specify integers or real numbers. The "." is used as the decimal point. A number is integer if it fits into a 32-bit integer number, otherwise it's treated as real.

Strings can be specified in two ways:

Special values are Pi (=3.14159265..., circumference/diameter ratio of a circle), True and False.

Some General Rules

Most operations return Empty when one of their arguments is Empty. Operations taking more than one argument usually evaluate them all, even if the result would be known after evaluating only some. Exceptions are explicitly specified.

String operations are case-insensitive by default. That is, "A" compare equal to "a". To get case-sensitive operations, use the StrCase() function.

Some operations taking numerical operands only work with integers. When doing arithmetic, PCC2 keeps track of which values are integers and which are fractions. Arithmetic operators and "+", "-", "*" yield integers when their operands are integers, others like "/" may generate fractions even when used on integers.

Operators

The following table shows all operators supported by PCC2. Operators have a certain precedence or binding strength, which determines which parts of the expression belong to that operator. For example, in 2 + 3 * 4, the precedence of * is higher than the precedence of +, so the multiplication is performed first. The addition then adds 2 and the result of 3 * 4. The table shows operators in increasing order of precedence, i.e. later operators are evaluated before those shown first.

a; b Sequence: evaluate a, discard its result, then evaluate b.
a := b Assignment: evaluate b, and assign it to a. Returns b.
a Or b Logical Or: return True if either operand is True. If the result is known after evaluating a, does not evaluate b (short-circuit evaluation).
a Xor b Logical Exclusive-Or: return True if one operand is True and one is False. If the result is known after evaluating a, does not evaluate b (short-circuit evaluation).
a And b Logical And: return False if either operand is False. If the result is known after evaluating a, does not evaluate b (short-circuit evaluation).
Not a Logical Not: return True if, False if operand is True.
a = b Comparison: return True if a is identical to b.
a <> bComparison: return True if a is different from b.
a < b Comparison: return True if a is less than b.
a > b Comparison: return True if a is greater than b.
a <= bComparison: return True if a less or equal to b.
a >= b Comparison: return True if a is greater or equal to b.
a # b Concatenation: convert a and b to strings and concatenate them.
a & bConcatenation: convert a and b to strings and concatenate them. If either is Empty but the other is not, treat the Empty one as empty string.
a + b Addition: add a and b, which may be numbers or strings.
a - b Subtraction: subtract b from a, which must both be numbers.
a * b Multiplication: multiply a and b, which must both be numbers.
a /  Division: divide a by b, which must both be numbers.
a \ b Integer division: divide a by b, which must both be integers, and discard the remainder.
a Mod b Integer remainder: divide a by b and return the remainder. Both operands must be integers.
-a Negation: change sign of a, which must be a number.
+a Unary plus: do not change sign of a, which must be a number. Exists for symmetry with "-".
a ^ b Power: compute a-to-the-bth. Both operands must be numbers.

Elementary Functions

Elementary functions are recognized whenever their name is followed by a parenthesized expression list. Elementary functions thus bypass normal name-lookup.

Most functions are regular, that is, they evaluate all their arguments, and yield Empty if an argument is Empty. Functions that do not follow these rules are marked as irregular.

Most functions expect their parameters of a particular type. In the descriptions, this is denoted by ":type" behind their name: Int=integer, Num=any numerical value, Str=string.

Abs(value:Num)
Yields the absolute value of value.
Asc(value)
If the argument is a string, return the ASCII code of its first character. If the argument is not a string, it is converted into one first. If the argument is an empty string, yields Empty.
ATan(value:Num)
ATan(x:Num, y:Num)
Compute the arc-tangent (=angle, in degrees) of x/y resp. value. With two arguments, the angle will have the correct quadrant. ATan(0,0) is Empty.
Atom(value:Str)
Places the string into an internal table, and returns an integer you can use to find it again later. When asking for the same string again, return the same integer again. This is used internally at a number of places in PCC2.
AtomStr(n:Int)
Performs the inverse mapping of Atom, i.e. return a previously stored string.
BitAnd(value:Int, ...)
Takes any number of integer arguments and returns the bitwise And of them.
BitNot(value:Int)
Returns the bitwise negation of its argument.
BitOr(value:Int, ...)
Takes any number of integer arguments and returns the bitwise Or of them.
BitXor(value:Int, ...)
Takes any number of integer arguments and returns the bitwise Xor of them.
Chr(value:Int)
Chr$(value:Int)
Returns a string consisting of the character with the given ASCII code.
Cos(angle:Num)
Returns the cosine of the angle, given in degrees.
Count(array, matchExpr) [irregular]
This function may or may not go away in a future version of PCC2. It is currently provided as a temporary replacement for PCC 1.x's CountShips and CountPlanets. Iterate over array, and evaluate matchExpr for every element. Returns the number of elements where that expression yields true (nonzero). If the matchExpr is omitted, counts all objects, as if the expression were True.
Exp(value:Num)
Returns the base-e exponential of the given value.
Find(array, matchExpr, valueExpr) [irregular]
This function may or may not go away in a future version of PCC2. It is currently provided as a temporary replacement for PCC 1.x's FindShip and FindPlanet. Iterate over array, and evaluate matchExpr for every element. If that yields true (nonzero), return valueExpr. If no element matches, return Empty.
First(line:Str, delim:Str)
Locate the first occurence of delim in line, and return everything before that. If delim does not occur in line, return the whole line.
If(cond:Bool, exprIfTrue) [irregular]
If(cond:Bool, exprIfTrue, exprIfFalse) [irregular]
Evaluate cond. If it returns true (nonzero), evaluate exprIfTrue. Otherwise, evaluate exprIfFalse (or, if that is not specified, return Empty).
InStr(haystack:Str, needle:Str)
Return the position (1-based) of the first occurence of needle in haystack. If needle does not occur in haystack, returns 0.
Int(n:Num)
Convert n to an integer by truncating fractional digits (round towards zero).
IsEmpty(n)
Returns True if n is Empty, otherwise False.
IsNum(n)
Returns True if n is numeric, otherwise False.
IsString(n)
Returns True if n is a string, otherwise False.
Left(s:Str, n:Int)
Returns the first n characters of s.
Len(s:Str)
Returns the number of characters in s.
Log(value:Num)
Returns the natural (base-e) logarithm of value.
LTrim(s:Str)
Removes left (leading) whitespace from s.
Max(value, ...)
Takes any number of arguments, which must be either all numeric or all strings. Returns the maximum value.
Mid(s:Str, start:Int)
Mid(s:Str, start:Int, len:Int)
Returns len characters from s starting at start (1-based). The two-argument form returns everything from start to the end of the string.
Min(value, ...)
Takes any number of arguments, which must be either all numeric or all strings. Returns the minimum value.
Rest(line:Str, delim:Str)
Locate the first occurence of delim in line, and return everything after that. If delim does not occur in line, return Empty.
Right(s:Str, n:Int)
Returns the last n characters of s.
Round(n:Num)
Convert n to an integer by rounding arithmetically (towards nearest integer).
RTrim(s:Str)
Removes right (trailing) whitespace from s.
Sin(angle:Num)
Returns the sine of the angle, given in degrees.
Sqr(value:Num)
Sqrt(value:Num)
Returns the square root of the value.
Str(value:Num)
Str(value:Num, digits:Int)
Convert value into a string. With two arguments, generate the specified number of fractional digits.
StrCase(expr)
Evaluates expr. All string operations in that expression are evaluated case-sensitively. This applies to comparisons and the Min/Max/InStr/First/Rest functions.
String(count:Int, str:Str)
String$(count:Int, str:Str)
Returns a string that contains count copies of str. If str is not specified, PCC2 uses a space character.
Tan(angle:Num)
Returns the tangent of the angle, given in degrees.
Trim(s:Str)
Removes all (leading and trailing) whitespace from s.
Val(s:Str)
Interprets the given string as a number and returns that. If the string cannot be interpreted as a number, returns Empty.
Z(value)
Zap(value)
If the value is 0 or an empty string, returns Empty, otherwise returns the value as is.

Functions and Arrays

Those items are found by regular name lookup. If you define a local variable named identical to one of these (this is not possible in beta 7, but will be possible in later versions), using that name will find the local variable.

All items that are documented as func(...).prop are actually arrays that can also be used with the Find function, as Find(func, ...).

Beam(id:Int).prop
Access properties of a beam weapon.
Cfg(name:Str)
Cfg(name:Str, index:Int)
Access configuration (pconfig). For array options, the index must be specified to determine which array item to access. As an exception, it can be omitted if the option is indexed by player, you will access your own value in this case.
Distance(x1:Int, y1:Int, x2:Int, y2:Int)
Distance(x1:Int, y1:Int, obj2)
Distance(obj1, x2:Int, y2:Int)
Distance(obj1, obj2)
Compute distance between two points. Each point can be specified either as an X/Y pair, or as an object. For example, Distance(1000,1000,Ship(10)) is the same as Distance(1000,1000,Ship(10).Loc.X,Ship(10).Loc.Y).
Engine(id:Int).prop
Access properties of an engine.
Hull(id:Int).prop
Access properties of a hull.
IsSpecialFCode(fc:Str)
Check whether the given friendly code is special.
Launcher(id:Int).prop
Access properties of a torpedo launcher.
Minefield(id:Int).prop
Access properties of a minefield.
Planet(id:Int).prop
Access properties of a planet.
PlanetName(id:Int)
Returns the name of the specified planet.
Ship(id:Int).prop
Access properties of a ship.
ShipName(id:Int)
Returns the name of the specified ship.
Storm(id:Int).prop
Access properties of an ion storm.
Torpedo(id:Int).prop
Access properties of a torpedo. Note that those are the same as the properties of the launcher, except for the Cost properties, which describe the actual torpedo here.
Truehull(slot:Int)
Truehull(slot:Int, player:Int)
Returns the number of the slot-th hull which the specified player (or you, if no player argument given) can build. slot can range from 1 to 20. If the specified slot is not taken, the result will be 0, otherwise you can use the result as parameter to Hull() to fetch properties of the actual hull.
Ufo(id:Int).prop
Access properties of an Ufo.

Formal Grammar

sequence:
      assignment
      sequence ";" assignment

assignment:
      or-expr
      assignment ":=" or-expr

or-expr:
      and-expr
      or-expr "Or" and-expr
      or-expr "Xor" and-expr

and-expr:
      not-expr
      and-expr "And" not-expr

not-expr:
      comparison
      "Not" not-expr

comparison:
      concat-expr
      comparison "=" concat-expr
      comparison "<" concat-expr
      comparison ">" concat-expr
      comparison "<=" concat-expr
      comparison ">=" concat-expr
      comparison "<>" concat-expr

concat-expr:
      add-expr
      concat-expr "#" add-expr
      concat-expr "&" add-expr

add-expr:
      mult-expr
      add-expr "+" mult-expr
      add-expr "-" mult-expr

mult-expr:
      neg-expr
      mult-expr "*" neg-expr
      mult-expr "/" neg-expr
      mult-expr "\" neg-expr
      mult-expr "Mod" neg-expr

neg-expr:
      pow-expr
      "-" neg-expr
      "+" neg-expr

pow-expr:
      primary-expr
      primary-expr "^" neg-expr

primary-expr:
      "(" sequence ")"
      string-literal
      integer-literal
      float-literal
      "True"
      "False"
      "Pi"
      identifier invocation*

invocation:
      "(" arguments ")"
      "." identifier

arguments:
      nothing
      sequence ("," sequence)*

identifier:
      sequence of letters, "$", "_", digits, ".",
        not starting with a digit or period
        not ending with a period

string-literal:
      "'" (any character except for "'")* "'"
      """ (any character except for """ and "\", or "\" followed by any character) """

integer-literal, float-literal:
      digit digit*
      digit digit* "."
      digit* "." digit digit*
        A value is an integer if it has no decimal point and fits into
        32-bit range. Otherwise, it's float.

Stefan Reuther
Best viewed with a CSS-capable browser.
Last modified: Fri Mar 5 21:53:24 CET 2010