Всем привет.
Я хотел опубликовать эту статью чуть позже, приурочив её к другому событию, но с выходом плагина nPawn думаю, сейчас самое время.
В названии указано Pawn 4.x вместо 4.0, поскольку в статье приведены отличия не только версии 4.0, но и экспериментальной ветки, в которой исправлены баги, оставшиеся в 4.0, и добавлено ещё несколько новых фич.
К сведению, nPawn использует именно экспериментальную ветку. ИМХО, она даже более стабильна, чем "стабильный" релиз 4.0.
Условные обозначения:
- (+) Новый функционал.
- (*) Изменение.
- (FIX) Багфикс.
- (4.x) Нет в релизе 4.0, т.к. реализовано позже и пока что находится в экспериментальной ветке.
Список отличий:
- (*) Ключевое слово enum заменено на const.
Теперь для того, чтобы сделать перечисление из нескольких поименованных констант, нужно использовать const. Также у первой константы обязательно должно быть указано значение.
Рассмотрим это на примере объявления ID диалогов в SA-MP. Вот как это объявление выглядело бы в Pawn 4.0:
Запятая после завершающей константы теперь не является ошибкой. Вы уже могли видеть это в модифицированном компиляторе от Zeex, но этого не было в Pawn 3.2.PHP код:
const
{
DIALOG_NONE = 0,
DIALOG_REGISTER,
DIALOG_LOGIN,
DIALOG_EMAIL,
DIALOG_EDIT_EMAIL,
};
По умолчанию константам задаётся целочисленный тег, но можно указать любой другой тег при объявлении:
PHP код:
const Float: // По умолчанию константам в списке будет задан тег Float, если не будет указан другой тег.
{
x = 2.0, // const Float:x = 2.0;
y = 3.0, // const Float:y = 3.0;
bool:b = true; // const bool:b = true;
z = 4.0, // const Float:z = 4.0;
};
- (+) Появилась возможность создавать структуры с Си-подобным синтаксисом обращения к их полям.
Рассмотрим это на примере структуры данных о студенте какого-нибудь ВУЗа:
Обращение к полю "ID" будет выглядеть следующим образом:PHP код:
const MAX_STUDENTS = 1000;
new student[MAX_STUDENTS][.ID, .name[16], .surname[32]];
Также можно отдельно описать саму структуру, чтобы иметь возможность использовать её в нескольких переменных.PHP код:
student[0].ID = random(-1);
printf("Student ID: %d\n", student[0].ID);
Для этого в директиву #define добавлен синтаксис с квадратными скобками, позволяющий объявить макрос из нескольких строк без использования символа переноса строки "\".
Тем не менее, можно объявить структуру и с помощью старого синтаксиса #define:PHP код:
#define s_Student [
.ID,
.name[16],
.surname[32]
]
new student[MAX_STUDENTS][s_Student];
или даже так:PHP код:
#define s_Student\
.ID,\
.name[16],\
.surname[32]
Во всех перечисленных выше вариантах можно добавить запятую после ".surname[32]", это не будет считаться ошибкой.PHP код:
#define s_Student .ID, .name[16], .surname[32]
- (*) Упразднён оператор char, теперь массивы могут объявляться как массивы байт и массивы ячеек.
PHP код:
// массив из ячеек
new cell_array[10];
// массив из байтов
// (фигурные скобки нужны, чтобы указать, что это массив байтов)
new byte_array{10};
- Для инициализации массивов начальными значениями используется новый синтаксис.
Какие скобки были использованы при указании размера массива (квадратные/фигурные), в такие и заключаются значения.
Оператор "..." всё ещё можно использовать для инициализации массивов, но теперь, если нужно задать список значений с инкрементом, следует указать, как минимум, два элемента макссива, а не один, как в предыдущих версиях.PHP код:
new byte_array{10} = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
new cell_array[10] = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
Также доступна прогрессивная инициализация для многомерных массивов:PHP код:
new some_array[4] = [ 1, 2, ... ]; // В Pawn 3.2 можно было написать "[ 1, ... ]", но в 4.0 это заполнит весь массив единицами.
Этот массив будет инициализирован следующими значениями:PHP код:
new some_array[4][4] = [ [ 1 ], [ 2, ... ], [ 3, 4, ... ], [ 5, 6, 9, ... ] ];
Код:// [ 1 0 0 0 ] - в 1-й строке указано значение лишь для 1-го столбца, остальные заполняются нулями. // [ 2 2 2 2 ] - использован оператор "...", но указано только одно значение "2", поэтому вся строка заполнена двойками. // [ 3 4 5 6 ] - использован "..." и указаны значения "3" и "4" - по ним компилятор поймёт, что каждый следующий элемент массива должен быть на 1 больше предыдущего. // [ 5, 6, 9, 12 ] - следует помнить, что компилятор учитывает только 2 последних значения перед "...", поэтому здесь инкремент равен трём (9 - 6 = 3).- (*) Изменения в синтаксисе строк.
Начиная с Pawn 4.0, все строки по умолчанию упакованные - теперь не нужно ставить восклицательный знак перед каждой строкой, чтобы она занимала меньше места в памяти.
Если вы хотите явным образом объявить массив для хранения упакованной строки, то вам понадобится массив байтов:PHP код:
"Это упакованная строка" // 22 символа -> 23 байта -> 8 ячеек (при размере ячейки в 4 байта)
Для неупакованных строк доступны сразу 2 варианта синтаксиса:PHP код:
new packed_string{} = "Это упакованная строка";
Об апострофах и грависах можете узнать из википедии: апостроф, гравис.PHP код:
new unpacked_string1[] = ''Это неупакованная строка''; // обратите внимание: вместо кавычек используются двойные апострофы.
new unpacked_string2[] = ``И это тоже неупакованная строка''; // альтернативный синтаксис: для открытия строки вместо апострофов используется удвоенный гравис.
При объявлении упакованной строки в неупакованном массиве и наоборот компилятор выдаст варнинг:
PHP код:
// на всех этих строках компилятор выдаст предупреждение
// "warning 229: mixing packed and unpacked array indexing or array assignment"
new packed_string1[] = "Sample text";
new packed_string2{} = ''Sample text'';
new unpacked_string1[] = "Sample text";
new unpacked_string2{} = ''Sample text'';
- (*) В Pawn 3.2 строки можно было разделять на отрывки следующим образом:
В версии 4.0 для этого требуется использовать оператор конкатенации "...":PHP код:
new str[] = "Отрывок1" "Отрывок2" "Отрывок3";
По аналогии оператор конкатенации теперь нужен и для переноса отрывков на следующую строку:PHP код:
new str[] = "Отрывок1" ... "Отрывок2" ... "Отрывок3";
PHP код:
new str[] =
"Отрывок1\n" ...
"Отрывок2\n" ...
"Отрывок3";
- (*) Теперь чтобы использовать знак ":" в макросах, он должен находиться внутри круглых "()" или угловых "<>" скобок.
Например, следующий макрос будет считаться неправильным:
Тем не менее, это ограничение можно обойти:PHP код:
#define fpub:%0(%1) forward %0(%1);public %0(%1) // Работает в Pawn 3.2, в 4.0 компилятор выдаёт синтаксическую ошибку.
Пока что я не знаю точно, было ли так задумано, или это баг.PHP код:
#define fpub%0(%1) forward%0(%1);public%0(%1)
- (*) В Pawn 3.2 можно было вставлять в запись числа знак нижнего подчёркивания, чтобы число было удобнее читать:
В Pawn 4.0 для тех же целей следует использовать апостроф, при попытке записи числа через нижнее подчёркивание компилятор выдаст ошибку.PHP код:
new x = 10_000_000;
PHP код:
new x = 10'000'000;
- (+) (4.x) Добавлены директивы #ifdef и #ifndef для большей совместимости с языком C.
К тому же, они просто удобнее, чем "#if defined".
- (+) (4.x) Добавлены директивы #warning и #pragma warning (push|pop|disable).
Они уже были доступны в форке Zeex, теперь они есть и в 4.x.
- (+) (4.x) Для инклудов в дополнение к расширению ".inc" теперь доступно расширение ".i" по аналогии с расширением ".p" в дополнение к ".pawn".
(Расширение ".pwn" не является стандартным, оно используется только в скриптах для SA-MP.)
Рассмотрим следующий пример:
Расширение инклуда "my_inc" не указано, поэтому компилятор попробует открыть файлы со следуюшими расширениями: ".i", ".inc", ".p", ".pawn".PHP код:
#include "my_inc"
main(){}
Поиск файла будет произведён строго в том порядке, который указан выше. Если в папке со скриптом есть файлы "my_inc.i" и "my_inc.inc", то компилятор найдёт первым и откроет файл с расширением ".i", проигнорировав "my_inc.inc".
Если же у инклуда такое расширение, которого нет в списке, в директиве #include это расширение нужно указывать в явном виде (т.е. не "my_inc", а, например, "my_inc.h").
- (+) (4.x) Компилятор сам объединяет одинаковые константные массивы.
Вы наверняка видели раньше тот трюк с объявлением массивов/строк вручную, чтобы они не дублировались в памяти:
В Pawn 4.0 этот приём устарел, поскольку теперь компилятор сам умеет объединять константные строки и массивы.PHP код:
static const string[] = "qwertyuiop\n";
printf(string);
printf(string);
PHP код:
printf("qwertyuiop\n");
printf("qwertyuiop\n"); // здесь будет обращение к тому же самому экземпляру строки
- (*) Удалены директивы #emit и #endscript.
- (*) (4.x) Также удалены операторы *begin, *end и *then. Паскальщики негодуют.
- (+) Проведена ревизия всего набора инструкций AMX. Добавлены упакованные инструкции, в которых код операции и 1-й операнд умещаются в одну ячейку, благодаря чему достигается большая компактность кода и потенциал к более быстрой работе интерпретатора.
Например, при конфигурации размера ячейки в 4 байта код операции располагается в младших 2 байтах, а операнд - в старших. Разумеется, это работает только если операнд умещается в те старшие 2 байта, иначе компилятор сгенерирует неупакованный вариант инструкции.
- (+) Помимо упакованных опкодов в поле flags заголовка AMX добавлен флаг AMX_FLAG_CRYPT, который сигнализирует о том, что скрипт зашифрован.
По умолчанию предлагается использовать алгоритм шифрования KeeLoq, но можно вручную добавить любой другой алгоритм.
- (+) (4.x) Кроме main() в Pawn 4.0 точкой входа в скрипт могут считаться функции entry() и @start(). Впрочем, в скрипте разрешается использовать только одну из них, т.к. точка входа может быть лишь одна.
Также теперь можно использовать exit() для указания точки выхода. Эти функции могут вызываться при загрузке и выгрузке скрипта соответственно (могут, но не обязаны, всё зависит от того, где используется интерпретатор Pawn и предусмотрен ли там вызов main/@start/entry/exit).
- (FIX) (4.x) Исправлен баг в strcmp, из-за которого функция возвращала 0, если одна из сравниваемых строк была пустая.
- (FIX) (4.x) Исправлен баг в strins, из-за которого был возможен выход за пределы буфера (функция игнорировала аргумент maxlength).
- (FIX) (4.x) Теперь функции printf и strformat правильно выводят число -2147483647 (раньше вместо этого числа выводился только знак "-").
- (FIX) (4.x) Исправлен баг, из-за которого оператор tagof нельзя было использовать со скобками в метках конструкции switch.
- (FIX) (4.x) Оператор tagof больше не возвращает разные ID для целых чисел и тега "_".
- (FIX) (4.x) Исправлена проблема, связанная с неправильным генерированием инструкций из кода, находящегося внутри условно компилируемых секций #if ... #else ... #endif.
Это весь список отличий, который мне удалось вспомнить. Если вы знаете что-то ещё, что есть в Pawn 4.x, но чего нет в Pawn 3.2, буду рад услышать об этом в комментариях.
Автор: Daniel_Cortez
Специально для Pro-Pawn.ruКопирование данной статьи на других ресурсах без разрешения автора запрещено!