public void BinaryExpression(CParser.BinaryExpression BinaryExpression)
{
var Operator = BinaryExpression.Operator;
var Left = BinaryExpression.Left;
var LeftCType = Left.GetCachedCType(this);
var LeftType = ConvertCTypeToType(LeftCType);
var Right = BinaryExpression.Right;
var RightCType = Right.GetCachedCType(this);
var RightType = ConvertCTypeToType(RightCType);
// Assignments
switch (Operator)
{
case "<<=":
case ">>=":
case "&=":
case "|=":
case "^=":
case "*=":
case "/=":
case "%=":
case "-=":
case "+=":
case "=":
{
LocalBuilder LeftValueLocal = null;
if (RequireYieldResult)
{
LeftValueLocal = SafeILGenerator.DeclareLocal(LeftType, "TempLocal");
}
var LeftFieldAccess = Left as CParser.FieldAccessExpression;
FieldInfo FieldToStore = null;
MethodInfo MethodInfoToCallSet = null;
MethodInfo MethodInfoToCallGet = null;
// This is a field? Instead of loading the address try to perform a StoreField.
if (LeftFieldAccess != null && LeftFieldAccess.Operator == ".")
{
var StructureCType = LeftFieldAccess.LeftExpression.GetCachedCType(this);
var StructureType = ConvertCTypeToType(StructureCType);
FieldToStore = StructureType.GetField(LeftFieldAccess.FieldName);
MethodInfoToCallSet = StructureType.GetMethod("set_" + LeftFieldAccess.FieldName);
MethodInfoToCallGet = StructureType.GetMethod("get_" + LeftFieldAccess.FieldName);
if (FieldToStore == null && MethodInfoToCallSet == null)
{
throw(new InvalidOperationException("Null"));
}
DoGenerateAddress(true, () =>
{
Traverse(LeftFieldAccess.LeftExpression);
});
}
// Other kind, get the address and later it will perform a StoreIndirect.
else
{
DoGenerateAddress(true, () =>
{
Traverse(Left);
});
}
// Just store.
if (Operator == "=")
{
DoGenerateAddress(false, () =>
{
Traverse(Right);
});
}
// Store the value modified.
else
{
SafeILGenerator.Duplicate();
if (MethodInfoToCallGet != null)
{
SafeILGenerator.Call(MethodInfoToCallGet);
}
else
{
SafeILGenerator.LoadIndirect(LeftType);
}
DoGenerateAddress(false, () =>
{
Traverse(Right);
});
_DoBinaryOperation(Operator.Substring(0, Operator.Length - 1), LeftCType.GetCSimpleType().Sign);
}
// Convert the value to the LeftType.
SafeILGenerator.ConvertTo(LeftType);
// Stores the value into the temp variable without poping it.
if (LeftValueLocal != null)
{
SafeILGenerator.Duplicate();
SafeILGenerator.StoreLocal(LeftValueLocal);
}
// Stores the result
if (FieldToStore != null)
{
SafeILGenerator.StoreField(FieldToStore);
}
else if (MethodInfoToCallSet != null)
{
SafeILGenerator.Call(MethodInfoToCallSet);
}
else
{
SafeILGenerator.StoreIndirect(LeftType);
}
// Yields the result.
if (LeftValueLocal != null)
{
SafeILGenerator.LoadLocal(LeftValueLocal);
}
}
return;
default:
{
// Pointer operations.
if (LeftType.IsPointer || RightType.IsPointer)
{
switch (Operator)
{
case "+":
DoGenerateAddress(false, () =>
{
Traverse(Left);
//Traverse(Right);
Traverse(new CParser.BinaryExpression(Right, "*", new CParser.SizeofTypeExpression(((CPointerType)LeftCType).ElementCType)));
});
//SafeILGenerator.Sizeof(LeftType.GetElementType());
//SafeILGenerator.BinaryOperation(SafeBinaryOperator.MultiplyUnsigned);
SafeILGenerator.BinaryOperation(SafeBinaryOperator.AdditionUnsigned);
break;
case "-":
// TODO: Check both types?!
DoGenerateAddress(false, () =>
{
Traverse(Left);
Traverse(Right);
});
SafeILGenerator.BinaryOperation(SafeBinaryOperator.SubstractionSigned);
SafeILGenerator.Sizeof(LeftType.GetElementType());
SafeILGenerator.BinaryOperation(SafeBinaryOperator.DivideUnsigned);
break;
case ">=":
case "<=":
case ">":
case "<":
case "==":
case "!=":
case "&&":
case "||":
DoGenerateAddress(false, () =>
{
Traverse(Left);
Traverse(Right);
});
_DoBinaryOperation(Operator, Left.GetCachedCType(this).GetCSimpleType().Sign);
break;
default:
Console.Error.WriteLine("Not supported operator '{0}' for pointer aritmetic types : {1}, {2}", Operator, LeftType, RightType);
throw (new NotImplementedException(String.Format("Not supported operator '{0}' for pointer aritmetic types : {1}, {2}", Operator, LeftType, RightType)));
}
}
// Non-pointer operations
else
{
DoBinaryOperation(Operator, Left, Right);
}
}
break;
}
}