public override sealed Reg CGenValue(CGenState state) {
// 1. Get the address of expr.
//
// regs:
// %eax = &expr
//
// stack:
// +-------+
// | ..... | <- %esp
// +-------+
//
this.Expr.CGenAddress(state);
// 2. Push address.
//
// regs:
// %eax = &expr
//
// stack:
// +-------+
// | ..... |
// +-------+
// | &expr | <- %esp
// +-------+
//
Int32 stack_size = state.CGenPushLong(Reg.EAX);
// 3. Get current Value of expr.
//
// 1) If expr is an integral or pointer:
//
// regs:
// %eax = expr
//
// stack:
// +-------+
// | ..... |
// +-------+
// | &expr | <- %esp
// +-------+
//
//
// 2) If expr is a float:
//
// regs:
// %eax = &expr
//
// stack:
// +-------+
// | ..... |
// +-------+
// | &expr | <- %esp
// +-------+
//
// float stack:
// +-------+
// | expr | <- %st(0)
// +-------+
//
Reg ret = this.Expr.CGenValue(state);
switch (ret) {
case Reg.EAX:
// expr is an integral or pointer.
// 4. Pop address to %ecx.
//
// regs:
// %eax = expr
// %ecx = &expr
//
// stack:
// +-------+
// | ..... | <- %esp
// +-------+
//
state.CGenPopLong(stack_size, Reg.ECX);
// 5. Cache current Value of Expr in %ebx.
//
// regs:
// %eax = expr
// %ebx = expr
// %ecx = &expr
//
// stack:
// +-------+
// | ..... | <- %esp
// +-------+
//
state.MOVL(Reg.EAX, Reg.EBX);
// 6. Calculate the new value in %ebx or %eax and save.
// Set %eax to be the return Value.
//
// regs:
// %eax = expr or (expr +- 1)
// %ebx = (expr +- 1) or expr
// %ecx = &expr
//
// stack:
// +-------+
// | ..... | <- %esp
// +-------+
//
switch (this.Expr.Type.Kind) {
case ExprTypeKind.CHAR:
case ExprTypeKind.UCHAR:
CalcAndSaveByte(state);
return Reg.EAX;
case ExprTypeKind.SHORT:
case ExprTypeKind.USHORT:
CalcAndSaveWord(state);
return Reg.EAX;
case ExprTypeKind.LONG:
case ExprTypeKind.ULONG:
CalcAndSaveByte(state);
return Reg.EAX;
case ExprTypeKind.POINTER:
CalcAndSavePtr(state);
return Reg.EAX;
default:
throw new InvalidProgramException();
}
case Reg.ST0:
// Expr is a float.
// 4. Pop address to %ecx.
//
// regs:
// %ecx = &expr
//
// stack:
// +-------+
// | ..... | <- %esp
// +-------+
//
state.CGenPopLong(stack_size, Reg.ECX);
// 5. Load 1.0 to FPU stack.
//
// regs:
// %ecx = &expr
//
// stack:
// +-------+
// | ..... | <- %esp
// +-------+
//
// float stack:
// +-------+
// | expr | <- %st(1)
// +-------+
// | 1.0 | <- %st(0)
// +-------+
//
state.FLD1();
// 6. Calculate the new value and save back.
// Set %st(0) to be the new or original Value.
//
// regs:
// %ecx = &Expr
//
// stack:
// +-------+
// | ..... | <- %esp
// +-------+
//
// float stack:
// +---------------------+
// | expr or (epxr +- 1) | <- %st(0)
// +---------------------+
//
switch (this.Expr.Type.Kind) {
case ExprTypeKind.FLOAT:
CalcAndSaveFloat(state);
return Reg.ST0;
case ExprTypeKind.DOUBLE:
CalcAndSaveDouble(state);
return Reg.ST0;
default:
throw new InvalidProgramException();
}
default:
throw new InvalidProgramException();
}
}