Élément techniques phases compilation

a marqué ce sujet comme résolu.

Ta question n’est effectivement pas claire du tout… L’analyse du typage est purement statique, il n’y a aucune notion de "retourner" ou renvoyer qui intervient.

Reprenons ton exemple, légèrement modifié pour donner un type concret à a immédiatement :

let a = 0u8;
let b = match a {
    0 => "null",
    _ => "nonzero",
};

Le système de type va attribuer des types à chaque expression dans sa représentation interne, ressemblant par exemple à ça dans un premier temps :

Assign(
    lhs = Ident("a", T_a),
    rhs = Literal(0, u8));
Assign(
    lhs = Ident("b", T_b),
    rhs = MatchStatement(
        expr = Expr(Ident("a", T_a), T_e),
        branches = [
            Branch(
                pat = Pattern(Literal(0, T_i), T_p1),
                val = Expr(Literal("null", &'static str), T_b1)
            ),
            Branch(
                pat = BlankPattern,
                val = Expr(Literal("nonzero", &'static str), T_b2)
            ),
        ],
        T_m,
    );

Les trucs en T_* sont les types pas encore connus à ce stade (i.e. qui n’étaient pas explicites). Puis le moteur d’inférence de types (ça peut paraître simple, mais en fait c’est un gros morceau !) construit un ensemble de contraintes que le code nous donne :

T_a < u8;
T_b < T_m;
T_e < T_a;
T_p1 < T_e;
T_e < T_i;
T_m < (T_b1, T_b2);
T_b1 < &'static str;
T_b2 < &'static str;

T_1 < T_2 veut dire que T_2 doit être cohérent avec T_1, autrement dit T_1 == T_2, ou bien T_2 est un sous-type de T_1 (en Rust, le seul cas de sous-typage est via les lifetimes) ou bien T_2 peut être coercé en T_1 implicitement (e.g. &mut T peut être coercé en &T).

Comme tu vois, tout ceci fonctionne purement par un set de contraintes que le code nous donne, la partie difficile étant d’écrire le solveur de contraintes correctement.

+2 -0

Bonjour,

J’ai réfléchis au fait que selon mes attentes je souhaitais que le back-end de mon langage soit effectué par LLVM, mais après réflexion, je pense que c’est trop optimiste pour mon expérience dans le domaine. Alors je me suis dis que ce serait une machine virtuelle qui s’occuperai d’exécuter le bytecode.

J’ai alors commencé par voir sur Wikipédia ce qu’était une VM et la partie qui me concerne est la suivante:

Dans la technique de la machine virtuelle de haut niveau, le code source des programmes est traduit par un compilateur en un code objet intermédiaire, qui sera traduit plus tard en un code machine utilisant le jeu d’instructions spécifique du processeur qui va simuler la machine. Les programmes sont distribués sur le marché sous forme de bytecode – du code intermédiaire – et peuvent être exécutés par tout appareil informatique qui possède le logiciel nécessaire pour simuler cette machine. Le bytecode utilise un jeu d’instruction d’une machine fictive, qui n’existe pas dans le commerce et il est conçu pour faire abstraction du jeu d’instruction final qui sera utilisé pour exécuter le programme.

Ce passage me laisse perplexe car je ne comprend pas si la machine virtuelle créé le bytecode et l’exécute, ou bien qu’ele créé du code objet puis le converti en code machine en bytecode qu’elle sera la seule à pouvoir exécuter.

Pouvez vous m’expliquer de façon plus complète la façon d’on ça se déroule, et connaisez vouz des ressources à ce sujet là (machine virtuelle de haut niveau).

Cordialement.

La machine virtuelle va lire ton programme sous forme de bytecode spécifique que tu auras toi-même défini et l’exécuter directement.

Mais cette exécution concrètement se traduit par le fait d’envoyer des instructions au processeur : ce n’est pas toi qui le fera directement car tu utiliseras un langage de plus haut niveau pour écrire ta VM, mais c’est ce qui se passe dans les faits.

Pour ce qui est des ressources, il me semble qu’on t’a déjà fourni tout ça dans les documentations à propos de LLVM.

Salut,

Je pense qu’un truc qui pourrait t’aider beaucoup à comprendre comment s’articulent toutes les notions de code source, représentation interne, bytecode, code machine, machine virtuelle serait d’implémenter un exemple beaucoup plus simple qu’un langage "complet" tel que tu as essayé jusqu’à présent. J’ai l’impression que pour l’instant, tu as passé beaucoup de temps à lire des trucs divers et variés sans forcément tout comprendre, mais sans rien implémenter de concret jusqu’au bout. En soi, c’est pas un mauvais exercice, mais il y a un moment où il faut se jeter à l’eau et implémenter quelque chose de bout en bout pour vraiment voir comment tout ça fonctionne.

Un exercice que je te propose donc est d’écrire un programme capable de faire tourner du brainfuck. Je me garderai bien d’étiquetter d’entrée de jeu ce que tu vas écrire, écrit simplement un programme (il a pas besoin d’être rapide ni bien écrit) qui prend un programme brainfuck en entrée et sort le résultat attendu. La page wikipedia explique plutôt bien le langage, et il y a quelque exemples pour vérifier que ton implémentation fonctionne.

Une fois que c’est fait, on peut réfléchir à coller les termes que tu as croisés jusqu’à maintenant à ton implémentation, et surtout à comment modifier ce que tu as écrit pour faire apparaître d’autres concepts.

EDIT : je t’invite aussi à relire cette réponse que j’ai apportée à un autre de tes sujets qui pourrait aussi t’aider à y voir un peu plus clair.

+2 -0

Un autre exercice qui irait dans ce sens serait de construire une calculatrice :

  • Les jetons sont assez simples à identifier (nombres, opérateurs simples, ± parenthèses)
  • Tu peux commencer très simple (gérer simplement une opération entre deux nombres : 3 * 5) et évoluer comme tu le sens en peaufinant ton parseur (gestion des priorités — 1 + 3 * 5, des parenthèses — (1 + 3) * 5, de l’associativité des opérateurs — 3 - 2 - 1, des opérateurs unaires — 3 * -4)
  • Tu peux facilement y ajouter une partie génération de bytecode par la suite pour explorer ça ensuite (transformer 1 + 3 * 5 en PUSH 1; PUSH 3; PUSH 5; MUL; ADD; par exemple)

Et ça permet quelque chose de plus évolutif :

  • Ajouter la gestion de variables à la calculatrice (a = 5, 3 * a)
  • Intégrer des conditions
  • Et des fonctions

Qui fait qu’au final tu te retrouves à implémenter pour de vrai un petit langage de programmation.


Ce n’est pas une proposition qui contredit la précédente sur le brainfuck, je pense que c’est plutôt complémentaire.

Je te conseille de t’exercer sur les deux aspects, qui te feront construire des langages différents et donc explorer différents aspects.

Ma question est: comment faire pour créer le principe de retournement dans un langage de programmation. Par exemple, quand tu fais en Rust

let a = 2;

let b = match b { 0 => "0", 1 => "Dragon", _ => "MHH"

 ```
 
 IL n'y a pas de notion de retournement ici. C'est du pattern matching ou du switch expression.
 C'est donc une expression. 
 
 La différence fondamentale entre une expression et une instruction qui n'est pas une expression, c'est que l'expression possède toujours un résultat, tandis que l'instruction jamais.
 Dit autrement, à la fin de l'exécution d'une expression, elle laissera une valeur sur la pile d'exécution (éventuellement plusieurs comme c'est possible en lua).
 
 Mais comme l'ont dit les précédents messages, tu es dans la confusion parce que tu essaies d'implémenter un truc trop compliqué pour toi.
 Commence plus simple avec une simple calculatrice est un très bon conseil. Une fois que tu as une calculatrice fonctionnelle, tu peux y ajouter des variables, différents types simples genre bool, etc.
 
 Une excellente ressource que je peux partager est craftinginterpreter.com. Le livre fait le tour d'à peu près tous les sujets connexes permettant de construire un langage complet de A à Z.
 La première partie est en Java, mais rien ne t'interdit de suivre le livre et les exercices en le remplaçant par Python, Rust, ou ce que tu veux d'autre. La machine virtuelle vient dans la seconde partie qui est présentée en C, mais là à nouveau rien ne t'interdit de continuer à faire du Python si tu veux. Vu que c'est pour le fun, ton langage n'a pas besoin d'être ultra rapide.
 
 
+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte