'Convert an address to a stack offset.
:param claripy.ast.Base addr:  The address to convert from.
:return:                       A stack offset if the addr comes from the stack pointer, or None if the address
does not come from the stack pointer.'

def _addr_to_stack_offset(self, addr):

    def _parse(addr):
        if (addr.op == '__add__'):
            parsed = [_parse(arg) for arg in addr.args]
            annotated = [True for (annotated, _) in parsed if (annotated is True)]
            if (len(annotated) != 1):
                raise ValueError()
            return (True, sum([offset for (_, offset) in parsed]))
        elif (addr.op == '__sub__'):
            parsed = [_parse(arg) for arg in addr.args]
            (first_annotated, first_offset) = parsed[0]
            if (first_annotated is False):
                raise ValueError()
            if any([annotated for (annotated, _) in parsed[1:]]):
                raise ValueError()
            return (True, (first_offset - sum([offset for (_, offset) in parsed[1:]])))
        else:
            anno = next(iter((anno for anno in addr.annotations if isinstance(anno, StackLocationAnnotation))), None)
            if (anno is None):
                if (addr.op == 'BVV'):
                    return (False, addr._model_concrete.value)
                raise ValueError()
            return (True, anno.offset)
    try:
        (annotated, offset) = _parse(addr)
    except ValueError:
        return None
    if (not annotated):
        return None
    return self._to_signed(offset)
