MB60UG
.pdfГлава 4: Основы языка MapBasic
которые должны были бы по смыслу Вашей задачи быть одинаковыми, будут восприняты как различные.
Чтобы получить вариант строки без завершающих дополнительных пробелов, используйте функцию RTrim$( ). Затем ее можно сравнить с результатом применения функции
RTrim$( ) к строке произвольной длины, не беспокоясь о влиянии дополняющих пробелов.
Логические операторы: Логические операторы применяются к логическим значениям и возвращают TRUE или FALSE:
Оператор |
TRUE, åñëè |
Пример |
And |
оба операнда истинны |
If a And b Then... |
Or |
значение одного из |
If a Or b Then... |
|
операндов – истина |
|
Not |
операнд ложен |
If Not a Then... |
Например, следующий оператор If...Then выполняет две проверки: меньше ли значение переменной x, чем ноль, и больше ли значение x, чем 10. Если проверка не проходит, программа выдает сообщение об ошибке.
If x < 0 or x > 10 Then
Note "Число вне допустимого диапазона."
End If
Географические операторы: Эти операторы применяются к выражениям типа Object и выдают логический результат TRUE или FALSE.
Оператор |
Возвращает TRUE, если |
Пример |
|
|
|
Contains |
первый объект содержит |
If a Contains b Then... |
|
центроид второго объекта |
|
|
|
|
Contains Part |
первый объект содержит часть |
If a Contains Part b Then... |
|
второго объекта |
|
|
|
|
Contains Entire |
первый объект полностью |
If a Contains Entire b Then... |
|
содержит второй объект |
|
|
|
|
Within |
центроид первого объекта |
If a Within b Then... |
|
содержит второй объект |
|
|
|
|
Partly Within |
второй объект содержит часть |
If a Partly Within b Then... |
|
первого объекта |
|
|
|
|
Entirely Within |
второй объект полностью |
If a Entirely Within b Then... |
|
содержит первый объект |
|
|
|
|
Intersects |
два объекта имеют общую точку |
If a Intersects b Then... |
|
|
|
Более подробные сведения о графических объектах содержатся в главе 9.
45
Глава 4: Основы языка MapBasic
Порядок применения операторов в языке MapBasic
Некоторые операторы имеют более высокий приоритет, чем другие. Это означает, что при вычислении сложных выражений MapBasic следует определенному порядку применения операторов. Чтобы понять, как MapBasic обрабатывает сложные выражения, Вы должны знать относительные приоритеты операторов языка MapBasic.
Рассмотрим следующий оператор присваивания:
x = 2 + 3 * 4
В правой части используется две операции – сложение и умножение. Понятно, что результат вычисления зависит от последовательности применения операторов. Если сначала выполнить сложение (сложим 2 + 3 и получим 5), а затем умножение (5 * 4), то итоговым результатом будет 20. В действительности, однако, умножение имеет более высокий приоритет, чем сложение. Это означает, что MapBasic сначала выполнит умножение (3 * 4, получим 12), а затем уже сложение (2 + 12, получим 14).
Чтобы изменить стандартный порядок применения операторов языка MapBasic, надо использовать группировку с помощью скобок. Например, чтобы в приведенном примере сначала выполнялось сложение, его нужно переписать следующим образом:
x = (2 + 3) * 4
В данной таблице приведены приоритеты операторов языка MapBasic.
Высший приоритет: скобки
возведение в степень
отрицание
умножение, деление, Mod, целочисленное деление
сложение, вычитание, склеивание строк &
географические операторы, операторы сравнения, Like
Not
And
Низший приоритет: Or
Операторы, перечисленные в одной строке, имеют одинаковый приоритет. Операторы с более высоким приоритетом выполняются ранее других. Операторы с одинаковым приоритетом выполняются в выражении слева направо, исключая операторы возведения в степень, которые выполняются справа налево.
46
Глава 4: Основы языка MapBasic
Циклы и другие управляющие операторы
Управляющие операторы определяют порядок выполнения других операторов. В языке
MapBasic имеется три типа управляющих операторов:
∙Условные операторы позволяют пропускать выполнение некоторых операторов в программе на языке MapBasic (например, If...Then, GoTo).
∙Операторы цикла позволяют повторять группу операторов несколько раз (например, For...Next, Do...While).
∙Другие специальные управляющие операторы (End Program è äð.).
Оператор If...Then
Оператор If...Then языка MapBasic очень похож на условные операторы If...Then в других языках программирования. В операторе If...Then проверяется истинность условия; если оно истинно, MapBasic выполняет операторы, расположенные после ключевого слова
Then. В следующем примере MapBasic выдает сообщение об ошибке и вызывает процедуру reset_counter, если значение счетчика слишком мало:
If counter < 0 Then
Note "Ошибка: Счетчик слишком мал."
Call reset_counter
End If
В операторе If...Then может также присутствовать предложение Else. Если условие ложно, то MapBasic выполняет операторы, расположенные после ключевого слова Else, вместо того, чтобы выполнять операторы, расположенные после ключевого слова Then. Вот пример использования предложения Else.
If counter < 0 Then
Note "Ошибка: Счетчик слишком мал."
Call reset_counter
Else
Note "Счетчик в порядке."
End If
В операторе If...Then можно также использовать одно или несколько предложений ElseIf. Предложение ElseIf предназначено для проверки дополнительных условий. Если в условном операторе присутствует предложение ElseIf и проверявшееся условие ложно, то MapBasic проверит условие из предложения ElseIf, например:
If counter < 0 Then
Note "Ошибка: Счетчик слишком мал." Call reset_counter
ElseIf counter > 100 Then counter = 100
Note "Ошибка: Значение счетчика (100) слишком велико." Else
Note "Счетчик в порядке." End If
Отметим, что ключевое слово ElseIf пишется слитно. Оператор If...Then может содержать несколько предложений ElseIf, указанные в них условия проверяются последовательно. Впрочем, если Вам нужно проверить несколько условий, Вы можете использовать оператор
47
Глава 4: Основы языка MapBasic
Do...Case (см. описание ниже) вместо оператора If...Then со множеством предложений
ElseIf.
Оператор Do Case
Оператор Do Case выполняет набор проверок, чтобы установить, какому из предусмотренных значений равно текущее значение выражения. Для каждого из предусмотренных значений выполняется своя последовательность операторов.
В следующем примере проверяется, к какому кварталу относится текущий месяц. Если текущий месяц относится к первому кварталу (Январь-Февраль-Март), то текстовой переменной присваивается константа “Первый квартал года". Аналогично, если текущий месяц относится ко второму кварталу, то текстовой переменной присваивается константа “Второй квартал года“ и т.д.
Dim current_month, quarter As SmallInt, report_title As String
current_month = Month( CurDate() )
'
'В данный момент значение переменной current_month равно 1,
'если текущим месяцем является январь, 2 – февраль и т.д.
Do Case current_month Case 1, 2, 3
'Если текущий месяц – 1 (янв), 2 (фев) или 3 (март),
'Сейчас первый квартал.
'Присвоить соответствующее значение.
'
report_title = "Первый квартал года" quarter = 1
Case 4, 5, 6
report_title = "Второй квартал года" quarter = 2
Case 7, 8, 9
report_title = "Третий квартал года" quarter = 3
Case Else
'
'Если текущий месяц имеет номер вне диапазона от 1 до 9,
'то сейчас – четвертый квартал.
'
report_title = "Четвертый квартал года" quarter = 4
End Case
Обратите внимание на предложение Case Else в конце оператора Do Case. Case Else –
необязательное предложение. Если оператор Do Case содержит предложение Case Else è
текущее значение выражения не равно ни одному из значений, перечисленных в предложениях Case, MapBasic выполнит операторы, расположенные после предложения
Case Else. Предложение Case Else должно быть последним предложением оператора Do
Case.
48
Глава 4: Основы языка MapBasic
Оператор GoTo
Оператор GoTo используется для перехода в заданное место программы с того места, где встретился оператор GoTo. В операторе GoTo указывается метка перехода; оператор GoTo
не будет работать, если в той же процедуре, где находится оператор перехода, нет метки с таким именем. Метка – это имя, сопоставленное некоторой строке программы и расположенное в начале этой строки; после имени метки должно стоять двоеточие (в операторе GoTo это двоеточие ставить не надо).
If counter < 0 Then GoTo get_out
End If
...
get_out: End Program
Многие профессиональные программисты не одобряют использование операторов перехода типа GoTo. Полноценное использование возможностей других управляющих операторов, таких как If...Then, обычно устраняет необходимость использования оператора GoTo. Так что Вы можете обходиться и без GoTo.
Оператор For...Next
Оператор For...Next определяет цикл, выполняющийся заданное число раз. Каждое повторение состоит в том, что MapBasic выполняет все операторы, находящиеся между For
è Next.
Перед использованием цикла For...Next Вы должны объявить имя числовой переменной, которая будет использоваться в качестве счетчика. Надо указать начальное и конечное значения этого счетчика. После выполнения каждого повтора (после каждой итерации) MapBasic будет увеличивать счетчик на заданную величину (шаг цикла). Стандартный шаг цикла равен единице (1); чтобы задать другой шаг, следует использовать необязательное предложение Step.
Ниже приводится пример использования цикла For...Next для увеличения всех элементов некоторого массива:
Dim monthly_sales(12), grand_total As Float, next_one As SmallInt
...
For next_one = 1 To 12
grand_total = grand_total + monthly_sales(next_one) Next
Начиная выполнять оператор For...Next, MapBasic присваивает переменной-счетчику начальное значение; в приведенном примере, MapBasic присвоит переменной next_one единицу. Затем MapBasic выполняет операторы, расположенные до ключевого слова Next. После каждой итерации цикла MapBasic увеличивает переменную-счетчик. Если счетчик меньше либо равен заданному Вами конечному значению (в примере, если next_one меньше или равна 12), MapBasic выполняет следующую итерацию цикла.
Выполнение оператора For...Next прерывается, если встретился оператор Exit For. Это позволяет при необходимости немедленно остановить цикл.
49
Глава 4: Основы языка MapBasic
Замечание: Åñëè öèêë For...Next использует явно заданные вещественные значения (например, For i = 0.1 to 1.0 Step 0.1), то такой цикл может выполняться в MapInfo для Macintosh иначе, чем в MapInfo для Windows или UNIX (т.е. может быть выполнено разное число итераций на Macintosh и PC под Windows). Это возможно из-за особого способа обработки плавающих вещественных чисел в компьютерах Macintosh.
Подробнее о цикле For...Next ñì. Справочнике MapBasic.
Оператор Do...Loop
Оператор Do...Loop выполняет группу операторов, пока заданное в нем условие остается истинным, либо пока условие остается ложным.
Возможны различные виды оператора Do...Loop, в зависимости от того, когда Вы хотите проверять условие цикла: до или после выполнения операторов, находящихся в теле цикла. В следующем примере программы условие проверяется в конце цикла:
Dim sales_total, new_accounts(10) As Float, next_one As SmallInt
next_one = 1 Do
sales_total = sales_total + new_accounts(next_one) next_one = next_one + 1
Loop While next_one <= UBound(new_accounts)
Обратим внимание, что такой цикл всегда выполняется хотя бы один раз, поскольку условие проверяется лишь в конце цикла (после выполнения первой итерации).
Следующий пример содержит проверку в начале цикла. Поскольку условие проверяется в начале цикла, операторы в теле цикла могут не выполниться ни разу. Если в момент начала выполнения цикла условие уже ложно, операторы в теле цикла Do...Loop не будут выполнены ни разу.
Dim sales_total, new_accounts(10) As Float, next_one As SmallInt
next_one = 1
Do While next_one <= UBound(new_accounts) sales_total = sales_total + new_accounts(next_one) next_one = next_one + 1
Loop
В обоих приведенных примерах оператора Do...Loop используется ключевое слово While; поэтому оба цикла выполняются до тех пор, пока указанное после этого ключевого слова условие остается истинным. С другой стороны, в операторе Do...Loop можно использовать ключевое слово Until вместо ключевого слова While. Если оператор Do...Loop содержит предложение Until, то цикл выполняется, пока контрольное условие остается ложным.
Выполнение оператора Do...Loop прерывается, если обнаружен оператор Exit Do. Это позволяет при необходимости немедленно остановить цикл.
Оператор While...Wend
MapBasic поддерживает также стандартный синтаксис оператора цикла в языке BASIC
While...Wend. Оператор While...Wend почти во всем совпадет с Do While...Loop.
50
Глава 4: Основы языка MapBasic
Если Вы много программировали на BASIC, то Вам может быть удобнее использовать синтаксис While...Wend и в MapBasic. Следует, однако, заметить, что синтаксис оператора
Do...Loop в некоторых аспектах значительно мощнее синтаксиса оператора While...Wend; например, Вы можете прервать выполнение цикла Do...Loop с помощью оператора Exit Do, â While...Wend же такой возможности нет.
Подробнее о цикле While...Wend ñì. â Справочнике MapBasic.
Завершение выполнения программы
Оператор End Program прерывает выполнение MapBasic-приложения, удаляет все пользовательские меню, созданные приложением, и выгружает приложение из памяти.
End Program также закрывает все файлы, открытые в процессе работы приложения (с помощью оператора Open File), но не закрывает открытые таблицы.
Оператор End Program не обязательно следует выполнять в каждой программе. В некоторых ситуациях Вам, наоборот, следует не выполнять оператор End Program. Например, Ваше приложение добавляет свои меню к системе меню MapInfo и Вы хотите, чтобы это приложение оставалось активным в течение всего сеанса работы с MapInfo, поскольку пользователь должен иметь доступ к меню Вашего приложения в течение всего сеанса работы. В таком случае Вам следует проследить, чтобы Ваша программа не выполняла оператор End Program, поскольку End Program остановит выполнение приложения и удалит все созданные Вашим приложением меню. Подробное обсуждение пользовательских меню Вы найдете в главе 6 "Создание пользовательского интерфейса".
Завершение выполнения программы и сеанса работы с MapInfo
Оператор End MapInfo не только останавливает работу приложения MapBasic (так, как это
делает оператор End Program), но также и закрывает MapInfo.
51
Глава 4: Основы языка MapBasic
Процедуры
Процедура (или подпрограмма) представляет собой основную структурную единицу программы на языке MapBasic. Типичная программа на MapBasic состоит из нескольких процедур; каждая такая процедура содержит операторы, вместе выполняющие некоторую конкретную задачу. Разбиение программы на процедуры придает Вашей программе модульную структуру, делает ее удобнее для дальнейшей разработки и поддержки.
Процедура Main
Каждая программа на MapBasic должна содержать по крайней мере одну процедуру, а именно процедуру со стандартным именем Main. При запуске приложения на MapBasic, автоматически начинает выполняться процедура Main из данного приложения.
Следующий пример программы демонстрирует синтаксис объявления и тела процедуры
Main. В этом примере процедура Main выполняет один только оператор Note:
Declare Sub Main
Sub Main
Note "Привет от MapBasic!"
End Sub
Оператор Declare Sub указывает MapBasic, что в программе встретится процедура с заданным именем. Каждой процедуре в программе должен соответствовать один и только один оператор Declare Sub. Причем оператор Declare Sub должен предшествовать телу объявляемой процедуры. Обычно все операторы Declare Sub располагаются в самом начале программы.
Вспомним, что в главе 3 мы говорили, что программа на MapBasic может состоять только из одной строки. Например, фрагмент:
Note "Привет от MapBasic'а!"
является завершенной программой на MapBasic, которую можно откомпилировать и запустить. Даже такая простейшая программа все равно содержит процедуру Main, однако, в таких случаях мы говорим, что процедура Main задана неявно (в примере же выше она была задана явно).
Вызов процедуры
При компиляции приложения MapInfo автоматически начинает с вызова процедуры Main
(независимо от того, явно или неявно она присутствует в программе). Затем процедура
Main может вызывать другие процедуры с помощью оператора Call. Вот пример программы, состоящей из двух процедур: процедуры Main и процедуры с именем announce_date.
Declare Sub Main
Declare Sub announce_date
Sub Main
Call announce_date( )
End Sub
Sub announce_date
Note "Сегодня " + Str$( CurDate() )
End Sub
52
Глава 4: Основы языка MapBasic
Вызов процедур, имеющих параметры
Как и другие BASIC-подобные языки, MapBasic позволяет создавать процедуры с параметрами. Если процедура имеет параметры, то при ее объявлении их следует перечислять в круглых скобках после имени процедуры в операторе Sub...End Sub.
Ниже приводится пример, в котором процедура check_date имеет один параметр (типа Date). Эта процедура проверяет, давно ли прошла дата, указанная в качестве параметра (прошло более 180 дней); если прошло более 180 дней, то процедура устанавливает значение параметра равным текущей дате.
Declare Sub Main
Declare Sub check_date(last_date As Date) Sub Main
Dim report_date As Date report_date = "01/01/94"
Call check_date( report_date )
'В данный момент переменная report_date
'может содержать текущую дату (в зависимости
'от результата работы процедуры check_date). End Sub
Sub check_date(last_date As Date) Dim elapsed_days As SmallInt
elapsed_days = CurDate() – last_date If elapsed_days > 180 Then
last_date = CurDate() End If
End Sub
Передача параметров ссылкой
По умолчанию все параметры процедур в MapBasic передаются ссылкой. При этом применяются следующие правила:
∙В операторе Call все параметры, передаваемые в процедуру, должны быть именами переменных.
∙Если в вызываемой процедуре передаваемому ссылкой параметру присваивается новое значение, то изменяется значение соответствующей внешней переменной. Другими словами, процедура может использовать передачу параметров ссылкой для изменения значений параметров-переменных.
Так, в последнем приведенном нами примере в операторе Call в качестве фактического параметра была указана переменная типа Date report_date:
Call check_date( report_date )
В процедуре check_date соответствующий (формальный) параметр носил имя last_date. Когда в процедуре check_date формальному параметру last_date присваивается текущая дата (last_date = CurDate( ) ), MapBasic автоматически изменяет и значение фактического параметра report_date в процедуре Main.
53
Глава 4: Основы языка MapBasic
Передача параметров значением
Иногда бывает неудобно передавать параметр ссылкой. Все такие параметры, передаваемые ссылкой, должны представлять собой имя переменной, а иногда это бывает утомительно (например, если если Вы не заводили переменных нужного типа).
Как и в других BASIC-подобных языках, в языке MapBasic Вы можете использовать передачу параметров значением вместо передачи ссылкой. Чтобы указать, что параметр передается значением, следует применить ключевое слово ByVal перед именем соответствующего параметра в операторе Sub...End Sub.
При передаче параметра значением действуют следующие правила:
∙В операторе Call (фактические) параметры не обязательно должны быть именами переменных. Вы можете использовать в операторе Call как имена переменных, так и константы и вообще любые выражения.
∙Если в вызываемой процедуре передаваемому значением формальному параметру присваивается новое значение, то это значение не влияет на соответствующую переменную (фактический параметр) в вызывающей процедуре. Иными словами, передачу значением нельзя использовать для изменения значения фактического параметра.
Следующий пример содержит процедуру (display_date_range), которая имеет два параметра типа Date, передаваемых значением.
Declare Sub Main
Declare Sub display_date_range(ByVal start_date As Date,
ByVal end_date As Date )
Sub Main
Call display_date_range( "1/1", CurDate() ) End Sub
Sub display_date_range(ByVal start_date As Date, ByVal end_date As Date )
Note "Период выдачи сообщений: с " + Str$(start_date) + " по " + Str$(end_date) + "."
End Sub
В данном примере оба параметра в процедуру display_date_range передаются значением. Так, при вызове display_date_range из продуры Main:
Call display_date_range( "1/1", CurDate() )
ни один из параметров не обязан быть именем переменной. Первый параметр (“1/1") является константным выражением типа Date, а второй – выражением, состоящим из вызова функции CurDate( ).
Рекурсивный вызов процедур
MapBasic поддерживает рекурсивные вызовы процедур и функций. Другими словами, процедуры MapBasic могут вызывать сами себя.
Применение рекурсии ограничивается количеством доступной памяти. Каждый раз, когда происходит вызов процедуры или функции, MapInfo запоминает текущие данные в стеке; если таких вызовов слишком много, произойдет ошибка “Недостаточно памяти”.
54