Référence du fichier main.c

fichier main contient le code des fonctions Plus de détails...

Aller au code source de ce fichier.

Fonctions

int sc_increment (mmachine m)
 auto increment
int sc_hello (mmachine m)
 fonction example_hello
int sc_division (mmachine m)
 fonction example_calcul
int sc_calcul_list (mmachine m)
 fonction example_list
int SCOLinitEXAMPLEclass (mmachine m)
 Fonction défininssant l'API Scol de la bibliothèque.
 __declspec (dllexport)
int SCOLloadEXAMPLE (mmachine m)
int SCOLfreeEXAMPLE ()
 Fonction de déchargement / libération.

Variables

cbmachine ww
mmachine mm
char * example_name [EXAMPLE_PKG_NB]
 Définition de l'API.
int(* example_fun [EXAMPLE_PKG_NB])(mmachine m)
 Définition des fonctions internes.
int example_narg [EXAMPLE_PKG_NB]
 Nombre d'arguments ou type d'objets.
char * example_type [EXAMPLE_PKG_NB]
 Prototypage Scol.

Description détaillée

fichier main contient le code des fonctions

Auteur:
iri <iri-@-irizone.net>
Date:
novembre 2010

Définition dans le fichier main.c.


Documentation des fonctions

__declspec ( dllexport   ) 

Définition à la ligne 508 du fichier main.c.

00509 {
00510     int k = 0;
00511     /* Affectation aux variables globales ww et mm des valeurs envoyées par le noyau des structures partagées.
00512     Il est impératif de les ajouter AVANT tout appel à des fonctions ou macros Scol sous peine de crash immédiat
00513     lors de l'exécution de Scol. */
00514     ww = w;
00515     mm = m;
00516 
00517     MMechostr (0, "EXAMPLE library : loading\n");
00518 
00519     if ((k = SCOLinitEXAMPLEclass (m))) return k;
00520 
00521     MMechostr (0, "\nEXAMPLE library loaded !\n");
00522     return k;
00523 }

int sc_calcul_list ( mmachine  m  ) 

fonction example_list

Paramètres:
mmachine m
Renvoie:
0

Code interne de la fonction Scol 'example_list'

Celle-ci attend trois arguments : une liste d'entiers, un entier et un drapeau. Selon la valeur du drapeau, chaque élément de la liste sera incrémenté ou décrémenté de la valeur du second argument. En retour, la fonction Scol donne la nouvelle liste d'entiers. Son prototype est donc :

 example_list : fun [[I r1] I I] [I r1]

Nous allons donc devoir extraire les éléments de la liste et en construire une nouvelle en sortie.

L'extraction d'une liste suit la même logique que pour un tuple sauf qu'on utilise une boucle 'while' puisqu'on ne connaît pas a priori le nombre d'éléments.

WHILE (liste non vide)
        e = premier élément de liste
        SI e non vide
            instructions
        liste = suite de la liste

Si 'e' est lui-même une liste ou un tuple, on traite de la même façon. Par exemple, si le type de l'argument est [[u0 u1 u2] r1], on aura :

while (mlist != NIL)
   {
       element = MMfetch (m, mlist, 0)>>1;
       if (element != NIL)
       {
            mvalue0 = MMfetch (m, element, 0)>>1;
            mvalue1 = MMfetch (m, element, 1)>>1;
            mvalue2 = MMfetch (m, element, 2)>>1;
            ...
        }
        mlist = MMfetch(m, mlist, 1)>>1;
   }

Pour créer une liste en sortie, le processus est similaire à celui vu à la fonction précédente.

On boucle pour possuer nos éléments un à un Une fois la liste terminée, on pousse un 'NIL' (toute liste se termine par 'nil' en Scol) Et on crée le tuple final (le premier élément de la liste et le reste de la liste)

Exemple de pseudo-code pour un type en retour : [[u0 u1 u2] r1]

 compteur = 0
  WHILE (liste_traitée)
      {
          values = liste_traitée->data
          x = values->x
          y = values->y
          z = values->z
          MMpush (m, PTOM (x))
          MMpush (m, PTOM (y))
          MMpush (m, PTOM (z))
          MMpush (m, ITOM (3))
          MBdeftab (m)
          compteur++
          liste_traitée = liste_traitée->next
      }
  MMpush (m, NIL)
  FOR (i=0; i< compteur; i++)
      {
          MMpush (m, ITOM (2))
          MBdeftab (m)
      }

Dans la boucle WHILE, on crée chaque tuple de trois éléments ([u0 u1 u2]) de valeur x, y, z Une fois cette boucle finie, on ajoute un NIL à la pile et on commence la boucle FOR d'un nombre de tours équivalent àcelui de la boucle WHILE. Là, on crée des tuples de deux éléments correspondant parfaitement (logique !) à la structure d'une liste.

Notez que la boucle WHILE peut être remplacéepar n'importe quel code C (telle une boucle FOR) selon vos besoins. Ce qui importe est que l'empilement des éléments et des tuples soit correct.

Pour rappel, une liste est définie de la sorte :

 liste = [first next]

où next a lui aussi la même structure, jusqu'au nil final :

 liste = [1 [2 [3 [4 [5 nil]]]]]

liste des 5 premiers entiers (qui peut également être écrite

 liste = 1 :: 2 :: 3 ::4 :: 5 :: nil

notation plus lisible mais moins parlante sur sa structure sous-jacente (et c'est elle qui est importante ici !

Dans cette fonction 'sc_calcul_list', on pratique l'extraction des entiers d'entrées et l'incorporation des entiers de sortie dans la même boucle WHILE pour éviter d'avoir à sauvegarder les entiers entre les deux, ce qui alourdirait le code C inutilement.

Définition à la ligne 306 du fichier main.c.

00307 {
00308     int mlist_enter, mnumber, mflag;
00309     int element_list, i, compteur = 0;
00310 
00311     MMechostr (MSKDEBUG, "sc_calcul_list : entering\n");
00312 
00313     mflag = MTOI (MMpull (m));
00314     mnumber = MTOI (MMpull (m));
00315     mlist_enter = MMpull (m)>>1;
00316 
00317     while (mlist_enter != NIL)
00318     {
00319          element_list = MTOI (MMfetch (m, mlist_enter, 0));
00320          if (element_list != NIL)
00321          {
00322              MMpush (m, ITOM (element_list + (mnumber * mflag)));
00323              compteur++;
00324          }
00325          mlist_enter = MTOI (MMfetch(m, mlist_enter, 1));
00326     }
00327 
00328     MMpush (m, NIL);
00329 
00330     for (i = 0; i < compteur; i++)
00331     {
00332         MMpush (m, ITOM (2));
00333         MBdeftab (m);
00334     }
00335     return 0;
00336 }

int sc_division ( mmachine  m  ) 

fonction example_calcul

Paramètres:
mmachine m
Renvoie:
0

Code interne de la fonction Scol 'example_calcul' Elle attend deux entiers en entrée sous la forme d'un tuple c'est-à-dire d'un seul argument contenant deux valeurs Elle retourne un autre tuple de deux entiers qui sont respectivement le quotient e tle reste de deux nombres passés en entrée.

Pour récupérer les valeurs contenues dans un tuple, on commence par dépiler ledit tuple, grâce à MMpull (1) puis on extraie les deux valeurs grâce à MMfetch. Elle ressemble quelque peu à MMget. MMfetch prend, en plus de la machine Scol courante, le tuple récupéré et l'index de l'élément désiré. Rien de plus simple :)

En sortie, la construction d'un tuple se construit diféremment puisqu'il faut construire la pile dans l'ordre voulu des éléments en les poussant (MMpush) (3) Puis on pousse le nombre d'éléments de notre tuple toujours avec MMpush (4), ici 2 puisque notre tuple contient le quotient et le reste. Enfin, le tuple est contruit grâce à ces informations (MBdeftab) (5) : le dernier élément de la pile est lu, il contient le nombre d'éléments à placer dans le tuple. Scol va alors chercher les N éléments sur les N étages de la pile.

On a ainsi une fonction Scol litérale : (quotient, reste) example_calcul (dividende, diviseur) soit,

 example_calcul : fun [[I I]] [I I] 

Remarque : il aurait été tout à fait possible d'avoir un prototype Scol : example_calcul : fun [I I] [I I] Il n'y aurait alors pas eu de tuple à récupérer et nous aurions alors eut :

 mdividende = MTOI (MMpull (m);
 mdiviseur = MTOI (MMpull (m));
 ...

En revanche, impossible de faire autrement que de passer par un tuple pour retourner deux ou plus valeurs à une fonction. Si ce nombre est inconnu (variable suivant les cas), on passera par une liste, c'est ce qu'illustre la fonction suivante.

Définition à la ligne 190 du fichier main.c.

00191 {
00192     int mtuple, mdividende, mdiviseur;
00193     int quotient, reste;
00194 
00195     MMechostr (MSKDEBUG, "sc_division : entering\n");
00196 
00197     mtuple = MTOI (MMpull (m));                     /* 1 */
00198     mdividende = MTOI (MMfetch (m, mtuple, 0));     /* 2 */
00199     mdiviseur = MTOI (MMfetch (m, mtuple, 1));      /* 2 */
00200 
00201     if (mdiviseur == 0)     /* on teste le cas de la division par zéro */
00202         return MMpush (m, NIL);
00203 
00204     quotient = mdividende / mdiviseur;
00205     reste = mdividende % mdiviseur;
00206 
00207     MMpush (m, ITOM (quotient));                    /* 3 */
00208     MMpush (m, ITOM (reste));                       /* 3 */
00209     MMpush (m, ITOM (2));                           /* 4 */
00210     return MBdeftab (m);                            /* 5 */
00211 }

int sc_hello ( mmachine  m  ) 

fonction example_hello

Paramètres:
mmachine m
Renvoie:
0

Code interne de la fonction de l'API 'example_hello' Son prototype est : fun [S] S L'argument de type chaine de caractères n'est pas à garder dans la pile car on n'en a plus besoin. on utilisera alors de préférence MMpull En sortie, on ajoutera l'élément non pas avec MMpull mais Mpushstrbloc qui remplit exactement la même fonction mais uniquement pour les chaînes

menter < contenu de la pile, ici son dernier élément

enter < chaine entrée

result < chaine résultante

MTOP < convertit le pointeur de la pile en un pointeur système

MMstartstr < replace le cursuer au début de la chaîne

Mpushstrbloc < on pousse le résultat chaine dans la pile, à la dernière position

Définition à la ligne 127 du fichier main.c.

00128 {
00129     int menter;             
00130     char * enter = NULL;    
00131     char * result = NULL;   
00133     MMechostr (MSKDEBUG, "sc_hello : entering\n");
00134 
00135     menter = MTOP (MMpull (m));    
00136     enter = MMstartstr (m, menter); 
00138     result = (char *) malloc (sizeof (char) * (strlen (enter) +7)); /* allocation dynamique selon la taille de la chaine */
00139     sprintf (result, "%s %s", "Hello", enter);
00140 
00141     Mpushstrbloc (m, result);   
00142     free (result);  /* on libère ce qu'on a alloué précédemment */
00143     return 0;
00144 }

int sc_increment ( mmachine  m  ) 

auto increment

Paramètres:
mmachine structure
Renvoie:
0

Code interne de la fonction de l'API Scol "example_increment" tel que définie plas bas, lors du chargement de la bibliothèque par le noyau. Le but de cette fonction est de simplement incrémenter de 1 la valeur passée en argument de la fonction Scol

MSKDEBUG est une macro permettant l'écriture d'un message dans le log, dépendant du masque choisi lors de l'exécution. Les différents masques possibles :

 (aucun)     -> 0
    MSKFOO      -> 1
    MSKRUNTIME  -> 2
    MSKWARNING  -> 4
    MSKTRACE    -> 8
    MSKDEBUG    -> 16

Une fonction Scol peut avoir 0 ou n arguments qui sont contenus dans la pile lors de l'appel. Sauf s'il n'y en a aucun, bien évidemment, il faut dépiler chaque argument grâce à l'une des deux fonctions suivantes : MMpull ou MMget.

MMpull dépile le dernier élément de la pile (celui d'index 0) ; il est par conséquent supprimé de la pile et l'élémentd'index 1 précédemment prend sa place, et ainsi de suite.

 int p_var = MMpull (m);

MMget a contrario, lit simplement un élément de la pile sans le dépiler donc : il reste ainsi à sa place dans la pile et peut être réutilisé / modifié par la suite.

 int p_var = Mget (m, 2);

lit le contenu de la pile à l'index 2 (antépénultième entrée).

 int p_var = MMget (m, 0);

n'est pas équivalent à

 int p_var = MMpull (m);

car dans le second cas, l'objet est dépilé et n'est donc plus accessible pour un traitement ultérieur.

On peut dépiler plusieurs fois de suite : si on souhaite les objets d'indices 0, 1, 2, on pourra, si on ne souhaite pas les garder dans la pile, appeler MMpull trois fois.

Les deux macros MTOI et ITOM : la première convertit une valeur de la machine Scol en un int système classique, la seconde est la réciproque : du int habituel à la machine Scol.

Deux autres macros du même type, plus générale : MTOP et PTOM qui converti vers et depuis un pointeur système.

Pour empiler un nouvel objet dans la pile, utilisez simplement la fonction MMpush (pousser) : l'objet qui était en position 0 passe alors en position 1. C'est le fonctionnement de base d'une pile ... :)

 MMpush (m, p);

où p devrait être un pointeur (ou un entier).

Il est possible de modifier la valeur présente à un étage quelconque de la pile : c'est lafonction MMset.

 MMset (m, pos, p);

où pos est l'index dans la pile et p le nouveau pointeur que contient l'objet de la machine Scol.

Ces différentes fonctions retournent 0 si succès. Le retour de la fonction interne n'a aucune influence sur ce que retourne la fonction Scol.

Dans le cas proposé ici, nous aurions pu coder la fonction avec le couple MMpull / MMpush plutôt que MMget / MMset. Cela n'aurait pas eu d'effets apparemment. Dans la plupart des cas, il est nécessaire d'utiliser l'un plutôt que l'autre ou, souvent, de les combiner.

Définition à la ligne 101 du fichier main.c.

00102 {
00103     int mnumber;
00104 
00105     MMechostr (MSKDEBUG, "sc_increment : entering\n");
00106 
00107     mnumber = MTOI (MMget (m, 0));
00108     mnumber++;
00109     MMset (m, 0, ITOM (mnumber));
00110     return 0;
00111 }

int SCOLfreeEXAMPLE (  ) 

Fonction de déchargement / libération.

Renvoie:
0 si succès

La fonction est appelée lorsque Scol se termine. Elle définit, comme pour la fonction de chargement, dans le fichier usm.ini (voir ci-dessus).

Les éventuels objets Scol présents devront avoir été détruits au préalable. Ici, on peut, par exemple, libérer des ressources tierces telle qu'une bibliothèque

Définition à la ligne 561 du fichier main.c.

00570 {
00571     MMechostr(MSKDEBUG, "\nEXAMPLE library release !\n");
00572     return 0;
00573 }

int SCOLinitEXAMPLEclass ( mmachine  m  ) 

Fonction défininssant l'API Scol de la bibliothèque.

Paramètres:
structure mmachine
Renvoie:
0 si succès

Une API Scol est définie par 4 tableaux et une fonction.

Les 4 tableaux ont tous une taille identique. Ceux-ci définissent respectivement le nom Scol des objets de l'API, le nom des fonctions internes correspondantes, le nombre d'arguments ou le type d'objet, et le prototypage Scol.

La fonction interne 'PKhardpak' les chargera dans l'environnement minimal. Ses arguments sont respectivement définis comme suit :

  • la machine Scol correspondante
  • le nom interne du package
  • le nombre d'éléments de l'API (donc la taille de chaque tableau)
  • les noms des éléments de votre API (fonctions, types, flags, ...)
  • leurs correspondants internes
  • le nombre d'argument qu'ils attendent (si cela a un sens, sinon ce sera NULL)
  • le typage Scol

Dans notre exemple, cette API est définie par 4 tableaux de EXAMPLE_PKG_NB cases précisément. Il est impératif que les 4 tableaux aient le même nombre de cases et que cenombre soit strictement équivalent au nombre de fonctions de l'API.

Le comppilateur pourra ne rien dire si le nombre de cases est plus grand que le nombre réelle de fonctions de l'API (le cas inverse engendrera un warning si vous avez suivi mes options de compilation). Cependant, à l'exécution, la bibliothèque ne sera pas chargée et il n'y aura aucun message d'erreur. Ŝoyez attentif à ce niveau (comme au reste !). Notez que "nombre de fonctions" inclue les fonctions proprement dit mais aussi les objets Scol (les types Scol), les flags, etc ... définis dans votre API.

Les tableaux doivent correspondre, c'est-à-dire que le nom de l'élément de l'API situé à la première case doit correspondre la fonction interne situé à la même case du second tableau, qui doit correspondre au nombre d'argument situé à la même case du troisième tableau et même chose pour le quatrième tableau.

Enfin, il va de soi que le nombre d'arguments défini pour un élément de l'API dans le troisème tableau doit être strictement cohérent avec le typage défini au quatrième tableau.

Par exemple : si le nombre d'argument est 2, le typage de la fonction pourra être "fun [I S] I" ou "fun [Chn S]" mais pas "fun [I S I]" ou "fun [S] I". Là encore, aucune erreur ne peut être détecté lors de la compilation mais lorsque la tentative de chargement de votre bibliothèque par le noyau échouera immanquablement sans la moindre erreur apparente.

Définition à la ligne 471 du fichier main.c.

00472 {
00473     int k = 0;
00474 
00475     MMechostr (MSKDEBUG, "SCOLinitEXAMPLEclass library : loading\n");
00476 
00477     k = PKhardpak (m, "EXAMPLEengine", EXAMPLE_PKG_NB, example_name, example_fun, example_narg, example_type);
00478     return k;
00479 }

int SCOLloadEXAMPLE ( mmachine  m  ) 

Définition à la ligne 527 du fichier main.c.

00528 {
00529     int k = 0;
00530     /* Affectation à la variable globale mm des valeurs envoyées par le noyau des structures partagées.
00531     Il est impératif de l'ajouter AVANT tout appel à des fonctions ou macros Scol sous peine de crash immédiat
00532     lors de l'exécution de Scol. */
00533     mm = m;
00534 
00535     MMechostr (0, "EXAMPLE library : loading\n");
00536 
00537     if ((k = SCOLinitEXAMPLEclass (m))) return k;
00538 
00539     MMechostr (0, "\nEXAMPLE library loaded !\n");
00540     return k;
00541 }


Documentation des variables

int(* example_fun[EXAMPLE_PKG_NB])(mmachine m)
Valeur initiale :
{
    sc_increment,   
    sc_hello,
    sc_division,
    sc_calcul_list,

    (void*) ((-1)*2),
    (void*) (1*2)
}

Définition des fonctions internes.

Ce tableau donne la correspondance des fonctions Scol vers le code interne. À ce sujet, en C, les flags peuvent poser problèmes. Le code présenté ici n'est pas valide ANSI C (une option -ansi de gcc provoquera un warning non bloquant).

Dans le code source existant, il existe parfois ceci :

 #define bullshit int (__cdecl *)(struct Mmachine *)
 (bullshit) (1*2)

Cette solution fonctionne dans la plupart des cas mais n'est pas garantie (outre le fait que gcc lancera au mieux un warning , probablement une erreur à moins d'être très laxiste sur ces options.

Définition à la ligne 379 du fichier main.c.

char* example_name[EXAMPLE_PKG_NB]
Valeur initiale :
{
    
    "example_increment",    
    "example_hello",
    "example_calcul",
    "example_list",

    
    "EXAMPLE_MOINS",
    "EXAMPLE_PLUS"
}

Définition de l'API.

Paramètres:
\return sans intérêt ici

Quatre tableaux qui sont présentés à la fonction 'SCOLinitEXAMPLEclass' Les éléments définis dans ce preimer tableau seront alors accessibles depuis n'importe quel script Scol.

Définition à la ligne 353 du fichier main.c.

int example_narg[EXAMPLE_PKG_NB]
Valeur initiale :
{
    1,      
    1,
    1,
    3,

    TYPVAR,
    TYPVAR
}

Nombre d'arguments ou type d'objets.

Lorsqu'il s'agit d'une fonction Scol, le nombre exact d'arguments doit être indiqué. Sinon, divers flags sont possibles. Les plus courants sont TYPVAR pour une valeur numérique et TYPTYPE pour un type objet Scol. Les autres sont listés sur le tutoriel ou, de façon moins expliquée, sur scol_plugin_xxx.h

Définition à la ligne 397 du fichier main.c.

char* example_type[EXAMPLE_PKG_NB]
Valeur initiale :
{
    "fun [I] I",    
    "fun [S] S",
    "fun [[I I]] [I I]",
    "fun [[I r1] I I] [I r1]",

    "I",
    "I"
}

Prototypage Scol.

Les prototypes Scol des fonctions doivent correspondre avec le nmbre d'arguments notés au tableau 3. Dans le cas contraire, il y aura une erreur à l'exécution lors de l'appel de la fonction

Définition à la ligne 413 du fichier main.c.

Définition à la ligne 38 du fichier main.c.

Définition à la ligne 36 du fichier main.c.

Généré le Tue Nov 16 20:25:11 2010 pour example par  doxygen 1.6.3