Remarque: Lorsque j'ai utilisé "complexe" dans le titre, je veux dire que l'expression a de nombreux opérateurs et opérandes. Non pas que l'expression elle-même soit complexe.
J'ai récemment travaillé sur un simple compilateur pour l'assemblage x86-64. J'ai terminé la partie frontale principale du compilateur - lexer et analyseur - et je suis maintenant capable de générer une représentation d'arbre de syntaxe abstraite de mon programme. Et comme mon langage sera tapé statiquement, je passe maintenant à la phase suivante: taper le code source. Cependant, je suis arrivé à un problème et je n'ai pas pu le résoudre raisonnablement moi-même.
Prenons l'exemple suivant:
L'analyseur de mon compilateur a lu cette ligne de code:
int a = 1 + 2 - 3 * 4 - 5
Et l'a converti en AST suivant:
=
/ \
a(int) \
-
/ \
- 5
/ \
+ *
/ \ / \
1 2 3 4
Il doit maintenant taper vérifier l'AST. il commence par le premier type de vérification de l' =
opérateur. Il vérifie d'abord le côté gauche de l'opérateur. Il voit que la variable a
est déclarée comme un entier. Il doit donc maintenant vérifier que l'expression de droite s'évalue en un entier.
Je comprends comment cela pourrait être fait si l'expression n'était qu'une seule valeur, comme 1
ou 'a'
. Mais comment cela pourrait-il être fait pour les expressions avec plusieurs valeurs et opérandes - une expression complexe - comme celle ci-dessus? Pour déterminer correctement la valeur de l'expression, il semble que le vérificateur de type devrait réellement exécuter l'expression elle-même et enregistrer le résultat. Mais cela semble évidemment aller à l'encontre du but de séparer les phases de compilation et d'exécution.
La seule autre façon dont j'imagine que cela pourrait être fait est de vérifier récursivement la feuille de chaque sous-expression dans l'AST et de vérifier que tous les types de feuille correspondent au type d'opérateur attendu. Donc, en commençant par l' =
opérateur, le vérificateur de type scannerait alors tous les AST du côté gauche et vérifierait que les feuilles sont toutes des entiers. Il répéterait alors ceci pour chaque opérateur dans la sous-expression.
J'ai essayé de faire des recherches sur le sujet dans ma copie de "The Dragon Book" , mais il ne semble pas entrer dans les détails, et réitère simplement ce que je sais déjà.
Quelle est la méthode habituelle utilisée lorsqu'un compilateur vérifie les expressions avec de nombreux opérateurs et opérandes? Certaines des méthodes que j'ai mentionnées ci-dessus sont-elles utilisées? Sinon, quelles sont les méthodes et comment fonctionneraient-elles exactement?
double a = 7/2
essaierait d'interpréter le côté droit comme double, donc d'essayer d'interpréter le numérateur et le dénominateur comme double et de les convertir si nécessaire; en conséquence a = 3.5
. Le bas vers le haut effectuerait une division entière et ne se convertirait qu'à la dernière étape (affectation) a = 3.0
.
int a = 1 + 2 - 3 * 4 - 5
mais àint a = 5 - ((4*3) - (1+2))