Code Migration - graphitemaster/gmqcc GitHub Wiki

Migration to GMQCC specific code and features

As you may have guessed, gmqcc shouldn't "just" replace your compiler, but it should also add some features will make your life easier, and some which are simply overdue. Of course the current focus is still on being compatible, but nonetheless we're slowly planning and adding features to come.

UTF-8 Support

QCFLAGS: -futf8

Description

For a while now, darkplaces supports utf-8 strings. Using an utf-8 string in QC code always worked. But there are 2 additions with this flag:

  1. utf-8 character constants. float chr = '∑'; will correctly set chr = 0x2211.

  2. utf-8 escape sequences in strings and character constants. In the code string foo = "\{x2211}"; the U+2211 constant will be utf-8 encoded.

Migration

Nothing special required.

The ternary operator

QCFLAGS: -fcorrect-ternary

Description

This changes the ternary's precedence to behave like in C. So you can safely write print(a ? str1 : str2, "\n"); Note however that by default a warning will be displayed for this kind of ternary use.

Migration

In order to make sure your code does not suddenly start behaving differently, enable the ternary-precedence warning with -Wternary-precedence, then fix all warnings. After that you can switch to using -fcorrect-ternary.

Enhanced switch statements

TODO

varargs support

QCFLAGS: -fvariadic-args

Description

With this option it is possible to access varargs from within QC. This is done with the following syntax:

...(parameter, TYPE)

The parameter can be an expression, or a constant. Note that much like with arrays, constants will cause direct access, while variable expressions will call an accessor function. The TYPE can be any type without attributes.

In order to know how many parameters were passed to a function, the ... parameter has to be suffixed with a name, which will implicitly become a local variable of type float containing the number of varargs.

Here's an example:

void print_nth_string(float n, ...count) {
    if (n >= count)
        print("*** invalid parameter\n");
    else
        print("String ", ftos(n), " is: `", ...(n, string), "`\n");
}

Additionally, a type-restriction syntax has been added, so you can make sure the function cannot be called with types other than string by changing ...count into string...count:

void print_nth_string(float n, string...count) {
    if (n >= count)
        print("*** invalid parameter\n");
    else
        print("String ", ftos(n), " is: `", ...(n, string), "`\n");
}

Migration

None required.

Type restricted variadic arguments

Description

In order to be a bit stricter concering parameter types of variadic functions, we added a way to restrict the type of all variadic parameters at once. This is done by prefixing the ... with a type.

For instance, to turn the print builtin into a function which accepts a variable amount of strings:

void print(string...) = #1234;

Migration

Not required, but we suggest changing builtins like print(...) into print(string...).

Labeled loops

QCFLAGS: -floop-labels

Description

Labeling a loop allows you to use break and continue from nested loops to break out of outer loops. Just look at this example code:

void   print(...)   = #1;
string ftos (float) = #2;
void main(float a, float b) {
    float i, j;
    for :outer (i = 0; i < 5; ++i) {
        for (j = 0; j < 8; ++j) {
            print(ftos(j), " ");
            if (i == a && j == b) {
                print("OUT\n");
                continue outer; // or 'break' to stop both loops
            }
        }
        print("\n");
    }
}

Obviously this is different from simply putting a label in front of a loop and using goto in that a continue will for instance jump to a for-loop's incrementing-statement, while a break will jump out of the loop. Using regular labels with goto would require multiple labels for this type of behaviour.

Migration

Nothing special required. There's no option to help you find goto using code which could be improved with loop-labels. You can however just grep your source for goto, it shouldn't yield many results. If it does, change that, because goto yields bad code (and disables some optimizations).

Untyped null-constant

QCFLAGS: -funtyped-nil

Description

Often you see QC code declare various kinds of null variables which are simply uninitialized globals. Like a void SUB_null();. Usually one such function suffices, but modern compilers will warn when trying to assign this function to one of a different signature.

For this we added an untyped nil, which can be assigned to anything: functions, entities, strings, floats.

void clear() {
    self.other = nil;
    self.think = nil;
    self.name = nil; // NOT the same as assigning ""
}

Migration

There are 2 warn-flags which are useful to find globals like SUB_null: -Wuninitialized-constant and -Wuninitialized-global. The first will warn about uninitialized globals declared using the const keyword, the other one will warn about any global without the var keyword which is not initialized.

AST Macros

TODO