Instruction:
How would you explain what the following Python 3 function does
def _astorestr(ins):
    ''' Stores a string value into a memory address.
    It copies content of 2nd operand (string), into 1st, reallocating
    dynamic memory for the 1st str. These instruction DOES ALLOW
    immediate strings for the 2nd parameter, starting with '#'.
    '''
    output = _addr(ins.quad[1])
    op = ins.quad[2]

    indirect = op[0] == '*'
    if indirect:
        op = op[1:]

    immediate = op[0] == '#'
    if immediate:
        op = op[1:]

    temporal = op[0] != '$'
    if not temporal:
        op = op[1:]

    if is_int(op):
        op = str(int(op) & 0xFFFF)
        if indirect:
            if immediate:  # *#<addr> = ld hl, (number)
                output.append('ld de, (%s)' % op)
            else:
                output.append('ld de, (%s)' % op)
                output.append('call __LOAD_DE_DE')
                REQUIRES.add('lddede.asm')
        else:
            # Integer does not make sense here (unless it's a ptr)
            raise InvalidICError(str(ins))

            output.append('ld de, (%s)' % op)
    elif op[0] == '_':  # an identifier
        temporal = False  # Global var is not a temporary string

        if indirect:
            if immediate:  # *#_id = _id
                output.append('ld de, (%s)' % op)
            else:  # *_id
                output.append('ld de, (%s)' % op)
                output.append('call __LOAD_DE_DE')
                REQUIRES.add('lddede.asm')
        else:
            if immediate:
                output.append('ld de, %s' % op)
            else:
                output.append('ld de, (%s)' % op)
    else:  # tn
        output.append('pop de')

        if indirect:
            output.append('call __LOAD_DE_DE')
            REQUIRES.add('lddede.asm')

    if not temporal:
        output.append('call __STORE_STR')
        REQUIRES.add('storestr.asm')
    else:  # A value already on dynamic memory
        output.append('call __STORE_STR2')
        REQUIRES.add('storestr2.asm')

    return output

Response: Stores a string value into a memory address.


Instruction:
How would you code a function in Python 3 to
return a pop sequence for 32 bit operands.

Response:
def _32bit_oper(op1, op2=None, reversed=False, preserveHL=False):
    """ Returns pop sequence for 32 bits operands
    1st operand in HLDE, 2nd operand remains in the stack

    Now it does support operands inversion calling __SWAP32.

    However, if 1st operand is integer (immediate) or indirect, the stack
    will be rearranged, so it contains a 32 bit pushed parameter value for the
    subroutine to be called.

    If preserveHL is True, then BC will be used instead of HL for lower part
    for the 1st operand.
    """
    output = []

    if op1 is not None:
        op1 = str(op1)

    if op2 is not None:
        op2 = str(op2)

    op = op2 if op2 is not None else op1

    int1 = False  # whether op1 (2nd operand) is integer

    indirect = (op[0] == '*')
    if indirect:
        op = op[1:]

    immediate = (op[0] == '#')
    if immediate:
        op = op[1:]

    hl = 'hl' if not preserveHL and not indirect else 'bc'

    if is_int(op):
        int1 = True
        op = int(op)

        if indirect:
            if immediate:
                output.append('ld hl, %i' % op)
            else:
                output.append('ld hl, (%i)' % op)

            output.append('call __ILOAD32')
            REQUIRES.add('iload32.asm')

            if preserveHL:
                output.append('ld b, h')
                output.append('ld c, l')
        else:
            DE, HL = int32(op)
            output.append('ld de, %i' % DE)
            output.append('ld %s, %i' % (hl, HL))
    else:
        if op[0] == '_':
            if immediate:
                output.append('ld %s, %s' % (hl, op))
            else:
                output.append('ld %s, (%s)' % (hl, op))
        else:
            if immediate:
                output.append('ld %s, (%s) & 0xFFFF' % (hl, op))
            else:
                output.append('pop %s' % hl)

        if indirect:
            output.append('call __ILOAD32')
            REQUIRES.add('iload32.asm')

            if preserveHL:
                output.append('ld b, h')
                output.append('ld c, l')
        else:
            if op[0] == '_':
                output.append('ld de, (%s + 2)' % op)
            else:
                if immediate:
                    output.append('ld de, (%s) >> 16' % op)
                else:
                    output.append('pop de')

    if op2 is not None:
        op = op1

        indirect = (op[0] == '*')
        if indirect:
            op = op[1:]

        immediate = (op[0] == '#')
        if immediate:
            op = op[1:]

        if is_int(op):
            op = int(op)

            if indirect:
                output.append('exx')
                if immediate:
                    output.append('ld hl, %i' % (op & 0xFFFF))
                else:
                    output.append('ld hl, (%i)' % (op & 0xFFFF))

                output.append('call __ILOAD32')
                output.append('push de')
                output.append('push hl')
                output.append('exx')
                REQUIRES.add('iload32.asm')
            else:
                DE, HL = int32(op)
                output.append('ld bc, %i' % DE)
                output.append('push bc')
                output.append('ld bc, %i' % HL)
                output.append('push bc')
        else:
            if indirect:
                output.append('exx')  # uses alternate set to put it on the stack
                if op[0] == '_':
                    if immediate:
                        output.append('ld hl, %s' % op)
                    else:
                        output.append('ld hl, (%s)' % op)
                else:
                    output.append('pop hl')  # Pointers are only 16 bits ***

                output.append('call __ILOAD32')
                output.append('push de')
                output.append('push hl')
                output.append('exx')
                REQUIRES.add('iload32.asm')
            elif immediate:
                output.append('ld bc, (%s) >> 16' % op)
                output.append('push bc')
                output.append('ld bc, (%s) & 0xFFFF' % op)
                output.append('push bc')
            elif op[0] == '_':  # an address
                if int1 or op1[0] == '_':  # If previous op was integer, we can use hl in advance
                    tmp = output
                    output = []
                    output.append('ld hl, (%s + 2)' % op)
                    output.append('push hl')
                    output.append('ld hl, (%s)' % op)
                    output.append('push hl')
                    output.extend(tmp)
                else:
                    output.append('ld bc, (%s + 2)' % op)
                    output.append('push bc')
                    output.append('ld bc, (%s)' % op)
                    output.append('push bc')
            else:
                pass  # 2nd operand remains in the stack

    if op2 is not None and reversed:
        output.append('call __SWAP32')
        REQUIRES.add('swap32.asm')

    return output


Instruction:
Implement a function in Python 3 to
add a 32 - bit integer to the stack and returns the result.

Response:
def _add32(ins):
    """ Pops last 2 bytes from the stack and adds them.
    Then push the result onto the stack.

    Optimizations:
      * If any of the operands is ZERO,
        then do NOTHING: A + 0 = 0 + A = A
    """
    op1, op2 = tuple(ins.quad[2:])

    if _int_ops(op1, op2) is not None:
        o1, o2 = _int_ops(op1, op2)

        if int(o2) == 0:  # A + 0 = 0 + A = A => Do Nothing
            output = _32bit_oper(o1)
            output.append('push de')
            output.append('push hl')
            return output

    if op1[0] == '_' and op2[0] != '_':
        op1, op2 = op2, op1  # swap them

    if op2[0] == '_':
        output = _32bit_oper(op1)
        output.append('ld bc, (%s)' % op2)
        output.append('add hl, bc')
        output.append('ex de, hl')
        output.append('ld bc, (%s + 2)' % op2)
        output.append('adc hl, bc')
        output.append('push hl')
        output.append('push de')
        return output

    output = _32bit_oper(op1, op2)
    output.append('pop bc')
    output.append('add hl, bc')
    output.append('ex de, hl')
    output.append('pop bc')
    output.append('adc hl, bc')
    output.append('push hl')  # High and low parts are reversed
    output.append('push de')

    return output


Instruction:
Here you have a function in Python 3, explain what it does
def _sub32(ins):
    op1, op2 = tuple(ins.quad[2:])

    if is_int(op2):
        if int(op2) == 0:  # A - 0 = A => Do Nothing
            output = _32bit_oper(op1)
            output.append('push de')
            output.append('push hl')
            return output

    rev = op1[0] != 't' and not is_int(op1) and op2[0] == 't'

    output = _32bit_oper(op1, op2, rev)
    output.append('call __SUB32')
    output.append('push de')
    output.append('push hl')
    REQUIRES.add('sub32.asm')
    return output

Response: Sub32 implementation of the 32 - bit sub - function.


Instruction:
Implement a Python 3 function for
multiplying two last 32bit values on top of the stack and returns the value on top of the stack and .

Response:
def _mul32(ins):
    """ Multiplies two last 32bit values on top of the stack and
    and returns the value on top of the stack

    Optimizations done:

        * If any operand is 1, do nothing
        * If any operand is 0, push 0
    """
    op1, op2 = tuple(ins.quad[2:])
    if _int_ops(op1, op2):
        op1, op2 = _int_ops(op1, op2)
        output = _32bit_oper(op1)

        if op2 == 1:
            output.append('push de')
            output.append('push hl')
            return output  # A * 1 = Nothing

        if op2 == 0:
            output.append('ld hl, 0')
            output.append('push hl')
            output.append('push hl')
            return output

    output = _32bit_oper(op1, op2)
    output.append('call __MUL32')  # Inmmediate
    output.append('push de')
    output.append('push hl')
    REQUIRES.add('mul32.asm')
    return output


Instruction:
Implement a function in Python 3 to
compare top 2 operands and returns a 32 bit unsigned version of the top 2 operands.

Response:
def _ltu32(ins):
    """ Compares & pops top 2 operands out of the stack, and checks
        if the 1st operand < 2nd operand (top of the stack).
        Pushes 0 if False, 1 if True.

        32 bit unsigned version
    """
    op1, op2 = tuple(ins.quad[2:])
    rev = op1[0] != 't' and not is_int(op1) and op2[0] == 't'
    output = _32bit_oper(op1, op2, rev)
    output.append('call __SUB32')
    output.append('sbc a, a')
    output.append('push af')
    REQUIRES.add('sub32.asm')
    return output


Instruction:
Create a Python 3 function to
compare top 2 operands and returns a 32 bit unsigned version of the tree.

Response:
def _gtu32(ins):
    """ Compares & pops top 2 operands out of the stack, and checks
        if the 1st operand > 2nd operand (top of the stack).
        Pushes 0 if False, 1 if True.

        32 bit unsigned version
    """
    op1, op2 = tuple(ins.quad[2:])
    rev = op1[0] != 't' and not is_int(op1) and op2[0] == 't'
    output = _32bit_oper(op1, op2, rev)
    output.append('pop bc')
    output.append('or a')
    output.append('sbc hl, bc')
    output.append('ex de, hl')
    output.append('pop de')
    output.append('sbc hl, de')
    output.append('sbc a, a')
    output.append('push af')
    return output


Instruction:
Write a Python 3 function that can
compare top 2 operands and returns a 32 bit un - signed version of the stack.

Response:
def _eq32(ins):
    """ Compares & pops top 2 operands out of the stack, and checks
        if the 1st operand == 2nd operand (top of the stack).
        Pushes 0 if False, 1 if True.

        32 bit un/signed version
    """
    op1, op2 = tuple(ins.quad[2:])
    output = _32bit_oper(op1, op2)
    output.append('call __EQ32')
    output.append('push af')
    REQUIRES.add('eq32.asm')
    return output


Instruction:
Given the following Python 3 function, write the documentation
def _and32(ins):
    op1, op2 = tuple(ins.quad[2:])

    if _int_ops(op1, op2):
        op1, op2 = _int_ops(op1, op2)

        if op2 == 0:  # X and False = False
            if str(op1)[0] == 't':  # a temporary term (stack)
                output = _32bit_oper(op1)  # Remove op1 from the stack
            else:
                output = []
            output.append('xor a')
            output.append('push af')
            return output

            # For X and TRUE = X we do nothing as we have to convert it to boolean
            # which is a rather expensive instruction

    output = _32bit_oper(op1, op2)
    output.append('call __AND32')
    output.append('push af')
    REQUIRES.add('and32.asm')
    return output

Response:
Compares and pops top 2 operands out of the stack and checks
           .


Instruction:
Here you have a function in Python 3, explain what it does
def _not32(ins):
    output = _32bit_oper(ins.quad[2])
    output.append('call __NOT32')
    output.append('push af')
    REQUIRES.add('not32.asm')
    return output

Response: Negates top ( Logical NOT ) of the stack


Instruction:
Given the following Python 3 function, write the documentation
def _bnot32(ins):
    output = _32bit_oper(ins.quad[2])
    output.append('call __BNOT32')
    output.append('push de')
    output.append('push hl')
    REQUIRES.add('bnot32.asm')
    return output

Response: Negates top ( 32 bits in DEHL and push hl


Instruction:
How would you code a function in Python 3 to
negate top of the stack.

Response:
def _neg32(ins):
    """ Negates top of the stack (32 bits in DEHL)
    """
    output = _32bit_oper(ins.quad[2])
    output.append('call __NEG32')
    output.append('push de')
    output.append('push hl')
    REQUIRES.add('neg32.asm')
    return output


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _abs32(ins):
    output = _32bit_oper(ins.quad[2])
    output.append('call __ABS32')
    output.append('push de')
    output.append('push hl')
    REQUIRES.add('abs32.asm')
    return output

Response: Returns the absolute value of top of the stack.


Instruction:
Given the following Python 3 function, write the documentation
def _shl32(ins):
    op1, op2 = tuple(ins.quad[2:])

    if is_int(op2):
        output = _32bit_oper(op1)

        if int(op2) == 0:
            output.append('push de')
            output.append('push hl')
            return output

        if int(op2) > 1:
            label = tmp_label()
            output.append('ld b, %s' % op2)
            output.append('%s:' % label)
            output.append('call __SHL32')
            output.append('djnz %s' % label)
        else:
            output.append('call __SHL32')

        output.append('push de')
        output.append('push hl')
        REQUIRES.add('shl32.asm')
        return output

    output = _8bit_oper(op2)
    output.append('ld b, a')
    output.extend(_32bit_oper(op1))
    label = tmp_label()
    output.append('%s:' % label)
    output.append('call __SHL32')
    output.append('djnz %s' % label)
    output.append('push de')
    output.append('push hl')
    REQUIRES.add('shl32.asm')
    return output

Response: Logical Left shift 32bit unsigned integers.


Instruction:
Make a summary of the following Python 3 code
def _float_oper(op1, op2=None):
    ''' Returns pop sequence for floating point operands
    1st operand in A DE BC, 2nd operand remains in the stack

    Unlike 8bit and 16bit version, this does not supports
    operands inversion. Since many of the instructions are implemented
    as functions, they must support this.

    However, if 1st operand is a number (immediate) or indirect, the stack
    will be rearranged, so it contains a 48 bit pushed parameter value for the
    subroutine to be called.
    '''
    output = []
    op = op2 if op2 is not None else op1

    indirect = (op[0] == '*')
    if indirect:
        op = op[1:]

    if is_float(op):
        op = float(op)

        if indirect:
            op = int(op) & 0xFFFF
            output.append('ld hl, (%i)' % op)
            output.append('call __ILOADF')
            REQUIRES.add('iloadf.asm')
        else:
            A, DE, BC = _float(op)
            output.append('ld a, %s' % A)
            output.append('ld de, %s' % DE)
            output.append('ld bc, %s' % BC)
    else:
        if indirect:
            if op[0] == '_':
                output.append('ld hl, (%s)' % op)
            else:
                output.append('pop hl')

            output.append('call __ILOADF')
            REQUIRES.add('iloadf.asm')
        else:
            if op[0] == '_':
                output.append('ld a, (%s)' % op)
                output.append('ld de, (%s + 1)' % op)
                output.append('ld bc, (%s + 3)' % op)
            else:
                output.extend(_fpop())

    if op2 is not None:
        op = op1
        if is_float(op):  # An float must be in the stack. Let's pushit
            A, DE, BC = _float(op)
            output.append('ld hl, %s' % BC)
            output.append('push hl')
            output.append('ld hl, %s' % DE)
            output.append('push hl')
            output.append('ld h, %s' % A)
            output.append('push hl')
        elif op[0] == '*':  # Indirect
            op = op[1:]
            output.append('exx')  # uses alternate set to put it on the stack
            output.append("ex af, af'")
            if is_int(op):  # noqa TODO: it will fail
                op = int(op)
                output.append('ld hl, %i' % op)
            elif op[0] == '_':
                output.append('ld hl, (%s)' % op)
            else:
                output.append('pop hl')

            output.append('call __ILOADF')
            output.extend(_fpush())
            output.append("ex af, af'")
            output.append('exx')
            REQUIRES.add('iloadf.asm')
        elif op[0] == '_':
            if is_float(op2):
                tmp = output
                output = []
                output.append('ld hl, %s + 4' % op)
                '''
                output.append('ld hl, (%s + 3)' % op)
                output.append('push hl')
                output.append('ld hl, (%s + 1)' % op)
                output.append('push hl')
                output.append('ld a, (%s)' % op)
                output.append('push af')
                '''
                output.append('call __FP_PUSH_REV')
                output.extend(tmp)
                REQUIRES.add('pushf.asm')
            else:
                '''
                output.append('ld hl, (%s + 3)' % op)
                output.append('push hl')
                output.append('ld hl, (%s + 1)' % op)
                output.append('push hl')
                output.append('ld hl, (%s - 1)' % op)
                output.append('push hl')
                '''
                output.append('ld hl, %s + 4' % op)
                output.append('call __FP_PUSH_REV')
                REQUIRES.add('pushf.asm')
        else:
            pass  # Else do nothing, and leave the op onto the stack

    return output

Response: Returns pop sequence for floating point operands in A DE BC 2nd operand remains in the stack.


Instruction:
Can you create a Python 3 function that
adds 2 float values. The result is pushed onto the stack.

Response:
def _addf(ins):
    ''' Adds 2 float values. The result is pushed onto the stack.
    '''
    op1, op2 = tuple(ins.quad[2:])

    if _f_ops(op1, op2) is not None:
        opa, opb = _f_ops(op1, op2)
        if opb == 0:  # A + 0 => A
            output = _float_oper(opa)
            output.extend(_fpush())
            return output

    output = _float_oper(op1, op2)
    output.append('call __ADDF')
    output.extend(_fpush())
    REQUIRES.add('addf.asm')
    return output


Instruction:
Can you tell what is the following Python 3 function doing
def _divf(ins):
    ''' Divides 2 float values. The result is pushed onto the stack.
    '''
    op1, op2 = tuple(ins.quad[2:])

    if is_float(op2) and float(op2) == 1:  # Nothing to do. A / 1 = A
        output = _float_oper(op1)
        output.extend(_fpush())
        return output

    output = _float_oper(op1, op2)
    output.append('call __DIVF')
    output.extend(_fpush())
    REQUIRES.add('divf.asm')
    return output

Response: Divides 2 float values. The result is pushed onto the stack.


Instruction:
Explain what the following Python 3 code does
def _modf(ins):
    ''' Reminder of div. 2 float values. The result is pushed onto the stack.
    '''
    op1, op2 = tuple(ins.quad[2:])
    output = _float_oper(op1, op2)
    output.append('call __MODF')
    output.extend(_fpush())
    REQUIRES.add('modf.asm')
    return output

Response: Reminder of div. 2 float values. The result is pushed onto the stack.


Instruction:
Explain what the following Python 3 code does
def _ltf(ins):
    ''' Compares & pops top 2 operands out of the stack, and checks
        if the 1st operand < 2nd operand (top of the stack).
        Pushes 0 if False, 1 if True.

        Floating Point version
    '''
    op1, op2 = tuple(ins.quad[2:])
    output = _float_oper(op1, op2)
    output.append('call __LTF')
    output.append('push af')
    REQUIRES.add('ltf.asm')
    return output

Response:
Compares top 2 operands out of the stack and checks
        if the 1st operand < 2nd operand.


Instruction:
How would you code a function in Python 3 to
negate top of the stack ( 48 bits )

Response:
def _notf(ins):
    ''' Negates top of the stack (48 bits)
    '''
    output = _float_oper(ins.quad[2])
    output.append('call __NOTF')
    output.append('push af')
    REQUIRES.add('notf.asm')
    return output


Instruction:
How would you code a function in Python 3 to
change sign of top of the stack ( 48 bits )

Response:
def _negf(ins):
    ''' Changes sign of top of the stack (48 bits)
    '''
    output = _float_oper(ins.quad[2])
    output.append('call __NEGF')
    output.extend(_fpush())
    REQUIRES.add('negf.asm')
    return output


Instruction:
How would you implement a function in Python 3 that
returns the absolute value of the top of the stack.

Response:
def _absf(ins):
    ''' Absolute value of top of the stack (48 bits)
    '''
    output = _float_oper(ins.quad[2])
    output.append('res 7, e')  # Just resets the sign bit!
    output.extend(_fpush())
    return output


Instruction:
Make a summary of the following Python 3 code
def get_uniques(l):
    result = []

    for i in l:
        if i not in result:
            result.append(i)

    return result

Response: Returns a list with no repeated elements.


Instruction:
How would you explain what the following Python 3 function does
def t_CHAR(self, t):
        r"'.'"  # A single char

        t.value = ord(t.value[1])
        t.type = 'INTEGER'
        return t

Response: r "'.. "' r'.


Instruction:
Here you have a function in Python 3, explain what it does
def t_BIN(self, t):
        r'(%[01]+)|([01]+[bB])'  # A Binary integer
        # Note 00B is a 0 binary, but
        # 00Bh is a 12 in hex. So this pattern must come
        # after HEXA

        if t.value[0] == '%':
            t.value = t.value[1:]  # Remove initial %
        else:
            t.value = t.value[:-1]  # Remove last 'b'

        t.value = int(t.value, 2)  # Convert to decimal
        t.type = 'INTEGER'
        return t

Response: A Binary integer t


Instruction:
How would you implement a function in Python 3 that
processes preprocessor ID directives.

Response:
def t_preproc_ID(self, t):
        r'[_a-zA-Z][_a-zA-Z0-9]*'  # preprocessor directives
        t.type = preprocessor.get(t.value.lower(), 'ID')
        return t


Instruction:
Can you generate a brief explanation for the following Python 3 code
def t_INITIAL_SHARP(self, t):
        r'\#'

        if self.find_column(t) == 1:
            t.lexer.begin('preproc')
        else:
            self.t_INITIAL_preproc_error(t)

Response: r \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S + \ S +


Instruction:
Implement a Python 3 function for
defining input string removing current lexer.

Response:
def input(self, str):
        """ Defines input string, removing current lexer.
        """
        self.input_data = str
        self.lex = lex.lex(object=self)
        self.lex.input(self.input_data)


Instruction:
Can you generate the documentation for the following Python 3 function
def typecast(self, type_):
        self.value = SymbolTYPECAST.make_node(type_, self.value, self.lineno)
        return self.value is not None

Response: Test typecast to the argument expression.


Instruction:
Make a summary of the following Python 3 code
def _paddr(offset):
    ''' Generic array address parameter loading.
    Emmits output code for setting IX at the right location.
    bytes = Number of bytes to load:
        1 => 8 bit value
        2 => 16 bit value / string
        4 => 32 bit value / f16 value
        5 => 40 bit value
    '''
    output = []

    indirect = offset[0] == '*'
    if indirect:
        offset = offset[1:]

    I = int(offset)
    if I >= 0:
        I += 4  # Return Address + "push IX"

    output.append('push ix')
    output.append('pop hl')
    output.append('ld de, %i' % I)
    output.append('add hl, de')

    if indirect:
        output.append('ld c, (hl)')
        output.append('inc hl')
        output.append('ld h, (hl)')
        output.append('ld l, c')

    output.append('call __ARRAY')
    REQUIRES.add('array.asm')
    return output

Response: Generic array address parameter loading.


Instruction:
Write a Python 3 function that can
load an 8 bit value from a memory address.

Response:
def _paload8(ins):
    ''' Loads an 8 bit value from a memory address
    If 2nd arg. start with '*', it is always treated as
    an indirect value.
    '''
    output = _paddr(ins.quad[2])
    output.append('ld a, (hl)')
    output.append('push af')

    return output


Instruction:
Explain what the following Python 3 code does
def _paload16(ins):
    ''' Loads a 16 bit value from a memory address
    If 2nd arg. start with '*', it is always treated as
    an indirect value.
    '''
    output = _paddr(ins.quad[2])

    output.append('ld e, (hl)')
    output.append('inc hl')
    output.append('ld d, (hl)')
    output.append('ex de, hl')
    output.append('push hl')

    return output

Response: Load a 16 bit value from a memory address


Instruction:
Can you tell what is the following Python 3 function doing
def _paload32(ins):
    ''' Load a 32 bit value from a memory address
    If 2nd arg. start with '*', it is always treated as
    an indirect value.
    '''
    output = _paddr(ins.quad[2])

    output.append('call __ILOAD32')
    output.append('push de')
    output.append('push hl')

    REQUIRES.add('iload32.asm')

    return output

Response: Load a 32 bit value from a memory address.


Instruction:
Given the following Python 3 function, write the documentation
def _paloadf(ins):
    ''' Loads a floating point value from a memory address.
    If 2nd arg. start with '*', it is always treated as
    an indirect value.
    '''
    output = _paddr(ins.quad[2])
    output.append('call __ILOADF')
    output.extend(_fpush())

    REQUIRES.add('iloadf.asm')

    return output

Response: Load a floating point value from a memory address.


Instruction:
Create a Python 3 function to
load a string value from a memory address.

Response:
def _paloadstr(ins):
    ''' Loads a string value from a memory address.
    '''
    output = _paddr(ins.quad[2])

    output.append('call __ILOADSTR')
    output.append('push hl')
    REQUIRES.add('loadstr.asm')

    return output


Instruction:
Make a summary of the following Python 3 code
def _pastore8(ins):
    ''' Stores 2º operand content into address of 1st operand.
    1st operand is an array element. Dimensions are pushed into the
    stack.
    Use '*' for indirect store on 1st operand (A pointer to an array)
    '''
    output = _paddr(ins.quad[1])

    value = ins.quad[2]
    if value[0] == '*':
        value = value[1:]
        indirect = True
    else:
        indirect = False

    try:
        value = int(ins.quad[2]) & 0xFFFF
        if indirect:
            output.append('ld a, (%i)' % value)
            output.append('ld (hl), a')
        else:
            value &= 0xFF
            output.append('ld (hl), %i' % value)
    except ValueError:
        output.append('pop af')
        output.append('ld (hl), a')

    return output

Response: Stores 2º operand content into address of 1st operand.


Instruction:
How would you code a function in Python 3 to
store 2º operand content into address of 1st operand.

Response:
def _pastore16(ins):
    ''' Stores 2º operand content into address of 1st operand.
    store16 a, x =>  *(&a) = x
    Use '*' for indirect store on 1st operand.
    '''
    output = _paddr(ins.quad[1])

    value = ins.quad[2]
    if value[0] == '*':
        value = value[1:]
        indirect = True
    else:
        indirect = False

    try:
        value = int(ins.quad[2]) & 0xFFFF
        output.append('ld de, %i' % value)
        if indirect:
            output.append('call __LOAD_DE_DE')
            REQUIRES.add('lddede.asm')

    except ValueError:
        output.append('pop de')

    output.append('ld (hl), e')
    output.append('inc hl')
    output.append('ld (hl), d')

    return output


Instruction:
Can you tell what is the following Python 3 function doing
def _pastore32(ins):
    ''' Stores 2º operand content into address of 1st operand.
    store16 a, x =>  *(&a) = x
    '''
    output = _paddr(ins.quad[1])

    value = ins.quad[2]
    if value[0] == '*':
        value = value[1:]
        indirect = True
    else:
        indirect = False

    try:
        value = int(ins.quad[2]) & 0xFFFFFFFF  # Immediate?
        if indirect:
            output.append('push hl')
            output.append('ld hl, %i' % (value & 0xFFFF))
            output.append('call __ILOAD32')
            output.append('ld b, h')
            output.append('ld c, l')  # BC = Lower 16 bits
            output.append('pop hl')
            REQUIRES.add('iload32.asm')
        else:
            output.append('ld de, %i' % (value >> 16))
            output.append('ld bc, %i' % (value & 0xFFFF))
    except ValueError:
        output.append('pop bc')
        output.append('pop de')

    output.append('call __STORE32')
    REQUIRES.add('store32.asm')

    return output

Response: Stores 2º operand content into address of 1st operand.


Instruction:
How would you code a function in Python 3 to
store 2º operand content into address of 1st operand.

Response:
def _pastoref16(ins):
    ''' Stores 2º operand content into address of 1st operand.
    storef16 a, x =>  *(&a) = x
    '''
    output = _paddr(ins.quad[1])

    value = ins.quad[2]
    if value[0] == '*':
        value = value[1:]
        indirect = True
    else:
        indirect = False

    try:
        if indirect:
            value = int(ins.quad[2])
            output.append('push hl')
            output.append('ld hl, %i' % (value & 0xFFFF))
            output.append('call __ILOAD32')
            output.append('ld b, h')
            output.append('ld c, l')  # BC = Lower 16 bits
            output.append('pop hl')
            REQUIRES.add('iload32.asm')
        else:
            de, hl = f16(value)
            output.append('ld de, %i' % de)
            output.append('ld bc, %i' % hl)
    except ValueError:
        output.append('pop bc')
        output.append('pop de')

    output.append('call __STORE32')
    REQUIRES.add('store32.asm')

    return output


Instruction:
Here you have a function in Python 3, explain what it does
def _pastoref(ins):
    ''' Stores a floating point value into a memory address.
    '''
    output = _paddr(ins.quad[1])

    value = ins.quad[2]
    if value[0] == '*':
        value = value[1:]
        indirect = True
    else:
        indirect = False

    try:
        if indirect:
            value = int(value) & 0xFFFF  # Inmediate?
            output.append('push hl')
            output.append('ld hl, %i' % value)
            output.append('call __ILOADF')
            output.append('ld a, c')
            output.append('ld b, h')
            output.append('ld c, l')  # BC = Lower 16 bits, A = Exp
            output.append('pop hl')     # Recovers pointer
            REQUIRES.add('iloadf.asm')
        else:
            value = float(value)  # Inmediate?
            C, DE, HL = fp.immediate_float(value)  # noqa TODO: it will fail
            output.append('ld a, %s' % C)
            output.append('ld de, %s' % DE)
            output.append('ld bc, %s' % HL)
    except ValueError:
        output.append('pop bc')
        output.append('pop de')
        output.append('ex (sp), hl')  # Preserve HL for STOREF
        output.append('ld a, l')
        output.append('pop hl')

    output.append('call __STOREF')
    REQUIRES.add('storef.asm')

    return output

Response: Stores a floating point value into a memory address.


Instruction:
Write a Python 3 script for
storing a string value into a memory address.

Response:
def _pastorestr(ins):
    ''' Stores a string value into a memory address.
    It copies content of 2nd operand (string), into 1st, reallocating
    dynamic memory for the 1st str. These instruction DOES ALLOW
    inmediate strings for the 2nd parameter, starting with '#'.
    '''
    output = _paddr(ins.quad[1])
    temporal = False
    value = ins.quad[2]

    indirect = value[0] == '*'
    if indirect:
        value = value[1:]

    immediate = value[0]
    if immediate:
        value = value[1:]

    if value[0] == '_':
        if indirect:
            if immediate:
                output.append('ld de, (%s)' % value)
            else:
                output.append('ld de, (%s)' % value)
                output.append('call __LOAD_DE_DE')
                REQUIRES.add('lddede.asm')
        else:
            if immediate:
                output.append('ld de, %s' % value)
            else:
                output.append('ld de, (%s)' % value)
    else:
        output.append('pop de')
        temporal = True

        if indirect:
            output.append('call __LOAD_DE_DE')
            REQUIRES.add('lddede.asm')

    if not temporal:
        output.append('call __STORE_STR')
        REQUIRES.add('storestr.asm')
    else:  # A value already on dynamic memory
        output.append('call __STORE_STR2')
        REQUIRES.add('storestr2.asm')

    return output


Instruction:
How would you code a function in Python 3 to
convert an integer to a little - endian t - tuple of bytes.

Response:
def num2bytes(x, bytes):
    """ Returns x converted to a little-endian t-uple of bytes.
    E.g. num2bytes(255, 4) = (255, 0, 0, 0)
    """
    if not isinstance(x, int):  # If it is another "thing", just return ZEROs
        return tuple([0] * bytes)

    x = x & ((2 << (bytes * 8)) - 1)  # mask the initial value
    result = ()

    for i in range(bytes):
        result += (x & 0xFF,)
        x >>= 8

    return result


Instruction:
Explain what the following Python 3 code does
def argval(self):
        if self.arg is None or any(x is None for x in self.arg):
            return None

        for x in self.arg:
            if not isinstance(x, int):
                raise InvalidArgError(self.arg)

        return self.arg

Response: Returns the value of the arg.


Instruction:
Can you tell what is the following Python 3 function doing
def bytes(self):
        result = []
        op = self.opcode.split(' ')
        argi = 0

        while op:
            q = op.pop(0)

            if q == 'XX':
                for k in range(self.argbytes[argi] - 1):
                    op.pop(0)

                result.extend(num2bytes(self.argval()[argi], self.argbytes[argi]))
                argi += 1
            else:
                result.append(int(q, 16))  # Add opcode

        if len(result) != self.size:
            raise InternalMismatchSizeError(len(result), self)

        return result

Response: Returns a t - tuple with instruction bytes


Instruction:
Write a Python 3 function for
warning for implicit type x for id_.

Response:
def warning_implicit_type(lineno, id_, type_=None):
    """ Warning: Using default implicit type 'x'
    """
    if OPTIONS.strict.value:
        syntax_error_undeclared_type(lineno, id_)
        return

    if type_ is None:
        type_ = global_.DEFAULT_TYPE

    warning(lineno, "Using default implicit type '%s' for '%s'" % (type_, id_))


Instruction:
How would you code a function in Python 3 to
return operands of an ASM instruction.

Response:
def oper(inst):
    """ Returns operands of an ASM instruction.
    Even "indirect" operands, like SP if RET or CALL is used.
    """
    i = inst.strip(' \t\n').split(' ')
    I = i[0].lower()  # Instruction
    i = ''.join(i[1:])

    op = i.split(',')
    if I in {'call', 'jp', 'jr'} and len(op) > 1:
        op = op[1:] + ['f']

    elif I == 'djnz':
        op.append('b')

    elif I in {'push', 'pop', 'call'}:
        op.append('sp')  # Sp is also affected by push, pop and call

    elif I in {'or', 'and', 'xor', 'neg', 'cpl', 'rrca', 'rlca'}:
        op.append('a')

    elif I in {'rra', 'rla'}:
        op.extend(['a', 'f'])

    elif I in ('rr', 'rl'):
        op.append('f')

    elif I in {'adc', 'sbc'}:
        if len(op) == 1:
            op = ['a', 'f'] + op

    elif I in {'add', 'sub'}:
        if len(op) == 1:
            op = ['a'] + op

    elif I in {'ldd', 'ldi', 'lddr', 'ldir'}:
        op = ['hl', 'de', 'bc']

    elif I in {'cpd', 'cpi', 'cpdr', 'cpir'}:
        op = ['a', 'hl', 'bc']

    elif I == 'exx':
        op = ['*', 'bc', 'de', 'hl', 'b', 'c', 'd', 'e', 'h', 'l']

    elif I in {'ret', 'reti', 'retn'}:
        op += ['sp']

    elif I == 'out':
        if len(op) and RE_OUTC.match(op[0]):
            op[0] = 'c'
        else:
            op.pop(0)

    elif I == 'in':
        if len(op) > 1 and RE_OUTC.match(op[1]):
            op[1] = 'c'
        else:
            op.pop(1)

    for i in range(len(op)):
        tmp = RE_INDIR16.match(op[i])
        if tmp is not None:
            op[i] = '(' + op[i].strip()[1:-1].strip().lower() + ')'  # '  (  dE )  ' => '(de)'

    return op


Instruction:
Make a summary of the following Python 3 code
def condition(i):
    I = inst(i)

    if I not in {'call', 'jp', 'jr', 'ret'}:
        return None  # This instruction always execute

    if I == 'ret':
        i = [x.lower() for x in i.split(' ') if x != '']
        return i[1] if len(i) > 1 else None

    i = [x.strip() for x in i.split(',')]
    i = [x.lower() for x in i[0].split(' ') if x != '']
    if len(i) > 1 and i[1] in {'c', 'nc', 'z', 'nz', 'po', 'pe', 'p', 'm'}:
        return i[1]

    return None

Response:
Returns the flag this instruction uses
    or None. E. g. c z p m is not - zero etc.


Instruction:
Can you tell what is the following Python 3 function doing
def single_registers(op):
    result = set()
    if isinstance(op, str):
        op = [op]

    for x in op:
        if is_8bit_register(x):
            result = result.union([x])
        elif x == 'sp':
            result.add(x)
        elif x == 'af':
            result = result.union(['a', 'f'])
        elif x == "af'":
            result = result.union(["a'", "f'"])
        elif is_16bit_register(x):  # Must be a 16bit reg or we have an internal error!
            result = result.union([LO16(x), HI16(x)])

    return list(result)

Response: Given a list of single registers returns a list of single registers.


Instruction:
How would you code a function in Python 3 to
return the list of 8 - bit registers that can be used by an asm instruction to return a result.

Response:
def result(i):
    """ Returns which 8-bit registers are used by an asm
    instruction to return a result.
    """
    ins = inst(i)
    op = oper(i)

    if ins in ('or', 'and') and op == ['a']:
        return ['f']

    if ins in {'xor', 'or', 'and', 'neg', 'cpl', 'daa', 'rld', 'rrd', 'rra', 'rla', 'rrca', 'rlca'}:
        return ['a', 'f']

    if ins in {'bit', 'cp', 'scf', 'ccf'}:
        return ['f']

    if ins in {'sub', 'add', 'sbc', 'adc'}:
        if len(op) == 1:
            return ['a', 'f']
        else:
            return single_registers(op[0]) + ['f']

    if ins == 'djnz':
        return ['b', 'f']

    if ins in {'ldir', 'ldi', 'lddr', 'ldd'}:
        return ['f', 'b', 'c', 'd', 'e', 'h', 'l']

    if ins in {'cpi', 'cpir', 'cpd', 'cpdr'}:
        return ['f', 'b', 'c', 'h', 'l']

    if ins in ('pop', 'ld'):
        return single_registers(op[0])

    if ins in {'inc', 'dec', 'sbc', 'rr', 'rl', 'rrc', 'rlc'}:
        return ['f'] + single_registers(op[0])

    if ins in ('set', 'res'):
        return single_registers(op[1])

    return []


Instruction:
Can you generate a brief explanation for the following Python 3 code
def block_partition(block, i):
    i += 1
    new_block = BasicBlock(block.asm[i:])
    block.mem = block.mem[:i]
    block.asm = block.asm[:i]
    block.update_labels()
    new_block.update_labels()

    new_block.goes_to = block.goes_to
    block.goes_to = IdentitySet()

    new_block.label_goes = block.label_goes
    block.label_goes = []

    new_block.next = new_block.original_next = block.original_next
    new_block.prev = block
    new_block.add_comes_from(block)

    if new_block.next is not None:
        new_block.next.prev = new_block
        new_block.next.add_comes_from(new_block)
        new_block.next.delete_from(block)

    block.next = block.original_next = new_block
    block.update_next_block()
    block.add_goes_to(new_block)

    return block, new_block

Response: Partition a basic block into two blocks.


Instruction:
Here you have a function in Python 3, explain what it does
def partition_block(block):
    result = [block]

    if not block.is_partitionable:
        return result

    EDP = END_PROGRAM_LABEL + ':'

    for i in range(len(block) - 1):
        if i and block.asm[i] == EDP:  # END_PROGRAM label always starts a basic block
            block, new_block = block_partition(block, i - 1)
            LABELS[END_PROGRAM_LABEL].basic_block = new_block
            result.extend(partition_block(new_block))
            return result

        if block.mem[i].is_ender:
            block, new_block = block_partition(block, i)
            result.extend(partition_block(new_block))
            op = block.mem[i].opers

            for l in op:
                if l in LABELS.keys():
                    JUMP_LABELS.add(l)
                    block.label_goes += [l]
            return result

        if block.asm[i] in arch.zx48k.backend.ASMS:
            if i > 0:
                block, new_block = block_partition(block, i - 1)
                result.extend(partition_block(new_block))
                return result

            block, new_block = block_partition(block, i)
            result.extend(partition_block(new_block))
            return result

    for label in JUMP_LABELS:
        must_partition = False
        if LABELS[label].basic_block is block:
            for i in range(len(block)):
                cell = block.mem[i]
                if cell.inst == label:
                    break

                if cell.is_label:
                    continue

                if cell.is_ender:
                    continue

                must_partition = True

            if must_partition:
                block, new_block = block_partition(block, i - 1)
                LABELS[label].basic_block = new_block
                result.extend(partition_block(new_block))
                return result

    return result

Response: Partition a block into a list of blocks with the same block.


Instruction:
Implement a function in Python 3 to
get all the labels in the global label table.

Response:
def get_labels(MEMORY, basic_block):
    """ Traverses memory, to annotate all the labels in the global
    LABELS table
    """
    for cell in MEMORY:
        if cell.is_label:
            label = cell.inst
            LABELS[label] = LabelInfo(label, cell.addr, basic_block)


Instruction:
Implement a function in Python 3 to
initialize the global memory array with the given one

Response:
def initialize_memory(basic_block):
    """ Initializes global memory array with the given one
    """
    global MEMORY

    MEMORY = basic_block.mem
    get_labels(MEMORY, basic_block)
    basic_block.mem = MEMORY


Instruction:
Write a Python 3 script to
clean up initial memory.

Response:
def cleanupmem(initial_memory):
    """ Cleans up initial memory. Each label must be
    ALONE. Each instruction must have an space, etc...
    """
    i = 0
    while i < len(initial_memory):
        tmp = initial_memory[i]
        match = RE_LABEL.match(tmp)
        if not match:
            i += 1
            continue

        if tmp.rstrip() == match.group():
            i += 1
            continue

        initial_memory[i] = tmp[match.end():]
        initial_memory.insert(i, match.group())
        i += 1


Instruction:
Here you have a function in Python 3, explain what it does
def cleanup_local_labels(block):
    global PROC_COUNTER

    stack = [[]]
    hashes = [{}]
    stackprc = [PROC_COUNTER]
    used = [{}]  # List of hashes of unresolved labels per scope

    MEMORY = block.mem

    for cell in MEMORY:
        if cell.inst.upper() == 'PROC':
            stack += [[]]
            hashes += [{}]
            stackprc += [PROC_COUNTER]
            used += [{}]
            PROC_COUNTER += 1
            continue

        if cell.inst.upper() == 'ENDP':
            if len(stack) > 1:  # There might be unbalanced stack due to syntax errors
                for label in used[-1].keys():
                    if label in stack[-1]:
                        newlabel = hashes[-1][label]
                        for cell in used[-1][label]:
                            cell.replace_label(label, newlabel)

                stack.pop()
                hashes.pop()
                stackprc.pop()
                used.pop()
            continue

        tmp = cell.asm.strip()
        if tmp.upper()[:5] == 'LOCAL':
            tmp = tmp[5:].split(',')
            for lbl in tmp:
                lbl = lbl.strip()
                if lbl in stack[-1]:
                    continue
                stack[-1] += [lbl]
                hashes[-1][lbl] = 'PROC%i.' % stackprc[-1] + lbl
                if used[-1].get(lbl, None) is None:
                    used[-1][lbl] = []

            cell.asm = ';' + cell.asm  # Remove it
            continue

        if cell.is_label:
            label = cell.inst
            for i in range(len(stack) - 1, -1, -1):
                if label in stack[i]:
                    label = hashes[i][label]
                    cell.asm = label + ':'
                    break
            continue

        for label in cell.used_labels:
            labelUsed = False
            for i in range(len(stack) - 1, -1, -1):
                if label in stack[i]:
                    newlabel = hashes[i][label]
                    cell.replace_label(label, newlabel)
                    labelUsed = True
                    break

            if not labelUsed:
                if used[-1].get(label, None) is None:
                    used[-1][label] = []

                used[-1][label] += [cell]

    for i in range(len(MEMORY) - 1, -1, -1):
        if MEMORY[i].asm[0] == ';':
            MEMORY.pop(i)

    block.mem = MEMORY
    block.asm = [x.asm for x in MEMORY if len(x.asm.strip())]

Response: Removes any local labels from the block and returns a unique version of the block.


Instruction:
Given the following Python 3 function, write the documentation
def optimize(initial_memory):
    global BLOCKS
    global PROC_COUNTER

    LABELS.clear()
    JUMP_LABELS.clear()
    del MEMORY[:]
    PROC_COUNTER = 0

    cleanupmem(initial_memory)
    if OPTIONS.optimization.value <= 2:
        return '\n'.join(x for x in initial_memory if not RE_PRAGMA.match(x))

    optimize_init()
    bb = BasicBlock(initial_memory)
    cleanup_local_labels(bb)
    initialize_memory(bb)

    BLOCKS = basic_blocks = get_basic_blocks(bb)  # 1st partition the Basic Blocks

    for x in basic_blocks:
        x.clean_up_comes_from()
        x.clean_up_goes_to()

    for x in basic_blocks:
        x.update_goes_and_comes()

    LABELS['*START*'].basic_block.add_goes_to(basic_blocks[0])
    LABELS['*START*'].basic_block.next = basic_blocks[0]

    basic_blocks[0].prev = LABELS['*START*'].basic_block
    LABELS[END_PROGRAM_LABEL].basic_block.add_goes_to(LABELS['*__END_PROGRAM*'].basic_block)

    for x in basic_blocks:
        x.optimize()

    for x in basic_blocks:
        if x.comes_from == [] and len([y for y in JUMP_LABELS if x is LABELS[y].basic_block]):
            x.ignored = True

    return '\n'.join([y for y in flatten_list([x.asm for x in basic_blocks if not x.ignored])
                      if not RE_PRAGMA.match(y)])

Response: This will remove useless instructions from the memory and return a string of the resulting basic blocks.


Instruction:
Can you implement a function in Python 3 that
resets the flags to an unknown state

Response:
def reset_flags(self):
        """ Resets flags to an "unknown state"
        """
        self.C = None
        self.Z = None
        self.P = None
        self.S = None


Instruction:
Here you have a function in Python 3, explain what it does
def get(self, r):
        if r is None:
            return None

        if r.lower() == '(sp)' and self.stack:
            return self.stack[-1]

        if r[:1] == '(':
            return self.mem[r[1:-1]]

        r = r.lower()
        if is_number(r):
            return str(valnum(r))

        if not is_register(r):
            return None

        return self.regs[r]

Response: Returns the precomputed value of the given expression


Instruction:
Write a Python 3 script for
liking get but returns the <int > value.

Response:
def getv(self, r):
        """ Like the above, but returns the <int> value.
        """
        v = self.get(r)
        if not is_unknown(v):
            try:
                v = int(v)
            except ValueError:
                v = None
        else:
            v = None
        return v


Instruction:
Explain what the following Python 3 code does
def eq(self, r1, r2):
        if not is_register(r1) or not is_register(r2):
            return False

        if self.regs[r1] is None or self.regs[r2] is None:  # HINT: This's been never USED??
            return False

        return self.regs[r1] == self.regs[r2]

Response: True if values of r1 and r2 registers are equal


Instruction:
Given the following Python 3 function, write the documentation
def inc(self, r):
        self.set_flag(None)

        if not is_register(r):
            if r[0] == '(':  # a memory position, basically: inc(hl)
                r_ = r[1:-1].strip()
                v_ = self.getv(self.mem.get(r_, None))
                if v_ is not None:
                    v_ = (v_ + 1) & 0xFF
                    self.mem[r_] = str(v_)
                    self.Z = int(v_ == 0)  # HINT: This might be improved
                else:
                    self.mem[r_] = new_tmp_val()
            return

        if self.getv(r) is not None:
            self.set(r, self.getv(r) + 1)
        else:
            self.set(r, None)

Response: Does inc on the register and precomputes flags


Instruction:
Implement a Python 3 function for
doing a ROTATION to the RIGHT |>>

Response:
def rrc(self, r):
        """ Does a ROTATION to the RIGHT |>>
        """
        if not is_number(self.regs[r]):
            self.set(r, None)
            self.set_flag(None)
            return

        v_ = self.getv(self.regs[r]) & 0xFF
        self.regs[r] = str((v_ >> 1) | ((v_ & 1) << 7))


Instruction:
Given the following Python 3 function, write the documentation
def rr(self, r):
        if self.C is None or not is_number(self.regs[r]):
            self.set(r, None)
            self.set_flag(None)
            return

        self.rrc(r)
        tmp = self.C
        v_ = self.getv(self.regs[r])
        self.C = v_ >> 7
        self.regs[r] = str((v_ & 0x7F) | (tmp << 7))

Response: Like the above bus uses carry


Instruction:
Implement a Python 3 function for
doing a ROTATION to the LEFT <<|

Response:
def rlc(self, r):
        """ Does a ROTATION to the LEFT <<|
        """
        if not is_number(self.regs[r]):
            self.set(r, None)
            self.set_flag(None)
            return

        v_ = self.getv(self.regs[r]) & 0xFF
        self.set(r, ((v_ << 1) & 0xFF) | (v_ >> 7))


Instruction:
Implement a Python 3 function for
liking the above bus uses carry

Response:
def rl(self, r):
        """ Like the above, bus uses carry
        """
        if self.C is None or not is_number(self.regs[r]):
            self.set(r, None)
            self.set_flag(None)
            return

        self.rlc(r)
        tmp = self.C
        v_ = self.getv(self.regs[r])
        self.C = v_ & 1
        self.regs[r] = str((v_ & 0xFE) | tmp)


Instruction:
Write a Python 3 function that can
true if value of r is val.

Response:
def _is(self, r, val):
        """ True if value of r is val.
        """
        if not is_register(r) or val is None:
            return False

        r = r.lower()
        if is_register(val):
            return self.eq(r, val)

        if is_number(val):
            val = str(valnum(val))
        else:
            val = str(val)

        if val[0] == '(':
            val = self.mem[val[1:-1]]

        return self.regs[r] == val


Instruction:
Implement a Python 3 function for
updating the registers values with the given instruction.

Response:
def op(self, i, o):
        """ Tries to update the registers values with the given
        instruction.
        """
        for ii in range(len(o)):
            if is_register(o[ii]):
                o[ii] = o[ii].lower()

        if i == 'ld':
            self.set(o[0], o[1])
            return

        if i == 'push':
            if valnum(self.regs['sp']):
                self.set('sp', (self.getv(self.regs['sp']) - 2) % 0xFFFF)
            else:
                self.set('sp', None)
            self.stack.append(self.regs[o[0]])
            return

        if i == 'pop':
            self.set(o[0], self.stack and self.stack.pop() or None)
            if valnum(self.regs['sp']):
                self.set('sp', (self.getv(self.regs['sp']) + 2) % 0xFFFF)
            else:
                self.set('sp', None)
            return

        if i == 'inc':
            self.inc(o[0])
            return

        if i == 'dec':
            self.dec(o[0])
            return

        if i == 'rra':
            self.rr('a')
            return
        if i == 'rla':
            self.rl('a')
            return
        if i == 'rlca':
            self.rlc('a')
            return
        if i == 'rrca':
            self.rrc('a')
            return
        if i == 'rr':
            self.rr(o[0])
            return
        if i == 'rl':
            self.rl(o[0])
            return

        if i == 'exx':
            tmp = self.regs['bc']
            self.set('bc', "bc'")
            self.set("bc'", tmp)
            tmp = self.regs['de']
            self.set('de', "de'")
            self.set("de'", tmp)
            tmp = self.regs['hl']
            self.set('hl', "hl'")
            self.set("hl'", tmp)
            return

        if i == 'ex':
            tmp = self.get(o[1])
            self.set(o[1], o[0])
            self.set(o[0], tmp)
            return

        if i == 'xor':
            self.C = 0

            if o[0] == 'a':
                self.set('a', 0)
                self.Z = 1
                return

            if self.getv('a') is None or self.getv(o[0]) is None:
                self.Z = None
                self.set('a', None)
                return

            self.set('a', self.getv('a') ^ self.getv(o[0]))
            self.Z = int(self.get('a') == 0)
            return

        if i in ('or', 'and'):
            self.C = 0

            if self.getv('a') is None or self.getv(o[0]) is None:
                self.Z = None
                self.set('a', None)
                return

            if i == 'or':
                self.set('a', self.getv('a') | self.getv(o[0]))
            else:
                self.set('a', self.getv('a') & self.getv(o[0]))

            self.Z = int(self.get('a') == 0)
            return

        if i in ('adc', 'sbc'):
            if len(o) == 1:
                o = ['a', o[0]]

            if self.C is None:
                self.set(o[0], 'None')
                self.Z = None
                self.set(o[0], None)
                return

            if i == 'sbc' and o[0] == o[1]:
                self.Z = int(not self.C)
                self.set(o[0], -self.C)
                return

            if self.getv(o[0]) is None or self.getv(o[1]) is None:
                self.set_flag(None)
                self.set(o[0], None)
                return

            if i == 'adc':
                val = self.getv(o[0]) + self.getv(o[1]) + self.C
                if is_8bit_register(o[0]):
                    self.C = int(val > 0xFF)
                else:
                    self.C = int(val > 0xFFFF)
                self.set(o[0], val)
                return

            val = self.getv(o[0]) - self.getv(o[1]) - self.C
            self.C = int(val < 0)
            self.Z = int(val == 0)
            self.set(o[0], val)
            return

        if i in ('add', 'sub'):
            if len(o) == 1:
                o = ['a', o[0]]

            if i == 'sub' and o[0] == o[1]:
                self.Z = 1
                self.C = 0
                self.set(o[0], 0)
                return

            if not is_number(self.get(o[0])) or not is_number(self.get(o[1])) is None:
                self.set_flag(None)
                self.set(o[0], None)
                return

            if i == 'add':
                val = self.getv(o[0]) + self.getv(o[1])
                if is_8bit_register(o[0]):
                    self.C = int(val > 0xFF)
                    val &= 0xFF
                    self.Z = int(val == 0)
                    self.S = val >> 7
                else:
                    self.C = int(val > 0xFFFF)
                    val &= 0xFFFF

                self.set(o[0], val)
                return

            val = self.getv(o[0]) - self.getv(o[1])
            if is_8bit_register(o[0]):
                self.C = int(val < 0)
                val &= 0xFF
                self.Z = int(val == 0)
                self.S = val >> 7
            else:
                self.C = int(val < 0)
                val &= 0xFFFF

            self.set(o[0], val)
            return

        if i == 'neg':
            if self.getv('a') is None:
                self.set_flag(None)
                return

            val = -self.getv('a')
            self.set('a', val)
            self.Z = int(not val)
            val &= 0xFF
            self.S = val >> 7
            return

        if i == 'scf':
            self.C = 1
            return

        if i == 'ccf':
            if self.C is not None:
                self.C = int(not self.C)
            return

        if i == 'cpl':
            if self.getv('a') is None:
                return

            self.set('a', 0xFF ^ self.getv('a'))
            return

        # Unknown. Resets ALL
        self.reset()


Instruction:
Can you generate a brief explanation for the following Python 3 code
def opers(self):
        i = [x for x in self.asm.strip(' \t\n').split(' ') if x != '']

        if len(i) == 1:
            return []

        i = ''.join(i[1:]).split(',')
        if self.condition_flag is not None:
            i = i[1:]
        else:
            i = i[0:]

        op = [x.lower() if is_register(x) else x for x in i]
        return op

Response: Returns a list of operators this mnemonic uses


Instruction:
Can you tell what is the following Python 3 function doing
def destroys(self):

        if self.asm in arch.zx48k.backend.ASMS:
            return ALL_REGS

        res = set([])
        i = self.inst
        o = self.opers

        if i in {'push', 'ret', 'call', 'rst', 'reti', 'retn'}:
            return ['sp']

        if i == 'pop':
            res.update('sp', single_registers(o[:1]))
        elif i in {'ldi', 'ldir', 'ldd', 'lddr'}:
            res.update('a', 'b', 'c', 'd', 'e', 'f')
        elif i in {'otir', 'otdr', 'oti', 'otd', 'inir', 'indr', 'ini', 'ind'}:
            res.update('h', 'l', 'b')
        elif i in {'cpir', 'cpi', 'cpdr', 'cpd'}:
            res.update('h', 'l', 'b', 'c', 'f')
        elif i in ('ld', 'in'):
            res.update(single_registers(o[:1]))
        elif i in ('inc', 'dec'):
            res.update('f', single_registers(o[:1]))
        elif i == 'exx':
            res.update('b', 'c', 'd', 'e', 'h', 'l')
        elif i == 'ex':
            res.update(single_registers(o[0]))
            res.update(single_registers(o[1]))
        elif i in {'ccf', 'scf', 'bit', 'cp'}:
            res.add('f')
        elif i in {'or', 'and', 'xor', 'add', 'adc', 'sub', 'sbc'}:
            if len(o) > 1:
                res.update(single_registers(o[0]))
            else:
                res.add('a')
            res.add('f')
        elif i in {'neg', 'cpl', 'daa', 'rra', 'rla', 'rrca', 'rlca', 'rrd', 'rld'}:
            res.update('a', 'f')
        elif i == 'djnz':
            res.update('b', 'f')
        elif i in {'rr', 'rl', 'rrc', 'rlc', 'srl', 'sra', 'sll', 'sla'}:
            res.update(single_registers(o[0]))
            res.add('f')
        elif i in ('set', 'res'):
            res.update(single_registers(o[1]))

        return list(res)

Response: Returns a list of all the destroys for the current entry.


Instruction:
Write a Python 3 script to
return the set of registers operands etc. required by an instruction.

Response:
def requires(self):
        """ Returns the registers, operands, etc. required by an instruction.
        """
        if self.asm in arch.zx48k.backend.ASMS:
            return ALL_REGS

        if self.inst == '#pragma':
            tmp = self.__instr.split(' ')[1:]
            if tmp[0] != 'opt':
                return
            if tmp[1] == 'require':
                return set(flatten_list([single_registers(x.strip(', \t\r')) for x in tmp[2:]]))

            return set([])

        result = set([])
        i = self.inst
        o = [x.lower() for x in self.opers]

        if i in ['ret', 'pop', 'push']:
            result.add('sp')

        if self.condition_flag is not None or i in ['sbc', 'adc']:
            result.add('f')

        for O in o:
            if '(hl)' in O:
                result.add('h')
                result.add('l')

            if '(de)' in O:
                result.add('d')
                result.add('e')

            if '(bc)' in O:
                result.add('b')
                result.add('c')

            if '(sp)' in O:
                result.add('sp')

            if '(ix' in O:
                result.add('ixh')
                result.add('ixl')

            if '(iy' in O:
                result.add('iyh')
                result.add('iyl')

        if i in ['ccf']:
            result.add('f')

        elif i in {'rra', 'rla', 'rrca', 'rlca'}:
            result.add('a')
            result.add('f')

        elif i in ['xor', 'cp']:
            # XOR A, and CP A don't need the a register
            if o[0] != 'a':
                result.add('a')

                if o[0][0] != '(' and not is_number(o[0]):
                    result = result.union(single_registers(o))

        elif i in ['or', 'and']:
            # AND A, and OR A do need the a register
            result.add('a')

            if o[0][0] != '(' and not is_number(o[0]):
                result = result.union(single_registers(o))

        elif i in {'adc', 'sbc', 'add', 'sub'}:
            if len(o) == 1:
                if i not in ('sub', 'sbc') or o[0] != 'a':
                    # sbc a and sub a dont' need the a register
                    result.add('a')

                if o[0][0] != '(' and not is_number(o[0]):
                    result = result.union(single_registers(o))
            else:
                if o[0] != o[1] or i in ('add', 'adc'):
                    # sub HL, HL or sub X, X don't need the X register(s)
                    result = result.union(single_registers(o))

            if i in ['adc', 'sbc']:
                result.add('f')

        elif i in {'daa', 'rld', 'rrd', 'neg', 'cpl'}:
            result.add('a')

        elif i in {'rl', 'rr', 'rlc', 'rrc'}:
            result = result.union(single_registers(o) + ['f'])

        elif i in {'sla', 'sll', 'sra', 'srl', 'inc', 'dec'}:
            result = result.union(single_registers(o))

        elif i == 'djnz':
            result.add('b')

        elif i in {'ldir', 'lddr', 'ldi', 'ldd'}:
            result = result.union(['b', 'c', 'd', 'e', 'h', 'l'])

        elif i in {'cpi', 'cpd', 'cpir', 'cpdr'}:
            result = result.union(['a', 'b', 'c', 'h', 'l'])

        elif i == 'ld' and not is_number(o[1]):
            result = result.union(single_registers(o[1]))

        elif i == 'ex':
            if o[0] == 'de':
                result = result.union(['d', 'e', 'h', 'l'])
            elif o[1] == '(sp)':
                result = result.union(['h', 'l'])  # sp already included
            else:
                result = result.union(['a', 'f', "a'", "f'"])

        elif i == 'exx':
            result = result.union(['b', 'c', 'd', 'e', 'h', 'l'])

        elif i == 'push':
            result = result.union(single_registers(o))

        elif i in {'bit', 'set', 'res'}:
            result = result.union(single_registers(o[1]))

        elif i == 'out':
            result.add(o[1])
            if o[0] == '(c)':
                result.add('c')

        elif i == 'in':
            if o[1] == '(c)':
                result.add('c')

        elif i == 'im':
            result.add('i')

        result = list(result)
        return result


Instruction:
Implement a Python 3 function for
returning if this instruction affects any of the registers in reglist.

Response:
def affects(self, reglist):
        """ Returns if this instruction affects any of the registers
        in reglist.
        """
        if isinstance(reglist, str):
            reglist = [reglist]

        reglist = single_registers(reglist)

        return len([x for x in self.destroys if x in reglist]) > 0


Instruction:
Implement a function in Python 3 to
return if this instruction needs any of the registers in reglist.

Response:
def needs(self, reglist):
        """ Returns if this instruction need any of the registers
        in reglist.
        """
        if isinstance(reglist, str):
            reglist = [reglist]

        reglist = single_registers(reglist)

        return len([x for x in self.requires if x in reglist]) > 0


Instruction:
How would you code a function in Python 3 to
return a list of required labels for this instruction

Response:
def used_labels(self):
        """ Returns a list of required labels for this instruction
        """
        result = []

        tmp = self.asm.strip(' \n\r\t')
        if not len(tmp) or tmp[0] in ('#', ';'):
            return result

        try:
            tmpLexer = asmlex.lex.lex(object=asmlex.Lexer(), lextab='zxbasmlextab')
            tmpLexer.input(tmp)

            while True:
                token = tmpLexer.token()
                if not token:
                    break

                if token.type == 'ID':
                    result += [token.value]
        except:
            pass

        return result


Instruction:
Can you tell what is the following Python 3 function doing
def replace_label(self, oldLabel, newLabel):
        if oldLabel == newLabel:
            return

        tmp = re.compile(r'\b' + oldLabel + r'\b')
        last = 0
        l = len(newLabel)
        while True:
            match = tmp.search(self.asm[last:])
            if not match:
                break

            txt = self.asm
            self.asm = txt[:last + match.start()] + newLabel + txt[last + match.end():]
            last += match.start() + l

Response: Replaces old label with a new one.


Instruction:
How would you explain what the following Python 3 function does
def is_partitionable(self):
        if len(self.mem) < 2:
            return False  # An atomic block

        if any(x.is_ender or x.asm in arch.zx48k.backend.ASMS for x in self.mem):
            return True

        for label in JUMP_LABELS:
            if LABELS[label].basic_block == self and (not self.mem[0].is_label or self.mem[0].inst != label):
                return True

        return False

Response: Returns if this block can be partitioned in 2 or more blocks.


Instruction:
How would you code a function in Python 3 to
remove the basic_block from the list for the entry in the entry list.

Response:
def delete_from(self, basic_block):
        """ Removes the basic_block ptr from the list for "comes_from"
        if it exists. It also sets self.prev to None if it is basic_block.
        """
        if basic_block is None:
            return

        if self.lock:
            return

        self.lock = True

        if self.prev is basic_block:
            if self.prev.next is self:
                self.prev.next = None
            self.prev = None

        for i in range(len(self.comes_from)):
            if self.comes_from[i] is basic_block:
                self.comes_from.pop(i)
                break

        self.lock = False


Instruction:
Create a Python 3 function to
add the basic_block to the comes_from list.

Response:
def add_comes_from(self, basic_block):
        """ This simulates a set. Adds the basic_block to the comes_from
        list if not done already.
        """
        if basic_block is None:
            return

        if self.lock:
            return

        # Return if already added
        if basic_block in self.comes_from:
            return

        self.lock = True
        self.comes_from.add(basic_block)
        basic_block.add_goes_to(self)
        self.lock = False


Instruction:
Implement a Python 3 function for
updating the next basic block and the next sets.

Response:
def update_next_block(self):
        """ If the last instruction of this block is a JP, JR or RET (with no
        conditions) then the next and goes_to sets just contains a
        single block
        """
        last = self.mem[-1]
        if last.inst not in ('ret', 'jp', 'jr') or last.condition_flag is not None:
            return

        if last.inst == 'ret':
            if self.next is not None:
                self.next.delete_from(self)
                self.delete_goes(self.next)
            return

        if last.opers[0] not in LABELS.keys():
            __DEBUG__("INFO: %s is not defined. No optimization is done." % last.opers[0], 2)
            LABELS[last.opers[0]] = LabelInfo(last.opers[0], 0, DummyBasicBlock(ALL_REGS, ALL_REGS))

        n_block = LABELS[last.opers[0]].basic_block
        if self.next is n_block:
            return

        if self.next.prev == self:
            # The next basic block is not this one since it ends with a jump
            self.next.delete_from(self)
            self.delete_goes(self.next)

        self.next = n_block
        self.next.add_comes_from(self)
        self.add_goes_to(self.next)


Instruction:
How would you implement a function in Python 3 that
updates the goes_to and comes_from sets of the receivers.

Response:
def update_goes_and_comes(self):
        """ Once the block is a Basic one, check the last instruction and updates
        goes_to and comes_from set of the receivers.
        Note: jp, jr and ret are already done in update_next_block()
        """
        # Remove any block from the comes_from and goes_to list except the PREVIOUS and NEXT
        if not len(self):
            return

        if self.mem[-1].inst == 'ret':
            return  # subroutine returns are updated from CALLer blocks

        self.update_used_by_list()

        if not self.mem[-1].is_ender:
            return

        last = self.mem[-1]
        inst = last.inst
        oper = last.opers
        cond = last.condition_flag

        if oper and oper[0] not in LABELS.keys():
            __DEBUG__("INFO: %s is not defined. No optimization is done." % oper[0], 1)
            LABELS[oper[0]] = LabelInfo(oper[0], 0, DummyBasicBlock(ALL_REGS, ALL_REGS))

        if inst == 'djnz' or inst in ('jp', 'jr') and cond is not None:
            if oper[0] in LABELS.keys():
                self.add_goes_to(LABELS[oper[0]].basic_block)

        elif inst in ('jp', 'jr') and cond is None:
            if oper[0] in LABELS.keys():
                self.delete_goes(self.next)
                self.next = LABELS[oper[0]].basic_block
                self.add_goes_to(self.next)

        elif inst == 'call':
            LABELS[oper[0]].basic_block.add_comes_from(self)
            stack = [LABELS[oper[0]].basic_block]
            bbset = IdentitySet()

            while stack:
                bb = stack.pop(0)

                while bb is not None:
                    if bb in bbset:
                        break

                    bbset.add(bb)
                    if len(bb):
                        bb1 = bb[-1]
                        if bb1.inst == 'ret':
                            bb.add_goes_to(self.next)
                            if bb1.condition_flag is None:  # 'ret'
                                break

                        if bb1.inst in ('jp', 'jr') and bb1.condition_flag is not None:  # jp/jr nc/nz/.. LABEL
                            if bb1.opers[0] in LABELS:  # some labels does not exist (e.g. immediate numeric addresses)
                                stack += [LABELS[bb1.opers[0]].basic_block]

                    bb = bb.next  # next contiguous block

            if cond is None:
                self.calls.add(LABELS[oper[0]].basic_block)


Instruction:
Implement a function in Python 3 to
check whether any of the given regs are required from the given point to the end or not.

Response:
def is_used(self, regs, i, top=None):
        """ Checks whether any of the given regs are required from the given point
        to the end or not.
        """
        if i < 0:
            i = 0

        if self.lock:
            return True

        regs = list(regs)  # make a copy
        if top is None:
            top = len(self)
        else:
            top -= 1

        for ii in range(i, top):
            for r in self.mem[ii].requires:
                if r in regs:
                    return True

            for r in self.mem[ii].destroys:
                if r in regs:
                    regs.remove(r)

            if not regs:
                return False

        self.lock = True
        result = self.goes_requires(regs)
        self.lock = False

        return result


Instruction:
Create a Python 3 function for
giving a list of registers returns a list of them that are safe to write from the given index until the given end_.

Response:
def safe_to_write(self, regs, i=0, end_=0):
        """ Given a list of registers (8 or 16 bits) returns a list of them
        that are safe to modify from the given index until the position given
        which, if omitted, defaults to the end of the block.
        :param regs: register or iterable of registers (8 or 16 bit one)
        :param i: initial position of the block to examine
        :param end_: final position to examine
        :returns: registers safe to write
        """
        if is_register(regs):
            regs = set(single_registers(regs))
        else:
            regs = set(single_registers(x) for x in regs)
        return not regs.intersection(self.requires(i, end_))


Instruction:
Can you write a function in Python 3 where it
returns a list of registers and variables that this block requires. By default checks from the beginning.

Response:
def requires(self, i=0, end_=None):
        """ Returns a list of registers and variables this block requires.
        By default checks from the beginning (i = 0).
        :param i: initial position of the block to examine
        :param end_: final position to examine
        :returns: registers safe to write
        """
        if i < 0:
            i = 0
        end_ = len(self) if end_ is None or end_ > len(self) else end_
        regs = {'a', 'b', 'c', 'd', 'e', 'f', 'h', 'l', 'i', 'ixh', 'ixl', 'iyh', 'iyl', 'sp'}
        result = []

        for ii in range(i, end_):
            for r in self.mem[ii].requires:
                r = r.lower()
                if r in regs:
                    result.append(r)
                    regs.remove(r)

            for r in self.mem[ii].destroys:
                r = r.lower()
                if r in regs:
                    regs.remove(r)

            if not regs:
                break

        return result


Instruction:
Given the following Python 3 function, write the documentation
def destroys(self, i=0):
        regs = {'a', 'b', 'c', 'd', 'e', 'f', 'h', 'l', 'i', 'ixh', 'ixl', 'iyh', 'iyl', 'sp'}
        top = len(self)
        result = []

        for ii in range(i, top):
            for r in self.mem[ii].destroys:
                if r in regs:
                    result.append(r)
                    regs.remove(r)

            if not regs:
                break

        return result

Response: Returns a list of registers this block destroys by default checks from the beginning.


Instruction:
Here you have a function in Python 3, explain what it does
def swap(self, a, b):
        self.mem[a], self.mem[b] = self.mem[b], self.mem[a]
        self.asm[a], self.asm[b] = self.asm[b], self.asm[a]

Response: Swaps the memory positions a and b.


Instruction:
Can you tell what is the following Python 3 function doing
def goes_requires(self, regs):
        if len(self) and self.mem[-1].inst == 'call' and self.mem[-1].condition_flag is None:
            for block in self.calls:
                if block.is_used(regs, 0):
                    return True

                d = block.destroys()
                if not len([x for x in regs if x not in d]):
                    return False  # If all registers are destroyed then they're not used

        for block in self.goes_to:
            if block.is_used(regs, 0):
                return True

        return False

Response: Returns True if any of the goes_to blocks requires any of the given registers.


Instruction:
Explain what the following Python 3 code does
def get_label_idx(self, label):
        for i in range(len(self)):
            if self.mem[i].is_label and self.mem[i].inst == label:
                return i

        return None

Response: Returns the index of a label. Returns None if the label is not found.


Instruction:
How would you explain what the following Python 3 function does
def get_first_non_label_instruction(self):
        for i in range(len(self)):
            if not self.mem[i].is_label:
                return self.mem[i]

        return None

Response: Returns the first non - label instruction in the block.


Instruction:
Create a Python 3 function for
trying to detect peep - hole patterns in this basic block and remove them.

Response:
def optimize(self):
        """ Tries to detect peep-hole patterns in this basic block
        and remove them.
        """
        changed = OPTIONS.optimization.value > 2  # only with -O3 will enter here

        while changed:
            changed = False
            regs = Registers()

            if len(self) and self[-1].inst in ('jp', 'jr') and \
                    self.original_next is LABELS[self[-1].opers[0]].basic_block:
                # { jp Label ; Label: ; ... } => { Label: ; ... }
                LABELS[self[-1].opers[0]].used_by.remove(self)
                self.pop(len(self) - 1)
                changed = True
                continue

            for i in range(len(self)):
                try:
                    if self.mem[i].is_label:
                        # ignore labels
                        continue
                except IndexError:
                    print(i)
                    print('\n'.join(str(x) for x in self.mem))
                    raise

                i1 = self.mem[i].inst
                o1 = self.mem[i].opers

                if i > 0:
                    i0 = self.mem[i - 1].inst
                    o0 = self.mem[i - 1].opers
                else:
                    i0 = o0 = None

                if i < len(self) - 1:
                    i2 = self.mem[i + 1].inst
                    o2 = self.mem[i + 1].opers
                else:
                    i2 = o2 = None

                if i < len(self) - 2:
                    i3 = self.mem[i + 2].inst
                    o3 = self.mem[i + 2].opers
                else:
                    i3 = o3 = None

                if i1 == 'ld':
                    if OPT00 and o1[0] == o1[1]:
                        # { LD X, X } => {}
                        self.pop(i)
                        changed = True
                        break

                    if OPT01 and o0 == 'ld' and o0[0] == o1[1] and o1[0] == o0[1]:
                        # { LD A, X; LD X, A} => {LD A, X}
                        self.pop(i)
                        changed = True
                        break

                    if OPT02 and i0 == i1 == 'ld' and o0[1] == o1[1] and \
                            is_register(o0[0]) and is_register(o1[0]) and not is_16bit_idx_register(o1[0]):
                        if is_8bit_register(o1[0]):
                            if not is_8bit_register(o1[1]):
                                # { LD r1, N; LD r2, N} => {LD r1, N; LD r2, r1}
                                changed = True
                                self[i] = 'ld %s, %s' % (o1[0], o0[0])
                                break
                        else:
                            changed = True
                            # {LD r1, NN; LD r2, NN} => { LD r1, NN; LD r2H, r1H; LD r2L, r1L}
                            self[i] = 'ld %s, %s' % (HI16(o1[0]), HI16(o0[0]))
                            self.insert(i + 1, 'ld %s, %s' % (LO16(o1[0]), LO16(o0[0])))
                            break

                    if OPT03 and is_register(o1[0]) and o1[0] != 'sp' and \
                            not self.is_used(single_registers(o1[0]), i + 1):
                        # LD X, nnn ; X not used later => Remove instruction
                        tmp = str(self.asm)
                        self.pop(i)
                        changed = True
                        __DEBUG__('Changed %s ==> %s' % (tmp, self.asm), 2)
                        break

                    if OPT04 and o1 == ['h', 'a'] and i2 == 'ld' and o2[0] == 'a' \
                            and i3 == 'sub' and o3[0] == 'h' and not self.is_used('h', i + 3):
                        if is_number(o2[1]):
                            self[i] = 'neg'
                            self[i + 1] = 'add a, %s' % o2[1]
                            self[i + 2] = 'ccf'
                            changed = True
                            break

                    if OPT05 and regs._is(o1[0], o1[1]):  # and regs.get(o1[0])[0:3] != '(ix':
                        tmp = str(self.asm)
                        self.pop(i)
                        changed = True
                        __DEBUG__('Changed %s ==> %s' % (tmp, self.asm), 2)
                        break

                    if OPT06 and o1[0] in ('hl', 'de') and \
                            i2 == 'ex' and o2[0] == 'de' and o2[1] == 'hl' and \
                            not self.is_used(single_registers(o1[0]), i + 2):
                        # { LD HL, XX ; EX DE, HL; POP HL } ::= { LD DE, XX ; POP HL }
                        reg = 'de' if o1[0] == 'hl' else 'hl'
                        self.pop(i + 1)
                        self[i] = 'ld %s, %s' % (reg, o1[1])
                        changed = True
                        break

                    if OPT07 and i0 == 'ld' and i2 == 'ld' and o2[1] == 'hl' and not self.is_used(['h', 'l'], i + 2) \
                            and (o0[0] == 'h' and o0[1] == 'b' and o1[0] == 'l' and o1[1] == 'c' or
                                 o0[0] == 'l' and o0[1] == 'c' and o1[0] == 'h' and o1[1] == 'b' or
                                 o0[0] == 'h' and o0[1] == 'd' and o1[0] == 'l' and o1[1] == 'e' or
                                 o0[0] == 'l' and o0[1] == 'e' and o1[0] == 'h' and o1[1] == 'd'):
                        # { LD h, rH ; LD l, rl ; LD (XX), HL } ::= { LD (XX), R }
                        tmp = str(self.asm)
                        r2 = 'de' if o0[1] in ('d', 'e') else 'bc'
                        self[i + 1] = 'ld %s, %s' % (o2[0], r2)
                        self.pop(i)
                        self.pop(i - 1)
                        changed = True
                        __DEBUG__('Changed %s ==> %s' % (tmp, self.asm), 2)
                        break

                    if OPT08 and i1 == i2 == 'ld' and i > 0 and \
                            (o1[1] == 'h' and o1[0] == 'b' and o2[1] == 'l' and o2[0] == 'c' or
                             o1[1] == 'l' and o1[0] == 'c' and o2[1] == 'h' and o2[0] == 'b' or
                             o1[1] == 'h' and o1[0] == 'd' and o2[1] == 'l' and o2[0] == 'e' or
                             o1[1] == 'l' and o1[0] == 'e' and o2[1] == 'h' and o2[
                             0] == 'd') and \
                            regs.get('hl') is not None and not self.is_used(['h', 'l'], i + 2) and \
                            not self[i - 1].needs(['h', 'l']) and not self[i - 1].affects(['h', 'l']):
                        # { LD HL, XXX ; <inst> ; LD rH, H; LD rL, L } ::= { LD HL, XXX ; LD rH, H; LD rL, L; <inst> }
                        changed = True
                        tmp = str(self.asm)
                        self.swap(i - 1, i + 1)
                        __DEBUG__('Changed %s ==> %s' % (tmp, self.asm), 2)
                        break

                    if OPT09 and i > 0 and i0 == i1 == i2 == 'ld' and \
                            o0[0] == 'hl' and \
                            (o1[1] == 'h' and o1[0] == 'b' and o2[1] == 'l' and o2[0] == 'c' or
                             o1[1] == 'l' and o1[0] == 'c' and o2[1] == 'h' and o2[0] == 'b' or
                             o1[1] == 'h' and o1[0] == 'd' and o2[1] == 'l' and o2[0] == 'e' or
                             o1[1] == 'l' and o1[0] == 'e' and o2[1] == 'h' and o2[0] == 'd') and \
                            not self.is_used(['h', 'l'], i + 2):
                        # { LD HL, XXX ;  LD rH, H; LD rL, L } ::= { LD rr, XXX }
                        changed = True
                        r1 = 'de' if o1[0] in ('d', 'e') else 'bc'
                        tmp = str(self.asm)
                        self[i - 1] = 'ld %s, %s' % (r1, o0[1])
                        self.pop(i + 1)
                        self.pop(i)
                        __DEBUG__('Changed %s ==> %s' % (tmp, self.asm), 2)
                        break

                if OPT10 and i1 in ('inc', 'dec') and o1[0] == 'a':
                    if i2 == i0 == 'ld' and o2[0] == o0[1] and 'a' == o0[0] == o2[1] and o0[1][0] == '(':
                        if not RE_INDIR.match(o2[0]):
                            if not self.is_used(['a', 'h', 'l'], i + 2):
                                # { LD A, (X); [ DEC A | INC A ]; LD (X), A} ::= {LD HL, X; [ DEC (HL) | INC (HL) ]}
                                tmp = str(self.asm)
                                self.pop(i + 1)
                                self[i - 1] = 'ld hl, %s' % (o0[1][1:-1])
                                self[i] = '%s (hl)' % i1
                                changed = True
                                __DEBUG__('Changed %s ==> %s' % (tmp, self.asm), 2)
                                break
                        else:
                            if not self.is_used(['a'], i + 2):
                                # { LD A, (IX + n); [ DEC A | INC A ]; LD (X), A} ::=
                                # { [ DEC (IX + n) | INC (IX + n) ] }
                                tmp = str(self.asm)
                                self.pop(i + 1)
                                self.pop(i)
                                self[i - 1] = '%s %s' % (i1, o0[1])
                                changed = True
                                __DEBUG__('Changed %s ==> %s' % (tmp, self.asm), 2)
                                break

                if OPT11 and i0 == 'push' and i3 == 'pop' and o0[0] != o3[0] \
                        and o0[0] in ('hl', 'de') and o3[0] in ('hl', 'de') \
                        and i1 == i2 == 'ld' and (
                        o1[0] == HI16(o0[0]) and o2[0] == LO16(o0[0]) and o1[1] == HI16(o3[0]) and
                        o2[1] == LO16(o3[0]) or
                        o2[0] == HI16(o0[0]) and o1[0] == LO16(o0[0]) and o2[1] == HI16(
                        o3[0]) and o1[1] == LO16(o3[0])):
                    # { PUSH HL; LD H, D; LD L, E; POP HL } ::= {EX DE, HL}
                    self.pop(i + 2)
                    self.pop(i + 1)
                    self.pop(i)
                    self[i - 1] = 'ex de, hl'
                    changed = True
                    break

                if i0 == 'push' and i1 == 'pop':
                    if OPT12 and o0[0] == o1[0]:
                        # { PUSH X ; POP X } ::= { }
                        self.pop(i)
                        self.pop(i - 1)
                        changed = True
                        break

                    if OPT13 and o0[0] in ('de', 'hl') and o1[0] in ('de', 'hl') and not self.is_used(
                            single_registers(o0[0]), i + 1):
                        # { PUSH DE ; POP HL } ::= { EX DE, HL }
                        self.pop(i)
                        self[i - 1] = 'ex de, hl'
                        changed = True
                        break

                    if OPT14 and 'af' in (o0[0], o1[0]):
                        # { push Xx ; pop af } => { ld a, X }
                        if not self.is_used(o1[0][1], i + 1):
                            self[i - 1] = 'ld %s, %s' % (HI16(o1[0]), HI16(o0[0]))
                            self.pop(i)
                            changed = True
                            break
                    elif OPT15 and not is_16bit_idx_register(o0[0]) and not is_16bit_idx_register(
                            o1[0]) and 'af' not in (o0[0], o1[0]):
                        # { push Xx ; pop Yy } => { ld Y, X ; ld y, x }
                        self[i - 1] = 'ld %s, %s' % (HI16(o1[0]), HI16(o0[0]))
                        self[i] = 'ld %s, %s' % (LO16(o1[0]), LO16(o0[0]))
                        changed = True
                        break

                if OPT16 and i > 0 and not self.mem[i - 1].is_label and i1 == 'pop' and \
                        (not self.mem[i - 1].affects([o1[0], 'sp']) or
                         self.safe_to_write(o1[0], i + 1)) and \
                        not self.mem[i - 1].needs([o1[0], 'sp']):
                    # { <inst>;  POP X } => { POP X; <inst> } ; if inst does not uses X
                    tmp = str(self.asm)
                    self.swap(i - 1, i)
                    changed = True
                    __DEBUG__('Changed %s ==> %s' % (tmp, self.asm), 2)
                    break

                if OPT17 and i1 == 'xor' and o1[0] == 'a' and regs._is('a', 0) and regs.Z and not regs.C:
                    tmp = str(self.asm)
                    self.pop(i)
                    __DEBUG__('Changed %s ==> %s' % (tmp, self.asm), 2)
                    changed = True
                    break

                if OPT18 and i3 is not None and \
                        (i0 == i1 == 'ld' and i2 == i3 == 'push') and \
                        (o0[0] == o3[0] == 'de' and o1[0] == o2[0] == 'bc'):  # and \
                    if not self.is_used(['h', 'l', 'd', 'e', 'b', 'c'], i + 3):
                        # { LD DE, (X2) ; LD BC, (X1); PUSH DE; PUSH BC } ::=
                        # { LD HL, (X2); PUSH HL; LD HL, (X1); PUSH HL }
                        self[i - 1] = 'ld hl, %s' % o1[1]
                        self[i] = 'push hl'
                        self[i + 1] = 'ld hl, %s' % o0[1]
                        self[i + 2] = 'push hl'
                        changed = True
                        break

                if i1 in ('jp', 'jr', 'call') and o1[0] in JUMP_LABELS:
                    c = self.mem[i].condition_flag
                    if OPT19 and c is not None:
                        if c == 'c' and regs.C == 1 or \
                                c == 'z' and regs.Z == 1 or \
                                c == 'nc' and regs.C == 0 or \
                                c == 'nz' and regs.Z == 0:
                            # If the condition is always satisfied, replace with a simple jump / call
                            changed = True
                            tmp = str(self.asm)
                            self[i] = '%s %s' % (i1, o1[0])
                            self.update_goes_and_comes()
                            __DEBUG__('Changed %s ==> %s' % (tmp, self.asm), 2)
                            break

                    ii = LABELS[o1[0]].basic_block.get_first_non_label_instruction()
                    ii1 = None if ii is None else ii.inst
                    cc = None if ii is None else ii.condition_flag
                    # Are we calling / jumping into another jump?
                    if OPT20 and ii1 in ('jp', 'jr') and (
                            cc is None or
                            cc == c or
                            cc == 'c' and regs.C == 1 or
                            cc == 'z' and regs.Z == 1 or
                            cc == 'nc' and regs.C == 0 or
                            cc == 'nz' and regs.Z == 0):
                        if c is None:
                            c = ''
                        else:
                            c = c + ', '

                        changed = True
                        tmp = str(self.asm)
                        LABELS[o1[0]].used_by.remove(self)  # This block no longer uses this label
                        self[i] = '%s %s%s' % (i1, c, ii.opers[0])
                        self.update_goes_and_comes()
                        __DEBUG__('Changed %s ==> %s' % (tmp, self.asm), 2)
                        break

                if OPT22 and i0 == 'sbc' and o0[0] == o0[1] == 'a' and \
                        i1 == 'or' and o1[0] == 'a' and \
                        i2 == 'jp' and \
                        self[i + 1].condition_flag is not None and \
                        not self.is_used(['a'], i + 2):
                    c = self.mem[i + 1].condition_flag
                    if c in ('z', 'nz'):
                        c = 'c' if c == 'nz' else 'nc'
                        changed = True
                        self[i + 1] = 'jp %s, %s' % (c, o2[0])
                        self.pop(i)
                        self.pop(i - 1)
                        break

                if OPT23 and i0 == 'ld' and is_16bit_register(o0[0]) and o0[1][0] == '(' and \
                        i1 == 'ld' and o1[0] == 'a' and o1[1] == LO16(o0[0]) and not self.is_used(
                        single_registers(o0[0]), i + 1):
                    # { LD HL, (X) ; LD A, L } ::=  { LD A, (X) }
                    self.pop(i)
                    self[i - 1] = 'ld a, %s' % o0[1]
                    changed = True
                    break

                if OPT24 and i1 == i2 == 'ccf':  # { ccf ; ccf } ::= { }
                    self.pop(i)
                    self.pop(i)
                    changed = True
                    break

                if OPT25 and i1 == 'ld' and is_register(o1[0]) and o1[0] != 'sp':
                    is8 = is_8bit_register(o1[0])
                    ss = [x for x, y in regs.regs.items() if x != o1[0] and y is not None and y == regs.get(o1[1]) and
                          not is_8bit_register(o1[1])]
                    for r_ in ss:
                        if is8 != is_8bit_register(r_):
                            continue
                        changed = True
                        if is8:   # ld A, n; ld B, n => ld A, n; ld B, A
                            self[i] = 'ld %s, %s' % (o1[0], r_)
                        else:    # ld HL, n; ld DE, n => ld HL, n; ld d, h; ld e, l
                            # 16 bit register
                            self[i] = 'ld %s, %s' % (HI16(o1[0]), HI16(r_))
                            self.insert(i + 1, 'ld %s, %s' % (LO16(o1[0]), LO16(r_)))
                        break

                    if changed:
                        break

                if OPT26 and i1 == i2 == 'ld' and (o1[0], o1[1], o2[0], o2[1]) == ('d', 'h', 'e', 'l') and \
                        not self.is_used(['h', 'l'], i + 2):
                    self[i] = 'ex de, hl'
                    self.pop(i + 1)
                    changed = True
                    break

                if OPT27 and i1 in ('cp', 'or', 'and', 'add', 'adc', 'sub', 'sbc') and o1[-1] != 'a' and \
                        not self.is_used(o1[-1], i + 1) and i0 == 'ld' and o0[0] == o1[-1] and \
                        (o0[1] == '(hl)' or RE_IXIND.match(o0[1])):
                    template = '{0} %s{1}' % ('a, ' if i1 in ('add', 'adc', 'sbc') else '')
                    self[i] = template.format(i1, o0[1])
                    self.pop(i - 1)
                    changed = True
                    break

                regs.op(i1, o1)