PowerBASIC: различия между версиями

643 байта добавлено ,  4 года назад
Нет описания правки
м (→‎Ссылки: простановка шаблона "по алфавиту" по запросу на Форуме с помощью AWB)
Оптимизация затрагивает и промежуточный и машинный код и представляет собой процесс удаления избыточного кода для уменьшения размера и увеличения скорости программы. Так например,
 
<source lang="vb">%TWO = 2 'Константа
a = 1 + %TWO</source>
 
может быть записано минуя тупиковые операции
 
<source lang="vb"> a = 3</source>
a = 3
 
Или например в условии
 
<source lang="vb"> If a(y*3) < 0 OR b(y*3) > 10 Then a(y*3) = 0</source>
 
три умножения y*3 могут быть вынесены за пределы выражения и принять вид
 
<source lang="vb"> с=y*3
If a(с) < 0 OR b(с) > 10 Then a(с) = 0</source>
 
Также оптимизация может включать ряд мероприятий по ускорению, как отдельных элементов, так и блоков или процедур.
Как и в VB, минимально допустимая конструкция в PB состоит из стартовой процедуры, только в PB она является функцией и называется PbMain. Кроме того, необходимо специальной директивой #Compile указать компилятору тип создаваемого файла.
 
<source lang="vb"> #Compile Exe
Function PbMain
MsgBox "Минимальное приложение.", 64
End Function</source>
 
Если рассмотреть минимальное приложение поблочно, то можно разделить его на секцию глобальных объявлений (начало первой процедуры символизирует её окончание) и секцию процедур. Как и в VB, внутри процедур PB нет жёсткого разделения на секции объявлений и кода (можно объявлять переменные в любом месте программы).
Специальной директивой компилятору указывается, что создаваемый модуль является библиотекой. Изменение типа модуля с приложения на библиотеку влечёт за собой и изменение вида стартовой процедуры.
 
<source lang="vb"> #Compile Dll
Function PbLibMain
[...]
End Function</source>
 
Стартовая процедура библиотеки отличается от стартовой процедуры приложения тем, что в приложении по завершении работы кода функции PbMain (или принудительного выхода из неё) полностью завершается работа программы, а функция PbLibMain служит для инициализации при подключении библиотеки к процессу или потоку. Если вы хотите управлять инициализацией, то вы должны сменить PbLibMain на LibMain, предоставляющую более широкие возможности. Стартовая процедура в библиотеке является служебной, а исполняемый код библиотеки должен находиться внутри экспортируемых функций. Строение библиотеки здесь можно сравнить с объектом. Экспортируемые функции являются публичными и могут быть вызваны из приложения, а неэкспортируемые являются приватными и видны только внутри библиотеки. Экспортируемая процедура или функция имеет два дополнительных ключевых слова в описании каркаса.
 
<source lang="vb"> Function MyFunc Alias "MyFunc"(Parameter As Long) Export As Long</source>
End Function
 
Библиотеки, создаваемые PB, являются обычными не ActiveX библиотеками, их не нужно регистрировать в ОС, но функции, которыми вы будете пользоваться, должны быть объявлены в вызывающем модуле. Например, объявление в VB:
 
<source lang="vb"> Declare Function MyFunc Lib "pb.dll" Alias "MyFunc"(Parameter As Long) As Long</source>
 
Если имя и псевдоним функции одинаковы, VB уберёт Alias"MyFunc", считая их равнозначными. В любом случае псевдоним (Alias"MyFunc") должен быть идентичен псевдониму в PB (именно псевдоним записывается внутрь библиотеки как имя экспортируемой функции).
Код для VB:
 
<source lang="vb"> Private Declare Sub TestSub Lib "testdll.dll" (ByVal StrTest As String)
Private Sub Form_Load()
Dim Str As String
TestSub Str
MsgBox Str, 64
End Sub</source>
 
Код для PB:
 
<source lang="vb"> #Compile Dll "testdll.dll"
Function PBLibMain
Function = 1
Sub TestSub Alias "TestSub" (StrTest As Asciiz) Export
StrTest="Привет Мир!"
End Sub</source>
 
VB при передаче во внешнюю библиотеку строки по значению (ByVal), создаёт копию этой строки в формате Asciiz и передаёт в библиотеку указатель на эту копию. После того как внешняя процедура отработала, копия строки преобразуется обратно. Подстраиваясь под эту особенность, процедура в библиотеке может принять копию строки как "строку фиксированной длины с нулём в конце". Соответственно изменить её размер она не может, зато может изменить её данные.
 
Давайте рассмотрим пример, иллюстрирующий насколько проста работа с объектами в ПБ.
<source lang="vb"> 'Первая переменная это объект, а вторая изменяемого типа
Dim oWord As Dispatch, vBool As Variant
'Word.Application.10 - это PROGID, определяющий имя сервера
'Изменяется одно из свойств объекта командой Let
'В данном случае устанавливается видимость.
Object Let oWord.Visible = vBool</source>
 
Интерфейс позднего связывания (Dispatch) предоставляет удобное средство взаимодействия с COM, однако оставляет нераскрытым вопрос где же брать описание объекта. Если при раннем связывании объект описывается программистом, то для позднего связывания существует специальный инструмент — обозреватель объектов (PowerBasic COM Browser).
Приведённая ниже модель позволяет создать только один поток для процедуры Thread1, что в принципе не отменяет создание новых потоков в других процедурах. Кроме того, такая модель не является аксиомой<sup>12</sup>(просто к такой реализации я пришёл методом научного тыка, возможно вы найдёте и лучше), можно создавать сколь угодно много отдельных потоков в одной и той же процедуре.
 
<source lang="vb"> 'Глобальная переменная для хранения состояния потока
'Объявляется в секции глобальных объявлений
Global hThread1 As Long
'и будет выполняться параллельно с другими потоками
MsgBox Str$(wParam)
End Function</source>
 
== Графический интерфейс пользователя. ==
Команда создания диалоговой формы довольно проста, в самом сокращённом варианте нужно указать лишь имя заголовка и размеры
 
<source lang="vb"> Dialog New 0, "Заголовок",,, 160, 50 To hDlg</source>
 
Здесь цифра, следующая за ключевым словом New, указывает на родителя создаваемого окна. В данном случае 0 — Рабочий стол. Подряд идущие запятые значат что какие то значения берутся из значений по умолчанию (либо не используются вовсе). В данном случае это стартовые позиции окна.
Элемент управления добавляется командой с практически идентичным строением, за исключением того, что должна быть указана принадлежность его окна к определённому классу. Имена стандартных классов пишутся прямым текстом, а имена дополнительных классов берутся в кавычки.
 
<source lang="vb"> Control Add TextBox, hDlg, %IDTEXT, "", 14, 12, 134, 12</source>
 
Здесь TextBox указывает на то что э.у. принадлежит к классу текстового поля. То что имя класса не берётся в кавычки говорит о том, что это стандартный класс. hDlg — ручка родительской диалоговой формы. %IDTEXT — порядкой номер э.у.(произвольное число, задаётся программистом), может быть просто числом, но рекомендуется использовать константы. Остальные параметры задают положение э.у. на диалоговой форме, его размеры и текст.
Как уже говорилось ранее, обработка событий э.у. и диалоговых окон происходит в специальных оконных процедурах. В отличие от VB, в ПБ все события окна обрабатываются в одной процедуре. Кроме того, так как э.у. принадлежат диалоговой форме, то их события могут быть обработаны в оконной процедуре диалоговой формы (иными словами все события в диалоговой форме могут быть обработаны в одной процедуре). Однако во избежание нагромождения кода рекомендуется выделять код э.у. в отдельную процедуру.
 
<source lang="vb"> #Compile Exe
'Системная константа
'Может объявляться либо непосредственно,
Function = 1
End If
End Function</source>
 
Для понимания механизма оконной процедуры необходимо разобрать её внутренние ключевые слова:
Следующий пример иллюстрирует простоту использования ассемблера в PowerBasic:
 
<source lang="vb"> Function CalcASM(ByVal Value As Long) As Long
' Переслать константу в счётчик цикла
! MOV ECX,10
' Функция возвращает результат
! MOV Function,EAX
End Function</source>
 
== Другие расширения и дополнения языка (детально). ==
В простейшем случае макрокоманда выглядит так:
 
<source lang="vb"> MACRO Имя [(Параметр1, Параметр2, ...)] = <Выражение></source>
 
Если параметры существуют, то логично их будет использовать в выражении. Здесь левая часть является описанием макрокоманды, по которому она находится компилятором, а правая часть — тело макрокоманды, которое будет подставлено в исходный код при компиляции. Макрокоманды позволяют расширить синтаксис языка новыми ключевыми словами. Например, определение констант в VB может быть выражено через:
 
<source lang="vb"> MACRO CONST = MACRO
...
CONST Version = 1&</source>
 
Если макрокоманда применяется как часть формулы (выражения), то макропроцедура (макроблок) представляет собой многострочный кусок кода.
 
<source lang="vb"> MACRO Имя [(Параметр1, Параметр2, ...)]
[MACROTEMP Идентификатор1 [,Идентификатор2, ...]]
DIM Идентификатор1 AS Type [,Идентификатор2 AS Type, ...]]
[EXIT MACRO]
{тело макроблока}
END MACRO</source>
 
MACROTEMP позволяет создавать идентификаторы и автоматически следит за их уникальностью. Так, например, если бы вы каждый раз кусок однотипного кода писали вручную (без использования макроблока), вам бы пришлось и самому придумывать имена переменных для каждого такого блока. Объявлять дважды переменную с одним именем нельзя, поэтому уникальность переменных, заявленных ключевым словом MACROTEMP осуществляется путём приставки к правой части переменной возрастающего при каждом обращении к макроблоку числа. Например, если в теле макроблока встречается переменная MyVariable, то при первой подстановке в код она будет носить имя MyVariable000, при второй подстановке MyVariable001 и т. д.
Макрофункция является комбинацией макроблока и линейной макрокоманды. Соответственно тело макрофункции является их гибридом. Для объявления макрофункции в начало макроблока добавляется ключевое слово FUNCTION, а в конце конструкции указывается возвращаемое значение:
 
<source lang="vb"> MACRO FUNCTION Имя [(Параметр1, Параметр2, ...)]
END MACRO = Значение</source>
 
=== Обработка массивов. ===
К примеру, символ номер 194 содержит код 193 (буква "Б"), а символ номер 226 содержит код 225 (буква "б"). Заменив значение символа под номером 226 (смещение на одну позицию происходит потому что первым символом является 0, который тоже входит в таблицу ASCII) мы получим два одинаковых кода по разным позициям (в нашем случае 225 заменяется на 193).
 
<source lang="vb"> 'Объявить динамический массив и задать его размер
Dim A$(): ReDim A$(1 To 10)
'Присвоить 7-мому элементу строчный литерал
'To I& - результат.
Array Scan A$(), From 8 To 11, Collate C$, = "МИР", To I&
MsgBox Str$(I&)</source>
 
SORT — упорядочивание массива. По умолчанию упорядочивается по возрастанию (ASCEND), начиная с первого элемента. Порядок сортировки (ASCEND или DESCEND) и стартовый элемент (Массив([Индекс])) могут быть настроены. Построение команды аналогично ARRAY SCAN, но имеется дополнительное ключевое слово TAGARRAY. Этим словом указывается второй массив, зависимый от сортируемого массива. Перестановка элементов в сортируемом массиве повлечёт за собой перестановку элементов и в зависимом массиве. Элементы в зависимом массиве будут выстроены в порядке сортируемого массива.
Функция PARSE$ предназначена для получения только одного элемента массива, полученного разбиением строки через разделители. Например, в строке "Привет Мир!", используя в качестве разделителя пробел и указав возвратить первый элемент, вы получите слово "Привет".
 
<source lang="vb"> BIT CALC intvar, bitnumber, calcexpr</source>
 
Устанавливает или сбрасывает бит в источнике intvar по позиции bitnumber в зависимости от логического результата выражения. Примечательно то, что источником может быть массив, интерпретируемый как битовое поле.
В этом примере сбрасывается 96-й бит битового поля Fld128.
 
<source lang="vb"> Dim Fld128(3) As Long
Bit Calc Fld128(0), 96, 1 And 2
MsgBox Bin$(Fld128(3))</source>
 
BIT
5266

правок