Процедуры и обработчики событий

Процедуры: подпрограммы и функции

Tibbo BASIC предлагает два вида процедур: подпрограммы (sub) - процедуры, которые не возвращают значение (напрямую), и функции (function) - процедуры, которые значение возвращают.

И у подпрограмм, и у функций могут быть аргументы.

Параллельные конструкции в Tibbo C - функция типа void и функция, не являющаяся void.

Тип возвращаемого значения функции всегда нужно указывать явно. Пропускать его нельзя.

sub fill_the_screen(color as word)
   lcd.forecolor=color
   lcd.fill(0,0,lcd.width,lcd.height)
end sub
function sum_total(a as word, b as word) as word
   sum_total=a+b 'this is how you return a value from a Tibbo BASIC function
end function
void fill_the_screen(unsigned int color){
   lcd.forecolor=color;
   lcd.fill(0,0,lcd.width,lcd.height);
}
unsigned int sum_total(unsigned int a, unsigned int b){
   return a+b;
}

Обратите внимание, как функция на BASIC возвращает значение: для функции с именем sum_total автоматически создаётся локальная переменная с тем же именем. Присвойте этой переменной нужное возвращаемое значение.

Процедуры нужно определять или объявлять до использования

В Tibbo BASIC/C процедуры должны быть определены или объявлены до того, как их начнут использовать.

Определение процедуры - это её тело. Если разместить тело выше первого вызова процедуры, объявление не нужно:

function sum_total(a as word, b as word) as word
   sum_total=a+b
end function
sub on_sys_init
   dim i as word=sum_total(10,20)
end sub
unsigned int sum_total(unsigned int a, unsigned int b){
   return a+b;
}
void on_sys_init(){
   unsigned int i=sum_total(10,20);
}

Если процедура вызывается раньше, чем определена, перед первым вызовом нужно поместить объявление:

declare function sum_total(a as word, b as word) as word
sub on_sys_init
   dim i as word=sum_total(10,20)
end sub
function sum_total(a as word, b as word) as word
   sum_total=a+b
end function
unsigned int sum_total(unsigned int a, unsigned int b);
void on_sys_init(){
   unsigned int i=sum_total(10,20);
}
unsigned int sum_total(unsigned int a, unsigned int b){
   return a+b;
}

Каждый файл исходного кода (и HTML-файл) компилируется отдельно, поэтому процедуры, определённые в других файлах, нужно объявить до их вызова. Такие объявления обычно помещают в заголовочные файлы - .TPH для Tibbo BASIC и .TH для Tibbo C. Заголовочные файлы должны быть подключены к файлу с исходным кодом; одного их присутствия в дереве проекта недостаточно:

include "global.tbh"
#include "global.th"

Обработчики событий

Обработчики событий - это подпрограммы в Tibbo BASIC и функции типа void в Tibbo C. Объявлять их не нужно, так как они уже объявлены в файлах платформы.

Когда виртуальная машина (VM) доходит до обработки очередного события, она вызывает соответствующий обработчик этого события, если такой обработчик есть в вашем коде.

sub on_sys_init
   'always called once on boot
end sub
sub on_sys_timer
   'called periodically (by default, at 0.5 second intervals)
end sub
void on_sys_init(){
   //always called once on boot
}
void on_sys_timer(){
   //called periodically (by default, at 0.5 second intervals)
}

Как отличить обработчик события от обычной процедуры? Имена обработчиков событий подсвечиваются зелёным. Кроме того, имена всех обработчиков событий начинаются с on_, что означает при наступлении x выполнить....

Список доступных событий находится на панели Browser-Project: View > Browser-Project -> Events.

Примечание

Неактивные события (без обработчиков) выделены серым. Дважды щёлкните неактивное событие, чтобы добавить его обработчик в конец текущего файла.

Дважды щёлкните активное событие, чтобы «телепортироваться» к телу его обработчика.

События на самом деле являются частью объектов платформы. Подробнее см. в разделе Объекты и системные функции.

Прямая передача аргументов

В Tibbo BASIC аргументы процедур можно передавать по значению (ByVal) или по ссылке (ByRef). По умолчанию используется ByVal, поэтому указывать его не обязательно.

Аргумент ByVal передаёт копию значения. Если вызванная процедура изменяет это значение, меняется только копия, а оригинал остаётся прежним.

В мире C этому соответствует передача самого аргумента, а не указателя на него.

sub print(i as word) 'you could write "sub print(ByVal i as word)"
   sys.debugprint(str(i)+chr(13)+chr(10))
end sub
void print(unsigned int i){
   sys.debugprint(str(i)+chr(13)+chr(10));
}

И в Tibbo BASIC, и в Tibbo C напрямую можно передавать даже «громоздкие» элементы.

В Tibbo BASIC к ним относятся строковые переменные и типы (структуры). В Tibbo C это строковые переменные, массивы, структуры и объединения.

Заметили? Массивов в списке для BASIC нет! В Tibbo BASIC нельзя передать массив в подпрограмму или функцию и нельзя вернуть массив из функции.

Вот пример функции, которая увеличивает на единицу каждый элемент массива и возвращает массив обратно. Поскольку массивы нельзя передавать в процедуры BASIC и из них, в примере на BASIC массив обёрнут в тип.

Обратите внимание на необычный синтаксис, которым в C указывается, что функция возвращает массив.

'TERRIBLY INEFFICIENT but will work!
type type_a
   arr(5) as byte
end type
function arr_increment(input as type_a) as type_a
   dim f as byte
   for f=0 to countof(input.arr)-1
      input.arr(f)=input.arr(f)+1
   next f
   arr_increment=input
end function
sub on_sys_init()
   dim master_arr as type_a
   ...
   master_arr=arr_increment(master_arr)
end sub
//TERRIBLY INEFFICIENT but will work!
unsigned char arr_increment(unsigned char input[5])[5]{
   //the highlighted [5] above specifies that this function returns an array
   unsigned char f;
   for(f=0;f<sizeof(input);f++)
      input[f]++;
   return input;
}
void on_sys_init(){
   unsigned char master_arr[5];
   ...
   master_arr=arr_increment(master_arr);
}

Косвенная передача аргументов

В Tibbo BASIC аргумент ByRef передаёт ссылку на значение. Если вызванная процедура изменяет такой аргумент, изменяется и оригинал.

Это примерно равнозначно использованию указателя в C, с той разницей, что сам указатель недоступен коду на BASIC и изменить его он не может.

Для громоздких типов рекомендуется передача ByRef в BASIC и указатели в C: это экономит память и повышает производительность.

ByRef и указатели можно использовать и для косвенного возврата значения из процедуры (функции типа void).

Вот предыдущий пример с увеличением элементов массива, переписанный с аргументом ByRef и указателем. Он гораздо эффективнее, так как лишнее копирование не выполняется.

type type_a
   arr(5) as byte
end type
sub indir_arr_increment(byref input as type_a)
   dim f as byte
   for f=0 to countof(input.arr)-1
      input.arr(f)=input.arr(f)+1
   next f
end sub
sub on_sys_init()
   dim master_arr as type_a
   ...
   indir_arr_increment(master_arr)
end sub
void indir_arr_increment(unsigned char *ptr,unsigned char len){
   unsigned char f;
   for(f=0;f<len;f++)
      (*ptr++)++;
}
void on_sys_init(){
   unsigned char master_arr[5]};
   ...
   indir_arr_increment2(&master_arr,sizeof(master_arr));
}

Tibbo BASIC и C никогда не переключаются автоматически на метод ByRef (указатель) вместо передачи самого значения.

В некоторых языках такое переключение происходит всякий раз, когда нужно передать громоздкий элемент. Например, есть системы, которые не передают структуру напрямую и не сообщают о произведённой подмене.

Tibbo считает это крайне вводящим в заблуждение. В Tibbo BASIC (и C) «что определили, то и получили».

Никакой рекурсии, реентерабельного кода и указателей на функции

Tibbo BASIC и Tibbo C не допускают рекурсии, то есть процедуры не могут вызывать сами себя (даже косвенно).

Создавать реентерабельные функции тоже нельзя.

Кроме того, в Tibbo C запрещены указатели на функции.

Всё это связано с тем, как выделяется память для процедур.

Исходный материал Tibbo обновлён 12 июля 2022Оригинал на docs.tibbo.com · Сообщить об ошибке