[go: up one dir, main page]

Aller au contenu

Pawn (langage)

Un article de Wikipédia, l'encyclopédie libre.

Pawn[1]
Logo.

Date de première version 1998
Paradigme Procédural, impératif, structuré
Développeur ITB Compuphase
Dernière version 4.0.5749 ()
Typage Fort, statique
Influencé par Small-C, C
Système d'exploitation Windows, GNU/Linux, Mac OS X
Licence Libre
Site web (en) « Site de Compuphase »
Extensions de fichiers .pwn, .p, .inc

Le PAWN[2] (successeur du Small-C) est un langage de programmation open source utilisé sur différentes plates-formes.

Sa syntaxe est assez proche de celle du langage C bien que le typage soit différent. À défaut de ne pas fournir de pointeurs, les programmes implémentés dans la machine abstraite du PAWN assurent une vérification des indices de tableau ainsi qu'une protection quant au dépassement de la mémoire programme donnée[3].

Utilisations

[modifier | modifier le code]

Le pawn étant un langage adapté pour des machines à ressource limitée, il a été utilisé dans quelques technologies embarquées comme le satellite ESTCube-1[1] ou plus communément pour des serveurs de jeux notamment SA-MP (San Andreas - MultiPlayer)[4].

On citera par ailleurs Eternal Lands qui a été développé en Small-C.

Éléments du PAWN

[modifier | modifier le code]

Comme tout langage de programmation, le PAWN a ses propres spécificités.

main()
{
   print("Hello world !");
}
/* Ici main désigne le point d'entrée du programme, il est impératif de le mettre.
   Ainsi, dès l'exécution, le programme affichera "Hello World".
*/

Les variables

[modifier | modifier le code]

Les types de variables sont plus restreints qu'en C et leur déclaration est différente.

Effectivement, on va introduire le mot-clé « new » suivi du type (s'il y a) ainsi que le nom de la variable.

Par défaut, les variables sont déclarées comme des entiers, il n'est donc pas nécessaire de préciser un type dans ce cas-là.

Il est préférable d'initialiser chaque variable que l'on déclare afin qu'elle ne contienne pas une valeur erronée même si une valeur par défaut leur est attribuée.

Type Déclaration Spécificateur
Entier
new a = 3;
%d, %i
Flottant
new Float:pi = 3.14;
%f (%.2f → 2 décimales)
Booléen
new bool:lightOn = false;
%b
Caractère
new lettreB = 'B';
%c (%d → code ASCII)
Chaîne de caractères
new monEncyclopedie[] = "Wikipédia";
%s
main()
{
   new Float:pi = 3.14;
   printf("Une valeur approchée de pi est %f", pi);
}

Les structures conditionnelles

[modifier | modifier le code]

On distinguera deux principales structures conditionnelles : « if » ainsi que le « switch ».

Structure « if »

[modifier | modifier le code]

Cette structure se compose du mot-clé « if » précédant une expression booléenne.

Une première forme de cette structure se définit en une simple vérification comme ci-dessous :

main()
{
   new a = -4;
   if(a < 0)
   {
      printf("Le nombre est négatif ! (%d)", a);
   }
}

Néanmoins, nous pouvons tout aussi gérer la négation de la condition entrée avec le mot-clé « else ».

main()
{
   new a = -4;
   if(a < 0)
   {
      printf("Le nombre est négatif ! (%d)", a);
   }
   else
   {
      printf("Le nombre est positif ! (%d)", a);
   }
}

Un dernier mot-clé qui permet de vérifier une expression si jamais la précédente renvoyait la valeur « faux » : « else if ».

main()
{
   new a = -4;
   if(a < 0)
   {
      printf("Le nombre est négatif ! (%d)", a);
   }
   else if(a == 0)
   {
      printf("Le nombre est nul !");
   }
   else
   {
      printf("Le nombre est strictement positif ! (%d)", a);
   }
}

Remarque : en utilisant le « else » à la fin, je vérifie si aucune des conditions le précédant n'ont été remplies.

La structure globale débute, quoi qu'il en soit, par un « if ».

Structure « switch »

[modifier | modifier le code]

La structure « switch » (ou « cas..parmi » en terme algorithmique) est utilisée dans le cas où vous auriez à vérifier successivement les valeurs d'une variable. Vous pourrez utiliser une structure « if » avec un nombre considérable de « else if ».

Cependant, la structure « switch » s'adapte bien à ce genre de cas.

main()
{
   new a = 3;
   switch(a)
   {
       case 1:
       {
          printf("La variable 'a' stocke la valeur 1");
       }
       case 0, -1:
       {
          printf("La variable 'a' stocke la valeur 0 ou -1");
       }
       case 2..5:
       {
          printf("La variable 'a' stocke une valeur comprise entre 2 et 5");
       }
       default:
       {
          printf("La variable 'a' stocke une valeur différente de celles vérifiées précédemment");
       }
   }
}

Les structures itératives

[modifier | modifier le code]

Une structure itérative (ou boucle) va répéter un certain nombre de fois une ou plusieurs instructions (on parle d'itérations).

On distingue également deux principales structures itératives, chacune caractérisée par un nombre d'itérations déterminé.

Boucle « pour »

[modifier | modifier le code]

La boucle « pour » va conventionnellement exécuter un nombre de fois déterminé les instructions imbriquées dans celle-ci.

On parle alors de boucle déterministe[5].

Dans une telle boucle, on utilisera souvent un incrément. Elle est particulièrement utile quand il faut répéter une instruction plusieurs fois comme un message à afficher ou des calculs successifs.

main()
{
   new somme = 0;
   for(new i = 0; i < 10; i++)
   {
       somme += i; // Équivalent à somme = somme + i;
   }
   printf("La somme des 10 premiers entiers est égale à %d.", somme);
/*
Ici on calcule la somme des 10 premiers entiers.
*/
}

Boucle «while»

[modifier | modifier le code]

La boucle «while» est, quant à elle, une boucle indéterministe.

Elle est généralement guidée par une condition qui ne vérifie pas un nombre d'itérations effectuées.

Une telle boucle ne nécessite pas forcément d'un incrément comme celle présentée ci-dessus.

main()
{
    new nb = 17;
    while(nb > 0)
    {
        nb /= 2;   // Équivalent à nb = nb / 2;
    }
/*
Dans cet exemple, on divise le nombre de départ successivement par 2 jusqu'à ce qu'il atteigne 0.
*/
}

Boucle «do..while»

[modifier | modifier le code]

La boucle «do..while» est, elle aussi, indéterministe.

Contrairement à la boucle «while», elle va exécuter les instructions qu'elles comportent avant de vérifier la condition.

Cela garantit au moins un passage dans la boucle. Elle est particulièrement sollicitée lors de contrôles de saisie utilisateur.

/* Programme calculant la somme des N premiers entiers non nuls (où N est saisi par l'utilisateur) */
main()
{
    new n_entiers = 0, sum = 0;
    /* Contrôle de la saisie utilisateur */
    do
    {
        printf("Saisissez jusqu'à quel entier la somme s'effectuera (nombre > 1): ");
        n_entiers = getvalue(); // La fonction getvalue() récupère la valeur entière saisie par l'utilisateur dans la console

    }
    while(n_entiers <= 1);

    /* Calcul de la somme des entiers consécutifs jusqu'à n_entiers */
    for(new i = 0; i <= n_entiers; i++)
        sum += i;

    /* Affichage des résultats */
    printf("La somme des entiers allant de 1 à %d est égale à %d", n_entiers, sum);
}

Les fonctions / procédures

[modifier | modifier le code]

En algorithmique, on distingue souvent la fonction d'une procédure par l'existence ou non d'une valeur de retour. En C, la distinction s'effectue par le mot-clé mis devant la définition de la fonction (void ou un type de données). Le PAWN applique cependant une confusion entre les deux termes puisqu'il ne permet pas d'établir explicitement la différence entre ces deux notions.

Déclaration d'une fonction

[modifier | modifier le code]

Ainsi, la déclaration d'une fonction en PAWN se fait de la manière suivante :

main()
{
    /* Saisies de l'utilisateur */
    new a = getvalue();
    new b = getvalue();
    /* Affichage du résultat */
    printf("La multiplication de a par b retourne : %d", multiplie(a, b)); // Appel de la fonction créée
}
multiplie(a, b) // Multiplie un entier a par b
{
    return a * b; // On invoque ici le mot-clé return afin d'attribuer une valeur de retour à la fonction.
}

De même, si l'on souhaite renvoyer une donnée d'un type différent de l'entier il suffira de préciser le type devant la déclaration :

bool:AreEquals(a, b) // La fonction renvoie ici vrai ou faux
{
    return a == b; // Renvoie la valeur du test d'égalité
}

Il sera cependant nécessaire de préciser que la fonction renvoie un type différent de celui par défaut : l'entier. De ce fait, il faudra créer le prototype (ou encore entête) de votre fonction avant de l'appeler. On aura ainsi :

forward bool:AreEquals(a, b); // Création d'une entête en invoquant le mot-clé forward

main()
{
   new a = 5, b = 3;
   printf("A et B égaux ? %b\n", AreEquals(a, b));
}
bool:AreEquals(a, b)
{
   return a == b;
}

Passage de paramètres

[modifier | modifier le code]

Une fonction peut présenter (ou non) des arguments dans la déclaration de sa fonction. Le langage Pawn propose deux types pour transmettre des paramètres à la fonction.

Le premier étant le passage de paramètres par valeur qui a la particularité de créer une copie de la variable passée en paramètre lors de l'appel de la fonction. Une telle copie ne peut donc affecter la valeur de la variable de départ.

main()
{
    new a = 2;
    square(a);
    printf("a vaut maintenant : %d", a); // a vaudra 2, avec un tel passage de paramètre
}
square(value)
{
   value *= value; // On ne retourne pas de résultat ici, on essaie d'agir directement sur la variable.
}

Ce passage de paramètres est favorisé pour des traitements sur la valeur d'une variable ou sa lecture. Néanmoins, si l'on veut modifier la valeur de la variable passée en paramètre il faudra favoriser le second passage de paramètres : par référence. Un tel passage implique la transmission à la fonction non pas de la valeur de la variable mais de son adresse mémoire permettant donc d'agir sur la variable en mémoire sans passer par une duplication de celle-ci[6].

main()
{
   new a = 2;
   square(a);
   printf("a vaut maintenant : %d", a); // a vaudra 4 en ayant changé le type de passage de paramètre
}
square(&value) // Il suffira d'ajouter un & qui récupèrera l'adresse mémoire de la variable et non pas la donnée qu'elle stocke.
{
   value *= value;
}

Ce type de passage est largement favorisé quand on est contraint de retourner plus d'une valeur (exemple : fonction qui convertit le nombre de secondes en hh-mm-ss)[6].

Notes et références

[modifier | modifier le code]
  1. a et b (en) « The Pawn language »
  2. (en) « Tutoriel PAWN »,
  3. (en) « The Pawn features »
  4. (en) « Wiki PAWN (SA-MP) »,
  5. (en) « Structures itératives »
  6. a et b « Passage de paramètres - Applications en C/C++ »