return в SectorC
Вчера перед сном пришло в голову, что один из недостатков языка SectorC, — отсутствие конструкции return, можно отчасти компенсировать средствами самого языка. Достаточно написать функцию return(), которая будет делать две вещи — возвращать значение (об этом ниже) и прерывать выполнение функции из которой её вызвали.
Я уже достаточно знаю об его внутренностях, чтобы понимать как это можно сделать.
Второе реализовать совсем просто, тут мне помогает некогда богатый опыт программирования на Ассемблерах. SectorC транслируется напрямую в машинный код, а значит адреса возвратов из функций хранятся на стеке. Так что надо всего лишь удалить верхний адрес возврата и мы вернёмся не в функцию, которая нас вызвала, а на уровень выше. Я делаю это командой pop ax.
Теперь посмотрим на первую задачу.
Как я уже писал язык устроен так, что присваивание переменных друг другу происходит через регистр AX, таким образом, присваивая переменную самой себе, мы помещаем её в этот регистр. Этот факт используется в стандартной библиотеке языка, так что можно считать, что это стабильное поведение.
Напрашивается следующая реализация, — перед вызовом присваиваем возвращаемую переменную самой себе, в функции return() записываем содержимое AX в какую-нибудь переменную (я выбрал return) и возвращаемся.
Моя реализация вместе с примером использования ниже:
void return()
{
// mov [&return], ax
asm 163; asm 236; asm 229;
// pop ax (clear stack from prev return address)
asm 88;
}
void random()
{
// xor ax, ax int 0x1A xchg ax, dx
asm 49; asm 192; asm 205; asm 26; asm 146;
// xor dx, dx mov cx, 10
asm 49; asm 210; asm 185; asm 10; asm 0;
// div cx inc dx xchg ax, dx
asm 247; asm 241; asm 66; asm 146;
return();
}
void function()
{
i = 0; while( i < 20 ){
random();
if( i > return ){
i = i; return();
}
i = i + 1;
}
i = 0; return();
}
void main()
{
function();
print_num = return; print_u16();
}
Кстати, возникает любопытный сторонний эффект — так как через AX делается не только присваивание, а вообще все операции, то функция return() захватывает любое последнее вычисленное выражение, что тоже может быть удобно.