diff --git a/Source/Parser/Expressions/Trigger/MemoryAccessorExpression.cs b/Source/Parser/Expressions/Trigger/MemoryAccessorExpression.cs index e5e8a50e..aef7565e 100644 --- a/Source/Parser/Expressions/Trigger/MemoryAccessorExpression.cs +++ b/Source/Parser/Expressions/Trigger/MemoryAccessorExpression.cs @@ -132,7 +132,13 @@ public bool PointerChainMatches(MemoryAccessorExpressionBase that) var memoryValue = that as MemoryValueExpression; if (memoryValue != null) - return PointerChainMatches(memoryValue.MemoryAccessors.Last().MemoryAccessor); + { + var memoryAcessorExpression = memoryValue.MemoryAccessors.Last(); + if (memoryAcessorExpression.ModifyingOperator != RequirementOperator.None) + return false; + + return PointerChainMatches(memoryAcessorExpression.MemoryAccessor); + } return (_pointerChain == null || _pointerChain.Count == 0); } diff --git a/Source/Parser/Expressions/Trigger/RequirementConditionExpression.cs b/Source/Parser/Expressions/Trigger/RequirementConditionExpression.cs index 42fcc684..30205ad5 100644 --- a/Source/Parser/Expressions/Trigger/RequirementConditionExpression.cs +++ b/Source/Parser/Expressions/Trigger/RequirementConditionExpression.cs @@ -73,18 +73,68 @@ protected override bool Equals(ExpressionBase obj) public override ErrorExpression BuildTrigger(TriggerBuilderContext context) { ErrorExpression error; + var comparison = Comparison; + var left = Left; var right = MemoryAccessorExpressionBase.ReduceToSimpleExpression(Right); - var memoryValue = Left as MemoryValueExpression; + var rightAccessor = right as MemoryAccessorExpression; + if (rightAccessor != null && rightAccessor.HasPointerChain) + { + if (rightAccessor.PointerChainMatches(left as MemoryAccessorExpressionBase)) + { + rightAccessor = rightAccessor.Clone(); + rightAccessor.ClearPointerChain(); + } + else + { + var leftMemoryValue = left as MemoryValueExpression; + if (leftMemoryValue != null && leftMemoryValue.MemoryAccessors.All(m => m.ModifyingOperator != RequirementOperator.None)) + { + // all elements on left side are modified, so we'd need a 0 placeholder for the comparison + // attempt to avoid that by making the right value the AddSource element. + // + // A / 2 > B -> - A / 2 + B < 0 + // + // move the left side to the right side and invert + var newLeft = new MemoryValueExpression(); + newLeft = newLeft.Combine(right, MathematicOperation.Add) as MemoryValueExpression; + left = newLeft.Combine(left, MathematicOperation.Subtract); + comparison = ComparisonExpression.ReverseComparisonOperation(comparison); + } + else + { + // move the right side to the left side and compare to zero. + // + // A > B / 2 -> - B / 2 + A > 0 + // + var newLeft = new MemoryValueExpression(); + newLeft = newLeft.Combine(left, MathematicOperation.Add) as MemoryValueExpression; + left = newLeft.Combine(right, MathematicOperation.Subtract); + } + + if (comparison == ComparisonOperation.LessThan || comparison == ComparisonOperation.LessThanOrEqual) + { + // can't comare "<0" or "<=0". invert comparison + var newLeft = new MemoryValueExpression(); + left = ((MemoryValueExpression)left).InvertAndMigrateAccessorsTo(newLeft); + comparison = ComparisonExpression.ReverseComparisonOperation(comparison); + } + + right = new IntegerConstantExpression(0); + rightAccessor = null; + } + } + + var memoryValue = left as MemoryValueExpression; if (memoryValue != null) { error = memoryValue.BuildTrigger(context, right); } else { - var trigger = Left as ITriggerExpression; + var trigger = left as ITriggerExpression; if (trigger == null) - return new ErrorExpression(string.Format("Cannot compare {0} in a trigger", Left.Type), Left); + return new ErrorExpression(string.Format("Cannot compare {0} in a trigger", left.Type), left); error = trigger.BuildTrigger(context); } @@ -94,29 +144,15 @@ public override ErrorExpression BuildTrigger(TriggerBuilderContext context) var lastRequirement = context.LastRequirement; - var rightAccessor = right as MemoryAccessorExpression; if (rightAccessor != null) - { - if (rightAccessor.HasPointerChain) - { - if (!rightAccessor.PointerChainMatches(Left as MemoryAccessorExpressionBase)) - return new ErrorExpression("Cannot compare values with different pointer chains", this); - - rightAccessor = rightAccessor.Clone(); - rightAccessor.ClearPointerChain(); - } - lastRequirement.Right = FieldFactory.CreateField(rightAccessor); - } else - { lastRequirement.Right = FieldFactory.CreateField(right); - } if (lastRequirement.Right.Type == FieldType.None) return new ErrorExpression(string.Format("Cannot compare {0} in a trigger", Right.Type), Right); - lastRequirement.Operator = ConvertToRequirementOperator(Comparison); + lastRequirement.Operator = ConvertToRequirementOperator(comparison); return null; } diff --git a/Tests/Parser/Expressions/Trigger/RequirementConditionExpression_Tests.cs b/Tests/Parser/Expressions/Trigger/RequirementConditionExpression_Tests.cs index d0e64cfa..72edc115 100644 --- a/Tests/Parser/Expressions/Trigger/RequirementConditionExpression_Tests.cs +++ b/Tests/Parser/Expressions/Trigger/RequirementConditionExpression_Tests.cs @@ -60,6 +60,9 @@ public void TestAppendString(string input) [TestCase("byte(0x1234) - byte(0x2345) == 4294967295", "B:0xH002345=0_0xH001234=4294967295")] // don't invert very high positive value [TestCase("byte(0x1234) - byte(0x2345) <= -1", "A:1=0_0xH001234<=0xH002345")] [TestCase("dword(0x1234) - prev(dword(0x1234)) >= 0x1000", "A:4096=0_d0xX001234<=0xX001234")] + [TestCase("word(dword(0x7f6f10) + 0xB00) > word(dword(0x7f6f10) + 0xB02)", "I:0xX7f6f10_0x 000b00>0x 000b02")] + [TestCase("word(dword(0x7f6f10) + 0xB00) > word(dword(0x7f6f10) + 0xB02) / 2", "I:0xX7f6f10_B:0x 000b02/2_I:0xX7f6f10_0x 000b00>0")] // cannot share addaddress if one value is modified + [TestCase("word(dword(0x7f6f10) + 0xB00) / 2 > word(dword(0x7f6f10) + 0xB02)", "I:0xX7f6f10_B:0x 000b02_I:0xX7f6f10_A:0x 000b00/2_0>0")] // cannot share addaddress if one value is modified public void TestBuildTrigger(string input, string expected) { var clause = TriggerExpressionTests.Parse(input);