-
Notifications
You must be signed in to change notification settings - Fork 33
Code Migration
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.
QCFLAGS: -futf8
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:
-
utf-8 character constants.
float chr = '∑';will correctly setchr = 0x2211. -
utf-8 escape sequences in strings and character constants. In the code
string foo = "\{x2211}";the U+2211 constant will be utf-8 encoded.
Nothing special required.
QCFLAGS: -fcorrect-ternary
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.
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.
TODO
QCFLAGS: -fvariadic-args
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");
}None required.
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;Not required, but we suggest changing builtins like print(...) into print(string...).
QCFLAGS: -floop-labels
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.
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).
QCFLAGS: -funtyped-nil
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 ""
}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.
TODO