And partial implementations in qfcc (most places will generate an
internal error (not implemented) or segfault, but some low-hanging fruit
has already been implemented).
Forgetting to invoke [super dealloc] in a derived class's -dealloc
method has caused me to waste far too much time chasing down the
resulting memory leaks and crashes. This is actually the main focus of
issue #24, but I want to take care of multiple paths before I consider
the issue to be done.
However, as a bonus, four cases were found :)
While get_selector does the job of getting a selector from a selector
reference expression, I have long considered lumping various expression
types under ex_expr to be a mistake. Not only is this a step towards
sorting that out, it will make working on #24 easier.
When a type is aliased, the alias has two type chains: the simple type
chain with all other aliases stripped, and the full type chain. There
are still plenty of bugs in it, but having the clean type chain takes
care of the major issue that was in the previous attempt as only the
head of the type-chain needs to be skipped for type comparison.
Most of the bugs are in finding the locations where the head needs to be
skipped.
That is, those created by operand_address. The dag code needs the
expression that is attached to the statement to have the correct
expression type in order to do the right thing with the operands and
aliasing, especially when generating temps. This fixes assignchain when
optimizing (all tests pass again).
Now convert_nil only assigns the nil expression a type, and nil makes
its way down to the statement emission code (where it belongs, really).
Breaks even more things :)
It's not possible to take the address of constants (at this stage) and
trying to use a move instruction with .zero as source would result in
the VM complaining about null pointer access when bounds checking is on.
Thus, don't convert a nil source expression until it is known to be
safe, and use memset when it is not.
This fixes the problem of using the return value of a function as an
element in a compound initializer. The cause of the problem is that
compound initializers were represented by block expressions, but
function calls are contained within block expressions, so def
initialization saw the block expression and thought it was a nested
compound initializer.
Technically, it was a bug in the nested element parsing code in that it
wasn't checking the result value of the block expression, but using a
whole new expression type makes things much cleaner and the work done
paves the way for labeled initializers and compound assignments.
Multi-line calls (especially messages) got rather confusing to read as
the lines jumped back and forth. Now the binding is better but the dags
code is reordering the parameters sometimes.
Only as scalars, I still need to think about what to do for vectors and
quaternions due to param size issues. Also, doubles are not yet
guaranteed to be correctly aligned.
Currently, they can represent either vectors or quaternions, and the
quaternions can be in either [s, v] form or [w, x, y, z] form.
Many things will not actual work yet as the vector expression needs to be
converted into the appropriate form for assigning the elements to the
components of the "vector" type.
This is a nice feature found in fteqcc (also a bit of a challenge from
Spike). Getting bison to accept the new expression required rewriting the
state expression grammar, so this is mostly for the state expression. A
test to ensure the state expression doesn't break is included.
This goes towards complementing the "if not" logic extension. I need to
check if fteqcc supports "not" with "while" (the version I have access to
at the moment does not), and also whether it would be good to support
"not" with "for", and if so, what form the syntax should take.
It is syntactic sugar for if (!(foo)), but is useful for avoiding
inconsistencies between such things as if (string) and if (!string), even
though qcc can't parse if not (string). It also makes for easier to read
code when the logic in the condition is complex.
Since there is now a proper symbol table, defs are now just references to
memory locations and the symbol table takes care of duplicates.
Also, start using far data for ObjQC structures.
The qfo functions have been stubbed out until I figure out what to do with
object files in the new scheme.
That which isn't rewritten is horribly broken. However, this does include a
nice mechanism for building QC structs for emitting data.
emit.c has been gutted in the spirit of "throw one away".
There is much work to be done to get even variables emitted, let alone
code. Things should be a little more fun from here on.
o add OP_JUMPB
o OP_JUMPB renumberd some opcodes, so up PROG_VERSION
pr_edict.c:
o make the version error reporting more informative
pr_exec.c:
o implement OP_JUMPB (goto *(ptr + index))
pr_opcode.c: (libs/gamecode/engine)
o add OP_JUMPB to the table
expr.h:
o ex_uinteger support
o some const correctness
o prototype new_label_expr
qfcc.h:
o uinteger ussport
o add pointers for op_jump and op_jumpb
o prototype PR_GetArray
emit.c:
o general uinteger support
o new reference/reloc type 3: absolute statement address
o jumpb support (binary goto)
expr.c:
o uinteger support
o break the label name creation out of new_label_expr into
new_label_name
o some const correctness
pr_def.c:
o add PR_GetArray to allocate an array in global space
o factor out some code common to PR_GetDef and PR_GetArray that would
otherwise be duplicated
pr_imm.c:
o some const correctness
o uinteger support
pr_lex.c:
o uinteger support
pr_opcode.c: (tools/qfcc/source)
o support jump and jumpb
switch.c:
o rewrite the binary search code to support ranges.
o add ev_uniteger to the types enum
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
progs.h:
o add uinteger accessors
pr_exec.c:
o implement ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
pr_opcode.c:
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
expr.h:
o prototype inc_users
qfcc.h:
o add externs for op_ifbe, op_ifb, op_ifae and op_ifa
emit.c:
o don't bother emiting an assignment to a temp def that's only used once
(ie, it's never read, only written to)
o support the new if* instructions
expr.c:
o support the new if* insructions
o dectect expression loops in append_expr
o support unsigned integers
o re-work temp def usage counting
pr_def.c
o debugging for temp def usage counts
pr_opcode.c:
o support the new if* instructions
qc-parse.y:
o provide defines for IFBE IFB IFAE IFA
switch.c:
o do binary searches for strings, floats and ints if there are more than
8 cases in a switch. Strings need more testing.
get_type and extract_type prototypes and add extern for type_names
emit.c:
use extract_type instead of get_type
expr.c:
get_type now returns the type pointer rather than the qc type enum.
extract_type uses get_type to return the qc type enum.
make type_names global
use get_type instead of ex_expr/ex_def to cover more cases
clean up function call/return processing as a result of get_type
pr_opcode.c:
use opcode_priority_type_table_ab when var_c is null and a minor
cleanup in PR_Opcode_Find
*/CRITICAL/* implication: DO NOT /EVER/ RELY ON EVALUATION ORDER. This
isn't /really/ that bad: evaluation order will be consistent for similar
expressions, but for (eg) foo() + bar()*2, bar will be called first.