Manuel de référence complet pour la version 14.0 de Scriptol.
Le langage est entièrement implémenté dans le compilateur de Scriptol en PHP ou binaire.
- L'inclusion en page Web est possible seulement avec le compilateur de Scriptol en PHP.
- Utiliser XML comme structure de données est possible avec le compilateur en binaire.
- L'interpréteur est un outil d'apprentissage et ne reconnait qu'une partie
du langage pour le moment (voir la page "Change" pour plus de détails).
- XML est traité par l'interpréteur comme une structure dynamique.
- XML est traité par le compilateur C++ comme une classe nommée "dom" et décrite dans le document "dom.html".
Dans un futur proche, le format XML de l'interpréteur sera étendu aux deux compilateurs.
Le nouveau langage de programmation Scriptol peut être utilisé avec un interpréteur
et des compilateurs.
Une version Windows et Unix existe pour chaque compilateur.
L'objectif du langage est d'être simple, naturel et donc de réduire le risque
d'erreurs. Scriptol signifie: "Scriptwriter Oriented Language" ou "langage de scénariste"
en français.
C'est un langage universel conçu pour produire des pages web dynamiques, des scripts et des
applications avec interface graphique. Ce peut être aussi un langage de script
pour les applications traitant ou produisant des documents XML.
Scriptol peut être imbriqué dans une page HTML et est converti en la même page
avec du code PHP, prêt pour le Net et totalement portable.
Le langage a été défini selon sept règles et une
page explique en détail pourquoi utiliser Scriptol.
Veuillez noter que les symboles [] inclus dans la syntaxe des instructions
ne font pas partie de la syntaxe et indiquent un élément optionel, sauf pour
les indices et intervalles qui utilisent précisément ces caractères.
La commande est:
si [options] fichiersource
Si des erreurs sont trouvées, elle sont affichées et le programme ne s'exécute pas.
Options de l'interpréteur:
aucune: interprète et exécute un fichier source Scriptol. -v: verbeux, affiche des informations détaillés. -q: silencieux (quiet), aucun message. -f: force, ignore les erreurs et exécute le programme.
Sous Windows, la commande est:
solp [options] nomfichier
Si le source est déja compilé, le programme est interprété, sinon il est
compilé avant d'être interprété s'il n'y a pas d'erreur.
Tant que le source a des erreurs une nouvelle commande "solp nomfichier" va le compiler.
Si le source est une page HTML, il n'est pas exécuté après compilation.
Sous Linux, la commande pour compiler est:
solp options nomfichier
suivie de:
php -q nomfichier.php pour l'exécuter.
Options du compilateur Scriptol-php:
aucune: compile un script en PHP ou le lance si déja compilé. -w compile du code inclus dans une page HTML et crée un fichier PHP. -t teste seulement, n'exécute pas. -r force l'exécution. Compile si besoin seulement. -b recompile le fichier et fichiers inclus. Le programme n'est pas lancé. -t invoque la traduction du source s'il est en français. -v affiche plus d'informations lors de la compilation. -q pas de message de compilation. -4: compile selon la syntaxe PHP 4 (les classes propres à PHP 5 ne sont pas utilisables).
Ces lettres peuvent être combinées en une seule option. Ainsi -be est équivalent à -b -e
Pour être compilé en C++, un programme doit avoir la structure suivante:
1) Déclarations des variables globales.
2) Définition des classes et fonctions.
3) Les instructions. Elle peuvent être encloses dans une fonction main() ou non.
Ces règles ne sont pas imposées pour la compilation en PHP ou pour l'interpréteur.
La commande de compilation est:
solc [options] fichiermain
Le fichier main est celui qui contient la fonction main(). Les dépendances sont
calculées par le compilateur qui sait ce qui doit être compilé ou non.
Options du compîlateur Scriptol-C++:
-b compiler tous les fichiers objets. -c compiler tous les sources en C++ seulement. -e lier les objets en un exécutable. -r lancer l'exécutable. -t invoquer la traduction. -v informations de compilation détaillées. -q pas de messages.
Un source Scriptol est juste un fichier de texte contenant des commandes, une
par ligne.
Exemples:
print x * 2 print x + (y / 2)
Avec un éditeur de texte, comme Advanced Editor, taper cette ligne:
print "Bonjour le monde"Sauver dans le fichier bonjour.sol.
Si vous travaillez dans une fenêtre de ligne de commande (MS-DOS sous Windows, console sous Unix), tapez simplement:
solj bonjour ...ou solp bonjour
Vous pouvez aussi construire un exécutable avec la commande:
solc -bre bonjouret lancez le programme bonjour.exe généré.
Il est possible de travailler à la fois avec l'éditeur et une fenêtre de console.
Aucun fichier projet n'est nécessaire.
En Java ou PHP, un programme est un source qui inclut d'autres sources. Scriptol conserve
cette structure.
Un source scriptol doit avoir une instruction "include" pour chaque fichier
dont le contenu est utilisé.
Le compilateur calcule les dépendances sur plusieurs niveaux d'inclusions,
et parmi les inclusions mutuelles.
Un fichier Scriptol doit avoir l'extension "sol", et sera
converti en un fichier d'extension php, ou cpp et hpp, ou un exécutable.
Cela la forme du source, on aura un script ou une application.
Script
Le source d'un script est une séquence d'instructions et de définitions de
fonctions ou de classes. Il peut inclure d'autre fichiers contenant des
déclarations de fonctions, de variables, de classes.
Un script ne peut contenir de fonction "main" (pour le compilateur, il est
lui-même une fonction "main").
Application
Un fichier d'application contient seulement des déclarations de fonctions,
variables et classes. Le source principal est celui que l'on passe en ligne de
commande du compilateur, il doit contenir une fonction "main", et une commande
d'appel de cette fonction, comme ci-dessous:
int main() ... instructions ... return 0 main() // lancement du programme.
Scriptol peut être défini comme:
- orienté objet.
- orienté XML (un document XML peut être une structure de donnée du langage).
- universel: utilisable pour faire des scripts, des applications ou pages web dynamiques.
- naturel: les types viennent de la culture et non du matériel (number, text, real, ...).
- style XML pour la syntaxe.
- ayant des structures nouvelles et plus puissantes.
- traitement de liste avec tableaux et dictionnaires.
- compatible avec C, PHP, Java (peut utiliser leurs librairies).
C'est un langage clair grâce à:
- une syntaxe simple.
- les instructions terminées par la fin de ligne.
- un opérateur unique pour les intervalles, les sous-listes.
- une syntaxe similaire pour toutes les structures.
Sensibilité à la casse:
- On ne peut utiliser un même mot en majuscules et minuscule.
- les mot-clés sont en minuscule.
- les identifieurs sont sensibles à la casse, mais on ne peut redéfinir
un identifieur avec une casse différente.
Identifieurs:
- taille jusqu'à 255 caractères ou moins selon le langage cible.
- commence par une lettre majuscule ou minuscule.
- suivi de lettres, caractères de soulignements, ou chiffres.
Nombres:
- les entiers sont signés sur 32 bits (comme "int" en C).
- les naturels sont non-signés sur 64 bits.
- réels, nombres ("number") sont en virgule flottante sur 64 bits ("double" en C).
Conversion (cast):
- utilisation de méthodes.
Garbage-collector (allocation de mémoire):
- aucun besoin d'allouer ou libérer la mémoire.
Orienté-objet:
- les primitives sont des objets et ont des méthodes.
- les litéraux sont des objets et ont des méthods.
- héritage simple.
- surcharge de méthodes (version C++ seulement pour l'instant).
- constructeurs. Pas de destructeurs.
Orienté-XML:
- des documents XML peuvent être inclus dans un source Scriptol, XML est une
structure de donnée du langage .
- instances de documents XML.
Pour que le code Scriptol puisse être inséré dans du HTML, il doit être inclus dans les balises suivantes:
<?sol ...code... ?> ou <?script langage=scriptol> ...code... </script>'scriptol' ou "scriptol" sont reconnus également. Le mot-clé "script" peut être requis pas certains éditeurs HTML. La dernière ligne d'un script Scriptol doit être terminée par un point-virgule ou un saut de ligne, avant le symbole ?>
Tester les pages HTML Si vous avez installé un serveur comme Apache ou Xitami ou Windows Server sur votre ordinateur, et l'avez configuré pour reconnaitre l'extension php, votre code sera traité comme sur le web, une fois compilé en PHP. Autrement, il vous rediriger dans un fichier test.HTML la page dynamique, et ensuite exécuter le code PHP:
solp -w mapage
php mapage.php > test.HTML
Une instruction est terminée par un point virgule ou par la fin de la ligne. Quand une instruction dépasse la largeur d'une ligne, elle est concaténée avec la suivante pourvu qu'elle soit terminée par une virgule, un opérateur ou tout autre symbole qui ne peut terminer une instruction. Aucun symbole n'est requis pour continuer une instruction sur la ligne suivante. Plusieurs instructions sur une même ligne sont séparés par un point virgule. Cela peut être utile si vous placez du code Scriptol dans une page HTML et si l'éditeur concatène les lignes!
Commentaires d'une seule ligne: ` le commentaire va du symbole jusqu'à la fin de la ligne. // le symbole du C++ est reconnu aussi. Les commentaires ne sont pas conservés dans le langage cible. " le symbole doublé rend un commentaire persistant dans le code cible. Un commentaire de plusieurs lignes commence par /* et se termine par */
Le langage Scriptol n'utilise jamais le même symbole pour des usages
conceptuellement différents.
+ addition - sousctraction * multiplication / division ^ puissance = opérateur d'assignement. < moins que. > supérieur à. <= inférieur ou égal. >= supérieur ou égal. := assignement conditionnel. ; est un terminateur d'instruction. , sépare les éléments d'un initialiseur ou d'un tuple. : attache un corps à une en-tête, une valeur à une clé... . associe la référence d'une méthode à un objet. () regroupe des sous-expressions, les arguments d'une fonction. .. sépare les limites d'un intervalle. -- intervalle avec la limite supérieure non incluse. [] contiennent un index ou un intervalle. ? sépare condition et action dans une structure d'une seule ligne. <> opérateur de différence. & et binaire ou intersection de de tableaux. | ou binaire ou union de tableaux. << décalage à gauche. >> décalage à droite. and et logique (sur valeurs booléennes). or ou logique. not négation logique. mod modulo (C utilise %). ~~ un code à insérer directement dans le code généré.
Les identifieurs sont les noms de variables, fonctions et objets. Ils commencent par une lettre, suivie de lettres, chiffres ou caractères de soulignement. On ne peut les différencier par la casse: on ne peut donner le même nom à deux objets différents, l'un en majuscules, l'autre en minuscules. Les mot-clés sont les mots réservés du langage, ils sont en minuscules.
Les primitives sont des objets de base. Quand elle sont les arguments d'une
fonction, la fonction utilise une copie de leur contenu, de leur valeur, et ne
modifie par l'original, tandis qu'elle utilise un alias pour les autres objets.
Les primitives de Scriptol sont celles-ci:
number toute sorte de nombre (jusqu'au double du C++). int un nombre arrondi à la partie entière. 32 bits. -1 vaut nil. integer identique. natural entier non signed de 64 bits. 0 vaut nil. real un nombre avec des décimales. -1 vaut nil. boolean la valeur vrai ou faux. text une chaîne de caractères. "" vaut nil. array une liste dynamique indexée d'objets. dict une liste associative formée de couples clé:valeur.D'autres types speciaux existent:
dyn élément générique de array ou valeur de dict. file un fichier. dir un répertoire. byte type externe de C. cstring utilisé dans les déclarations externes en langage C (traduit par char *). * désigne un pointeur de C associé à un type.
Les primitives ont des constructeurs comme les autres objets avec différents argument,
ce qui permet de les utiliser pour des conversions de type.
Syntaxe:
int(int | number | text)
Examples:
int("123") ...représente le nombre 123 text(10) ...représente la chaîne "10".
Les primitives sont des variable sauf si elles sont explicitement déclarées comme constantes, avec le mot-clé "constant".
Les nombres litéraux s'écrivent:
123 entier (int) 123n naturel (natural) 123.0 réel (real) 0.123 réel (real) 1.2e10 réel (real) 0xf8 hexadécimal true/false booléen (boolean)
Un texte litéral s'écrit: "untexte" ou 'untexte'.
Example:
print "abc$xyz" print 'abc$xyz'dans les deux cas affiche abc$xyz.
Codes d'échappement
Pour les caractères qui ne peuvent être placés directement dans un texte, on utilise le code spécial: \ Par exemple pour afficher un guillement, on écrira: "abc\"def"
\" insère un guillemet double. \' insère un guillemet simple. \n insère a retour à la ligne. \t insère une tabulation. \\ insère l'anti-slash lui-même.
Supposons que vous voulez assigner la variable a avec exactement ce texte: ma "jolie" voiture. Vous ne pouvez le mettre entre guillements: a = "ma "jolie" voiture" Le compilateur ne saura comment le traiter! Un code special est utilisé pour dire que les guillemet sont dans le texte plutôt qu'ils ne le délimitent, c'est \ a = "ma \"jolie\" voiture" Vous pouvez aussi alterner les types de guillemets: a = "ma 'jolie' voiture" ou a = 'ma "jolie" voiture'
Multi-lignes
Vous pouvez aussi avoir un texte répartis sur plusieurs lignes enclos dans les
symboles "~~".
Example:
x = ~~ ligne 1 ligne 2 ~~
Le retour à la ligne peut être direct ou introduit par un code d'échappement.
x = "un\ndeux" ...valide x = "un deux" ... non valide x = ~~un deux~~ ... valide
Si une chaîne est entre double guillemets, les séquences de caractères commençant pas $ sont des noms de variables.
text xyz = "def" text t = "abc$xyz"
De même, les symboles {} ont une signification particulière pour l'interpréteur PHP,
mais cela ne fait pas partie du langage Scriptol.
Les textes entre guillemets simples, et précédés de $ ne sont pas interprétés du tout.
text t = 'av$er\n'affichera: av$er\n
La déclaration d'une variable a la forme:
type nom [ = valeur ] int x text t = "demo"
Pourvu qu'elles aient toutes le même type, il est possible de déclarer
et initialiser plusieurs variables à la fois.
La syntaxe est alors:
type nom [= value], name [= value], etc... int x = 1, y, z = 2On ne peut mêler plusieurs types dans une seule déclaration. On ne peut faire d'assignements multiples, comme il est décrit plus loin, dans une déclaration.
int x, y = 0, 0
Le modifieur "constant" dénote une primitive dont la valeur ne peut changer. Une valeur
doit être assignée lors de la déclaration.
Syntaxe et exemples de déclarations de constantes:
constant type nom = valeur constant int X = 1 constant boolean B = true constant text T = "texte quelconque"
Les constantes sont usuellement en majuscules.
Il y a des constantes prédéfinies qui sont des mot-clés du langage:
true correspond à une expression vraie. false le contraire. zero la valeur 0. nil objet non trouvé dans une séquence (Not In List). null assigné à un objet quand il n'est pas encore initialisé.
Le mot-clé nil réfère au contenu d'un objet, tandis que null remplace une adresse.
null signifie "sans valeur", ou "déclaré mais non défini", tandis que nil signifie
"non trouvé" ou "vide".
Le mot-clé null est converti en "null" en PHP et "NULL" en C++;
Si null est assigné à une identifieur, il ne peut être référencé ou donc utilisé jusqu'à
ce qu'on lui assigne une valeur. On peut seulement le comparer dans une condition
mot-clé null.
Nil n'est pas une vraie valeur mais plutôt une construction du langage.
Voici les valeurs de nil en différents contextes...
Quand du code C++ est généré, nil est remplacé par ces valeurs:
boolean false int -1 natural 0 real -1 text "" array {} dict {} file NULL dir NULL objet NULL dyn selon le contenu.Quand on assigne nil à un intervalle dans un tableau, nil supprime cet intervalle du tableau.
Quand du code PHP est généré, nil est remplacé par ces valeurs:
retour d'une fonction: false dans une expression: false assignement: comme C++
La syntaxe d'un assignement simple est:
identifieur = expression
La valeur assignée doit avoir le type de la variable:
int i = 10 int j = "343" ... incorrect
Cependant, les constructeurs de primitives permettent de faire des conversions.
Lorsque une opération est effectuée sur une variable, et le résultat assigné
à la même variable, il est possible de simplifier l'instruction, en assignement
augmenté (d'une opération) .
La syntaxe d'un assignement augmenté est:
identifieur opérateur expression
Par exemple, ajouter 10 à x et mettre le résultat dans x. Au lieu d'écrire x = x + 10, on écrira plus simplement: x + 10
Les opérateurs possibles sont: + - * / mod << >> & | ^ #
Examples:
a = 1 ... donne à a la valeur 1. a + 1 ... ajoute 1 à a. x * y ... remplace le contenu de x par le résultat x * y. a * (x + 2) ... multiplie a par l'expression. a = a * (x + 2) ... comme ci-dessus. a & b ... remplace le tableau a par l'intersection des tableaux a et b.
Noter que dans un test de condition, x + 10 retourne simplement le résultat de l'addition de 10 au contenu de x, sans modifier x. Dans une instruction augmentée, ce résultat est affecté à x.
if x + 1 : ... ici x n'est pas modifié.
Un tuple de valeurs peut être assigné à un groupe de variable. Syntaxe et exemple:
nom [, nom]* = expression [, expression]* x, y, z = 1, x2, 8
Le nombre d'expressions à droite doit correspondre au nombre d'expressions à gauche.
Sauf dans le cas ou une seule expression figure à droite, elle sera assignée à chaque
variable du groupe.
Noter qu'une fonction peut retourner plusieurs valeurs et sera assignée à un groupe
de variables.
Exemples:
x, y, z = 0 a, b = mafonction()
Au contraire de la déclaration multiple, un assignement multiple peut
se faire avec des variables de types différents.
Exemple:
int x text t x, t = 1000, "abc"
L'assignement multiple peut s'utiliser avec les éléments d'un tableau.
Les tableaux ont une taille dynamique et donc, le nombre de cible n'a pas
besoin de correspondre au nombre d'éléments, et si le tableau n'a qu'un seul
élément, seule la première variable sera assignée.
Exemple:
x, y, z = array(1, 2, 3, 4)Est équivalent à: x = 1, y = 2, z = 3.
x, y, z = array(1)Est équivalent à: x = 1.
Vous pouvez assigner plusieurs variables à la fois avec:
- une valeur ou expression.
- un array
- les valeurs d'un dict (utiliser la méthode values()).
- un appel de fonction.
- un tuple de valeurs ou expressions séparées par des virgules.
Dans le cas d'array ou dict, de tuple, de fonction retournant plusieurs
valeurs, on affecte aux variables 1 à n les éléments 1 à n, dans le même
ordre. Si le nombre ne correspond pas, c'est une erreur.
Si la fonction ne retourne qu'une seule valeur, la même valeur est
assignée à toutes les variables à gauche.
Cet assignement spécial a pour but d'assigner une propriété ou autre variable
qui a déja une valeur par défaut, quand une nouvelle valeur est donnée.
Le symbole := assigne conditionellement une variable, si la valeur à assigner ne vaut
pas nil.
Le drapeau error est mis à "vrai" si l'expression à affecter vaut nil.
Example:
x := z error ? print "z est nil"L'instruction ci-dessus équivaud à:
if z <> nil x = z else print "z est nil" /if
Les opérateurs de comparaison sont:
= (égal) < (inférieur) > (supérieur) <= (inférieur ou égal) >= (supérieur ou égal) <> (différent)
L'opérateur "in" teste la présence d'un élément dans une séquence: texte dans un texte, objet dans un tableau, valeur dans un intervalle.
if "a" in line print "dans le texte" if x in 1..10 print "dans l'intervalle"
Les opérateurs binaires sont:
& (et) | (ou) ^ (ou exclusif) ~ (non) << (décalage à gauche) >> (décalage à droite).
Les opérateurs de tableaux sont:
& (intersection) | (union) ^ (complément d'intersection).
Précédence
Les opérateurs unaires ont la précédence sur les opérateurs binaires. Entre opérateurs de même arité, la précédence est donnée par les parenthèses.
Une expression est une combinaison de valeurs et d'opérateurs.
Expressions arithmétiques
Ce sont des valeurs arithmétiques ou des appels de fonctions combinés avec
ces opérateurs:
+ - * / ^ puissance mod modulo, retourne le reste d'une division...
Example:
print 100 mod 3 ... affiche 1 le rester de 100 divisé par 3.
Expressions relationnelles
Les expressions arithmétiques peuvent être comparées grâce à un ensemble d'opérateurs:
= égal < inférieur à > supérieur à <= inférieur ou égal >= supérieur ou égal <> différentLa comparaison retourne une valeur booléenne: true ou false (vrai ou faux). Cette valeur booléenne peut être assignée à une variable booléenne ou utilisée comme condition d'une structure de contrôle, telle que "if" notamment.
Expressions logiques
Une expression logique est une combinaison de valeurs booléennes ou
d'expressions (relationnelles ou logiques) et d'opérateurs logiques.
Les opérateurs logiques sont:
and et or ou not non
L'expression "and" retourne vrai si les deux termes sont vrais, faux sinon.
L'expression "or" retourne vrai si un des deux termes est vrai, faux si les
deux sont faux.
Example:
boolean x = true boolean y = false if x and y print "vrai"; else print "faux" ... doit afficher faux not(x or y) ... est faux x and not y ... est vrai
Expressions binaires
Les opérateurs binaires sont ceux que la plupart des langages utilisent:
& et binaire | ou binaire ^ ou exclusif ~ négation binaire << rotation à gauche qui équivaud à multiplier par 2 >> rotation à droite qui équivaud à diviser par 2
Expressions textuelles
Les opérateurs de texte sont:
=, <, >, <=, >= comparaison de deux textes. + concaténation de deux textes. [] indexation, slicing ou splicing (voir chapitre Text). in teste si un text fait partie d'un autre.
Exemple:
text t = "préfixe" print t + "suffixe" ...affichera: préfixesuffixe
Expressions de listes dynamiques
Les opérateurs de listes (array, dict) sont:
= < > <= >= <> compare les valeurs de deux listes. + concatène deux listes (des doubles peuvent en résulter). - enlève d'une liste les éléments d'une autre (sauf doubles). [] indexation, slicing or splicing (voir Array et Dict). in teste si un élément est dans la liste. & intersection. | union. ^ complément d'intersection.
L'intersection de deux listes retourne les éléments communs aux deux. L'union de deux listes retourne l'ensemble de leurs éléments. Les éléments appartenant aux deux ne sont gardés qu'une fois. Si une des listes a déja un élément en double, seule la première occurence est conservée.
Quelques langages de programmation on institué des règles de précédence,
ainsi, quand les parenthèses sont omises, on sait quel terme est concerné
par chaque opérateur.
Bien que le précédence ait été construite dans le parseur Scriptol, des
erreurs de messages seront envoyés si les parenthèses sont omises, car elles
sont nécessaires à la lisibilité.
Le seul cas ou la précédence est admise sans parenthèse est pour les
opérateurs unaires: not, ~
Un opérateur unaire s'applique toujours au terme qui le suit, donc pour
l'appliquer à une expression il faut la mettre entre parenthèses.
Exemple:
if not a and b if not (a and b)L'opérateur not est associé à l'objet "a" dans le premier, dans le second on a la négation de l'expression.
Dans les assignements composé (voir plus loin) le premier opérateur concerne la variable à assigner avec l'expression à sa droite.
Une fonction est définie avec une interface qui indique comment l'appeler, un ensemble d'instrucitons,
et se termine avec le mot-clé "return".
Le type de retour est requis et le type des arguments aussi. On utilise
"void" si la fonction ne retourne rien.
Syntaxe:
type [,type]* nom ( argument [, argument]* ) [:] ... instructions ... return [expression [, expression]*]
Example:
int multiply(int x, int y) int z z = x * y return z
Cela peut être écrit plus simplement:
int multiply(int x, int y) return x * y
Le corps de la fonction est une liste d'instructions, incluant des instructions "return"
si besoin.
La fin de définition est un return avec zéro, une, ou plusieurs valeurs.
return return x return x, y, 5
Si la fonction retourne plusieurs valeurs, elle doit avoir plusieurs types
de retour et l'instruction de retour à plusieurs paramètres (dans le même
ordre que les types de retour).
Exemple:
text, int, int coordonnees(int num) int x = matable[num].x int y = matable[num].y return "coordonnées=", x, y
Appel de fonction
L'appel d'une fonction peut assigner zéro, une, ou plusieurs variables.
mafonc() a = mafonc() a,b,c = mafonc()
Quand une fonction a des objects comme arguments, les noms des arguments sont des alias des objects, et toute modification dans la fonction sont effectués en fait sur les objets originaux. Par défaut, les primitives sont des copies et les objets des alias. On peut le changer avec un modifieur: "alias": le nom de la primitive devient un alias de l'original.
void mafonc(number x) x + 1 print x return void foncalias(alias number x) x + 1 print x return number y = 5 mafonc(y) print y ... doit afficher 6 puis 5 foncalias(y) print y ... doit afficher 6 puis 6.
Assigner une valeur par défaut permet d'ommettre un paramètre à l'appel d'une fonction. La syntaxe complète de l'interface est:
type [,type]* nom(type nom [= expression] [, type nom [= expression]]* )
Exemple:
int increment(int x, int y = 1) x + y return x print increment(10, 5) ...affichera: 15 print increment(10) ...affichera: 11La valeur par défaut 1 a été utilisée pour remplacer le paramètre manquant.
Si l'interface d'une fonction a plusieurs arugments avec une valeur par
défaut, vous ne pouvez en omettre un lors de l'appel sans omettre tous les
suivants. Les arguments ne peuvent être reconnus par leur type.
Si ce que vous voulez, c'est écrire une fonction ayant un nombre et des types
de paramètres variable, vous devez plutôt utiliser un tableau ou dictionnaire.
Example:
void param(dict parlist) taille = parlist["taille"] nom = parlist["nom"] valeur = parlist["valeur"] return
Dans cet exemple, les variables "taille", "nom", "valeur" sont globales, et
elle sont assignée par le contenu du dict en argument.
Pour que cet exemple soit parfait en fait, on devrait utiliser des assignements
conditionnels, grâce à un test. Ou grâce au symbole d'assignement
conditionnel :=
x := y
x est assigné par la valeur de y seulement si y n'est pas nil.
Le scope est un niveau de l'espace de visibilité des objets déclarés.
Une fonction ouvre un nouveau scope pour toutes les variables déclarées à
l'intérieur. Si la fonction est dans le scope global, toutes les variables
globales compilées avant la fonction sont visibles dans la fonction.
On ne peut redéclarer dans la fonction une variable avec le même nom qu'une
variable globale.
Si la fonction est une méthode d'une classe, toutes les variables déclarées
dans la classe avant la fonction sont visibles dans la fonction.
Les objets déclarés dans la fonction sont visibles dans les structures de
contrôle à l'intérieur de la fonction.
Il est possible d'empêcher que l'interpréteur PHP n'affiche les messages d'erreur ou
d'avertissement en faisant précéder l'appel d'une fonction du symbole @.
Le symbole est ignoré par le compilateur binaire.
@mafonction(x, y)
Il est utile de pouvoir passer des paramètres à un programme à partir de la
ligne de commande.
Un script Scriptol (comme PHP) utilise la variable PHP $argv".
Pour imiter la façon dont C++ passe des paramètres à un programme, créer
une fonction "main" et appelez-la avec $argv en argument (et $argc si besoin):
int main(int argnum, array arglist) print argnum, "arguments" scan arglist print arglist[] /scan return 0 main($argv, $argc) // argv and argc sont des variables PHP externes.
La fonction main, soit n'a aucun argument, soit en a deux:
int main() int main(int, array)
Echo
Affiche une expression, ou une liste d'expressions séparées par des virgules, sans
espaces entre elles et sans retour à la ligne à la fin (comme le fait print).
Syntaxe: echo expression [, expression]
Exemple:
x = 5 y = 20 z = 1 echo "values", x, y / 2 echo zCe sera affiché à l'écran comme ceci:
Exemple:
echo "demo", 5 echo "next"affiche: demo5next
Print
Un affichage plus élaboré est obtenu avec l'instruction print. Les expressions sont
séparées et on va à la ligne en fin d'instruction.
Syntaxe: print expression [, expression]
Exemple:
print "demo", 5affiche: demo 5
Une instruction print simple, sans expression, envoie un retour à la ligne.
Exemple:
Pour entrer du texte à partir du clavier, utiliser la commande input.
Un texte peut être affiché avant la saisie du texte.
Exemple:
text name input name print nameExample:
input "who are you? ", name
La variable a assigner doit être déclarée avant la commande input, ce peut être un text ou un nombre de type quelconque.
Les structures de contrôle sont:
if if else /if. if une instruction. if composite. for for /for. for une instruction. - options: in intervalle, in séquence. scan by fonction. scan une instruction. scan /scan. while while let. while une instruction. while forever do while do until. do /do condition. do case / else / always /do. enum enum simple. enum dictionnaire. error error /error. error une instruction.
Scriptol a une syntaxe différente pour les structures de contrôle d'une
instruction, ou multi-lignes.
Une structure de contrôle d'une seule instruction a la forme:
mot-clé-de-structure expression let instruction ou mot-clé-de-structure expression ? instruction ou mot-clé-de-structure expression instruction commençant par un mot-clé.Il n'y a pas d'autre marqueur de fin que la fin de ligne. L'instruction est basique et ne peut être un autre construct.
Une structure de contrôle multi-lignes a la forme:
nom-structure expression [:] ... instructions ... /nom-structureLe deux-points est optionnel (sauf si une instruction est mise sur la même ligne).
Exemple avec séparateurs:
if a = b : print t ; /if
Une structure de contrôle conditionnelle d'une ligne à la forme:
if expression-booléene let instruction [else instruction] ou: if condition let instruction ; else instructionCela se lit ainsi: si condition vraie? alors action; sinon action
Scriptol utilise soit le mot-clé "let" ou "?" quand l'action est une instruction
unique ou ":" ou un retour à la ligne quand c'est une bloc d'instructions.
Examples:
if a = 5 ? break if a < 5 ? print "moins que" else print "plus que ou égal" if a = 1 ? print "un"; else print "plusieurs"
Multi-lignes
Syntaxe:
if condition-booléenne [:] ... instruction ... else ...optionnel ... instructions ... /ifN.B.: Le symbole deux-points est optionnel après la condition, comme le point-virgule après une instruction, mais il est requis quand on concatène les lignes.
Exemple:
if (x + y) > 8 print "> 8" print x else print "<= 8" /if if (x + y) > 8 : print "> 8" ; print x ; else print "<= 8"; /if
Le construct switch case du C++ ou Java n'existe pas en Scriptol car il est
trop limité et inutile (en Scriptol). Il est replacé par une variante du
construct if plus puissante, qui peut tester tout type de variable et plusieurs
genres de comparaisons.
La syntaxe est:
if expression non-booléenne [:] operateur expression : instructions operateur expression : instructions ... else ... instructions ... /if
Une expression non-booléenne est une variable, un littéral, ou toute
expression qui ne retourne pas la valeur booléenne vrai ou faux.
On ne place pas le mot-clé "break" à la fin d'un groupe case comme en C. Un break
produirait une sortie de la structure de contrôle qui contient le construct if.
Les opérateurs valides sont:
=, <, >, <=, >=, !=, <>, in, else.
Le "else" ici est équivalent au "default" du switch case de C.
Exemple:
if a = 1: print 1 = 2: print 2 > 2: print ">2" else print "<1" /if if x in array(1,2,3): print "premier" in array(4,5,6): print "second" in array(7,8) : print "troisième" else print "autre" /if
Cettre structure de contrôle parcourt soit un intervalle d'entiers, soit une tableau et assigne
tour à tour chaque élément à une variable.
Syntaxe de for sur un intervalle:
for variable in début..fin [step s] [:] ... instructions ... /for
Début, fin, et le pas (step) sont des identifieurs ou des littéraux.
Le pas est optionnel, la valeur par défaut est 1.
La limite fin est incluse dans l'intervalle, si le symbole d'intervalle est ".." et pas
si le symbole est "-".
La fin peut avoir une valeur inférieure au début, si "step" est présent et contient
un pas négatif.
La variable conteneur peut être déclarée dans l'en-tête. Dans ce cas elle est
locale à la structure de contrôle.
Syntaxe de for sur une liste:
for variable in expression-tableau [:] ... instructions ... /for
Dans ce cas, le contenu de l'expression est parcouru et chaque élément assigné
à la variable. Cette expression doit être un tableau ou une combinaison produisant un tableau.
Exemples:
for i in 1..10 print i /for for w in montableau print w /for for w in arr1 + (arr2 & arr3[0..5]) print w /for
For à une instruction
La syntaxe courte, d'une instruction est:
for variable in liste let instruction-basiqueExemples:
for w in maliste let print w for x in 10..1 step -1 let print w + 10
Permet de scanner des tableaux et d'appliquer une fonction à chaque élément.
Syntaxe:
scan a by f ou scan a [, b, c ... ] ... statements ... /scan- a, etc... sont des tableaux (array, dict).
Le format scan by s'applique à un tableau unique pour la compatibilité avec PHP 5, on peut utiliser
plusieurs tableaux avec le format en balises, éventuellement placer l'appel de la fonction dans le bloc.
Scan applique la fonction f à chaque élément du tableau, qui lui est donné en
paramètre.
Quand le dernier élement du tableau est atteint, le traitement se termine.
Pour que l'élément puisse être modifié par la fonction, le modifieur "alias"
doit précéder le type de l'argument dans la déclaration de la fonction utilisée.
Scan by requiert une fonction définie par l'utilisateur, et non une méthode
de classe.
Sous la forme balisée, chaque élément du tableau est traité par les instructions
à l'intérieur du corps du construct. L'élément courant est accédé par
l'indexation vide [].
La syntaxe à une instruction est aussi permise:
scan a let instruction
Exemples:
array a = {1,2,3,4} void fun(number x) : print x * x; return scan a by fn scan a : print a[] * a[]; /scan
Ces deux exemples ont le même résultat.
On peut modifier le tableau avec a[] = ...
Exemples:
scan a let a[] = 0 scan a a[] * a[] print a[] /scan
Exemple avec plusieurs tableaux:
void mulfon(dyn a, dyn b) print a * b; return scan a, b by mulfon ou scan a, b let print a[] * b[]
Voici un exemple pour créer et parcourir un tableau à deux dimensions:
array a = ( ("a", "b", "c"),("x", "y", "z"), (1, 2, 3))Ce tableau contient en fait trois dyn (variables dynamiques) qui contiennent chacune un tableau.
scan a array x= a[] scan x print x[] /scan /scan
La structure de contrôle while est une boucle conditionnelle.
Syntaxe à instruction unique:
while expression let instruction
Syntaxe standard:
while expression [:] ... instructions ... /while
Exemple:
int x = 10 while x < 20 print x x + 1 /while
Une instruction "break" sort de la boucle.
Une instruction "continue" ignore tout ce qui suit et commence une nouvelle
boucle.
Cette syntaxe est recommandée pour éviter le risque de boucles infinies.
L'instruction qui fait évoluer la valeur de l'expression testée comme condition de
l'itération est déplacée après le marqueur /while grâce à l'instruction "let".
Exemple:
while x < 10 if (x mod 2) = 0 continue print x /while let x + 1
L'instruction continue saute sur l'instruction let.
Il n'y a pas d'équivalent en C ou PHP parceque l'instruction continue saute le code
qui suit, y compris l'incrémentation de x, d'ou une boucle infinie.
La syntaxe simplifiée et recommendée est:
while condition ...instructions... let incrementationExemple sur une instruction:
while x < 10 let x + 1 while x < 10 : print x; let x + 1
La condition de la boucle while peut être le mot-clé "forever", et l'on entre dans une boucle infinie, dont on sort par un break.
Le bloc d'instructions entre les marqueurs do /do est un nouvel espace de visibilité,
et les instructions encloses sont excécutée selon une condition éventuelle.
Syntaxe générale:
do ... instructions ... /do [ condition ]et /do condition peut être simplifié en "until".
Syntaxe de do until:
do .. instructions ... until expression do print x x + 1 until x = 10
C'est un puissant construct de "pattern-matching". Il contient un ou
plusieurs groupes case suivis par un "else" optionnel, et un "always"
optionnel. Un seul groupe case est exécuté, le premier dont la condition est
satisfaite. Always est toujours exécuté, else quand aucune condition n'est
satisfaite.
Syntaxe de do case:
do case condition : instructions [ case condition : instructions ] [ else instructions ] [ always instructions ] /do [while expression]
- une condition est suivie par un deux-points, ou une fin de ligne.
"else" et "always" aussi, pour homogéniser mais optionnellement. - un seul case est exécuté, ou aucun si l'expression n'est pas reconnue.
- un groupe else équivaud au "default" de de c.
- un groupe always est toujours exécuté, après un autre cas éventuellement.
- the end tag is /do or /do forever or /do while.
- Une commande forever ou while fait de la structure un automate.
Il peut falloir un break pour en sortir.
- Il ne faut pas placer un break à la fin d'un groupe comme en C. Cela quitterait la structure,
non le groupe.
Exemples:
do case nom = "pussycat": print "c'est un chat" case nom = "flipper": print "c'est un dauphin" case nom = "mobby dick": print "c'est une baleine" else print "un autre animal" /do int state = ON do case state = ON: counter + 1 case state = OFF: break always state = getState() ` une fonction quelconque /do while forever
L'automate qui lit son état à partir d'une et continue de tourner jusqu'a ce que l'état OFF soit rencontré, produit par la fonction appelée.
Le marqueur de fin do peut être complété d'une condition, while ou forever.
Le bloc d'instruction sera exécuté au moins une fois et tant que la condtion est vraie.
Syntaxe:
do ... instructions ... /do while expression do print x x + 1 /do while x < 3
Options - do ... /do ... bloc d'instructions avec ou sans groupes case. - do ... /do while forever ... boucle infinie. - do ... /do forever ... boucle infinie simplifiée. une boucle infinie requiert un "break" pour cesser de s'exécuter.
Commande pour sortir d'une boucle.
Exemple utilisant le mot-clé "forever" (pour toujours) qui crée délibérément une boucle infinie.
int x = 0 while forever print x if x > 100 break /if x + 1 /whileQuand x atteint la valeur 100, l'instruction break fait que le programme saute au-dela de /while, sur l'instuction après la structure while.
Continue
Cette seconde commande permet de sauter toutes les instructions de la position actuelle, jusqu'en fin de structure, donc de démarrer une nouvelle boucle.
int x = -1 while x < 20 x + 1 if (x mod 2) = 0 continue print x /whileCet exemple affiche seulement les valeurs paires de x, car lorsque l'on rencontre une valeur impaire, la condition x mod 2 est vérifié et une commande continue est exécutée.
Enum permet d'assigner séquentiellement des valeurs à des
identifieur, et en Scriptol, il permet d'assigner des valeurs non entière: des réels ou
des textes.
Par défaut un nombre entier est assigné, à partir de zéro, et incrémenté pour
chaque identifieur de la liste.
On utilise un double point pour assigner une valeur donnée à un identifieur et
le signe égal pour redémarrer la une valeur donnée.
Syntaxe:
enum identifieur [ : value | = value ] [ identifieur ...]* /enum
enum: Z, UN, DEUX, TROIS /enumCela assigne 0 à Z, 1 à UN, et ainsi de suite. C'est équivalent à:
constant int Z = 0 constant int UN = 1 etc... ou: enum: Z:0, UN:1, DEUX:2 /enum
Exemple plus complexe assignant des valeur hétérogènes et démarrant une séquence:
enum Z : "a0", ... assigne a0 UN : "a1", ... assigne a1 TROIS, ... assigne 0 QUATRE : 3.15, ... assigne 3.15 CINQ = 5, ... assigne 5 et redémarre la séquence SIX ... assigne 6 /enum
Exemple de syntaxe simplifiée en une instruction:
enum ZERO, UN, DEUX, TROIS
La syntaxe d'un indice dans un texte ou un tableau est: [indice]. L'indice doit être une expression simple sans crochets imbriqués. Une expression simple est un nombre littéral, un identifieur, un appel de fonction, ou une expression arithmétique et doit être évaluée comme un nombre entier.
La syntaxe d'un intervalle est:
début..finPour indicer une liste, is est enclos entre crochets:
nom-liste[début..fin]
Début et fin sont des expressions entières. Le dernier élément est inclus dans l'intervalle à moins que l'on utilise l'opérateur: "-"
a[0 -- 100] équivaud à [0..99] a[x -- y] équivaud à a[x..y-1]
Exemples d'intervalles:
0..10 x..y x * 2 / 4 .. y + 10
Vous pouvez utiliser un intervalle pour:
- tester si une valeur est dans un intervalle: if x in 10..100
- scanner un intervalle: for x in 1..100
- extraire une partie de liste: array b = a[x..y]
- changer une partie de liste: a[x..y] = autre-liste
Quand on indice une liste, la limite inférieure ou la limite supérieure de l'intervalle peut être omise.
Il y a trois moyens pour découper une liste: array a = array(x0, x1, x2, x3, x4, x5, x6, x7, x8) array b = a[..2] array c = a[3..5] array d = a[6..] On obtient trois tableaux avec ces contenus: b: (x0, x1, x2) c: (x3, x4, x5) d: (x6, x7, x8) On les affiche: b.display() c.display() d.display() On doit voir: array ( [0] => x0 [1] => x1 [2] => x2 ) et ainsi de suite...
Pour remplacer un intervalle par une autre liste, il suffit d'un assignement:
a[3..5] = array("a", "b", "c")
Le contenu devient:
(x0, x1, x2, "a", "b", "c", x6, x7, x8)
Avec la même syntaxe, on remplace une sous-liste par une liste ou un élément:
a[3..5] = "xyz"
The original liste become:
(x0, x1, x2, "xyz", x6, x7, x8)
Pour supprimer une sous-liste, on la déclare nil, "not in liste" (pas dans la liste):
a[3..5] = nil
On a supprimé la sous-liste 3..5 qui est (x3, x4, x5), on obtient:
(x0, x1, x2, x6, x7, x8)
On peut tester si une valeur appartient à une sous-liste.
Example:
array a = array("un, "deux", "trois") if "deux" in a[2..5] print "dedans"
Un texte est un objet basique avec des méthodes et qui contient une chaîne
de caractères.
Quand un texte est argument d'une fonction, la fonction utilise une copie et
non un alias sur le texte original.
Un indice peut être négatif dans un intervalle, pas dans l'indexation.
Syntaxe:
text s crée un texte. s = "str" initialise. s = s[i] prend un caractère. s[i] = s2 remplace un caractère, s2 a un seul caractère. s = s[i..j] prend une sous-chaîne, de i jusqu'à j inclus. s[i..j] = s remplace une sous-chaîne. s[i..j] = "" supprime une sous-chaîne.
Un texte litéral est une chaîne de caractères enclose par des guillemets simples ou doubles.
Le symbole + peut être utilisé avec les textes, et il représente
la concaténation de deux chaînes.
Exemple:
text b = "préfixe" text a = b + "suffixe"Le contenu de a sera: "préfixesuffixe".
Return Method Fonction Méthodes de text ---------------------------------------------------------------------------- Retour Méthode Fonction ---------------------------------------------------------------------------- text capitalize() met la première lettre en majuscule. int compare(text) compare lexicographiquement deux textes (ignore maj). retourne -1, 0, 1. text dup(int) retourne un texte dupliqué n fois. Ex: "*".dup(10). void fill(text, int) remplit avec le texte en argument dupliqué n fois. int find(text s2) retourne la position du texte s2 dans le texte, retourne "nil" si non trouvé. (tester si = nil car <> nil ne va pas en PHP) int identical(text) compare, différencie maj/min. Retourne -1, 0, 1 void insert(int, text) insère in text à la position donnée. boolean isNumber() retourne true si le texte contient un nombre. int len() retourne la longueur. int length() retourne la longueur. text lower() met en minuscules. text ltrim() supprime blancs et codes de contrôle au début. text replace(ft, rt) remplace chaque occurence de ft par rt. void reserve(int) alloue la taille donnée pour utiliser comme buffer. array split(sep) découpe le texte en éléments séparés par sep. int toInt() convertit en entier. natural toNatural() convertit en naturel. real toReal() convertit en réel. text toText() cast une chaîne littérale en text (pour C++). text trim() supprime blancs et codes de contrôle en début et fin. text rtrim() supprime blancs et codes de contrôle en fin. text upper() met en majuscules. text wrap(int size) mots non coupés. ----------------------------------------------------------------------------
Sont déclarées avec le type: dyn.
Les variables dynamiques ont les méthodes de tous les autres types de
variables mais pas les méthodes de classes déclarées (voir extern).
Quand une variable est assigned a un dyn, un cast est requis pour assigner le
contenu du dyn à une variable typée.
Méthodes de dyn
- méthodes de conversion: toBoolean, toInt, toNatural, toText, toNumber,
toArray, toDict, toFile, toObject.
- méthodes de test de type: isBoolean, isInt, isInteger, isReal, isNumber, isNatural, isText,
isArray, isDict, isFile, isObject.
- méthode arrayType (retourne le type d'un tableau typé).
Une séquence est une liste soit statique (text) ou dynamique (array ou dict).
Listes et séquences ont les mêmes operateurs, sauf # et | propres aux listes.
Les opérations sur les listes sont:
[] : indice, lecture ou modification de sous-liste. + : fusion de deux séquences. Ou ajoute un élément à une liste. - : supprime une séquence d'une autre, ou un élément d'une liste. = : comparaison de deux séquences. in : teste si un objet est dans une séquence. & : intersection de deux listes (donne les éléments communs). | : union sans doublons de deux listes.
Il y a deux sortes de listes dynamiques en Scriptol:
array: (tableau) indicé par des nombres entiers. dict: (dictionnaire) les clés sont des textes.
Un tableau est une liste dynamique d'objets ou litéraux indexée.
Un tableau vide est représenté par {}.
Un tableau litéral est une liste d'expressions séparées par une virgule
et enclose entre { }.
Une variable peut être un élément de tableau.
Le constructeur débute par le mot-clé "array".
Pour afficher le contenu du tableau a, on type a.display(), et on obtient quelque chose de la forme:
array( 0 : un 1 : deux 2 : trois )
Le constructeur d'un tableau a la forme: array(valeur, valeur, etc...)
Le nombre d'argument va de 0 à n.
Un initialiseur vide s'écrit: array()
Un tableau litéral s'écrit: { ... valeurs ... }
On peut définir un tableau en assignant le constructeur, ou un tableau litéral,
ou une valeur unique.
Syntaxe:
array a crée un tableau. array a = array() crée un tableau vide. array a = {} crée un tableau vide. array a = array(x, y, ...) crée et initialise un tableau. array a = {x, y, ...} crée et initialise un tableau. array a = { 8, 9 } assigne un tableau litéral. array a = array(8) utilise le constructeur. array a = 3 crée un tableau d'un élement.
Les éléments d'un array peuvent être toute expression, *** sauf une expression booléenne ***. Si vous placez la valeur vrai dans un tableau PHP retournera vrai chaque fois que vous utilisez l'opérateur "in", avec toute valeur cherchée.
Un tableau peut être déclaré sans assignement de contenu, et rempli par la suite:
array a a.push("un") a.push("deux") a.push("trois")
Les éléments sont retrouvés par leur position dans le tableau.
Exemples:
a[1] = "a" a[2] = "b" scan a print a[] ... doit afficher: a b
Les éléments d'un tableau sont accédés par un numéro entier.
Syntaxe:
a[n] lit l'élément ayant le numéro n. a[n] = x remplace l'élément à la position n. a[n] = nil efface un élément. a = {} efface le tableau entier. a.[n].upper() appel d'une méthode sur l'élément n du tableau.
Un index vide désigne l'élément courant:
a[] élément à la position courante.
L'indice peut être toute expression qui s'évalue en un nombre entier. L'expression ne peut contenir un élément de tableau.
a[10 + x / 2] valide. a[10 + b[5]] n'est pas valide.
Puisqu'un tableau peut contenir tout type d'objet, ou même d'autres tableaux,
il faudra une variable dynamique pour lire un élément, à moins de connâitre
le type de l'élément à lire.
array a = { x, "two", 3 } dyn x = a[1] utilisation de dyn pour lire l'élément de type inconnu. text t = a[2] int i = a[3]
Quand un élément est ajouté hors de la limite, il est placé en dernière
position dans le tableau.
Si vous assignez un élement avec l'instruction suivante, le contenu changera
selon le langage cible:
a[1000] = "x" En PHP: array( 0 : un 1 : deux 2 : le dernier 1000: x ) En C++: array( 0 : un 1 : deux 2 : le dernier 3: x )
En PHP, l'indice 1000 est seulement temporaire, et changera dès qu'une instruction
change le tableau.
Une instruction de la forme a[n] = x sert à modifier la valeur à l'indice donné,
il ne faut pas assigner un tableau de cette façon qui ne convient qu'aux
dictionnaires (dict), comme on verra plus loin.
Le contenu d'un tableau peut être parcouru par un iterateur.
On pointe sur le premier élément avec la méthode begin(), ou sur le dernier avec
end(), l'élément courrant est obtenu par un index vide de la forme [].
begin() pointe sur le premier élement et retourne sa valeur. end() pointe sur le dernier élement et retourne sa valeur. inc() déplace sur l'élément suivant. Retourne la valeur pointée avant, ou nil au-dela du dernier élément. dec() déplace sur l'élément précédant. Retourne la valeur ou nil. index() retourne l'index de l'élément pointé. value() retourne la valeur de l'élément pointé. [] indice de l'élément courant. nil signifie "not in liste" et est retourné par différentes fonctions quand aucune valeur ne peut être retournée.
Exemple d'utilisation avec le tableau a:
a.begin() ` déplace sur le premier élément while a[] <> nil ` teste si la fin de liste est atteinte print a[] ` affiche l'élément actuellement pointé a.inc() ` déplace sur l'élément suivant /while
En ordre descendant:
a.end() while a[] <> nil print a[] a.dec() /while
Une fois le tableau créé, vous pouvez appliquer différentes fonctions de liste, ou de pile...
a.push("item") ...ajoute un élément à la fin de la liste a.unshift("item") ...ajoute un élément au début de la liste a.pop() ...lit et enlève le dernier élement a.shift() ...lit et enlève le premier élement
Vous pouvez ainsi lire et éliminer les éléments d'un tableau par des
instructions successives telles que:
print a.shift()
Un intervalle est délimité par un intervalle de positions.
a[pos..fin] la rangée entre "pos" et "fin" inclus. a[..fin] du début jusqu'à la position "fin". a[pos..] de la position "pos" à la fin du tableau. a[..] prend le tableau entier (peu utile). a[pos..fin] = nil supprime une rangée d'éléments. a[pos..fin] = dyn remplace une rangée par un tableau/élément (id).
Un élément, ou un groupe d'éléments, peut être ajouté ou supprimé avec les
opérateurs + et -.
Exemple:
array a = array("un", "deux") array b b = a + array("trois", "quatre") maintenant le contenu de b est de quatre éléments. a = b - array("un", "quatre") maintenant le contenu de a est: ("deux", "trois").
Seuls les opérateurs arithmétiques + et - sont utilisables sur les tableaux, avec l'opérateur d'appartenance "in".
L'opérateur "in"
Cet opérateur peut être utilisé pour tester si une valeur est contenue
dans une liste (array, dict ou même un text), et pour parcourir le contenu
également.
Syntaxe et exemples:
if variable in array for variable in array if x in a : print "dedans"; /if if x in array(1,2,3) : print "dedans"; /if for x in a print x for t in array("un", "deux", "trois") print t
Opérateurs binaires de listes dynamiques
Vous pouvez utilisez sur des listes dynamiques (array ou dict) les opérateurs binaires d'intersection et union. L'intersection de deux listes retourne seulement les éléments qui font partie à la fois des deux listes. L'union de deux listes est une nouvelle liste composée des éléments de la première, plus ceux de la seconde moins ceux qui font déja partie de la première.
& intersection | union ^ complément d'intersection a = array(1, 2, 3, 4) & array(3, 4, 5, 6) fait que a contient (3, 4).. a = array(1, 2, 3, 4) | array(3, 4, 5, 6) fait que a contient (1, 2, 3, 4, 5, 6).
Le nombre de dimensions n'est pas limité.
Pour un tableau à deux dimensions, la syntax pour...
- accéder à un élément est: x = nomarray[i][j]
- changer un élément est: nomarray[i][j] = x
Pour créer un élément, la syntaxe est:
nomarray[i] = array() nomarray[i][j] = x ou nomarray[i] = array(x)On ne peut créer directement un élément dans un sous-tableau inexistant. L'index i et j supposent qu'il existe déja i et j éléments.
Nous devons savoir comment les clés entières d'un tableau en PHP
changent selon les opérations que l'on peut accomplir. C'est important
pour comprendre les tableaux associatifs et éviter pas mal de bogues.
Après chaque opération le contenu est affiché.
array a = {} array ( ) a.push("un") array ( [0]=> un ) a + array("deux", "trois", "quatre") array ( [0]=> un [1]=> deux [2]=> trois [3]=> quatre ) a.shift() ... le premier élément est supprimé et les clés sont renumérotées. array ( [0]=> deux [1]=> trois [2]=> quatre ) a[1000] = "mille" array ( [0]=> deux [1]=> trois [2]=> quatre [1000]=> mille ) a.unshift("x") ... toutes les clés sont renumérotées, même la clé 1000. array ( [0]=> x [1]=> deux [2]=> trois [3]=> quatre [4]=> mille ) Créons deux nouveaux tableaux: array a = array("un","deux") array b = array() b[1000] = "mille" a + b Les clés sont renumérotées. array ( [0]=> un [1]=> deux [2]=> mille )
Si on remplace a + b par a.push("mille") le résultat sera le même.
Un dict est une liste dymamique de couples clé et valeur. Les clés sont
toujours des textes. Les valeurs peuvent être tout objet.
La clé et la valeur peuvent être des variables.
Le format pour un couple clé et valeur est: clé:valeur.
(L'équivalent PHP est: clé => valeur).
Un dict vide est représenté par {}.
Un dict litéral est une liste de couples separés par une virgule,
et enclos entre {}t.
Au contraire du tableau, le dict est rempli avec des assignements:
d[k] = "b" d["un"] = "element 1"
Array et dict ont les mêmes méthodes, mais certaines sont plus utiles avec l'un ou l'autre type.
Un dict peut être créé à partir d'un litéral ou un constructeur.
Syntaxe:
dict d crée un dict. dict d = {x:v, y:w,...} crée et initialise un dict. dict d = dict(x:v, y:w,...) c crée et initialise un dict.
Les valeurs peuvent être tout type d'objet.
La clé peut être une variable et la valeur une expression.
Exemple:
text k = "a" text v = "b" dict d = dict(k : v) dict d = dict(k : v + "x".dup(4) + 20.toText())
Cet exemple enregistre "bxxxx20" dans le dict d, avec la clé "a".
Les valeurs dans un dict sont accédées par une clé textuelle.
Syntaxe:
d["clé"] prend le premier élément avec la clé "clé". d[clé] = valeur remplace une valeur ou ajoute un couple clé-valeur si la clé n'est pas déja dans le dict. d[clé] = nil supprime un élément. d = {} efface le dict. Exemple: dict d d["program"] = "ce que l'on veut accélerer" print d["program"] affiche le texte ci-dessus.
La façon normale d'utiliser un dictionnaire est par le moyen des clés ou
itérateurs. En quelques occasions il peut être utile d'accéder à un intervalle
de valeurs directement.
- Quand on ajoute un élément ou un autre dict à un dict, au moyen d'intervalle,
de push, unshift, PHP génère une nouvelle clé pour cet élément. La nouvelle
clé est un nombre.
- Si vous remplacez un intervalle par un autre dict, certains éléments peuvent
être perdus. Cela se passe aussi lors de la fusion.
- Les clés du dict qui replace un intervalle ne sont pas conservées.
Exemples d'affichage:
Il doivent présenter toutes les clés et valeurs dans le dict.
dict d = {"a":"alia", "b":"beatrix", "c":"claudia"} création du dict d.display() affichage for k,v in d : print k, v; /for affichage avec une boucle for number i = 0 d.begin() while i < d.size() affichage avec un itérateur print i,"i", d.clé(), d[] d.inc() /while let i + 1
Exemple: lire le dernier couple:
v,k = d.end(), d.key()L'ordre est important car d.end() déplace le pointeur à la fin.
Return Name Actiondyn begin() pointe sur le premier élément. dyn dec() retourne un élément et décrémente le pointeur. void display() affiche le tableau. dyn end() pointe sur le dernier élément. boolean empty() return true si le tableau est vide. int find(dyn) recherche un élément, retourne l'index ou nil. void flip() les valeurs deviennent clés et inversement. dyn inc() retourne un élément et incrémente le pointeur. int index() retourne l'index de l'élément pointé. void insert(int, dyn) insère un élément à un index entier (pas un text). text join(text sep) convertit en text avec le séparateur donné. text key() retourne la clé de l'élément pointé. void kSort() réordonne les index en préservant les associations. boolean load(text nom) charge un fichier dans un tableau ("file" de PHP). dyn min() retourne la valeur la plus faible. dyn max() retourne la plus forte valeur. void pack() rend les éléments du tableau consécutifs. dyn pop() lit et supprime le dernier élément. dyn pop(int) lit et supprime l'élément à la position donnée. void push(val) ajoute un élément à la fin. dyn rand() retourne un élément à une position aléatoire. array reverse() retourne la liste en ordre inversé. dyn shift() lit et supprime le premier élément. int size() retourne le nombre d'éléments. void sort() trie les valeurs en ordre ascendant. void store(text nom) sauve le tableau dans un fichier. number sum() calcule la somme des éléments. array unique() retourne le tableau sans valeur en double, la première est gardée. void unshift(dyn) insère un élément en première position. dyn value() retourne la valeur pointée. k,v = d.key(), d.value() lit le couple clé:valeur
Un tableau typé contient un type d'objets unique. Il est beaucoup plus
efficient que le tableau commun parcequ'il est indexé, et non associatif,
et contient directement des objets de 32 ou 64 bits ou des pointeurs,
plutôt que des objets dynamiques (dyn).
Un tableau d'entiers est 100 fois plus rapide qu'un tableau standard pour les
exécutables binaires, mais il n'y a pas de différence en PHP.
Les tableaux typés sont aussi dynamiques, la taille n'est ni prédéfinie, ni limitée.
Le constucteur d'un tableau typé a la forme:
type(...éléments...) Exemple: int(1, 2, 3)Le nombre d'élément va de 0 à n.
Quand il y a un seul élément, il n'y a pas de différence entre une constructeur de tableau typé et un constructeur scalaire:
int(1) text("text")Ce n'est pas un problème lors de l'assignement, puisque l'on peut créer un tableau à un seul élément à partir d'un scalaire, mais il y a ambiguité dans une expression.
type{...éléments...}Les accolades ont la signification "tableau de".
La syntaxe pour déclarer un tableau d'entiers est:
int[] i = int(x, y, ....)Une fois qu'il est déclaré, il est utilisé comme un tableau mixte, mais seuls les nombres entiers peuvent être ajoutés au tableau.
Exemples:
int[] x = int(5) int[] x = int(1,2) int[] x = y + int{5}
La déclaration est:
text[] t = text(a, b, "demo", ...)Les règles sont les mêmes que pour les entiers.
Les déclarations sont:
real[] r = real(1.0, 2.0, etc...) natural[] n = natural(1, 2, etc...) number[] n = number(1, 2.0, ...)
La déclaration est:
class uneclasse ... /class uneclasse objet1 ... instance uneclasse objet2 ... instance objet[] = objet(objet1, objet2, ...) ... tableau d'objets
Vous pouvez assigner un tableau typé à un tableau mixte:
Exemple:
int[] i = int(...) array a = iMais vous ne pouvez créer un tableau mixte avec un constructeur typé:
Exemples:
{1,2,3} ... c'est un tableau mixte, avec des éléments entiers int[] i = {1,2,3} ... NON VALIDE, il faut plutôt écrire: int[] i = int{1,2,3} ... valide.
Exemples:
array a = int(1,2) ... NON valide array a = array(int(1,2)) ... NON valide
On peut assigner un tableau typé à un dyn.
int[] i = int(1,2) dyn d = dyn(i)
Deux méthodes sont fournies pour utiliser ce dyn:
arrayType() retourne le type de tableau contenu dans le dyn.
toList(int = 0) retourne le tableau typé contenu.
Le paramètre est le type, et est requis quand le dyn se
contient tableau mixte, que l'on veut convertir en
tableau typé.
Types reconnus:
$TYPE_INT tableau d'entiers $TYPE_TEXT $TYPE_REAL $TYPE_NATURAL $TYPE_NUMBER $TYPE_OBJECT
Exemple:
d = dyn(int(1,2)) if d.arrayType() = $TYPE_INT: int[] i = d.toList() = $TYPE_TEXT: text[] t = d.toList() /if
Pour la compatibilité avec PHP, ajouter un élément à un tableau au-dela
de la taille actuelle, a le même effet qu'ajouter cet élément, quelque
soit l'index donné.
Par exemple:
int[] i = nil i[10] = 10 équivaut à: i.push(10)
Empiler des valeurs est le moyen correct pour remplier un tableau.
Si on veut réellement placer un élément à une position donnée, on doit
remplier le tableau avec des valeurs nulles...
for int k in 0 .. 10 let i.push(0)Vous pouvez maintenant placer un élément en position 10.
- On ne peut appliquer une méthode directement à un élément indicé.
i[10].toText() .. non valide int x = i[10] x.toText() .. valide
- Vous ne pouvez comparer directement un élément et une chaîne. Ex:
text[] t = text("un", "deux") if t[0] = "one" .. non valide text t2 = t[0] if t2 = "one" .. valide
- Avec PHP 4.3, insérer un objet dans un tableau fait que les valeurs sont insérées,
pas le tableau lui-même! Je considère que c'est une boguee tdonc vous ne
pouvez insérer directement des objets, mais vous pouvez insérer un tableau
d'objet.
- La fonction "array_diff" de PHP ne fonctionne pas quand le tableau contient des
objets, on ne peut donc soustraire de tels tableaux.
File est un objet virtuel, pour traiter des fichiers locaux ou distant.
Pour une explication complète du système de fichier, voir "fopen"
dans le manuel C ou PHP.
Un objet file est créé par la déclaration d'une instance de type file. Le fichier
sur le disque est créé par la commande open. Elle permet d'accéder à un fichier
en différents modes, selon le second paramètre de la méthode.
La structure de contrôle error permet de tester si le fichier a été ouvert correctement
ou non.
Syntaxe pour créer ou ouvrir un fichier:
file nomfic declare un file. nomfic.open(path, mode) ouvre un fichier selon un chemin et un mode. Types de chemins: http://path fichier distant http. ftp://path fichier distant ftp. path fichier local. Modes: "r" lecture seulement, à partir du début. "w" écriture seulement à partir du début. "r+" lecture ou écriture au début du fichier. "a" ajout en fin de fichier en écriture seule. "a+" lecture à la position courante, ou écriture à la fin.
Les méthodes de fichier sont:
return méthode action int eof() retourne true quand la fin de fichier est atteinte. int open(text, text) crée ou ouvre un fichier. Positionne le drapeau "error". int close() ferme le fichier. text read(int) lit un bloc selon la taille en argument, retourne un text. text readLine() lit et retourne la ligne suivante dans un fichier de texte. int seek(int) va à la position donnée en argument, retourne 1 si ok. int size() retourne la taille du fichier. int time() retourne la date de dernière modification. int write(text) écrit le texte donné en argument, retourne la taille écrite. void writeLine(text) écrit le texte en argument.
Exemples:
file nomfic crée un objet file. nomfic.open("monfichier", "r") ouvre un fichier physique. nomfic.close() ferme le file. boolean b = nomfic.eof() assigne vrai à b si la fin de fichier est atteint. nomfic.seek(250) lecture ou écriture en sautant 250 octets.
Les fichiers distants ne sont pas gérés par Scriptol C++ et l'interpréteur pour l'instant.
Un fichier peut être lu ligne par ligne, ou par blocks binaires.
Dans le premier cas, la méthode readLine() est utilisée, sinon, on utilise
la méthode read avec la taille du bloc en paramètre.
Le code de fin de ligne dans le fichier est inclus, et peut être supprimé par la
méthode rTrim().
Exemples:
text t = nomfic.readLine() lecture d'une ligne de texte. text t = nomfic.read(1000) lecture de 1000 octets.
La méthode write place le contenu d'une variable de texte dans un fichier.
Une fois le fichier ouvert soit avec le mode "w" ou "a", et donc enregistré
soit à partir de zéro ou à la fin de son contenu actuel, chaque nouvel appel à
write ajoute un nouveau texte à la fin.
Exemple simple:
text nomfic = "monfic" ` nom du fichier file sortie ` nom de l'objet virtuel sortie.open(nomfic, "w") ` ouvert en écriture error? die("impossible d'ouvrir " + nomfic) for text ligne in maliste ` un tableau quelconque sortie.write(ligne) ` enregistrer un élément /for sortie.close() ` fermer le fichier
Le type dir a pour méthodes le constructeur et get(),
et sert à utiliser les fonctions intégrées de gestion de répertoire.
Le constructeur sert à créer un dir ou à l'afficher.
void dir(text) constructeur. L'argument est un chemin. array get() retourne le contenu du répertoire dans un tableau.
print dir("c:/jeux") ou dir x = dir("sousdir") print x ou array a = x.get() a.display()
Le séparateur de répertoires est "/" pour tous les systèmes.
Les fonctions de gestion de répertoires sont:
dir opendir(text) ouvre un répertoire, retourne un dir. text readdir(dir) lit l'entrée suivante et retourne le nom. void closedir(dir) ferme le répertoire. void rewinddir(dir) revient à la première entrée. boolean is_dir(text) retourne vrai si l'entrée est un répertoire. boolean is_file(text) retourne vrai si l'entrée est un fichier.
Les fonctions chdir, mkdir, rmdir sont détaillés dans le chapitre sur les fonction intégrées.
Exemple d'utilisation qui affiche le contenu d'un répertoire:
dir monrep = opendir("/chemin") while forever text t = readdir(monrep) if t = nil break if t[0] <> "." print t /while
Après une instruction open, le construct error ... /error devrait être exécuté en cas d'erreur d'accès. Mais l'interpréteur peut stopper le programme avant d'atteindre le construct. Sinon le contenu du bloc sera exécuté en cas d'erreur.
La syntaxe est:
xxx.open("nom fichier") error ...instructions... /error ou: xxx.open("nom fichier"); error ? action ou: xxx.open("nom fichier"); error action
Exemple:
file monfic monfic.open("nom", "r") error? exit()Si le fichier n'est pas trouvé ou ne peut être ouvert, le programme s'arrête.
Les règles de visibilités sont celles des principaux langages procéduraux, non celles des
langages de scripts.
Scriptol ajoute des règles de sureté, il ne permet pas de donner le même nom à
deux objets dans les scopes imbriqués (par exemple, dans le scope global et
celui d'une fonction). Mais les mêmes noms peuvent se réutiliser dans des
scopes successifs.
Il y a quatre niveaux de visibilité: - global, - classe, - corps d'une fonction, - et le corps d'une structure de contrôle.
La visibilité d'une variable est le niveau dans lequel elle est déclarée: global,
classe, fonction ou bloc délimité (if, do, for, etc.), ainsi que les niveaux contenus.
On ne peut redéclarer une variable là ou elle reste visible. On ne peut la
redéclarer que quand son scope est clos, dans des fonctions successives ou
des structures de contrôles successives.
L'en-tête du construct for fait partie du scope du bloc.
for text t in a t est visible seulement dans la boucle for. t = a.inc() /for
La partie let qui termine une boucle while est dans le scope de la boucle.
Les arguments d'une fonction sont dans le scope de la fonction.
A l'intérieur d'une fonction, si une variable est référencée avant tout
assignement, elle reférence une variable globale si elle existe, sinon c'est
une erreur.
A l'intérieur d'une méthode d'une classe, si elle est référencée avant tout
assignement, elle référence un attribut s'il existe, sinon c'est une erreur.
Les variables globales ne sont pas visibles dans une classe, sauf les variables
externes.
Les variables externes (celles de PHP, Apache, etc...) sont toujours dans le
scope, puisqu'il n'y a pas de contrôle sur elles. Donc vous devez connaître
leur nom pour ne pas le réutiliser, car les variables Scriptol sont
transformée en variable PHP avec $ devant.
Si vous utilisez des variables externes dans une fonction, il faut les déclarer
"global", car le compilateur ne les gère pas.
Les fonctions, variables et constantes PHP ou C++ peuvent être utilisées
dans du code Scriptol, comme des objets Scriptol.
Leur visibilité est externe, donc elles sont visibles comme les objets globaux
on de classes.
Les variables et constantes de PHP peuvent être utilisées comme celles de Scriptol
dès lors qu'elle sont déclarées avec le mot-clé "extern".
Les déclarations externes comme les includes sont placées en tête de fichier.
La syntaxe pour une variable externe est:
extern type identifieur extern constant type identifieur
Aucun test de contrôle sur le type ou le scope d'un objet externe.
Dans une fonction il faut une déclaration "global".
Exemple:
global argv array a = $argv
Une constante PHP est déclarée comme une variable avec le mot-clé "constant":
extern constant text PHP_VERSION ... print PHP_VERSION
Il est possible aussi d'utiliser une variable PHP ou C++ sans déclaration avec le
préfixe $ suivie d'un identifieur.
Celui-ci peut commencer par un caractère de soulignement.
$var_name $(constant_name) in PHP $constant_name. in C++
Les fonctions PHP peuvent être utilisées sans déclaration, ce qui n'est pas le cas
des fonctions C++.
On peut aussi les déclarer avec le mot-clé extern. Une valeur par défaut est
spécifiée par un assignement. Cette valeur est utilisée en C++, elle est ignorée par PHP.
Syntaxe et exemple:
extern type identifieur(... arguments...) extern text substr(text, int, int = 0)
Pour utiliser les méthodes de classes PHP ou C++, vous devez déclarer ces
classes et les membres que vous voulez utiliser.
Exemple:
extern class phpClass int phpAttribute void phpMethod(int argument) ... déclaration ... /class /extern
C++ permet de définir des types avec les directives "typedef" and "#define".
Il est possible d'intégrer ces nouveaux types avec l'instruction Scriptol
define.
Exemple: define uint
Cela correspond à "#define uint unsigned int" en C++.
Aucun code n'est généré par l'instruction define: le code C++ doit se
trouver dans un fichier C++ à inclure.
Voir "L'instruction define" pour plus de détails.
Si vous vouler insérer directement du code PHP dans votre programme,
utilisez les symboles ~~ pour définir le début et la fin du code à inclure.
Le compilateur ignore les contenu, comme s'il s'agissait de commentaires mais l'inclu
dans le code généré, PHP ou C++.
Vous pouvez insérer du code spécifique PHP ou C++ dans un même programme.
- Pour insérer du code PHP, utiliser:
require_once("lecode.php")
Cette instruction n'a d'effet que pour l'interpréteur PHP, compilée en C++
elle est ignorée.
- Pour insérer du code C++, utiliser:
#include "lecode.c++"
Ce sera compilé en C++, mais pour l'interréteur PHP c'est un commentaire.
Une classe est une structure qui contient des variables (attributs) et a des
fonctions (méthodes).
Une fois qu'une classe est définie, elle devient un nouveau type complexe du
langage avec lequel on déclare des objets, instances de la classe.
On utilise les attributs et méthodes de l'objet avec une commande de la forme:
x = objet.attribut objet.methode()
La description d'une classe débute avec le mot-clé "class" et se termine par "/class".
Les attributs (variables) doivent être placés avant les fonctions. Une classe ouvre un espace de visibilité. Les variables globales et les fonctions définies ne sont pas visibles à l'intérieur d'une classe. Les attributs et méthodes de la classe ou d'une instance d'une autre classe sont visibles dans toutes les méthodes de la classe avec le nom de l'instance en préfixe.
Exemple d'une déclaration de classe: class voiture ...membres... /class Exemple de classe avec attributes et méthodes: class voiture int lavitesse = 50 int passagers = 4 void voiture.vitesse(int i) int x = lavitesse * 2 return x /class Exemple d'instance avec référence aux méthodes: voiture mavoiture print mavoiture.passagers print mavoiture.vitesse()
Un constructeur est une méthode dont le nom est celui de la classe et qui
est appelée lors de la création d'une instance de la classe.
Il a toujours le type de retour "void", qui signifie: rien.
Exemple de constructeur:
class Voiture int vitesse void Voiture(int p) ` cette méthode est un constructeur vitesse = 0 ` vitesse est initialisée lors de la déclaration d'une instance return /class
La syntaxe pour créer une instance est:
Nomclasse nominstance = Nomclasse(argument [, arguments])
ou:
Nomclasse nominstance pour un constructeur sans arguments
Example:
Voiture mavoiture = Voiture(60) ... crée une voiture avec une vitesse de 60 Camion moncamion ... equivalent à ci-dessous Camion moncamion = Camion()
Il peut être pratique de rassembler toutes les fonctions concernant une tâche dans une classe et les déclarer "static". Ces fonctions peuvent alors être appelées directement avec le nom de la classe, sans avoir à créer d'instance.
Exemple:
node, ext = Dir.splitExt(chemin)
Les attributs peuvent également être statiques. Un attribut
statique est commun à toutes les instances et celles qui sont héritées.
Une méthode statique ne peut référencer des attributs, puisqu'ils n'existent
que dans les instances de la classe sauf s'ils sont statiques aussi.
On ne peut appeler une autre méthode dans le corps d'une méthode statique..
Le mot-clé "static" doit précéder le type de l'objet.
Un message d'erreur est émis quand une fonction statique utilise un attribut
non statique ou qu'elle appelle une autre méthode.
Exemple d'attributs et méthodes statiques:
class Voiture static usine = "Xxx" static void denomme(text x) usine = x return /class Voiture.denomme("nom") Voiture.usine = "nom"
Attributes et méthodes statiques peuvent être associés à une instance également:
Voiture maVoiture maVoiture.denomme("nom") maVoiture.usine = "nom"
L'effet sera le même.
Une classe peut hériter des attributs et méthodes d'une autre classe,
si elle est déclarée sous-classe de celle-ci.
La classe "nom" hérite des attributs et méthodes de "autrenom".
Cela fonctionne aussi avec les attributes et méthodes statiques.
La syntaxe de la déclaration d'héritage est:
class nom is autrenom
Exemple:
class Vehicule int fuel void Vehicule() fuel = 100 return /class class Voiture is Vehicule int passagers void Voiture() passagers = 3 fuel = 50 return /class class Camion is Vehicule int charge void Camion() fuel = 200 charge = 1000 return /class Camion bibendum Voiture daisy print bibendum.charge attribut de la classe Camion print bibendum.fuel attribut de la superclasse Vehicule print bibendum.passagers mauvais! passagers non accessible à Camion! print daisy.passagers bon, passagers est attribut de Voiture
Une méthode peut être redéfinie avec des arguments différents, à la fois
dans la même classe et dans les classes dérivées. Le type de retour de
toutes les versions de la méthode doit être le même.
Exemple:
void ajoute(int x, int y) void ajoute(real x, natural y)
Vous avez juste à appeler la méthode "ajoute" avec le type d'arguments voulus,
le compilateur associe la définition correspondante...
Le langage cible C++ requiert que les méthodes surchargées aient le même type
de retour, cela est conservé en Scriptol.
NOTE: XML statique est implémenté dans l'interpréteur uniquement pour le moment.
Le compilateur Scriptol en binaire, utilise la class dom, avec des méthodes similaires,
et requiert le fichier libdom.sol, qui décrit la classe.
Le compilateur Scriptol en PHP ne reconnait pas XML pour le moment.
A l'avenir le présent chapitre s'appliquera également aux compilateurs.
XML est une structure de données en Scriptol. Un document XML est défini sous
forme light, et ensuite utilisé pour stocker et délivrer des données, juste comme une
classe, avec plus de flexibilité.
Le document XML peut être utilisé statiquement, seul le contenu des éléments
et les valeurs des attributs sont modifiés.
On accède à un élément par la liste chaînée des noms d'élément le contenant.
dom.document.client.getData()
Des méthodes permettent aussi de changer la structure, ajouter ou supprimer des éléments. Ceci est couvert dans la section "XML dynamique".
Un document XML peut être inclus dans un source scriptol sous forme "légère",
sans les crochets angulaires.
La syntaxe d'une structure XML est:
xml [name] ... un nom optionel pour le document. [headers] ... des éléments d'en-tête optionels. [doctype] ... des "doctype". tag ... un ou plusieurs éléments balisés. /xml
En-tête
Syntaxe:
<? identifieurs et attributs ?>
Doctype
Syntaxe:
<! identifieurs et attributs >Noter que cela finit par > et non !>
Element
Un élément balisé a la forme:
nom [attribut [[,] attribut]* ] une liste d'attributs optionels [nom2]* aucun, un ou plusieurs sous-éléments. text ou un texte. ... / nom le nom de l'élément ici est optionel;
Si la liste des attributs continue sur la ligne suivante, une virgule doit
être au moins à la fin de la ligne.
Un document XML se déclare comme une classe, enclos entre les marqueurs XML et /XML,
au format light.
xml nomdocument nomelement [attributs] "données" ou ~~ données sur plusieurs lignes ~~ ou éléments imbriqués / nomelement /xml
On déclare ensuite des instances XML.
nomdocument instance1 nomdocument instance2
Les instances sont créées lors de la compilation, les changement sur le document lors de l'exécution ne se retrouveront pas dans les instances.
Des documents externes sont chargé dans un programme Scriptol avec la méthode "load", et un nom de fichier ou chemin en paramètre.
xml x /xml x.load("demo") ou: x xinstance xinstance.load("demo")
Le document, chargé et complété, ou défini dans un source Scriptol, est sauvé avec la méthode "save" et un nom de fichier ou chemin en paramètre.
Vous pouvez assigner à une instance XML un document. Il faut pour cela déclarer
un document maître XML vide, servant à déclarer l'instance, avant de l'assigner.
Exemple utilisant "nomdocument" défini ci-dessus.
xml dom /xml dom instance1 = nomdocument
Le contenu de "instance1" est maintenant celui du document "nomdocument".
Vous pouvez créer autant d'instances de "dom" que vous voulez.
L'itérateur est un ensemble de méthodes qui peuvent être utilisées avec les méthodes
de balise.
Les méthodes de balises sont associées au nom du document ou d'instance de document,
mais concernent la balise actuellement pointée.
Pour parcourir le contenu d'un document ou d'une instance, on utilise un itérateur,
qui se compose de plusieurs méthodes:
reset() aller au premier élément du document. begin() aller au premier élément du niveau courant. inc() pointer sur l'élément suivant. found() retourne vrai si un élément est trouvé par la méthode inc() ou down(). down() pointer sur l'élément contenu. up() revenir à l'élément contenant.
Le document peut être parcouré en partant de la fin avec ces méthodes:
end() aller au dernier élément du même niveau. dec() pointer sur l'élément précédent.
Exemple d'utilisation d'itérateur:
demo.reset() demo.down() while demo.found() print demo.getData() let demo.inc()
L'itérateur agit sur un niveau du document. Pour atteindre un niveau donné de contenu, on utilise la méthode at() avec la liste chainée des noms de niveaux contenants.
xml demo document element "data'" / element "data" / / /xml demo.document.element.at()
Nous sommes au niveau de "element" contenu dans document. La méthode reset() ramène l'élément courant au début du document.
On accède au contenu contenu d'un élément avec deux méthodes de balises, getData et setData:
text getData() retourne le contenu. void setData(text) change le contenu.
Ces méthodes sont associées au nom d'un document ou d'une instance, et concernent l'élément actuellement pointé.
nomdocument.getData() instance1.setData("quelque texte")
On accède à un attribut comme à un élément de dictionnaire. L'attribut est reconnu par son nom en paramètre de la fonction getAttribute() ou setAttribute().
xml doc elem1 att = "valeur" /elem1 /xml print doc.getAttribute("att1") doc.setAttribute("att1", "nouvelle valeur")
Vous pouvez utiliser une instance de document XML comme argument d'une fonction,
et en retourner par une fonction.
L'argument est une nouvelle instance et non pas un pointer sur l'instance originelle,
et l'objet retourné est aussi une nouvelle instance.
Un document XML peut être défini à l'intérieur d'une fonction. Si le document doit être retourné par la fonction, c'est un pointeur sur le document qui sera retourné, pour augmenter la vitesse d'exécution.
xml dom /xml dom mafonction() xml demo nomelement "contenu" / /xml return demo dom x = mafonction() print mafonction()
Ce chapitre décrit les fonctions pour modifier la structure d'un document XML ou d'une instance.
void clear()
Efface le contenu du document.
XML addChild(XML)
Ajoute un descendant à l'élément courant du document.
Le nouvel élément devient l'élement courant.
xml demo doc / /xml xml element inner "quelque texte" /inner /xml demo.addChild(element)
xml addNext(xml)
Ajoute un élément après l'élément courant du document.
Le nouvel élément devient l'élément courant pour le document.
Méthodes Définitions ------------------------------------------------------------------------------------ xml addChild(xml) Ajoute un descendant à l'élément courant. xml addNext(xml) Ajoute un successeur à l'élément courant. xml append(xml) Ajoute un autre document à la fin du document. Retourne le document augménté. xml at() Retourne l'élément pointé, sous forme de document XML. xml at(text) Pointer sur un élément dans le niveau, son nom en paramètre. xml at(text, text) Pointer sur un élément trouvé par l'attribut et sa valeur, en paramètres. xml begin() Pointer le début du niveau. Concrètement, sur le child du parent de la balise courante. void clear() Efface le contenu du document. xml clone(xml) Copie le contenu du document dans le document en paramètre. void display() Affiche le document. xml down() Aller sur le premier sous-élément de la balise courante. boolean empty() Retourne true si le document ne contient aucun élément. xml end() Aller sur la dernière balise du niveau. boolean found() Retourne true si dec ou inc ont atteint une balise, false sinon. text getData() Retourne le contenu de la balise courante. text getValue() Retourne la valeur de l'attribut en argument. boolean hasAttribute(text) Retourne true si l'attribut en argument existe dans la balise courant. xml inc() Pointe la balise suivante. int length() Retourne le nombre de balise dans le niveau. boolean load(text) Charge le fichier nommé en argument dans le document déclaré. xml reset() Va au premier élément du document. boolean save(text) Sauve le document dans un fichier nommé en argument. Retourne true si ok. void setData(text) Modifie le contenu d'une balise. void setValue(text, text) Modifie la valeur d'un attribute, ou le crée. xml up() Va au premier élément qui suit le conteneur de la balise courante. void xml([xml]) Constructeur, avec en option un autre document comme source. ------------------------------------------------------------------------------------
La syntaxe pour inclure un fichier Scriptol externe est:
include "nomfichier.sol"
Les parenthèses sont optionnelles. Les guillemets simples ou doubles sont
requis. Si vous voulez utiliser directement un fichier PHP, et que le
compilateur ne le traite pas, voir ci-dessous.
Seuls les fichiers avec l'extension ".sol" seront traités par les
compilateur, si elle est différente:
- solp (php) ignorera l'instruction.
- solc (c++) passera l'instruction au compilateur C++.
Si, au contraire, vous vouliez inclure un fichier dans le code PHP généré
et pas dans le code C++, vous pouvez utiliser la fonction require_once("nom de fichier")
qui sera ignorée par le compilateur en C++ solc, car l'insertion dynamique
ne peut se faire en C++.
Cette instruction permet de définir de nouveaux types que le parser puisse reconnaître, comme des primitives ou des classes.
Vous pouvez utiliser une fonction comme argument d'une autre fonction en
la définissant en tant que type. Cela ne fonctionne qu'au niveau global et
pas dans une classe. Une fois un type défini, on ne peut le redéfinir.
1) définir une fonction:
Exemple:
int compare(int a, int b) boolean b = (a < b) return b
2) définir un type, en utilisant cette fonction comme modèle:
define COMP = "compare"
3) définir une autre fonction générique qui utilisera cette fonction comme argument:
void mafonc(COMP a, int x, int y) print a(x,y) return
4) utiliser la fonction générique:
L'argument peut être la fonction originelle ou une autre fonction avec mêmes arguments
et même types de retour.
mafonc("compare2", 10, 8)
Vous pouvez maintenant définir une autre fonction, "mul" par exemple,
selon le même modèle, donc avec le même type de retour et d'arguments,
que la fonction "add", et l'utiliser à la place.
mafonc("mul", x, y)
La syntaxe:
define NOUVEAUTYPE
define NOUVEAUTYPE as
crée un nouveau type que l'on peut utiliser en argument de fonctions
externes. Voir les exemples GTK sur l'utilisation d'un type externe.
Le modificateur "as" fait que le nouveau type n'est pas considéré comme une
pointeur. Donc l'utiliser comme une primitive, comme uint ou gint par exemple.
Scriptol peut utiliser les fonctions PHP. Aucun contrôle n'est
effectué sur les arguments et types de retour des fonctions PHP.
Il faut juste configurer php.ini pour rendre les extensions visibles à
l'interpréteur PHP.
Les fonctions PHP les plus usuelles sont incluses dans la librairie Scriptol.
Pour utiliser les fonctions de librairies PHP dans un programme exécutable,
il faudra écrire une interface à inclure dans le projet. phpgd.h et phpgd.cpp en est un
exemple.
Une bibliothèque de fonctions en C ou C++, peut être utilisée simplement
par l'ajout du fichier ".lib" ou ".a" ou ".so" à la liste dans le fichier de
configuration ".ini" ou ".cfg".
Un fichier à inclure doit être écrit pour rendre visible au compilateur les
variables et les classes de l'extension ajoutée.
L'instruction "define" permet de créer un type pour donner une fonction en
paramètre d'une autre fonction.
Il est possible de déclarer directement des variables C:
extern ~~extern char *message~~ pour le fichier d'en-tête. char *message pour la visibilité en scriptol. /extern ~~char *message~~ création effective de la variable C.
Equivalences:
C Scriptol ---------------------------------------------- char * cstring void * object char ** cstring * unsigned char byte
- Un nom de fonction foncname en argument est écrit "foncname", voir define.
- Une fonction interne ne peut être utilisée en argument. Il faut l'encapsuler
dans une fonction définie par l'utilisateur.
- Si une instance est déclarée sous la forme C++: NomClasse instance, il
faut créer un pointeur plutôt (selon la forme C++: NomClasse *instance).
Ces fonctions sont communes à PHP, C, C++ et Scriptol. Si le nom PHP diffère, il est donné dans la liste.
La liste complète est dans le fichier fun.hpp.
void die(text message) Affiche un message en quittant le programme. void exit() Quitte le programme. Peut afficher un message. number min(number, number) Retourne le plus petit de deux scalaires. number max(number, number) Retourne le plus grand de deux scalaires. constant cstring plural(int x) Retourne le pluriel "s" si le nombre x > 0. array range(int x, int y) Génère un tableau des entiers compris entre x et y. cstring str(number) Convertit un nombre en chaîne de charactères. void swap(dyn, dyn) Echange le contenu de deux variables. text pad(text t, len l [, text c ] [, int o]]) Complète un texte avec des espaces ou la chaîne de caractères donnée. t: text à compléter. l: longueur à atteindre. c: texte à ajouter, des espaces par défaut. o: option STR_PAD_LEFT, STR_PAD_BOTH, par défaut à droite. (Voir: str_pad)
Casting
text chr(integer) Retourne le charactère pour une valeur ASCII. Ex: chr(32) retourne un espace blanc. int ord(text) Retourne la valeur ASCII d'un charactère. int intval(any) int doubleval(any) natural naturalval(any) text strval(any) Convertit un nombre en text. char *str(any) Convertit un nombre en chaîne de charactères C. boolean boolval(int)
Fonctions de fichiers (voir aussi les méthodes du type File):
void exec(text) Passe une commande au système d'exploitation. boolean file_exists(text) Teste si le fichier dont le nom est en argument existe. number filesize(text) Retourne la taille. number filetime(text) Retourne la taille (utiliser la fonction date pour afficher). text filetype(text) Retourne "dir" ou "file". boolean rename(text, text) Renomme un fichier. Retourne faux en cas d'échec. void system(text commande) Passe une commande au système d'exploitation. boolean unlink(text) Efface un fichier. Retourne true si effacé.
Fonctions de répertoire:
boolean chdir(text) Change le répertoire courant. Retourne false si échec. boolean mkdir(text) Crée un sous-répertoire. Retourne true si créé. boolean rmdir(text) Efface un sous-répertoire. Retourne true si éffacé. text getcwd() Retourne le chemin répertoire courant.
Fonctions mathématiques:
number abs(number) Retourne la valeur absolue d'un nombre. real acos(real) real asin(real) real atan(real) number ceil(number) Retourne le nombre arrondi à l'entier supérieur. real cos(real) real exp(real) number floor(number) Retourne le nombre arrondit à l'entier inférieur. number fmod(number, number) Return le modulo de deux nombres. real log(real) number pow(number, number) Retourne la puissance n d'un nombre. int rand() Retourne un nombre aléatoire. void randomize() Démarre une séquence de nombres aléatoires. real round(real) Arrondi au plus proche, plancher ou plafond. real sin(real) number sqrt(number) Retourne la racine d'un nombre. real tan(real)
Fonctions de temps:
int time() Temps en millisecondes depuis le 1 Janvier 1970. dict localtime() Temps et date courant lors de l'appel, dans un dictionaire, voir ci-dessous.
Clé du dict retourné par localtime:
tm_sec Secondes après la minute [0,61] tm_min Minutes après l'heure [0,59] tm_hour Heures après minuit [0,23] tm_mday Jour du mois [1,31] tm_mon Mois à partir de Janvier [0,11] tm_year Année depuis 1900 tm_wday Jour à partir de Dimanche [0,6] tm_yday Jour depuis le 1 Janvier [0,365] tm_isdst Indicateur d'heure d'hiver
Ce chapitre sera remplacé par les chapitres "XML statique" et "XML dynamique".
Ce qui est décrit ici est fonctionnel dans le compilateur de Scriptol en C++,
et restera compatible avec le nouveau mode d'utilisation de XML, plus simple,
qui est actuellement implémenté dans l'interpréteur.
Dom
Pour utiliser le document XML, une instance de dom doit être créée.
L'arborescence du dom est ensuite remplie par la méthode build() :
dom mondom
mondom.build()
Pour afficher le document, utiliser la méthode display().
Pour le sauver, la méthode save() avec le nom de fichier en argument.
Dans les deux cas, l'argument dom.LIGHT permet la présentation allégée.
Vous pouvez assigner un document dans un dom à un autre dom avec la
méthod assign.
Chemin
Une fois l'arborescence créée, vous pouvez accéder aux données et aux
attributs des éléments avec les méthodes de dom.
Mais Scriptol a une syntaxe spéciale pour pointer sur un élément dans le
document. Les éléments et éléments imbriqués sont traités comme des objets
et des sous-objets:
La syntaxe est:
instance [.nomelement]* "[" nom-attribut : value"]" ? [.nom-méthode(arguments)]
- le nom de l'instance de dom,
- un point suivi par le nom de l'élément,
- ceci pour chaque sous-élément,
- un couple attribut : valeur entre crochets, si nous voulons sélectionner un
élément parmi plusieurs de même nom,
- un point suivi par une méthode et ses arguments.
Si l'on veut juste pointer sur un élément, on utilise la méthode at().
Mais l'on peut ajouter toute autre méthode de dom au chemin d'un élément.
Voir demoxml.sol pour exemple.
Lecture et écriture
On peut lire et changer la valeur d'un attribut, de même pour les données.
- getValue(nom-attribut) retourne la valeur de l'attribut en argument.
- setValue(nom-attribut, valeur) assigne une valeur à un attribut.
- getData() retourne les données.
- setData(texte) change ou assigne le texte donné en paramètre.
Les données peuvent être aussi assignées directement:
mondom.unelement.souselement.setData("quelque texte") ou mondom.unelement.souselement = "quelque texte"
Itérateur
La classe dom class peut aussi utiliser le document comme une pile XML.
Plusieurs méthodes forment l'itérateur.
- begin() pointe sur le premier élément du document. - next() déplace sur l'élément suivant (dans le même élément conteneur). - up() déplace sur le successeur du conteneur. - down() pointe sur le sous-élément de l'élément courant. - found() retourne vrai si le successeur ou sous-élément existe, faux autrement.Une fois un élément pointé, on accède aux données avec les méthodes suivantes.
Insérer et supprimer des éléments
Vous pouvez insérer des éléments soit comme sous-élément ou comme successeur
d'un élément pointé, ou supprimer un élément pointé.
Syntaxe:
nominstance.chemin.addNext(xnode) nominstance.chemin.addChild(xnode) nominstance.chemin.remove()
Pour insérer un élément, vous devez le déclarer dans un aute document XML.
Vous pouvez déplacer un élément en l'insérant à une nouvelle position, puis
en supprimant l'occurence originelle.
HTML
Une page HTML a ce format:
xml html ...content... /html /xml
Scriptol implémente la déclaration d'objets Java,
grâce au modifieur "java", et pourvu que l'extension Java soit activée
(voir la fiche: install).
De la même façon que l'on inclut les fichiers dont on veut utiliser le contenu,
il faut importer les fichiers d'une classe Java pour l'utiliser.
Une fois la classe importée, on peut déclarer des instances et appeler ses
méthodes comme pour une classe Scriptol.
Le fichier source java doit être compilé par le compilateur java en .class
avant d'être importé.
La syntaxe est:
import java cheminclasse-nomclasse ou import ... déclarations de classes ... /import
Si le mot "java" est au début du chemin de la classe, le compilateur
l'identifie et le modifieur peut être omis:
Exemples:
import java java.awt.Dialog déclaration valide import java.awt.Dialog est aussi valide import java MaClasse déclaration valide import MaClasse n'est pas valide pour une classe Java.
Déclarer une instance d'une classe Java est comme
déclarer une instance d'une classe Scriptol.
Exemple:
java.awt.Dialog maDialogue ... ou simplement Dialog monDialogue MaClass monInstance
Si "Dialog" n'est déclaré comme classe Scriptol vous pouvez omettre le chemin.
Une fois l'instance déclarée, vous l'utilisez comme tout autre objet.
monDialogue.setVisible(true) monInstance.disp() print monInstance.x
Si vous écrivez votre propre classe Java, elle doit être dans un fichier séparé portant le nom de la classe, avec l'extension .java. Elle doit être compilée par javac.
Le traitement des exceptions n'est supporté que par les langages cibles C++
et PHP 5.
Syntaxe:
extern class exception string what() /class /extern try ... quelques instructions ... catch(exception e) print e.what() /try
Le préprocesseur permet d'écrire des programmes scriptol avec des mot-clés
dans toute langue.
Pour l'utiliser, il faut:
1) une liste de mot-clés.
2) l'option -t en ligne de commande (ne marche pas avec l'option -w).
3) une entrée dans le fichier solc.ini ou solp.ini (ou .cfg) de la forme:
Keywords=extension
L'extension est un code de deux lettres selon la langue utilisée, exemple:
Keywords=fr ...pour la langue française.
La liste originale des mot-clés est dans le fichier "keywords.en". S'il n'y a
pas de liste dans la langue que vous voulez utiliser il faut la créer avec
chaque mot étranger suivi par l'équivalent anglais (prendre keywords.fr pour
exemple).
Si le fichier ".ini" ou ".cfg" propre à un source n'a pas d'entrée Keyword,
l'option -t sera ignorée pour ce fichier.
- les symboles <- et ->.
- le mot-clé string est remplacé par cstring.
- les déclarations externes char * sont remplacées par cstring.
- l'opérateur match et sa définition sont obsolètes.
- les méthodes sur les nombres sont inutiles et supprimées.
- utiliser () pour un tableau vide est dépassé. Utiliser plutôt {} ou array().
- le préfixe pour une chaîne PHP est dépassé et inutile.