Ru:Introduction to SourcePawn

From AlliedModders Wiki
Revision as of 02:36, 23 December 2008 by Frenzzy (talk | contribs)
Jump to: navigation, search

Это руководство призвано дать Вам самые основные представления по основам написания сприптов в SourcePawn. Pawn это "скриптовый" язык используемый для внедрения функциональности в других программах. Это означает, что это не самостоятельный язык, как C++ или Java, и его элементы будут отличаться в различных приложениях. SourcePawn это вариация языка Pawn используемая в SourceMod.

Это руководство не расскажет Вам как писать SourceMod плагины; оно предназначено для получения общих представлений о синтаксисе и семантике этого языка. Читайте отдельную статью, Introduction to SourceMod Plugins для введения в SourceMod API.

Введение для новичков

Этот раздел создан не для программистов. Если Вы по прежнему в замешательстве, Вы можете прочитать книги о других языках программирования, таких как PHP, Python, или Java, чтобы получить более полное представление о программировании.

Идентификаторы/Ключевые слова

Идентификаторы представляет собой набор букв, цифр и/или нижнего подчеркивания, что представляет собой нечто уникальное. Идентификаторы вводятся с учетом регистра (в отличие от PHP, где иногда это не требуется). Идентификаторы не начинаются с какого-либо специального символа, но они должны начинаться с буквы.

Есть несколько зарезервированных символов, которые имеют особое значение. Например, if, for, и return специальные конструкции в языке, которые будут описаны позднее. Они не могут быть использованы в качестве названий идентификаторов.

Переменные

Существует несколько важных конструкций, которые Вы должны знать, прежде чем приступить к написанию сценария. Во-первых, это переменные. Переменная это идентификатор, который содержит данные. Например, переменная "a" может содержать числа "2", "16", "0", и так далее. Переменные создаются для хранения данных внутри программы. Переменные должны быть объявлены до их использования, с помощью ключевого слова "new". Данные можно присвоить переменной, используя знак равенства (=). Пример:

new a, b, c, d;
 
a = 5;
b = 16;
c = 0;
d = 500;

В SourcePawn, переменные бывают двух типов, которые будут более подробно описаны далее.

  • Числовые (могут содержать только произвольные числовые данные), как показано выше.
  • Строковые (могут содержать целый ряд текстовых символов)

Functions

The next important concept is functions. Functions are symbols or names that perform an action. That means when you activate them, they carry out a specific sequence of code. There are a few types of functions, but every function is activated the same way. "Calling a function" is the term for invoking a function's action. Function calls are constructed like this:

function(<parameters>)

Examples:

show(56);   //Activates "show" function, and gives the number 56 to it
show();     //Activates "show" function with no data, blank
show(a);    //Activates "show" function, gives a variable's contents as data

Every piece of data passed to a function is called a parameter. A function can have any number of parameters (there is a "reasonable" limit of 32 in SourceMod). Parameters will be explained further in the article.

Comments

Note any text that appears after a "//" is considered a "comment" and is not actual code. There are two comment styles:

  • // - Double slash, everything following on that line is ignored.
  • /* */ - Multi-line comment, everything in between the asterisks is ignored. You cannot nest these.


Block Coding

The next concept is block coding. You can group code into "blocks" separated by { and }. This effectively makes one large block of code act as one statement. For example:

{
   here;
   is;
   some;
   code;
}

Block coding using braces is used everywhere in programming. Blocks of code can be nested within each other. It is a good idea to adapt a consistent and readable indentation style early on to prevent spaghetti-looking code.


Language Paradigms

Pawn may seem similar to other languages, like C, but it has fundamental differences. It is not important that you immediately understand these differences, but they may be helpful if you're familiar with another language already.

  • Pawn is not typed. Pawn only has one data type, the cell. This will be explained in detail later. [Below it says that there are two types: cell and string.]
  • Pawn is not garbage collected. Pawn, as a language, has no built-in memory allocation, and thus has no garbage. If a function allocates memory, you may be responsible for freeing it.
  • Pawn is not object oriented. Pawn is procedural, and relies on subroutines. It also does not have C structs.
  • Pawn is not functional. Pawn is procedural, and does not support lambda functions or late binding or anything else you might find in a very high-level language, like Python or Ruby.
  • Pawn is single-threaded. As of this writing, Pawn is not thread safe.
  • Pawn is not interpreted. Well, it "sort of" is. It gets interpreted at a very low level. You must run your code through a compiler, which produces a binary. This binary will work on any platform that the host application uses. This speeds up loading time and lets you check errors easier.

These language design decisions were made by ITB CompuPhase. It is designed for low-level embedded devices and is thus very small and very fast.

Variables

In Pawn there are two variable types: the cell and the String. A cell can store 32 bits of numerical data. A String is a sequential/flat list of UTF-8 text characters.

A cell has no inherent type, however, cells can be tagged. A tag lets you enforce where certain cells can be used. The default tags are:

  • (nothing), or _ - No tag. Usually used for whole numbers (Integers).
  • Float - Used for floating point (fractional) numbers.
  • bool - Used for storing either true or false.

Strings are different and will be explained in the next sections.

Declaration

Examples of different valid variable declarations:

new a = 5;
new Float:b = 5.0;
new bool:c = true;
new bool:d = 0;      //Works because 0 is false

Invalid variable usage:

new a = 5.0;         //Tag mismatch.  5.0 is tagged as Float
new Float:b = 5;     //Tag mismatch.  5 is not tagged.

If a variable is not assigned upon declaration, it will be set to 0. For example:

new a;        //Set to 0
new Float:b;  //Set to 0.0
new bool:c;   //Set to false

Assignment

Variables can be re-assigned data after they are created. For example:

new a, Float:b, bool:c;
 
a = 5;
b = 5.0;
c = true;


Arrays

An array is a sequence of data in a sequential list. Arrays are useful for storing multiple pieces of data in one variable, and often greatly simplify many tasks.

Declaration

An array is declared using brackets. Some examples of arrays:

new players[32];     //Stores 32 cells (numbers)
new Float:origin[3]; //Stores 3 floating point numbers

By default, arrays are initialized to 0. You can assign them different default values, however:

new numbers[5] = {1, 2, 3, 4, 5};       //Stores 1, 2, 3, 4, 5 in the cells.
new Float:origin[3] = {1.0, 2.0, 3.0};  //Stores 1.0, 2.0, 3.0 in the cells.

You can leave out the array size if you're going to pre-assign data to it. For example:

new numbers[] = {1, 3, 5, 7, 9};

The compiler will automatically deduce that you intended an array of size 5.

Usage

Using an array is just like using a normal variable. The only difference is the array must be indexed. Indexing an array means choosing the element which you wish to use.

For example, here is an example of the above code using indexes:

new numbers[5], Float:origin[3];
 
numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;
numbers[4] = 5;
origin[0] = 1.0;
origin[1] = 2.0;
origin[2] = 3.0;

Note that the index is what's in between the brackets. The index always starts from 0. That is, if an array has N elements, its valid indexes are from 0 to N-1. Accessing the data at these indexes works like a normal variable.

To use an incorrect index will cause an error. For example:

new numbers[5];
 
numbers[5] = 20;

This may look correct, but 5 is not a valid index. The highest valid index is 4.

You can use any expression as an index. For example:

new a, numbers[5];
 
a = 1;                   //Set a = 1
numbers[a] = 4;          //Set numbers[1] = 4
numbers[numbers[a]] = 2; //Set numbers[4] = 2

Expressions will be discussed in depth later in the article.

Strings

Strings are a convenient method of storing text. The characters are stored in an array. The string is terminated by a null terminator, or a 0. Without a null terminator, Pawn would not know where to stop reading the string. All strings are UTF-8 in SourcePawn.

Notice that Strings are a combination of arrays and cells. Unlike other languages, this means you must know how much space a string will use in advance. That is, strings are not dynamic. They can only grow to the space you allocate for them.

Note for experts: They're not actually cells. SourcePawn uses 8-bit storage for String arrays as an optimization. This is what makes String a type and not a tag.

Usage

Strings are declared almost equivalently to arrays. For example:

new String:message[] = "Hello!";
new String:clams[6] = "Clams";

These are equivalent to doing:

new String:message[7], String:clams[6];
 
message[0] = 'H';
message[1] = 'e';
message[2] = 'l';
message[3] = 'l';
message[4] = 'o';
message[5] = '!';
message[6] = 0;
clams[0] = 'C';
clams[1] = 'l';
clams[2] = 'a';
clams[3] = 'm';
clams[4] = 's';
clams[5] = 0;

Although strings are rarely initialized in this manner, it is very important to remember the concept of the null terminator, which signals the end of a string. The compiler, and most SourceMod functions will automatically null-terminate for you, so it is mainly important when manipulating strings directly.

Note that a string is enclosed in double-quotes, but a character is enclosed in single quotes.

Characters

A character of text can be used in either a String or a cell. For example:

new String:text[] = "Crab";
new clam;
 
clam = 'D';         //Set clam to 'D'
text[0] = 'A';      //Change the 'C' to 'A', it is now 'Arab'
clam = text[0];     //Set clam to 'A'
text[1] = clam;     //Change the 'r' to 'A', is is now 'AAab'

What you can't do is mix character arrays with strings. The internal storage is different. For example:

new clams[] = "Clams";                       //Invalid, needs String: type
new clams[] = {'C', 'l', 'a', 'm', 's', 0};  //Valid, but NOT A STRING.


Functions

Functions, as stated before, are isolated blocks of code that perform an action. They can be invoked, or called, with parameters that give specific options.

There are two types of ways functions are called:

  • direct call - You specifically call a function in your code.
  • callback - The application calls a function in your code, as if it were an event trigger.

There are five types of functions:

  • native: A direct, internal function provided by the application.
  • public: A callback function that is visible to the application and other scripts.
  • normal: A normal function that only you can call.
  • stock: A normal function provided by an include file. If unused, it won't be compiled.
  • forward: This function is a global event provided by the application. If you implement it, it will be a callback.

All code in Pawn must exist in functions. This is in contrast to languages like PHP, Perl, and Python which let you write global code. That is because Pawn is a callback-based language: it responds to actions from a parent application, and functions must be written to handle those actions. Although our examples often contain free-floating code, this is purely for demonstration purposes. Free-floating code in our examples implies the code is part of some function.

Declaration

Unlike variables, functions do not need to be declared before you use them. Functions have two pieces, the prototype and the body. The prototype contains the name of your function and the parameters it will accept. The body is the contents of its code.

Example of a function:

AddTwoNumbers(first, second)
{
  new sum = first + second;
 
  return sum;
}

This is a simple function. The prototype is this line:

AddTwoNumbers(first, second)

Broken down, it means:

  • AddTwoNumbers - Name of the function.
  • first - Name of the first parameter, which is a simple cell.
  • second - Name of the second parameter, which is a simple cell.

The body is a simple block of code. It creates a new variable, called sum, and assigns it the value of the two parameters added together (more on expressions later). The important thing to notice is the return statement, which tells the function to end and return a value to the caller of the function. All functions return a cell upon completion. That means, for example:

new sum = AddTwoNumbers(4, 5);

The above code will assign the number 9 to sum. The function adds the two inputs, and the sum is given as the return value. If a function has no return statement or does not place a value in the return statement, it returns 0 by default.

A function can accept any type of input. It can return any cell, but not arrays or strings. Example:

Float:AddTwoFloats(Float:a, Float:b)
{
   new Float:sum = a + b;
 
   return sum;
}

Note that if in the above function, you returned a non-Float, you would get a tag mismatch.

You can, of course, pass variables to functions:

new numbers[3] = {1, 2, 0};
 
numbers[2] = AddTwoNumbers(numbers[0], numbers[1]);

Note that cells are passed by value. That is, their value cannot be changed by the function. For example:

new a = 5;
 
ChangeValue(a);
 
ChangeValue(b)
{
   b = 5;
}

This code would not change the value of a. That is because a copy of the value in a is passed instead of a itself.

More examples of functions will be provided throughout the article.


..в стадии перевода