public static void Emit(byte[] instruction, CompilationContext context) { // 20000000 // Use the conditional begin instruction stored in the stack. instruction = context.CurrentBlock.BaseInstruction; CodeType codeType = InstructionHelper.GetCodeType(instruction); // Pop the current block of operations from the stack so control instructions // for the conditional can be emitted in the upper block. IEnumerable <IOperation> operations = context.CurrentOperations; context.BlockStack.Pop(); ICondition condition; switch (codeType) { case CodeType.BeginMemoryConditionalBlock: condition = MemoryConditional.Emit(instruction, context); break; case CodeType.BeginKeypressConditionalBlock: condition = KeyPressConditional.Emit(instruction, context); break; case CodeType.BeginRegisterConditionalBlock: condition = RegisterConditional.Emit(instruction, context); break; default: throw new TamperCompilationException($"Conditional end does not match code type {codeType} in Atmosphere cheat"); } // Create a conditional block with the current operations and nest it in the upper // block of the stack. IfBlock block = new IfBlock(condition, operations); context.CurrentOperations.Add(block); }
private static void Emit(byte[] instruction, CompilationContext context, IEnumerable <IOperation> operationsElse) { // 2X000000 // X: End type (0 = End, 1 = Else). byte terminationType = instruction[TerminationTypeIndex]; switch (terminationType) { case End: break; case Else: // Start a new operation block with the 'else' instruction to signal that there is the 'then' block just above it. context.BlockStack.Push(new OperationBlock(instruction)); return; default: throw new TamperCompilationException($"Unknown conditional termination type {terminationType}"); } // Use the conditional begin instruction stored in the stack. var upperInstruction = context.CurrentBlock.BaseInstruction; CodeType codeType = InstructionHelper.GetCodeType(upperInstruction); // Pop the current block of operations from the stack so control instructions // for the conditional can be emitted in the upper block. IEnumerable <IOperation> operations = context.CurrentOperations; context.BlockStack.Pop(); // If the else operations are already set, then the upper block must not be another end. if (operationsElse != null && codeType == CodeType.EndConditionalBlock) { throw new TamperCompilationException($"Expected an upper 'if' conditional instead of 'end conditional'"); } ICondition condition; switch (codeType) { case CodeType.BeginMemoryConditionalBlock: condition = MemoryConditional.Emit(upperInstruction, context); break; case CodeType.BeginKeypressConditionalBlock: condition = KeyPressConditional.Emit(upperInstruction, context); break; case CodeType.BeginRegisterConditionalBlock: condition = RegisterConditional.Emit(upperInstruction, context); break; case CodeType.EndConditionalBlock: terminationType = upperInstruction[TerminationTypeIndex]; // If there is an end instruction above then it must be an else. if (terminationType != Else) { throw new TamperCompilationException($"Expected an upper 'else' conditional instead of {terminationType}"); } // Re-run the Emit with the else operations set. Emit(instruction, context, operations); return; default: throw new TamperCompilationException($"Conditional end does not match code type {codeType} in Atmosphere cheat"); } // Create a conditional block with the current operations and nest it in the upper // block of the stack. IfBlock block = new IfBlock(condition, operations, operationsElse); context.CurrentOperations.Add(block); }