Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion Source/Data/FieldSize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,5 +288,29 @@ public static bool IsBigEndian(this FieldSize size)
return false;
}
}

/// <summary>
/// Gets the big-endian size corresponding to the provided little-endian size or
/// the little-endian size corresponding to the provided big-endian size.
/// </summary>
public static FieldSize ToggleEndianness(this FieldSize size)
{
switch (size)
{
case FieldSize.Word: return FieldSize.BigEndianWord;
case FieldSize.TByte: return FieldSize.BigEndianTByte;
case FieldSize.DWord: return FieldSize.BigEndianDWord;
case FieldSize.Float: return FieldSize.BigEndianFloat;
case FieldSize.Double32: return FieldSize.BigEndianDouble32;
case FieldSize.BigEndianWord: return FieldSize.Word;
case FieldSize.BigEndianTByte: return FieldSize.TByte;
case FieldSize.BigEndianDWord: return FieldSize.DWord;
case FieldSize.BigEndianFloat: return FieldSize.Float;
case FieldSize.BigEndianDouble32: return FieldSize.Double32;
case FieldSize.MBF32: return FieldSize.LittleEndianMBF32;
case FieldSize.LittleEndianMBF32: return FieldSize.MBF32;
default: return size;
}
}
}
}
}
6 changes: 3 additions & 3 deletions Source/Parser/Expressions/ComparisonExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public override bool ReplaceVariables(InterpreterScope scope, out ExpressionBase
var comparisonNormalize = left as IComparisonNormalizeExpression;
if (comparisonNormalize != null)
{
var normalized = comparisonNormalize.NormalizeComparison(right, Operation, true);
var normalized = comparisonNormalize.NormalizeComparison(right, Operation, false);
if (normalized != null && normalized is not ComparisonExpression)
{
result = normalized;
Expand Down Expand Up @@ -257,11 +257,11 @@ public static ExpressionBase NormalizeFloatComparisonForInteger(ExpressionBase l
{
case ComparisonOperation.Equal:
// integer a == 4.2 can never be true
return new ErrorExpression("Result can never be true using integer math");
return new ErrorExpression("Result can never be true using integer math") { Location = left.Location.Union(right.Location) };

case ComparisonOperation.NotEqual:
// integer a != 4.2 is always true
return new ErrorExpression("Result is always true using integer math");
return new ErrorExpression("Result is always true using integer math") { Location = left.Location.Union(right.Location) };

case ComparisonOperation.LessThan:
// integer a < 4.2 becomes integer a <= 4
Expand Down
31 changes: 31 additions & 0 deletions Source/Parser/Expressions/Trigger/ErrorRequirementExpression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using RATools.Parser.Internal;
using System.Text;

namespace RATools.Parser.Expressions.Trigger
{
internal class ErrorRequirementExpression : RequirementExpressionBase
{
public ErrorRequirementExpression(ErrorExpression error)
{
_error = error;
}

private readonly ErrorExpression _error;

public override ErrorExpression BuildTrigger(TriggerBuilderContext context)
{
return _error;
}

internal override void AppendString(StringBuilder builder)
{
_error.AppendString(builder);
}

protected override bool Equals(ExpressionBase obj)
{
var that = obj as ErrorRequirementExpression;
return (that != null && that._error == _error);
}
}
}
232 changes: 232 additions & 0 deletions Source/Parser/Expressions/Trigger/MemoryValueExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ private ExpressionBase ApplyAddition(ExpressionBase right, RequirementType combi
if (_memoryAccessors == null)
_memoryAccessors = new List<ModifiedMemoryAccessorExpression>();
_memoryAccessors.Add(modifiedMemoryAccessor);

break;

default:
Expand Down Expand Up @@ -1543,8 +1544,16 @@ public ErrorExpression BuildTrigger(TriggerBuilderContext context, ExpressionBas
}

if (_memoryAccessors != null)
{
memoryAccessors.AddRange(_memoryAccessors);

if (_memoryAccessors.Any(a => a.ModifyingOperator == RequirementOperator.Multiply) &&
_memoryAccessors.Any(a => a.ModifyingOperator == RequirementOperator.None))
{
CombineNeighboringMemoryReads(memoryAccessors);
}
}

if (appendConstantAccessor)
memoryAccessors.Add(constantAccessor);

Expand Down Expand Up @@ -1658,6 +1667,229 @@ public ErrorExpression BuildTrigger(TriggerBuilderContext context, ExpressionBas
return null;
}

internal MemoryValueExpression NormalizeMemoryReads()
{
if (_memoryAccessors.Any(a => a.ModifyingOperator == RequirementOperator.Multiply) &&
_memoryAccessors.Any(a => a.ModifyingOperator == RequirementOperator.None))
{
var memoryAccessors = new List<ModifiedMemoryAccessorExpression>(_memoryAccessors);
CombineNeighboringMemoryReads(memoryAccessors);
if (memoryAccessors.Count != _memoryAccessors.Count)
{
var newMemoryValue = Clone();
newMemoryValue._memoryAccessors = memoryAccessors;
return newMemoryValue;
}
}

return this;
}

private static void CombineNeighboringMemoryReads(List<ModifiedMemoryAccessorExpression> memoryAccessors)
{
int initialCount;
do
{
initialCount = memoryAccessors.Count;

for (int i = memoryAccessors.Count - 1; i >= 0; --i)
{
var modifiedMemoryAccessor = memoryAccessors[i];
if (modifiedMemoryAccessor.ModifyingOperator != RequirementOperator.Multiply)
continue;

if (modifiedMemoryAccessor.Modifier.Type != FieldType.Value)
continue;
if (!modifiedMemoryAccessor.MemoryAccessor.Field.IsMemoryReference)
continue;
if (modifiedMemoryAccessor.MemoryAccessor.Field.IsFloat)
continue;
if (modifiedMemoryAccessor.MemoryAccessor.Field.Size.GetByteSize() == 4)
continue;

switch (modifiedMemoryAccessor.Modifier.Value)
{
case 0x10:
MergeLowNibble(memoryAccessors, i, modifiedMemoryAccessor);
break;

case 0x100:
MergeLowByte(memoryAccessors, i, modifiedMemoryAccessor, false);
break;

case 0x10000:
MergeLowWord(memoryAccessors, i, modifiedMemoryAccessor, false);
break;

case 0x1000000:
MergeLowTByte(memoryAccessors, i, modifiedMemoryAccessor, false);
break;

case 100:
MergeLowByte(memoryAccessors, i, modifiedMemoryAccessor, true);
break;

case 10000:
MergeLowWord(memoryAccessors, i, modifiedMemoryAccessor, true);
break;

case 1000000:
MergeLowTByte(memoryAccessors, i, modifiedMemoryAccessor, true);
break;
}
}
} while (memoryAccessors.Count != initialCount && memoryAccessors.Count > 1);
}

private static void MergeLowNibble(List<ModifiedMemoryAccessorExpression> memoryAccessors, int modifiedIndex, ModifiedMemoryAccessorExpression modifiedMemoryAccessor)
{
if (modifiedMemoryAccessor.MemoryAccessor.Field.Size == FieldSize.HighNibble)
{
var lowNibbleIndex = FindMemoryRead(memoryAccessors, FieldSize.LowNibble,
modifiedMemoryAccessor, modifiedMemoryAccessor.MemoryAccessor.Field.Value);
if (lowNibbleIndex != -1)
MergeMemoryReads(memoryAccessors, modifiedIndex, lowNibbleIndex, FieldSize.Byte);
}
}

private static void MergeLowByte(List<ModifiedMemoryAccessorExpression> memoryAccessors, int modifiedIndex, ModifiedMemoryAccessorExpression modifiedMemoryAccessor, bool matchBcd)
{
bool isBcd = modifiedMemoryAccessor.MemoryAccessor is BinaryCodedDecimalExpression;
if (isBcd != matchBcd)
return;

FieldSize targetSize;
var fieldSize = modifiedMemoryAccessor.MemoryAccessor.Field.Size;
switch (fieldSize)
{
case FieldSize.Byte:
targetSize = FieldSize.Word;
break;
case FieldSize.Word:
targetSize = FieldSize.TByte;
break;
case FieldSize.TByte:
targetSize = FieldSize.DWord;
break;
case FieldSize.BigEndianWord:
targetSize = FieldSize.BigEndianTByte;
break;
case FieldSize.BigEndianTByte:
targetSize = FieldSize.BigEndianDWord;
break;
default:
return;
}

MergeAccessors(memoryAccessors, modifiedIndex, modifiedMemoryAccessor,
FieldSize.Byte, fieldSize, targetSize, isBcd);
}

private static void MergeLowWord(List<ModifiedMemoryAccessorExpression> memoryAccessors, int modifiedIndex, ModifiedMemoryAccessorExpression modifiedMemoryAccessor, bool matchBcd)
{
bool isBcd = modifiedMemoryAccessor.MemoryAccessor is BinaryCodedDecimalExpression;
if (isBcd != matchBcd)
return;

FieldSize targetSize;
var fieldSize = modifiedMemoryAccessor.MemoryAccessor.Field.Size;
switch (fieldSize)
{
case FieldSize.Byte:
targetSize = FieldSize.TByte;
break;
case FieldSize.Word:
targetSize = FieldSize.DWord;
break;
case FieldSize.BigEndianWord:
targetSize = FieldSize.BigEndianDWord;
break;
default:
return;
}

MergeAccessors(memoryAccessors, modifiedIndex, modifiedMemoryAccessor,
FieldSize.Word, fieldSize, targetSize, isBcd);
}

private static void MergeLowTByte(List<ModifiedMemoryAccessorExpression> memoryAccessors, int modifiedIndex, ModifiedMemoryAccessorExpression modifiedMemoryAccessor, bool matchBcd)
{
bool isBcd = modifiedMemoryAccessor.MemoryAccessor is BinaryCodedDecimalExpression;
if (isBcd != matchBcd)
return;

if (modifiedMemoryAccessor.MemoryAccessor.Field.Size == FieldSize.Byte)
{
MergeAccessors(memoryAccessors, modifiedIndex, modifiedMemoryAccessor,
FieldSize.TByte, FieldSize.Byte, FieldSize.DWord, isBcd);
}
}

private static void MergeAccessors(List<ModifiedMemoryAccessorExpression> memoryAccessors,
int modifiedIndex, ModifiedMemoryAccessorExpression modifiedMemoryAccessor,
FieldSize mergeSize, FieldSize fieldSize, FieldSize targetSize, bool isBcd)
{
var address = modifiedMemoryAccessor.MemoryAccessor.Field.Value;

if (targetSize.IsBigEndian())
{
var lowIndex = FindMemoryRead(memoryAccessors, mergeSize.ToggleEndianness(),
modifiedMemoryAccessor,
address + fieldSize.GetByteSize(), isBcd);
if (lowIndex != -1)
MergeMemoryReads(memoryAccessors, lowIndex, modifiedIndex, targetSize, isBcd);
}
else
{
var lowIndex = FindMemoryRead(memoryAccessors, mergeSize,
modifiedMemoryAccessor, address - mergeSize.GetByteSize(), isBcd);
if (lowIndex != -1)
{
MergeMemoryReads(memoryAccessors, modifiedIndex, lowIndex, targetSize, isBcd);
}
else if (fieldSize == FieldSize.Byte)
{
lowIndex = FindMemoryRead(memoryAccessors, mergeSize.ToggleEndianness(),
modifiedMemoryAccessor, address + 1, isBcd);
if (lowIndex != -1)
MergeMemoryReads(memoryAccessors, lowIndex, modifiedIndex, targetSize.ToggleEndianness(), isBcd);
}
}
}

private static void MergeMemoryReads(List<ModifiedMemoryAccessorExpression> memoryAccessors, int fromIndex, int toIndex, FieldSize newSize, bool makeBcd = false)
{
var newAccessor = memoryAccessors[toIndex].MemoryAccessor.ChangeFieldSize(newSize);
if (makeBcd)
newAccessor = new BinaryCodedDecimalExpression(newAccessor);

var newModifiedAccessor = new ModifiedMemoryAccessorExpression(newAccessor) { CombiningOperator = memoryAccessors[toIndex].CombiningOperator };
newModifiedAccessor.Location = newAccessor.Location.Union(memoryAccessors[fromIndex].Location);
memoryAccessors[toIndex] = newModifiedAccessor;
memoryAccessors.RemoveAt(fromIndex);
}

private static int FindMemoryRead(List<ModifiedMemoryAccessorExpression> memoryAccessors, FieldSize size, ModifiedMemoryAccessorExpression matchMemoryAccessor, uint address, bool matchBcd = false)
{
for (int i = 0; i < memoryAccessors.Count; ++i)
{
var modifiedMemoryAccessor = memoryAccessors[i];
if (modifiedMemoryAccessor.ModifyingOperator == RequirementOperator.None &&
modifiedMemoryAccessor.MemoryAccessor.Field.Value == address &&
modifiedMemoryAccessor.MemoryAccessor.Field.Size == size &&
modifiedMemoryAccessor.CombiningOperator == matchMemoryAccessor.CombiningOperator &&
modifiedMemoryAccessor.MemoryAccessor.Field.Type == matchMemoryAccessor.MemoryAccessor.Field.Type &&
modifiedMemoryAccessor.MemoryAccessor.PointerChainMatches(matchMemoryAccessor.MemoryAccessor))
{
bool isBcd = (modifiedMemoryAccessor.MemoryAccessor is BinaryCodedDecimalExpression);
if (isBcd == matchBcd)
return i;
}
}

return -1;
}

public ErrorExpression Execute(InterpreterScope scope)
{
if (_memoryAccessors == null || _memoryAccessors.Count == 0)
Expand Down
Loading
Loading