La structure d'un programme
Écrire un programme que le compilateur accepte : lignes et deux-points, les six formes de commentaire, noms et casse, chaînes, la règle des parenthèses, et les garde-fous qui refusent une ligne.
En un mot#
Un programme BASIC est une liste de lignes. Chaque ligne porte une instruction,
ou plusieurs séparées par :. Le compilateur lit tout le programme avant de le
lancer, et il refuse une ligne qu'il ne comprend pas au lieu de deviner.
Ce chapitre traite de la forme d'un programme. Les valeurs qu'il manipule sont dans Variables et types, et les opérateurs dans Constantes et opérateurs.
Lignes et instructions#
<statement>
<statement> : <statement> [: <statement> ...]
<label>:
<label>: <statement> [: <statement> ...]
x = 10
y = 20 : total = x + y
Console(Str(total)) ' 30
- Une instruction par ligne, ou plusieurs séparées par
:. - L'indentation est libre. Les espaces et tabulations en début de ligne ne comptent pas. Les lignes vides sont permises partout.
- Un
:dans une chaîne ou entre parenthèses ne coupe pas la ligne :"time: 12:30"reste une seule chaîne. - Un bloc peut tenir sur une ligne :
FOR i = 1 TO 5 : total = total + i : NEXT.
Un IF sur une ligne garde tout ce qui suit THEN#
Après THEN, chaque : appartient au IF. Toutes les instructions ne
s'exécutent que si la condition est vraie.
lives = 0
IF lives = 0 THEN Console("Partie perdue") : lives = 3
Console(Str(lives)) ' 3
Le détail est dans Le contrôle du flux.
Les étiquettes#
Un nom suivi de : en début de ligne est une étiquette, la cible de
GOSUB et de GOTO. L'étiquette peut porter des instructions sur la même
ligne.
GOSUB Greet
Console("retour") ' affiché en second
END
Greet: Console("bonjour") : RETURN
⚠️ À cause de cette règle, un : placé juste après le premier mot d'une ligne
déclare toujours une étiquette. start: x = 1 est l'étiquette start, avec
x = 1 pour corps, et le compilateur réclame son RETURN :
BASIC label start requires RETURN.
Ce qui n'existe pas#
| Usage classique | Dans aukimi |
|---|---|
Numéros de ligne (10 x = 1) | refusés : Not a BASIC statement |
Suite de ligne (_ en fin de ligne) | refusée : écrivez l'instruction sur une ligne |
; comme commentaire | ce n'est pas un commentaire : la suite est compilée comme du code |
Une ligne qui n'est qu'une clôture de bloc de code Markdown (trois accents graves, avec ou sans nom de langage) est ignorée. Du code copié d'une page web avec sa clôture tourne quand même, et ses numéros de ligne restent justes.
Les commentaires#
Six formes sont acceptées.
| Forme | Où | Exemple |
|---|---|---|
' | partout ; le reste de la ligne est un commentaire | x = 1 ' note |
// | partout ; le reste de la ligne est un commentaire | x = 1 // note |
REM | en début de ligne, ou après une instruction | REM note |
` (accent grave) | en début de ligne, ou après une instruction | x = 1 ` note |
REMSTART … REMEND | bloc ; chacun des deux mots ouvre sa ligne | voir plus bas |
/* … */ | bloc ; /* ouvre sa ligne | voir plus bas |
' Un commentaire sur toute la ligne
REM Un autre commentaire sur toute la ligne
// Un commentaire de ligne à la manière du C
x = 1 ' après une instruction
y = 2 // après une instruction aussi
z = 3 ` la forme accent grave
REMSTART
Un bloc de notes
sur plusieurs lignes
REMEND
/* Un bloc à la manière du C
sur plusieurs lignes */
Console(Str(x + y + z)) ' 6
Utilisez
'ou//. Ce sont les deux seules formes sûres partout. Les quatre autres existent pour que le code venu d'autres dialectes compile encore.
⚠️ Un : dans un commentaire REM ou accent grave coupe la ligne#
Le découpage des lignes s'arrête à ' et à //. Il ne s'arrête ni à REM ni
à l'accent grave. Un deux-points placé après eux termine le commentaire, et la
suite est compilée comme du code.
x = 1 REM note: this part is compiled
Not a BASIC statement: this part is compiled
Il en va de même pour un commentaire accent grave sur toute la ligne qui
contient un deux-points. Un REM sur toute la ligne est sûr ; un REM après
une instruction ne l'est pas.
⚠️ Les commentaires en bloc ont trois règles#
-
REMSTART,REMENDet/*ouvrent leur ligne.x = 1 REMSTARTn'est pas un commentaire en bloc. -
Tout ce qui est sur la ligne de
/*est commentaire, et la fin de ligne après*/aussi. Le code écrit là ne s'exécute jamais :/* setup */ Console("jamais affiché") Console("affiché") ' affiché -
Une ligne dans un bloc ne doit pas commencer par un seul mot suivi de
:. Le compilateur litTODO:ouNote:comme une étiquette et refuse le programme.REMSTART TODO: tidy this up REMENDBASIC label TODO requires RETURNÉcrivez
TODO - à ranger, ou utilisez des lignes'.
Un bloc jamais refermé est une erreur : REMSTART requires REMEND, ou
/* requires */.
Casse et noms#
Tout est insensible à la casse : mots-clés, noms de commandes, variables,
fonctions utilisateur, champs d'enregistrement et constantes. IF, If et
if sont le même mot. Console, CONSOLE et console sont la même commande.
La première graphie d'un nom est conservée, et toutes les suivantes sont réécrites sur elle.
Score = 1
SCORE = SCORE + 1
score = score + 1
Console(Str(sCoRe)) ' 3
if score = 3 then Console("les mots-clés en minuscules marchent aussi")
Deux exceptions :
| Nom | Règle |
|---|---|
PI | en majuscules seulement. pi ou Pi est un nom inconnu : le programme s'arrête sur … is not defined. |
TRUE, FALSE, NULL | n'importe quelle casse. |
area = PI * 2 ^ 2
Console(Str(area)) ' 12.566370614359172
Écrire un nom#
- Des lettres, des chiffres et
_. Il commence par une lettre ou par_. - Une variable peut finir par un sigil :
$,#,%ou&. Ce que fait un sigil est dans Variables et types. - Une constante s'écrit avec
#devant :#MAX_LIVES. Voir Constantes et opérateurs.
Quels noms peuvent partager une graphie#
| Paire | Même graphie permise ? |
|---|---|
une variable et un champ d'enregistrement (speed et s.speed) | oui, ils ne se croisent jamais |
| une variable et une FUNCTION utilisateur | oui |
une variable et une commande du catalogue (left et Left) | oui, dès que le programme affecte la variable par nom = … |
| une FUNCTION utilisateur et une commande du catalogue | oui, et la fonction utilisateur l'emporte |
une constante et une variable (#SPEED et SPEED) | ⚠️ non : écrites pareil, le programme ne démarre pas |
TYPE Ship
speed
ENDTYPE
s AS Ship
s.speed = 4
speed = 9
Console(Str(s.speed) + " " + Str(speed)) ' 4 9
left = 10
x = left + 1
Console(Str(x) + Left("abc", 1)) ' 11a
FUNCTION Sin(v)
ENDFUNCTION v * 2
Console(Str(Sin(90))) ' 180 : votre Sin, pas celui du catalogue
⚠️ Les mots de JavaScript ne sont pas libres#
Le BASIC se compile en JavaScript. Une variable qui porte le nom d'un mot-clé JavaScript compile, mais le programme ne démarre pas.
class = 3
Évitez ces noms : class, const, debugger, default, enum, export,
extends, import, in, instanceof, let, new, super, switch,
this, throw, typeof, var, void, await. Évitez aussi les noms qui
commencent par _b ou __basic, et nextFrame : le compilateur s'en sert
pour lui-même.
Les chaînes#
"<text>"
- Guillemets droits doubles seulement. Un
'ouvre un commentaire, donc'texte'n'est pas une chaîne. - Deux échappements existent :
\"pour un guillemet, et\\pour un antislash. - Tout autre antislash est un antislash ordinaire. Un chemin Windows marche
tel quel, et
\nfait deux caractères, pas un retour à la ligne. - Une chaîne tient sur une ligne.
path$ = "media\background5.jpg"
quote$ = "Elle a dit \"salut\""
slash$ = "a\\b"
Console(path$) ' media\background5.jpg
Console(quote$) ' Elle a dit "salut"
Console(slash$) ' a\b
Pour un retour à la ligne ou un guillemet, construisez la chaîne avec Chr :
twoLines$ = "première" + Chr(10) + "seconde"
quoted$ = Chr(34) + "aukimi" + Chr(34)
Console(quoted$) ' "aukimi"
⚠️ Le guillemet doublé de QBasic et de Visual Basic ("") n'est pas pris en
charge. Il compile, mais le programme ne démarre pas. Écrivez \" ou
Chr(34).
say$ = "say ""hi"""
⚠️ Après un \", ne mettez ni : ni ' dans la même chaîne. Le découpage
des lignes ne connaît pas l'échappement : il croit que la chaîne s'arrête là.
label$ = "a\"b: c"
Not a BASIC statement: c"
Utilisez Chr(34) dans une telle chaîne. Les chaînes à {trous} s'écrivent
$"…" : voir Les raccourcis.
Les littéraux#
| Sorte | Exemples |
|---|---|
| entier | 42, -7 |
| décimal | 3.5, .5, 5. |
| exposant | 1.25e2, 1.5E-3 |
| hexadécimal | 0x1F, 0XFF |
| octal | 0c17 |
| binaire | %1010 |
| chaîne | "texte" |
| vérité et absence | TRUE, FALSE, NULL |
| π | PI |
d = 1.25e2
e = 0x1F
f = 0c17
g = %1010
Console(Str(d) + " " + Str(e) + " " + Str(f) + " " + Str(g)) ' 125 31 15 10
Le séparateur décimal est le point, jamais la virgule. Un littéral mal formé
est refusé sur sa ligne : Malformed BASIC numeric literal: 0x1G.
⚠️ $FF (PureBasic) et &HFF (QBasic, Visual Basic) ne sont pas de
l'hexadécimal ici. Écrivez 0xFF.
La façon dont chaque type stocke ces valeurs est dans Variables et types.
La règle des parenthèses#
Un appel de commande porte toujours des parenthèses, même sans argument.
<Command>([<argument> [, <argument> ...]])
elapsed# = Timer()
width = DeviceWidth()
Sync()
Les formes nues d'AGK, de DarkBASIC et de PureBasic sont refusées :
PRINT "hello"
Sync
x = DeviceWidth
BASIC commands require parentheses: Print(...)
BASIC commands require parentheses: Sync(...)
BASIC commands require parentheses: DeviceWidth(...)
C'est ce qui permet au compilateur de distinguer une commande d'une variable.
Un nom que le programme affecte (left = 10) est une variable ; un nom suivi
de ( est un appel.
⚠️ Une variable utilisée seulement par GLOBAL, LOCAL ou CATCH, et jamais
affectée par un simple nom = …, est encore lue comme la commande du même nom.
LOCAL left = 3 dans une fonction est refusé avec
BASIC commands require parentheses: Left(...). Choisissez un autre nom.
Les deux garde-fous#
Deux contrôles passent sur chaque ligne.
Commande inconnue#
Un appel dont le nom n'est ni une commande du catalogue, ni une fonction intégrée du compilateur, ni une FUNCTION utilisateur, ni un tableau, une liste ou un dictionnaire est refusé. Quand une commande du catalogue s'écrit presque pareil, le compilateur la nomme.
Prnt("hello")
Unknown BASIC command: Prnt() — did you mean Print()?
Blorp(1, 2)
Unknown BASIC command: Blorp()
La suggestion vient quand le nom diffère d'une lettre au plus (noms courts, jusqu'à quatre lettres) ou de deux lettres (noms plus longs).
Pas une instruction#
Une instruction est une affectation, un appel, ou commence par un mot-clé. Tout le reste est refusé, et le message cite le début de la ligne.
go to the shop
VAR n = 5
Not a BASIC statement: go to the shop
Not a BASIC statement: VAR n = 5
Ce que les garde-fous ne voient pas#
- Un appel après un point (
obj.method(...)) n'est pas comparé au catalogue. C'est ce qui garde les objets JavaScript accessibles. - Une expression inachevée, comme
x = 1 +oux =, passe les deux contrôles. Le programme ne démarre pas ensuite. - Un nom lu mais jamais affecté compile, et arrête le programme quand la
ligne s'exécute (
… is not defined). Voir Variables et types.
Print dessine, Console journalise#
| Commande | Ce qu'elle fait |
|---|---|
Print(...) | dessine du texte sur l'écran du jeu ; un jeu l'appelle à chaque image |
Console(...) | écrit une ligne dans la console de l'éditeur |
Debug(...) | la même chose que Console, sous le nom de PureBasic |
ConsoleWarning(...), ConsoleError(...) | une ligne d'avertissement ou d'erreur dans la console |
ClearConsole() | vide la console |
Pour vérifier une valeur pendant que vous travaillez, utilisez Console. Tous
les exemples de ce manuel le font.
Un programme minimal#
En ligne droite : tourne une fois#
Sans boucle d'image, le programme tourne une fois de haut en bas, puis s'arrête. C'est la bonne forme pour un test, un outil, ou tout ce qui écrit dans la console.
name$ = "aukimi"
Console("Bonjour, " + name$) ' Bonjour, aukimi
Avec une boucle d'image : tourne à chaque image#
Un jeu place sa préparation au-dessus de DO, et le corps de l'image entre
DO et LOOP. Sync() termine chaque image.
frames = 0
DO
frames = frames + 1
Print("Image " + Str(frames))
Sync()
LOOP
Une boucle sans Sync() ne laisserait jamais l'écran se dessiner, elle est
donc refusée :
DO
x = x + 1
LOOP
DO/LOOP requires SYNC() so the loop can yield a frame
⚠️ Dans un programme avec DO … LOOP, une FUNCTION ne voit pas les variables
ordinaires posées au-dessus de DO. Déclarez les valeurs partagées avec
GLOBAL. La raison, et la solution, sont dans
Variables et types.
Il y a une seule boucle DO … LOOP de premier niveau par programme. Tout le
reste sur les images, Wait, Sleep et les tâches est dans
Boucle de jeu et tâches.
Vous venez d'un autre BASIC#
| Vous écrivez | Dans aukimi |
|---|---|
PRINT "x", Sync, Debug "x" | Print("x"), Sync(), Debug("x") |
PRINT pour voir une valeur | Console(...) : Print dessine sur l'écran du jeu |
10 GOTO 20 | pas de numéros de ligne ; utilisez des étiquettes |
_ pour continuer une ligne | une instruction par ligne |
"" dans une chaîne | \" ou Chr(34) |
&HFF, $FF | 0xFF |
pi | PI |
; commentaire | ' commentaire |