It turns out gcc on little endian machines didn't guarantee the type of
ShortNoSwap due to it being a macro that just returned its parameter. At
the same time, LongNoSwap and FloatNoSwap have been fixed.
The bsp2 header is not necessarily correct (or even present), but the bsp29
header is: it was setup via set_bsp32_write. This fixes the bsp corruption
when vising a map (and, I expect, any problems with qfbsp on a big-endian
machine).
Since the hull depth needs to be set for the hull to be useful, it makes
sense to move the code into the same place that allocates new hulls (to me,
anyway).
MOVEP's opc itself is always known and used, whether it's a constant
pointer or variable doesn't matter. This fixes the lost pointer calculation
for va_list.list[j] = object_from_plist (item);
Dead nodes are those that generate unused values (unassigned leaf nodes,
expressions or destinationless move(p) nodes). The revoval is done by the
flow analysis code (via the dags code) so that any pre and post removal
flow analysis and manipulation may be done (eg, available expressions).
assign_expr mangles the destination expression for dereferenced
assignments into something that is invalid as an lvalue, so simply use
new_binary_expr with the same opcode.
It turns out expression trees are (mostly?) valid DAGs, so all edges being
constrained works, though the graphs get a little tall (but easier to read).
This fixes the infinite loop in if ((x = self.heat && x))
Really, I think I need to revisit the whole expression tree code. It's
proving to be rather fragile.
The source of the assignment is used as the value to test, and the
assignment itself is inserted into the boolean expressions's block. This
fixes the inernal error for "if ((x = 0))".
Normally, it will happen only as a follow-on error, but I can think of a
way to force it without other errors, so treating it as an internal error
is a bit harsh.
But reset current_symtab to its prior value when done. This fixes a
segfault caused by initializing the class system while parsing a struct
(eg, one of the members is of type id).
The keywords table was rather awkward to edit (and sometimes confusing).
Worse, because the hash table used to look up the keywords was initialized
only once, changing modes in the same execution of qfcc would not work
properly as keywords would not be added or removed as appropriate.
Now there are four categories of keywords:
o "core" Always available. They form the core of QuakeC except for two
extensions.
o "@" In extended and advanced modes, the preceeding @ is optional,
but tranditional mode requires the keywords to be preceeded by
an @. They are the C keywords that QuakeC did not use, but can
be implemented in v6 progs under certain circumstances.
o "QF" These keywords require the QuakeForge VM to be usable.
o "Obj" These keywords form Ruamoko/Objective-QuakeC and require both
advanced mode and the QuakeForge VM.
This fixes the segfault/null pointer access in sendv.r. While I wanted to
use the edge setting code to set the live bit, I didn't expect it to be
this easy. def_visit_all is proving to be worth every bit it consumes :)
It seems dag_set_live_vars still served a purpose after all, but I don't
feel like bringing it as I'd rather implement its param handing in
dagnode_set_edges. I've now got a test case for it, though the test
currently causes the VM to segfault (even with pr_boundscheck 2!).
If the final block ends in a conditional statement, appending return to the
block will hide the conditional statement from the flow analyzer. This may
cause the conditional statement's destination node be become unreachable
according to the analyzer and thus eliminated. The label for the branch
then loses its target sblock and thus the code generator will produce a
zero-distance jump resulting in an infinite loop.
Thus, if the final block ends in a conditional statement (or, for
completeness, a call statement), append a new empty block before adding the
return statement.