4D v14.3

Précisions de syntaxe

Accueil

 
4D v14.3
Précisions de syntaxe

Précisions de syntaxe  


 

 

Le compilateur suit la syntaxe habituelle des commandes 4D et, en ce sens, ne vous demande aucun comportement particulier dans l’optique de la compilation.

Cette section propose cependant certains rappels et quelques précisions :

  • Certaines commandes influant sur le type d’une variable peuvent, si vous n’y prêtez pas attention, conduire à des conflits de type.
  • Certaines commandes admettant des syntaxes ou des paramètres différents, il est préférable de savoir ce qu’il est plus approprié de choisir.

Pour les routines opérant sur les chaînes, seule la fonction Code de caractere réclame une attention plus particulière. Lorsque vous travaillez en mode interprété, vous pouvez indifféremment passer une chaîne non vide ou vide à cette fonction.
En compilé, vous ne pouvez pas passer une chaîne vide.
Si vous le faites, le compilateur ne peut détecter une erreur à la compilation si l’argument passé à Code de caractere est une variable.

ENVOYER VARIABLE(LaVariable)
RECEVOIR VARIABLE(LaVariable)

Ces deux commandes permettent d’écrire et de relire des variables envoyées sur disque. On passe des variables en paramètres à ces commandes.
Souvenez-vous simplement qu’il faudra toujours relire une variable d’un type dans une variable de même type. Supposons que vous souhaitiez envoyer une liste de variables dans un fichier. Afin de ne pas prendre de risque de changement de type par inattention, nous vous recommandons d’adopter une méthode de travail simple qui consiste à indiquer en début de liste le type des variables envoyées. Ainsi, lorsque vous relirez ces variables, vous commencerez toujours par récupérer cet indicateur dont vous connaissez le type. Ensuite, vous appellerez RECEVOIR VARIABLE en toute connaissance de cause par l’intermédiaire d’un Au cas ou.

Exemple :
 REGLER SERIE(12;"LeFichier")
 Si(OK=1)
    $Type:=Type([Client]CA_Cumulé)
    ENVOYER VARIABLE($Type)
    Boucle($i;1;Enregistrements trouves)
       $CA_Envoi:=[Client]CA_Cumulé
       ENVOYER VARIABLE($CA_Envoi)
    Fin de boucle
 Fin de si
 REGLER SERIE(11)
 REGLER SERIE(13;"LeFichier")
 Si(OK=1)
    RECEVOIR VARIABLE($Type)
    Au cas ou
       :($Type=Est une variable chaîne)
          RECEVOIR VARIABLE($LaChaine)
  `Traitement de la variable reçue
       :($Type=Est un numérique)
          RECEVOIR VARIABLE($LeRéel)
  `Traitement de la variable reçue
       :($Type=Est un texte)
          RECEVOIR VARIABLE($LeTexte)
  `Traitement de la variable reçue
    Fin de cas
 Fin de si
 REGLER SERIE(11)

Champ (Ptr_Champ) ou (NoDeTable;NoDeChamp)
Table(Ptr_Table)
ou (Ptr_Champ) ou (NoDeTable)

Dans l’optique du compilateur, ces deux commandes ne comportent rien de spécifique. Nous appelons simplement votre attention sur un cas pratique : ces deux commandes retournent des résultats de type différent suivant le paramètre qui leur est passé :

  • si vous passez un pointeur à la fonction Table, le résultat retourné sera de type Numérique.
  • si vous passez un Numérique à la fonction Table, le résultat retourné sera de type Pointeur.
    On comprend aisément que ces deux fonctions ne suffisent pas au compilateur pour déterminer le type du résultat. Dans ce cas, pour qu’il n’y ait aucune ambiguïté, utilisez une directive de compilation.

Nous rappellerons simplement que la référence d’un document renvoyée par les fonctions Ouvrir document, Ajouter a document et Creer document est de type Heure.

Modulo (LaValeur;Diviseur)

L’expression “25 modulo 3” peut s’écrire de deux façons différentes dans 4D :

 LaVariable:=Modulo(25;3)

ou

 LaVariable:=25%3

Il existe pour le compilateur une différence entre ces deux écritures : Modulo s’applique à tous les types de numériques tandis que l’opérateur % s’applique exclusivement aux Entiers et Entiers longs (si les opérandes de l’opérateur % dépassent les limites des Entiers longs, le résultat renvoyé sera probablement faux).

APPELER 4D
APPELER SUR EVENEMENT (LaMéthode {; NomProcess})
STOP

Pour la gestion des interruptions, le langage de 4D dispose de la commande APPELER 4D. Cette commande devra être utilisée lorsque vous vous servirez de la commande APPELER SUR EVENEMENT.

On pourrait définir cette commande comme une directive de gestion des événements.
Seul le noyau de 4D peut détecter un événement Système (clic souris, action sur le clavier…). Dans la plupart des cas, des appels au noyau sont lancés par le code compilé lui-même, de façon transparente pour vous.

En revanche, dans le cas où vous attendez un événement sans rien faire, comme dans une boucle d’attente, il est bien évident qu’aucun appel n’est effectué.

  `Méthode projet ClicSouris
 Si(MouseDown=1)
    <>vTest:=Vrai
    ALERTE("Quelqu’un a cliqué avec la souris")
 Fin de si
 
  `Méthode projet Attente
 <>vTest:=Faux
 APPELER SUR EVENEMENT("ClicSouris")
 Tant que(<>vTest=Faux)
  `Boucle d’attente de l’événement
 Fin tant que
 APPELER SUR EVENEMENT("")

Dans ce cas, vous ajouterez la directive APPELER 4D de la façon suivante :

  `Méthode projet Attente
 <>vTest:=Faux
 APPELER SUR EVENEMENT("ClicSouris")
 Tant que(<>vTest=Faux)
    APPELER 4D
  `Appel au noyau pour discerner un événement
 Fin tant que
 APPELER SUR EVENEMENT("")
STOP  

Cette commande ne doit être utilisée que dans des méthodes projet d’interception d’erreurs. Cette commande fonctionne comme en mode interprété, sauf dans une méthode ayant été appelée par l’une des commandes suivantes : EXECUTER, APPLIQUER A SELECTION et APPLIQUER A SOUS SELECTION. Il convient d’éviter cette situation.

Sept routines de 4D sont utilisées par le compilateur pour déterminer le type d’un tableau. Il s’agit de :

COPIER TABLEAU(TableauSource;TableauDestination)
SELECTION VERS TABLEAU(LeChamp;LeTableau)
TABLEAU VERS SELECTION(LeTableau; LeChamp)
SELECTION LIMITEE VERS TABLEAU(Début;Fin;LeChamp;LeTableau)
LISTE VERS TABLEAU(LaListe; LeTableau{;ItemRefs})
TABLEAU VERS ENUMERATION(LeTableau; LaListe{;ItemRefs})
VALEURS DISTINCTES(LeChamp;LeTableau)

COPIER TABLEAU admet deux paramètres de type Tableau. Lorsque le compilateur rencontre cette commande pendant le typage et que l’un des paramètres tableau n’est pas déclaré ailleurs, le compilateur déduit le type du tableau non déclaré suivant le type de celui qui l’est.
Cette déduction est faite dans les deux cas suivants :

  • le tableau typé ailleurs est le premier paramètre. Le compilateur donne au second tableau le type du premier.
  • le tableau déclaré est le second paramètre. Dans ce cas, le compilateur donne au premier tableau le type du second.

Le compilateur étant rigoureux sur les types, un COPIER TABLEAU ne peut se faire que d’un tableau d’un type vers un tableau de même type.
En conséquence, si vous souhaitez faire une copie d’un tableau d’éléments de types voisins, c’est-à-dire les Entiers, Entiers longs et Numérique ou les Textes et les Alphas ou les Alphas de longueurs différentes, vous devrez le faire élément par élément.

Imaginez que vous vouliez faire une copie d’un tableau d’Entiers vers un tableau de Numériques. Procédez comme suit :

 $Taille:=Taille tableau(TabEntier)
 TABLEAU REEL(TabRéel;$Taille)
  `Donnons la même taille au tableau de Réels qu’au tableau d’Entiers
 Boucle($i;1;$Taille)
    TabRéel{$i}:=TabEntier{$i}
  `Recopions chacun des éléments
 Fin de boucle


Souvenez-vous que vous ne pouvez changer le nombre de dimensions d’un même tableau en cours de route. Vous provoqueriez une erreur de typage en copiant un tableau à une dimension dans un tableau à deux dimensions.

De même que pour 4D en mode interprété, ces quatre commandes n’exigent pas de déclaration de tableau. Le tableau non déclaré recevra le même type que le champ spécifié dans la commande.
Si vous écrivez :

 SELECTION VERS TABLEAU([LaTable]ChampEntier;LeTableau)

le type de LeTableau sera donc Tableau d’Entiers à une dimension.

Dans le cas où le tableau a déjà été déclaré, veillez à ce que les champs soient du même type. Bien qu’Entier, Entier long et Réel soient des types voisins, vous ne pouvez pas supposer qu’il soient équivalents.
Vous avez en revanche plus de latitude lorsqu’il s’agit des types Texte et Alpha. Par défaut, lorsqu’un tableau n’a pas été déclaré au préalable et que vous appliquez l’une de ces commandes avec pour paramètre un champ de type Alpha, le type attribué au tableau sera Texte. Si le tableau a été déclaré auparavant comme étant de type Alpha ou de type Texte, ces commandes respecteront vos directives.

Il en est de même dans le cas des champs de type Texte : vos directives sont prioritaires.
Souvenez-vous que les commandes SELECTION VERS TABLEAU, SELECTION LIMITEE VERS TABLEAU, TABLEAU VERS SELECTION et VALEURS DISTINCTES ne s’appliquent qu’à des tableaux à une dimension.

La commande SELECTION VERS TABLEAU admet aussi une seconde syntaxe :
SELECTION VERS TABLEAU(LaTable;LeTableau)
Dans ce cas, la variable LeTableau sera de type Tableau d’Entiers longs. Il en est de même pour la commande SELECTION LIMITEE VERS TABLEAU.

Les commandes LISTE VERS TABLEAU et TABLEAU VERS ENUMERATION ne concernent que deux types de tableaux :

  • les tableaux Alpha à une dimension,
  • les tableaux Texte à une dimension.
    Ces deux commandes n’exigent pas la déclaration du tableau qui leur est passé en paramètre. Par défaut, un tableau non déclaré recevra le type Texte. Si le tableau a été déclaré auparavant comme étant de type Alpha ou de type Texte, ces commandes respecteront vos directives.

Le compilateur ne peut pas, durant le typage ou la compilation, détecter un conflit de type dans le cas où vous utiliseriez des pointeurs dépointés comme paramètre de commande de déclaration d’un tableau. Si vous écrivez :

 SELECTION VERS TABLEAU([LaTable]LeChamp;LePointeur->)

où LePointeur-> représente un tableau, le compilateur ne peut vérifier que le type du champ et du tableau sont identiques. Il vous appartient d’éviter alors ce type de conflit.

Pour cela, le compilateur vous fournit une aide précieuse : les Warnings. Chaque fois qu’il rencontre une routine de déclaration de tableau dans laquelle l’un des paramètres est un pointeur, il vous délivre un message vous invitant à la vigilance.

Si vous souhaitez compiler une base de données qui utilise des tableaux locaux (tableaux visibles uniquement par les méthodes qui les ont créés), il est nécessaire de les déclarer explicitement dans 4D avant de les utiliser.

La déclaration explicite d’un tableau signifie l’utilisation d’une commande de type TABLEAU REEL, TABLEAU ENTIER, etc.

Par exemple, si une méthode génère un tableau local d’entiers contenant 10 valeurs, vous devez écrire au préalable la ligne suivante :TABLEAU ENTIER($MonTableau;10)

Langage  

Pointeur vers(NomVariable)
Type (Objet)
EXECUTER FORMULE(Instruction)
TRACE
PAS DE TRACE

Pointeur vers est une fonction qui retourne un pointeur sur le paramètre que vous lui avez passé. Supposons que vous vouliez initialiser un tableau de pointeurs. Chacun des éléments de ce tableau pointe vers une variable donnée. Ces variables sont au nombre de douze et nous les appelons V1, V2, …V12. Vous pourriez écrire :

 TABLEAU POINTEUR(Tab;12)
 Tab{1}:=->V1
 Tab{2}:=->V2
 
 Tab{12}:=->V12

Vous pouvez aussi écrire :

 TABLEAU POINTEUR(Tab;12)
 Boucle($i;1;12)
    Tab{$i}:=Pointeur vers("V"+Chaine($i))
 Fin de boucle

A la fin de l’exécution de cette séquence, vous récupérez un tableau de pointeurs dont chaque élément pointe sur une variable Vi.

Ces deux séquences sont bien entendu compilables. Toutefois, si les variables V1 à V12 ne sont pas utilisées explicitement ailleurs dans la base, le compilateur ne pourra pas les typer. Il vous faut donc les nommer ailleurs explicitement.
Cette déclaration explicite peut se faire de deux façons :

  • soit en déclarant V1, V2, …V12 par une directive de compilation :
 C_ENTIER LONG(V1;V2;V3;V4;V5;V6;V7;V8;V9;V10;V11;V12)
  • soit en affectant ces variables dans une méthode :
 V1:=0
 V2:=0
 
 V12:=0

Chaque variable de la base compilée n’ayant qu’un seul type, la fonction Type peut sembler d’un intérêt limité. Elle est cependant très précieuse lorsqu’on travaille avec des pointeurs. En effet, il peut être nécessaire de connaître le type de la variable pointée par un pointeur, la souplesse des pointeurs faisant que l’on ne sait pas toujours sur quoi ils pointent.

La commande EXECUTER FORMULE, historique dans 4D, présente des avantages en mode interprété qui n’ont pas grand sens en mode compilé.
En effet, en mode compilé, le nom de la méthode passé en paramètre à cette commande sera simplement interprété. Vous ne bénéficierez donc pas de tous les avantages apportés par le compilateur, sans compter que la syntaxe de votre paramètre ne pourra pas être vérifiée.
De surcroît, vous ne pouvez pas lui passer des variables locales comme paramètres.
On peut avantageusement remplacer un EXECUTER FORMULE par une série d’instructions. Nous vous en donnons ici deux exemples.

Soit la séquence suivante :

 i:=FctFormulaire
 EXECUTER FORMULE("FORM FIXER ENTREE (Formulaire"+Chaine(i)+")")

Elle peut être remplacée par :

 i:=FctFormulaire
 VarFormulaire:="Formulaire"+Chaine(i)
 FORM FIXER ENTREE(VarFormulaire)

Examinons maintenant un deuxième cas :

 $Num:=ChoixImprimante
 EXECUTER FORMULE("Impri"+$Num)

Ici, l’EXECUTER peut être facilement remplacé par un Au cas ou :

 Au cas ou
    :($Num=1)
       Impri1
    :($Num=2)
       Impri2
    :($Num=3)
       Impri3
 Fin de cas

La commande EXECUTER peut toujours être avantageusement remplacée. En effet, la méthode à exécuter est prise dans la liste des méthodes projet de la base ou des commandes 4D, qui sont en nombre limité. En conséquence, il est toujours possible de remplacer la commande EXECUTER soit par un Au cas ou, soit par une autre commande.

Ces deux commandes, précieuses en mode interprété, n’ont pas de fonction en mode compilé. Vous pouvez cependant les laisser dans vos méthodes : TRACE et PAS DE TRACE seront simplement ignorées par le compilateur.

Indefinie(LaVariable)
ECRIRE VARIABLES(NomduDoc;Variable1{; Variable2…})
LIRE VARIABLES(NomduDoc;Variable1{; Variable2…})
EFFACER VARIABLE(LaVariable)

Compte tenu du processus de typage par le compilateur, une variable ne peut à aucun moment être indéfinie en mode compilé. En effet, toutes les variables ont une existence dès la fin de la compilation. La fonction Indefinie retourne donc toujours Faux, quel que soit le paramètre que vous lui passez.

Note : Pour savoir si une application tourne en mode compilé, utilisez la fonction Mode compile.

En mode interprété, après l’exécution d’un LIRE VARIABLES, vous pouvez savoir si le document existe en testant si l’une des variables, théoriquement lue, est indéfinie ou non. Ceci n’est bien évidemment plus possible avec le compilateur, puisque la fonction Indefinie renvoie toujours Faux.

La méthode la plus simple pour réaliser cette opération en mode interprété comme en mode compilé est la suivante :
1. Initialisez les variables que vous allez recevoir à une valeur dont vous êtes sûr qu’elles ne sont pas initialisées.
2. Après le LIRE VARIABLES, comparez l’une des variables reçues à la valeur d’initialisation.
La méthode s’écrira alors de la façon suivante :

 Var1:="xxxxxx"
  `"xxxxxx" est une valeur qui ne peut pas être ramenée par un LIRE VARIABLES
 Var2:="xxxxxx"
 Var3:="xxxxxx"
 Var4:="xxxxxx"
 LIRE VARIABLES("LeDocument";Var1;Var2;Var3;Var4)
 Si(Var1="xxxxxx")
  `Le document n’a pas été trouvé
 
 Sinon
  `Le document a été trouvé
 
 Fin de si

Cette routine admet deux syntaxes différentes en mode interprété :
EFFACER VARIABLE(LaVariable)
EFFACER VARIABLE("a")
En mode compilé, la première syntaxe, EFFACER VARIABLE(LaVariable), provoque non la destruction de la variable, mais sa réinitialisation (remise à zéro pour un numérique, chaîne vide pour une chaîne de caractères ou un texte…), aucune variable ne pouvant être indéfinie en mode compilé.
En conséquence, EFFACER VARIABLE ne libère pas de mémoire en mode compilé sauf dans quatre cas : les variables de type Texte, Image, BLOB et les tableaux.
Pour un tableau, EFFACER VARIABLE équivaut à une nouvelle déclaration du tableau ou les tailles sont remises à zéro.

Pour un tableau LeTableau dont les éléments sont de type Entier, EFFACER VARIABLE(LeTableau) équivaut à l’une des expressions suivantes :

 TABLEAU ENTIER(LeTableau;0)
  `s’il s’agit d’un tableau à une dimension
 TABLEAU ENTIER(LeTableau;0;0)
  `s’il s’agit d’un tableau à deux dimensions

La seconde syntaxe, EFFACER VARIABLE("a"), n’est pas compatible avec le compilateur puisque celui-ci accède aux variables non par leur nom, mais par leur adresse mémoire.

Les commandes suivantes ont un point commun : elles admettent toutes un premier paramètre [LaTable] facultatif alors que le second paramètre peut être un pointeur.

ADJOINDRE ELEMENT FORM FIXER ENTREE
ALLER A ENREGISTREMENT FORM FIXER SORTIE
ALLER DANS SELECTION GRAPHE SUR SELECTION
APPLIQUER A SELECTION IMPRIMER ETIQUETTES
CHARGER ENSEMBLE Imprimer ligne
CHERCHER IMPORTER TEXTE
CHERCHER DANS SELECTION LECTURE DIF
CHERCHER PAR FORMULE LECTURE SYLK
CHERCHER PAR FORMULE DANS SELECTION LIEN RETOUR
COPIER SELECTION NOMMER ENSEMBLE
DEPLACER SELECTION REDUIRE SELECTION
DIALOGUE ENLEVER ELEMENT
EXPORTER TEXTE TRIER
ECRITURE DIF TRIER PAR FORMULE
ECRITURE SYLK UTILISER PARAMETRES IMPRESSION
ENSEMBLE VIDE VERROUILLE PAR
QR ETAT

Il est parfaitement possible en mode compilé de garder ce caractère optionnel au paramètre [LaTable]. Le compilateur fait toutefois une supposition dans le cas où le premier paramètre passé à l’une de ces commandes est un pointeur. Ne pouvant pas savoir sur quoi pointe ce pointeur, il suppose qu’il s’agit d’un pointeur de Table.

Prenons par exemple le cas de la commande CHERCHER dont la syntaxe est la suivante :
CHERCHER({LaTable{;LaFormule{;*}}})
Le premier élément du paramètre LaFormule doit être un champ.
Si vous écrivez :

 CHERCHER(LePtrChamp->=Vrai)

le compilateur va chercher en deuxième élément de formule un symbole représentant un champ. Or, il trouvera le signe "=". Il délivrera un message d’erreur, ne pouvant identifier la commande avec une expression qu’il sait traiter.

En revanche, si vous écrivez :

 CHERCHER(LePtrTable->;LePtrChamp->=Vrai)

ou

 CHERCHER([LaTable];LePtrChamp->=Vrai)

vous levez toute ambiguïté.

Les commandes dont le premier paramètre [laTable] est facultatif et dont le second paramètre est également facultatif présentent une particularité lors de l'utilisation de pointeurs. Dans ce contexte, pour des raisons internes l'utilisation en tant que paramètre d'une commande retournant un pointeur (par exemple Table du formulaire courant) n'est pas autorisée par le compilateur (une erreur est générée).

C'est le cas, par exemple, de la commande FORM CAPTURE ECRAN. Le code suivant fonctionnera en mode interprété mais sera rejeté en cas de compilation :

  //provoque une erreur à la compilation
 FORM CAPTURE ECRAN(Table du formulaire courant->;$nomForm;$monImage)

Dans ce cas, il suffit d'utiliser une variable intermédiaire afin que le même code soit validé par le compilateur :

  //code équivalent compilable
 C_POINTEUR($ptr)
 $ptr:=Table du formulaire courant
 FORM CAPTURE ECRAN($ptr->;$nomForm;$monImage)

Si vous créez vos propres ressources 4DK# (constantes), assurez-vous que les numériques soient de type Entier long (L) ou Réel (R) et les alphas de type Chaîne (S). Tout autre type génèrera un Warning.

 
PROPRIÉTÉS 

Produit : 4D
Thème : Compilateur
Nom intl. : Syntax Details

 
VOIR AUSSI  

Conseils d’optimisation
Guide du typage
Messages d'erreurs
Utilisation des directives de compilation

 
UTILISATION DE L'ARTICLE

4D - Langage ( 4D v12.4)
4D - Langage ( 4D v14 R2)
4D - Langage ( 4D v14 R3)
4D - Langage ( 4D v13.5)
4D - Langage ( 4D v14.3)
4D - Langage ( 4D v14 R4)

Hérité de : Précisions de syntaxe ( 4D v11 SQL Release 6)