Q: What do the various compiler errors mean?
A: Here are the errors that might arise during script compilation, along with a more detailed explanation of the problem:
---Errors During Parsing or Preprocessing---
P00: Can't open of parse input file!
The compiler creates and uses a temporary file during its operation, so you may get this error if ZQ cannot create a file with write permission in its working directory.
More likely, though, you have made a typo in your ZScript source which is tripping up the lexer or parser. The lexing and parsing error handling is more primitive than the semantic checking, as I am using the flex and bison error handling "out of the box", but you should still be provided with a line number and context of the error, with the parser informing you of the kind of token it found, and what it expected instead. This list of expected tokens is however not all-inclusive.
Keep in mind that ZScript is a modified SUBSET of the C language, and some features are not yet (or never will be) implemented.
P01: Failure to parse imported file foo.
As in P00, but the problem is in an imported file, and not the main source.
P02: Recursion limit of x hit while preprocessing. Perhaps you have circular imports?
Suppose you have the following script files
a.z:
b.z:
and you try to compile a.z. The compiler will open b.z and attempt to recursively compile it. But b.z tries to import a.z, so the compiler enters an infinite loop of opening a.z, then b.z, then a.z, etc. To protect against this compilation halts if import recursion depth reaches a certain threshold.
Future versions of ZQ may have better import handling, which may eliminate this problem. For now, user care is the only solution.
---Errors During Symbol Table Construction---
S04: Function foo was already declared with that type signature.
You tried to declare two functions in the same scope with the same name and type signature. Note that return type is NOT enough to distinguish otherwise identical function declarations; recall also that int and float are the same type internally, so if two function type signatures are identical except that one has a parameter of type float where the other has the same parameter of type int, you will have a conflict.
There are two additional subtle situations where you might get a conflict:
1. A function declared at file scope might conflict with a function that's implicitly added to file scope by the preprocessor because of an import statement.
2. A function might conflict with one already reserved by the ZScript standard library. All current and future ZScript library functions start with a capital letter, and so starting user functions in lowercase might be a prudent convention.
S05: Function parameter foo cannot have void type.
It makes no sense to pass void parameters, and so declaring such is illegal.
S06: Duplicate script with name foo already exists.
Script names must be wholly unique; if there's already an ffc script named FOO you cannot create an item script so named.
Remember also that scripts might be imported by the preprocessor.
S07: Variable foo can't have type void.
Self-explanatory, and common sense.
S08: There is already a variable with name foo defined in this scope.
Since variables cannot be declared at file scope, and the ZScript library does not reserve any variables, this error should rarely cause confusion. Remeber that, as in C, you can use braces ({}) to introduce an extra scope, as in the following snippet:
Code:
int x;
{
int x; //legal
}
S09: Variable foo is undeclared.
A variable with the give name could not be found in the current or any enclosing scope. Keep in mind the following subtleties:
1. To access a different script's global variables, or to access a global variable from within a function delcared at file scope, you must use the dot operator: scriptname.varname.
2. To access the data members of the ffc or item associated with a script, you must use the this pointer: this->varname.
3. ZScript uses C++-style for loop scoping rules, so variables declared in the header part of the for loop cannot be accessed outside the loop:
Code:
for(int i=0; i<5;i++);
i = 2; //NOT legal
S10: Function foo is undeclared.
As S09, but with functions instead of variables. Points 1 and 2 of S09 apply here as well.
S11: Script foo must implement void run().
Every script must implement a function named run, with some type signature, and return type void. This is the method that's automatically invoked when a script is run by the ZC engine.
S12: Script foo's run() must have return type void.
Every script's run method must have void return type. Self-explanatory.
S26: Pointer types (ffc, etc) cannot be declared as global variables.
It is illegal to declare a global variable (that is, a variable in script scope) or any type other than int, float, and bool. Why? Recall that global variables are permanent; they persist from frame to frame, screen to screen. Pointer types, on the other hand, reference ffcs or items that are transitory; they become stale after a single WAITFRAME, so it makes no sense to try to store them for the long term.
S30: Script foo may have only one run method.
Your run method may have any type signature, but because of this flexibility, the compiler cannot determine which run script it the "real" entry point of the script if multiple run methods are declared.
S32: Script foo is of illegal type.
There is no such thing as an itemclass script or bool script. Don't even try.
---Errors During Type-Checking---
T16: Cast from foo to bar.
The only "safe" implicit casts are from int to float and vice-versa (since they are the same type), and from int (or float) to bool (0 becomes false, anything else true). The results of any other kind of cast are unspecified.
Explicit casts are unimplemented and unnecessary.
T17: Cannot cast from foo to bar.
As with T16, but in this case the cast is expressly forbidden.
T19: Constant division by zero.
While constant-folding, the compiler has detected a division by zero.
Note that not only division by a CONSTANT zero can be detected at compile time. The following code, for instace, compiles with no errors but will most likely still crash ZC:
T20: Truncation of constant x.
Both floats and ints can only be specified to four places of decimal precision. Any extra digits are simply ignored by the compiler, which then issues this warning.
T21: Could not match type signature foo.
The compiler can determine no way of casting the parameters of a function call so that they match the type signature of a declared function. For instance, in the following snippet
since true cannot be cast to a float, this function call cannot be matched to the library function Sin, triggering this error.
T22: Two or more functions match type signature foo.
If there is ambiguity as to which function declaration a function call should matched to, the compiler will attempt to determine the "best fit." These measures are however occasionally still not enough. Consider for instance the following snippet:
Code:
void foo(int x, bool y) {}
void foo(bool x, int y) {}
foo(1,1);
matching either of the two foo declarations requires one cast, so no match can be made. In contrast, the following code has no error:
Code:
void foo(int x, bool y) {}
void foo(bool x, bool y) {}
foo(1,1);
(The first foo function is matched.)
T23: This function must return a value.
All return statements must be followed by an expression if the enclosing function returns a value. Note that the compiler does NOT attempt to verify that all executions paths of a function with non-void return type actually returns a value; if you fail to return a value, the return value is undefined. For instace, the following is a legal (though incorrect) ZScript program:
L24: Too many global variables.
The assembly language to which ZScript is compiled has a built-in maximum of 256 global variables. ZScript can't do anything if you exceed this limit.
T25: Constant bitshift by noninteger amount; truncating to nearest integer.
Self-explanatory; the bitshift operators (<< and >>) require that their second parameters be whole integers.
T27: Left of the arrow (->) operator must be a pointer type (ffc, etc).
It makes no sense to write "x->foo" if x is of type int. You may only use the dereference (->) operator on pointer types.
T28: That pointer type does not have a function foo.
You tried to use the dereference operator (->) to call a function that does not exist for the pointer type being dereferenced. Check the list of member variables and functions and verify you have not mistyped the function you are trying to call.
T29: That pointer type does not have a variable foo.
As above, but the member variable you tried to access does not exist.
---Errors During Intermediate Code Generation---
G33: Break must lie inside of an enclosing for or while loop.
As in C, the break keyword aborts the innermost for or while loop being executed; as such it makes no sense to break if an enclosing for or while loop does not exist.
G34: Continue must lie inside of an enclosing for or while loop.
As the above error, but with the continue keyword. Continue aborts the current iteration of the loop and skips to the next iteration.
Any other errors you receive (in particular anything marked as an "Internal Error" is indicative of a bug in the
compiler, and should be reported promptly.