Sign in to follow this  
Followers 0
Guest

Урок №1 Состав языка Pawn

1 post in this topic

Код на языке Pawn состоит из двух частей:

  • Операторы описания
  • Исполняемые операторы
  • Комментарии


Оператор описания описывает данные, над которыми выполняются действия.
Исполняемый оператор задаёт действия, выполняемые над данными. Пример: сложение двух чисел, запись числа в память, вывод на экран.

Для удобства операторы описания называют описаниями, а исполняемые операторы - просто операторами.

Все исходные тексты на Pawn пишутся при помощи алфавита языка, который состоит из:

  • Прописных и строчных букв латинского алфавита
  • Цифр от "0" до "9"
  • Спец. символов: "_", "@", "&", "+", "*", "%" и т.д.


Комментарии - пояснения к исходному коду, служащие для его документирования. Компилятор их игнорирует, поэтому на скомпилированный скрипт (.amx) они никак не влияют.

В Pawn существуют два вида комментариев: однострочный и многострочный.
Однострочный комментарий начинается с символов "//" и продолжается до конца строки.
Пример:

// это комментарий

 

Многострочный комментарий начинается с символов "/*" и заканчивается символами "*/".
Пример:

 

/* это
многострочный
комментарий */



Скрипты на языке Pawn имеют 2 расширения: .pwn и .amx.
.pwn - файлы с исходным кодом на понятном человеку языке программирования.
.amx - файлы с машинным кодом, которые выполняются интерпретатором (в нашем случае - сервером SA:MP).

Машинный код (байт-код AMX) получается из файлов исходного кода (.pwn) путём компиляции. Компиляцией в Pawn занимается (внимание!) компилятор (pawncc).

Share this post


Link to post
Share on other sites

Your content will need to be approved by a moderator

Guest
You are commenting as a guest. If you have an account, please sign in.
Reply to this topic...

×   You have pasted content with formatting.   Remove formatting

  Only 75 emoticons maximum are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

Loading...
Sign in to follow this  
Followers 0

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • Jawn
      By Jawn
      1. Описание макроса.
      Данный макрос возвращает модуль указанного числа.
      2. Исходный код макроса.
      #if defined abs #undef abs #endif #define abs(%0)\ (%0 < 0) ? (-(%0)) : (%0) 3. Пример использования макроса.
      new a = random(100)-90; // значение переменной может быть отрицательным и положительным printf("Исходное число: %d. Модуль числа: %d.", a, abs(a));  
    • Jawn
      By Jawn
      Введение.
      К сожалению, у многих пользователей, работающих с языком pawn, возникают вопросы, связанные с подсчетом размера строки. Вероятно, их просто отпугивает ошеломляющий вид конечной строки (которую мы получим на выходе). Хотя на самом деле здесь нет ничего сложного. Данная тема обретает актуальность, потому что все большее количество разработчиков пользуются данным методом. Ну, что ж, попробуем разобраться.
       
      А действительно ли оно того стоит?
      Было время, когда я и сам использовал таковой метод. Однако со временем я решил воздержаться от него. Почему? Казалось бы, все удобно и чудесненько. Но меня напрягает в таком случае мой же код: появляется некий мусор, который только мешает мне обрабатывать код. Давайте взглянем на два примера. В одном из них я использую метод, о котором пойдет речь. В другом же я воздерживаюсь от него и делаю это альтернативно (узнаем дальше).
       
      Заметьте: во втором случае мы сразу видим, с какой именно строкой работаем (при форматировании) - это визуальное удобство. Да и сокращается количество строк. Это нисколько не оптимизация, просто намного удобнее, когда в коде нет ничего лишнего. Не так ли? Впрочем, дело ваше. А свою позицию я высказал.
       
      В чем принцип работы данного метода?
      Идея проста - мы создаем константное выражение. Как известно, обработкой констант занимается сам компилятор, а не сервер. Именно компилятор и рассчитывает размер строки, которую мы будем форматировать. Например, использовав такой код, мы получим размер строки (8, поскольку учитывается еще нуль-символ):
      new text[] = "привет"; printf("%d", sizeof text); Здесь компилятор подсчитывает количество ячеек в массиве "привет!". Именно это количество ячеек (и завершающий нуль-символ) есть размер строки, который выведет функция sizeof.
       
      Итак, в моем примере сама строка имеет следующий вид:
      static const fmt_str1[] = "Ваше сообщение успешно отправлено указанному игроку (%s, ID: %d)"; Именно ее размер компилятор посчитает автоматически (почему используется static const?).
      Далее мы создаем новую переменную, куда будем форматировать нашу строку. Но почему нельзя провернуть такую операцию с имеющейся строкой? Вся проблема в том, что наша строка (fmt_str1) объявлена на количество ячеек, которое занимает весь наш текст (а это количество ячеек - 64+1 - с учетом нуль-символа).
       
      Обратите внимание: в нашей исходной строке присутствуют спецификаторы (%s и %d), вместо которых при форматировании будут подставлены наши строковое и цифровое значения соответственно. Именно длины, необходимые для данных аргументов. Например, для аргумента "hello world" нам необходима длина в 11 символов, для записи года нам нужно будет 4 символа, для записи имени игрока - MAX_PLAYER_NAME (24) символов. Динамические (непостоянные) значения использовать не получится. Однако, можно лишь предохраниться и задействовать количество ячеек, в которое вы точно уложитесь.
       
      format - функция, которая осуществляет форматирование строки. Ее суть проста - мы передаем в функцию ту строку, в которую записываем (а если быть точнее, то ее адрес), передаем адрес строки, которую записываем, передаем аргументы. Далее обычный цикл перебирает все ячейки нашей строки (которую записываем) и ищет спецификаторы (%d, %s, %b, %c, %f, %x, %i). Эти спецификаторы также могут иметь и другие нюансы (измененное количество символов, например, см. дальше). Как только цикл находит спецификатор, то буквально стирает его и записывает наш аргумент первый. Находит второй спецификатор - записывает второй аргумент. Если же количество спецификаторов не совпадает с количеством аргументов, тогда записываются до тех пор, пока существуют "свободные" аргументы и спецификаторы. Не хватает аргументов - спецификаторы просто удаляются. Не хватает спецификаторов - аргументы просто игнорируются. Если тип спецификатора не соответствует типу аргумента, то запись производится неправильно (ибо для избежания этого не реализованы какие-либо проверки).
       
      Итак, как ранее было сказано, оператор sizeof вычисляет (причем еще на этапе компиляции!) длину строки, которая указана как аргумент. Наша переменная, в которую будем форматировать строку, должна иметь достаточное количество ячеек как для самой строки, так и для ее аргументов. Поэтому начинаем расписывать ее размер (самая пугающая для большинства часть). Кстати, если же рассмотреть со стороны математики, где A - размер переменной, B - размер строки, а C, D, E... (и так далее) - размеры аргументов, то мы получаем следующее множество: A=B+C+D+E..+Z.
       
      Создадим строку, на основе которой будем проводить наши расчеты:
      static const fmt_str[] = "Сегодня %02d/%02d/%d, время - %02d/%02d. Вас зовут %s. Ваше здоровье - %.2f"; new string[], year, month, day, hour, minute, Float:health; getdate(year, month, day); gettime(hour, minute); GetPlayerName(playerid, string, MAX_PLAYER_NAME); format(string, sizeof string, fmt_str, day, month, year, hour, minute, string, health); SendClientMessage(playerid, -1, string); Длина нашей строки - 75+1 символов (не забываем про нуль-символ). Любой нормальный редактор кода показывает количество символов в строке.
       
      Наша строка хранит в себе информацию о сегодняшней дате (дд/мм/гггг - это 2(дд)+2(мм)+4(гггг)+2(/) =  10 символов), о времени (чч/мм - это 2(чч)+2(мм)  = 4 символа), об имени игрока (MAX_PLAYER_NAME - это константа, которая имеет значение 24), а также о его здоровье. Вещественное (дробное) значение после запятой (плавающей точки) может хранить как 1, так и 6, 7, 8 символов. Потому я обрезал выводимое количество символов после запятой лишь до двух, о чем свидетельствует сама форма записи: "%.2f". Соответственно, если бы она имела вид "%.5f", вы бы увидели после запятой пять символов (при наличии лишь одного выведется "1.800000"). А если вам вообще не нужны цифры после запятой, делаем как-то вот так: "%.0f". Аналогичный метод работает и в целочисленных выражениях. Если мы записываем в форматировании спецификатор вида "%03d" - это значит, что выражение обязательно должно состоять из трех символов (если их больше, остальные просто не отображаются, а если меньше - дописываются нули в начале).
       
      Ранее было сказано, что наша форматируемая переменная в свои размеры обязательно включает размер строки с текстом (fmt_str), потому в квадратных скобках мы обязательно указываем "sizeof fmt_str" - это стандартная процедура, которая должна производиться всегда при использовании данного метода.
      Теперь мы как бы начинаем приплюсовывать длины наших аргументов. Словно читаем, слева направо имеем:
      Вывод дня, месяца, года. Отнимаем длины спецификаторов и заместо них добавляем длины, которые будут записаны вместо этих спецификаторов: (-4+2) - это мы вычисли длину спецификатора "%02d" и добавили длину аргумента (дня), который содержит не больше двух символов. Аналогично имеем для месяца (-4+2), а для года получаем выражение следующего вида: -2+4, ведь здесь спецификатор состоит лишь из двух символов ("%d"), а аргумент (год) состоит из четырех символов (2019). Итого по данному пункту наша строка имеет вид: "sizeof fmt_str+(-4+2)+(-4+2)+(-2+4)". Вывод времени. Здесь повторяем аналогичную операцию: вычитаем длину спецификаторов, прибавляем длину (максимальную) часов (2) и минут (2). Теперь наша строка должна выглядеть так: "sizeof fmt_str+(-4+2)+(-4+2)+(-2+4)+(-2+2)+(-2+2)". Вывод имени игрока. Как известно, максимальная длина имени игрока - MAX_PLAYER_NAME (константное выражение, равное 24). Хотя на самом деле максимальная длина ника составляет 22 символа, но все-таки принято использовать константы (ведь неизвестно, какие изменения произойдут с рабочими папками в последующих обновлениях SAMP/CRMP). Вычитаем длину спецификатора, обозначающего запись строки (%s), и записываем максимальную длину имени игрока (константу): (-2+MAX_PLAYER_NAME). Новый вид всей нашей строки: "sizeof fmt_str+(-4+2)+(-4+2)+(-2+4)+(-2+2)+(-2+2)+(-2+MAX_PLAYER_NAME)". Вывод количества здоровья игрока. Здесь мы сталкиваемся с вещественным числом. Известно, что здоровье игрока не может превышать 100. Следовательно, не может быть длиннее трех символов. А вот количество символов после запятой не ограничено системно (разве что максимальной вместимостью ячеек). Потому я их ограничил вручную, обрезав всего лишь до двух символов. Получаем нашего спецификатора "%.2f": 4. Вычитаем из длины форматируемой строки 4 символа, а заместо них добавляем максимальную длину здоровья игрока (3 символа до запятой и 2 символа после запятой): "-4+5". Теперь вся наша строка должна получить такой вид: "sizeof fmt_str+(-4+2)+(-4+2)+(-2+4)+(-2+2)+(-2+2)+(-2+MAX_PLAYER_NAME)+(-4+5)".  
      В свой пример я постарался уместить побольше различных типов данных и способов форматирования, чтобы разобрать более наглядно. Впрочем, может быть метод до сих пор и кажется страшным. Однако, в нем нет ничего сложного.
       
      Автор статьи: @odosenok.
       
      P.s. многовато получилось текста. Но я старался пояснить все, что только можно. Да и знания лишними не бывают. Не поленитесь и читайте статью полностью .
       
      Еще один примерчик, для самостоятельного разбора. Ничего в нем особенного нет. Впрочем, можете оставлять в теме свои строки, разберемся, с чем есть строки ваши.
       
       
    • Guest
      By Guest
      Константы


      Константа - величина, не меняющаяся в процессе выполнения скрипта. В Pawn константы объявляются почти так же, как и переменные, однако каждое объявление начинается со слова const:
      const <тип>:<имя> = <значение>;  

      Для примера объявим число Пи:
      const Float:M_PI = 3.141593;  

      Теперь объявим целочисленную константу (как и в new, для целых чисел указание типа не потребуется):
      const MAX_BYTE = 255;  

      Внимание! В отличие от переменных (new), в константах нужно обязательно указывать значение.

      Правила задания имён у констант те же, что и у переменных, за исключением одного необязательного:
      Имя константы должно записываться в верхнем регистре (все буквы большие), чтобы было легче отличить его от имён переменных и функций. Примеры имён констант: MAX_PLAYERS, MAX_VEHICLES, MAX_PLAYER_NAME.
    • Jawn
      By Jawn
      1. Введение. Суть перехватов.
      В данном уроке я постараюсь рассказать про то, что такое перехваты. Мы разберем некоторые примеры перехватов функций, покажем пример, где эти перехваты могут пригодиться.
       
      Что такое перехваты? Зачастую возникает ситуация, когда нам необходимо как-то изменить действия, происходящие в функции. Но редактирование уже имеющейся функции (как правило, это стандартные функции) не есть лучший вариант. Почему? Если мы хотим внести какие-то дополнительные действия в нужную нам функцию, придется открывать файл, в котором содержится данная функция, ее редактировать. А если выйдет новая версия файла a_samp? Все наши действия придется повторить сначала, теперь уже в новом файле.
       
      Для того собственно и придуман перехват. Так, мы перехватываем заранее объявленную функцию, вследствие чего меняется порядок вызова функций:
      перехваченная_функция_1 -> перехваченная_функция_2 -> перехваченная функция_3 -> основная_функция_которую_перехватывали Обратите внимание: в цепочке перехватов присутствуют несколько перехваченных функций. Отсюда можно сделать вывод, что число перехватов не ограничено никем и ничем. Более того, перехваты функций - это лишь смена названий каждой последующей функции препроцессором (перед началом компиляции), каждая из которых вызывается впоследствии системой.
       
      Для перехвата функций нам потребуются некоторые директивы (#define, #if defined, #endif), а также сами функции, которые мы внедряем в перехваты.
       
      2. Построение перехватов.
      Давайте попробуем немного проанализировать перехват функций, не имея пока что представления о том, как их правильно перехватывать.
       
      У нас есть функция A. Мы хотим, чтобы в ней происходил вывод текста "Hello world" в логи сервера. Как говорили ранее, внедрять этот текст в код функции A мы не будем (потому, что если выйдет обновление версии файла, в котором содержится эта функция, мы утратим свои корректировки в данной функции). Значит, нам нужно сделать так, чтобы это изменение могли внести без изменения кода файла.
       
      Рассмотрим следующий вариант:
      #define InterceptFunctionA()\ printf("Hello world");A(); В данном варианте мы создали макрос. Так, при использовании "InterceptFunctionA()" сначала в логи сервера будет вноситься наш текст, а затем вызываться сама функция. Но в данном методе есть два нюанса: во-первых, у нас теперь новое название функции (а мы не хотим поправлять его во всем моде), во-вторых, данный метод нам не подойдет, если вместе с данной функцией мы хотим выполнить еще с десяток других действий.
       
      Так я постарался дать понять Вам, что на самом деле перехваты не создают визуальных неудобств: функция будет называться так, как называлась, свой код в макросы вы не вписываете.
       
      В общем и целом метод перехватов, которому мы сейчас обучаемся, выглядит следующим образом:
      <перехватчик 1> <выполняем действия перехватчика 1> <вызываем следующий перехватчик> <конец перехватчика> <перехватчик 2> <выполняем действия перехватчика 2> <вызываем следующий перехватчик> <конец перехватчика> <перехватчик 3> <выполняем действия перехватчика 3> <вызываем перехватываемую функцию> <конец перехватчика> Каждый перехватчик есть ни что иное как отдельная функция. И, соответственно, в ходе перехватов мы поочередно вызываем функции, в которых прописаны Ваши действия перехватчика.
       
      Перехваты нативных функций и функций, вызывающихся автоматически, несколько отличаются. Поэтому урок мы немного разделим.
       
       
      Как правило, перехваты применяются тогда, когда одну и ту же функцию необходимо использовать по-разному в разных файлах. С помощью перехватов мы можем в каждом файле перехватывать отдельные функции и вносить корректировки в их работу.
       
      3. Перехваты функций: за и против.
      В каждой ситуации есть сторонники какой-либо идеи и ее противники. Сейчас я постараюсь рассказать основные аспекты использования перехвата функций. А использовать их или нет - решать Вам.
       
      1. Вы можете манипулировать одной и той же функцией по-разному в разных файлах. Это значит, что Вам не придется каждый раз добавлять различные проверки на то, подключен ли какой-либо файл, чтобы внести код "под него". Так, Вам достаточно лишь подключить нужный файл, чтобы вся цепочка вызовов работала как следует. Соответственно, при отключении файла проблем также не возникнет.
      2. Перехват функций есть ни что иное как последовательные вызовы функций. Несомненно, на вызов функций уходит какая-то часть времени, но это время ничтожно для того, чтобы Ваш сервер действительно стал подтормаживать.
      3. Если перехватываемую функцию использовать до того, как она перехвачена, функционировать она не будет (как Вы хотите). При этом про проблему в перехвате подумаете далеко не сразу. И главное - компилятор Вам не даст понять, что у Вас это не сработает, ведь со стороны его логики все сделано правильно. Поэтому перехватам вводят альтернативу: создают новую функцию с постфиксом "Ex", в которую уже помещают код перехвата и вызов самой функции:
      stock ПерехватываемаяФункцияEx(аргументы функции) { // ваш код return ПерехватываемаяФункция(аргументы функции); } Нюанс данной реализации в том, что теперь Вам придется использовать только ПерехватываемаяФункцияEx, о чем Вы можете забыть и вызвать не данную функцию, а ее оригинал.
       
      4. Авторское право.
      Автор данной статьи: @odosenok
      Отдельное спасибо за разъяснения: Daniel_Cortez
    • DEST
      By DEST
      Эта тема создана автоматически для возможности комментирования статьи Операции с текстом и данными в PAWN Автор статьи: @DEST
      Статья опубликована: 05.01.2018 17:52
       
       
       
      Просмотреть полную запись